xref: /openbsd-src/sys/netinet/in.c (revision a61bf6f2a88e2df8799431eff1412c6579005e38)
1*a61bf6f2Sbluhm /*	$OpenBSD: in.c,v 1.186 2024/01/06 10:58:45 bluhm Exp $	*/
2b400e158Sniklas /*	$NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $	*/
3df930be7Sderaadt 
4df930be7Sderaadt /*
5c800a1d2Sitojun  * Copyright (C) 2001 WIDE Project.  All rights reserved.
6c800a1d2Sitojun  *
7c800a1d2Sitojun  * Redistribution and use in source and binary forms, with or without
8c800a1d2Sitojun  * modification, are permitted provided that the following conditions
9c800a1d2Sitojun  * are met:
10c800a1d2Sitojun  * 1. Redistributions of source code must retain the above copyright
11c800a1d2Sitojun  *    notice, this list of conditions and the following disclaimer.
12c800a1d2Sitojun  * 2. Redistributions in binary form must reproduce the above copyright
13c800a1d2Sitojun  *    notice, this list of conditions and the following disclaimer in the
14c800a1d2Sitojun  *    documentation and/or other materials provided with the distribution.
15c800a1d2Sitojun  * 3. Neither the name of the project nor the names of its contributors
16c800a1d2Sitojun  *    may be used to endorse or promote products derived from this software
17c800a1d2Sitojun  *    without specific prior written permission.
18c800a1d2Sitojun  *
19c800a1d2Sitojun  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20c800a1d2Sitojun  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21c800a1d2Sitojun  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22c800a1d2Sitojun  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23c800a1d2Sitojun  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24c800a1d2Sitojun  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25c800a1d2Sitojun  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26c800a1d2Sitojun  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27c800a1d2Sitojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28c800a1d2Sitojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29c800a1d2Sitojun  * SUCH DAMAGE.
30c800a1d2Sitojun  */
31c800a1d2Sitojun 
32c800a1d2Sitojun /*
33df930be7Sderaadt  * Copyright (c) 1982, 1986, 1991, 1993
34df930be7Sderaadt  *	The Regents of the University of California.  All rights reserved.
35df930be7Sderaadt  *
36df930be7Sderaadt  * Redistribution and use in source and binary forms, with or without
37df930be7Sderaadt  * modification, are permitted provided that the following conditions
38df930be7Sderaadt  * are met:
39df930be7Sderaadt  * 1. Redistributions of source code must retain the above copyright
40df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer.
41df930be7Sderaadt  * 2. Redistributions in binary form must reproduce the above copyright
42df930be7Sderaadt  *    notice, this list of conditions and the following disclaimer in the
43df930be7Sderaadt  *    documentation and/or other materials provided with the distribution.
4429295d1cSmillert  * 3. Neither the name of the University nor the names of its contributors
45df930be7Sderaadt  *    may be used to endorse or promote products derived from this software
46df930be7Sderaadt  *    without specific prior written permission.
47df930be7Sderaadt  *
48df930be7Sderaadt  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49df930be7Sderaadt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50df930be7Sderaadt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51df930be7Sderaadt  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52df930be7Sderaadt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53df930be7Sderaadt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54df930be7Sderaadt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55df930be7Sderaadt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56df930be7Sderaadt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57df930be7Sderaadt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58df930be7Sderaadt  * SUCH DAMAGE.
59df930be7Sderaadt  *
60df930be7Sderaadt  *	@(#)in.c	8.2 (Berkeley) 11/15/93
61df930be7Sderaadt  */
62df930be7Sderaadt 
63df930be7Sderaadt #include <sys/param.h>
646dff20b9Sangelos #include <sys/systm.h>
65df930be7Sderaadt #include <sys/ioctl.h>
66df930be7Sderaadt #include <sys/malloc.h>
67df930be7Sderaadt #include <sys/socket.h>
68df930be7Sderaadt #include <sys/socketvar.h>
69df930be7Sderaadt 
70df930be7Sderaadt #include <net/if.h>
712bea58a8Smpi #include <net/if_var.h>
72df930be7Sderaadt #include <net/route.h>
73df930be7Sderaadt 
74df930be7Sderaadt #include <netinet/in.h>
75df930be7Sderaadt #include <netinet/in_var.h>
76b400e158Sniklas #include <netinet/igmp_var.h>
77df930be7Sderaadt 
78dcac5ed4Sniklas #ifdef MROUTING
79dcac5ed4Sniklas #include <netinet/ip_mroute.h>
80dcac5ed4Sniklas #endif
81dcac5ed4Sniklas 
82df930be7Sderaadt #include "ether.h"
83df930be7Sderaadt 
84df930be7Sderaadt 
85eab69afcSmpi void in_socktrim(struct sockaddr_in *);
86287546eaSitojun 
8736d351c1Skn int in_ioctl_set_ifaddr(u_long, caddr_t, struct ifnet *);
8836d351c1Skn int in_ioctl_change_ifaddr(u_long, caddr_t, struct ifnet *);
8939915755Stb int in_ioctl_get(u_long, caddr_t, struct ifnet *);
907899d34dSmpi void in_purgeaddr(struct ifaddr *);
91074bbb20Smpi int in_addhost(struct in_ifaddr *, struct sockaddr_in *);
92074bbb20Smpi int in_scrubhost(struct in_ifaddr *, struct sockaddr_in *);
935105ae10Smpi int in_insert_prefix(struct in_ifaddr *);
945105ae10Smpi void in_remove_prefix(struct in_ifaddr *);
95c800a1d2Sitojun 
96df930be7Sderaadt /*
97df930be7Sderaadt  * Determine whether an IP address is in a reserved set of addresses
98df930be7Sderaadt  * that may not be forwarded, or whether datagrams to that destination
99df930be7Sderaadt  * may be forwarded.
100df930be7Sderaadt  */
101df930be7Sderaadt int
in_canforward(struct in_addr in)10280481146Sdlg in_canforward(struct in_addr in)
103df930be7Sderaadt {
10464aa4cc7Sitojun 	u_int32_t net;
105df930be7Sderaadt 
106a96e5a4eSclaudio 	if (IN_MULTICAST(in.s_addr))
107df930be7Sderaadt 		return (0);
108df930be7Sderaadt 	if (IN_CLASSA(in.s_addr)) {
109df930be7Sderaadt 		net = in.s_addr & IN_CLASSA_NET;
11080481146Sdlg 		if (net == 0 ||
11180481146Sdlg 		    net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
112df930be7Sderaadt 			return (0);
113df930be7Sderaadt 	}
114df930be7Sderaadt 	return (1);
115df930be7Sderaadt }
116df930be7Sderaadt 
117df930be7Sderaadt /*
118df930be7Sderaadt  * Trim a mask in a sockaddr
119df930be7Sderaadt  */
120df930be7Sderaadt void
in_socktrim(struct sockaddr_in * ap)12180481146Sdlg in_socktrim(struct sockaddr_in *ap)
122df930be7Sderaadt {
12364aa4cc7Sitojun 	char *cplim = (char *) &ap->sin_addr;
12464aa4cc7Sitojun 	char *cp = (char *) (&ap->sin_addr + 1);
125df930be7Sderaadt 
126df930be7Sderaadt 	ap->sin_len = 0;
127df930be7Sderaadt 	while (--cp >= cplim)
128df930be7Sderaadt 		if (*cp) {
129df930be7Sderaadt 			(ap)->sin_len = cp - (char *) (ap) + 1;
130df930be7Sderaadt 			break;
131df930be7Sderaadt 		}
132df930be7Sderaadt }
133df930be7Sderaadt 
134531f8786Sdlg int
in_mask2len(struct in_addr * mask)13580481146Sdlg in_mask2len(struct in_addr *mask)
136287546eaSitojun {
137287546eaSitojun 	int x, y;
138287546eaSitojun 	u_char *p;
139287546eaSitojun 
140287546eaSitojun 	p = (u_char *)mask;
141287546eaSitojun 	for (x = 0; x < sizeof(*mask); x++) {
142287546eaSitojun 		if (p[x] != 0xff)
143287546eaSitojun 			break;
144287546eaSitojun 	}
145287546eaSitojun 	y = 0;
146287546eaSitojun 	if (x < sizeof(*mask)) {
147287546eaSitojun 		for (y = 0; y < 8; y++) {
148287546eaSitojun 			if ((p[x] & (0x80 >> y)) == 0)
149287546eaSitojun 				break;
150287546eaSitojun 		}
151287546eaSitojun 	}
152287546eaSitojun 	return x * 8 + y;
153287546eaSitojun }
154287546eaSitojun 
155531f8786Sdlg void
in_len2mask(struct in_addr * mask,int len)15680481146Sdlg in_len2mask(struct in_addr *mask, int len)
157287546eaSitojun {
158287546eaSitojun 	int i;
159287546eaSitojun 	u_char *p;
160287546eaSitojun 
161287546eaSitojun 	p = (u_char *)mask;
162287546eaSitojun 	bzero(mask, sizeof(*mask));
163287546eaSitojun 	for (i = 0; i < len / 8; i++)
164287546eaSitojun 		p[i] = 0xff;
165287546eaSitojun 	if (len % 8)
166287546eaSitojun 		p[i] = (0xff00 >> (len % 8)) & 0xff;
167287546eaSitojun }
168287546eaSitojun 
169b2a698eaSbluhm int
in_nam2sin(const struct mbuf * nam,struct sockaddr_in ** sin)170b2a698eaSbluhm in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
171b2a698eaSbluhm {
172b2a698eaSbluhm 	struct sockaddr *sa = mtod(nam, struct sockaddr *);
173b2a698eaSbluhm 
174b2a698eaSbluhm 	if (nam->m_len < offsetof(struct sockaddr, sa_data))
175b2a698eaSbluhm 		return EINVAL;
176b2a698eaSbluhm 	if (sa->sa_family != AF_INET)
177b2a698eaSbluhm 		return EAFNOSUPPORT;
178b2a698eaSbluhm 	if (sa->sa_len != nam->m_len)
179b2a698eaSbluhm 		return EINVAL;
180b2a698eaSbluhm 	if (sa->sa_len != sizeof(struct sockaddr_in))
181b2a698eaSbluhm 		return EINVAL;
182b2a698eaSbluhm 	*sin = satosin(sa);
183b2a698eaSbluhm 
184b2a698eaSbluhm 	return 0;
185b2a698eaSbluhm }
186b2a698eaSbluhm 
187df930be7Sderaadt int
in_sa2sin(struct sockaddr * sa,struct sockaddr_in ** sin)18871713a9bSbluhm in_sa2sin(struct sockaddr *sa, struct sockaddr_in **sin)
18971713a9bSbluhm {
19071713a9bSbluhm 	if (sa->sa_family != AF_INET)
19171713a9bSbluhm 		return EAFNOSUPPORT;
19271713a9bSbluhm 	if (sa->sa_len != sizeof(struct sockaddr_in))
19371713a9bSbluhm 		return EINVAL;
19471713a9bSbluhm 	*sin = satosin(sa);
19571713a9bSbluhm 
19671713a9bSbluhm 	return 0;
19771713a9bSbluhm }
19871713a9bSbluhm 
19971713a9bSbluhm int
in_control(struct socket * so,u_long cmd,caddr_t data,struct ifnet * ifp)20080481146Sdlg in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
201df930be7Sderaadt {
202d732431aSmpi 	int privileged;
203d732431aSmpi 
204d732431aSmpi 	privileged = 0;
205d732431aSmpi 	if ((so->so_state & SS_PRIV) != 0)
206d732431aSmpi 		privileged++;
207df930be7Sderaadt 
2086c1326fdSmpi 	switch (cmd) {
20929477734Sflorian #ifdef MROUTING
21078a62425Smpi 	case SIOCGETVIFCNT:
21178a62425Smpi 	case SIOCGETSGCNT:
212a9069a72Skn 		return mrt_ioctl(so, cmd, data);
2136c1326fdSmpi #endif /* MROUTING */
21429477734Sflorian 	default:
215a9069a72Skn 		return in_ioctl(cmd, data, ifp, privileged);
21629477734Sflorian 	}
217d732431aSmpi }
218d732431aSmpi 
219d732431aSmpi int
in_ioctl(u_long cmd,caddr_t data,struct ifnet * ifp,int privileged)220d732431aSmpi in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
221d732431aSmpi {
222d732431aSmpi 	struct ifreq *ifr = (struct ifreq *)data;
223d732431aSmpi 	struct ifaddr *ifa;
224d732431aSmpi 	struct in_ifaddr *ia = NULL;
225b36fd3daSbluhm 	struct sockaddr_in *sin = NULL, oldaddr;
22619223f69Stb 	int error = 0;
227d732431aSmpi 
2286c1326fdSmpi 	if (ifp == NULL)
229145df85aSmpi 		return (ENXIO);
2306c1326fdSmpi 
23139915755Stb 	switch (cmd) {
23239915755Stb 	case SIOCGIFADDR:
23339915755Stb 	case SIOCGIFNETMASK:
23439915755Stb 	case SIOCGIFDSTADDR:
23539915755Stb 	case SIOCGIFBRDADDR:
23639915755Stb 		return in_ioctl_get(cmd, data, ifp);
237574f2ebaStb 	case SIOCSIFADDR:
23836d351c1Skn 		if (!privileged)
23936d351c1Skn 			return (EPERM);
24036d351c1Skn 		return in_ioctl_set_ifaddr(cmd, data, ifp);
241a87a252cStb 	case SIOCAIFADDR:
242a87a252cStb 	case SIOCDIFADDR:
24336d351c1Skn 		if (!privileged)
24436d351c1Skn 			return (EPERM);
24536d351c1Skn 		return in_ioctl_change_ifaddr(cmd, data, ifp);
246a87a252cStb 	case SIOCSIFNETMASK:
247a87a252cStb 	case SIOCSIFDSTADDR:
248a87a252cStb 	case SIOCSIFBRDADDR:
249a87a252cStb 		break;
250a87a252cStb 	default:
251a87a252cStb 		return (EOPNOTSUPP);
25239915755Stb 	}
25339915755Stb 
25436d351c1Skn 	if (!privileged)
25536d351c1Skn 		return (EPERM);
25636d351c1Skn 
257b36fd3daSbluhm 	if (ifr->ifr_addr.sa_family == AF_INET) {
258b36fd3daSbluhm 		error = in_sa2sin(&ifr->ifr_addr, &sin);
259b36fd3daSbluhm 		if (error)
260b36fd3daSbluhm 			return (error);
261b36fd3daSbluhm 	}
262b36fd3daSbluhm 
26319223f69Stb 	NET_LOCK();
264*a61bf6f2Sbluhm 	KERNEL_LOCK();
265f2852e57Smpi 
26678a62425Smpi 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
267b36fd3daSbluhm 		if (ifa->ifa_addr->sa_family != AF_INET)
268b36fd3daSbluhm 			continue;
269b36fd3daSbluhm 		/* find first address or exact match */
270b36fd3daSbluhm 		if (ia == NULL)
271b36fd3daSbluhm 			ia = ifatoia(ifa);
272b36fd3daSbluhm 		if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
273b36fd3daSbluhm 			break;
274b36fd3daSbluhm 		if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
275b36fd3daSbluhm 		    sin->sin_addr.s_addr) {
276e5a6a6d7Smpi 			ia = ifatoia(ifa);
277df930be7Sderaadt 			break;
278e5a6a6d7Smpi 		}
27978a62425Smpi 	}
28019223f69Stb 	if (ia == NULL) {
281b36fd3daSbluhm 		error = EADDRNOTAVAIL;
282b36fd3daSbluhm 		goto err;
28319223f69Stb 	}
284bb62a498Stb 
285d0a0045aSkn 	switch (cmd) {
286d0a0045aSkn 	case SIOCSIFDSTADDR:
28719223f69Stb 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
28819223f69Stb 			error = EINVAL;
28919223f69Stb 			break;
29019223f69Stb 		}
291b36fd3daSbluhm 		error = in_sa2sin(&ifr->ifr_dstaddr, &sin);
292b36fd3daSbluhm 		if (error)
293b36fd3daSbluhm 			break;
294df930be7Sderaadt 		oldaddr = ia->ia_dstaddr;
295b36fd3daSbluhm 		ia->ia_dstaddr = *sin;
296dfab256eSmpi 		error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia);
297dfab256eSmpi 		if (error) {
298df930be7Sderaadt 			ia->ia_dstaddr = oldaddr;
29919223f69Stb 			break;
300df930be7Sderaadt 		}
301074bbb20Smpi 		in_scrubhost(ia, &oldaddr);
302074bbb20Smpi 		in_addhost(ia, &ia->ia_dstaddr);
303df930be7Sderaadt 		break;
304df930be7Sderaadt 
305df930be7Sderaadt 	case SIOCSIFBRDADDR:
30619223f69Stb 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
30719223f69Stb 			error = EINVAL;
30819223f69Stb 			break;
30919223f69Stb 		}
310b36fd3daSbluhm 		error = in_sa2sin(&ifr->ifr_broadaddr, &sin);
311b36fd3daSbluhm 		if (error)
312b36fd3daSbluhm 			break;
313b36fd3daSbluhm 		ifa_update_broadaddr(ifp, &ia->ia_ifa, sintosa(sin));
314df930be7Sderaadt 		break;
315df930be7Sderaadt 
316a87a252cStb 	case SIOCSIFNETMASK:
317b36fd3daSbluhm 		if (ifr->ifr_addr.sa_len < 8) {
318b36fd3daSbluhm 			error = EINVAL;
319b36fd3daSbluhm 			break;
320b36fd3daSbluhm 		}
3218718e781Sbluhm 		/* do not check inet family or strict len */
3228718e781Sbluhm 		sin = satosin(&ifr->ifr_addr);
3238718e781Sbluhm 		if (ntohl(sin->sin_addr.s_addr) &
3248718e781Sbluhm 		    (~ntohl(sin->sin_addr.s_addr) >> 1)) {
3258718e781Sbluhm 			/* non-contiguous netmask */
3268718e781Sbluhm 			error = EINVAL;
3278718e781Sbluhm 			break;
3288718e781Sbluhm 		}
329a87a252cStb 		ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
3308718e781Sbluhm 		    sin->sin_addr.s_addr;
331a87a252cStb 		break;
3326ee3b066Stb 	}
333b36fd3daSbluhm err:
33423506624Skn 	KERNEL_UNLOCK();
335*a61bf6f2Sbluhm 	NET_UNLOCK();
3366ee3b066Stb 	return (error);
3376ee3b066Stb }
3386ee3b066Stb 
3396ee3b066Stb int
in_ioctl_set_ifaddr(u_long cmd,caddr_t data,struct ifnet * ifp)34036d351c1Skn in_ioctl_set_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp)
3416ee3b066Stb {
3426ee3b066Stb 	struct ifreq *ifr = (struct ifreq *)data;
3436ee3b066Stb 	struct ifaddr *ifa;
3446ee3b066Stb 	struct in_ifaddr *ia = NULL;
345b36fd3daSbluhm 	struct sockaddr_in *sin;
3466ee3b066Stb 	int error = 0;
3476ee3b066Stb 	int newifaddr;
3486ee3b066Stb 
349574f2ebaStb 	if (cmd != SIOCSIFADDR)
35040e42c82Snayden 		panic("%s: invalid ioctl %lu", __func__, cmd);
351574f2ebaStb 
352b36fd3daSbluhm 	error = in_sa2sin(&ifr->ifr_addr, &sin);
353b36fd3daSbluhm 	if (error)
354b36fd3daSbluhm 		return (error);
355b36fd3daSbluhm 
3566ee3b066Stb 	NET_LOCK();
357*a61bf6f2Sbluhm 	KERNEL_LOCK();
3586ee3b066Stb 
3596ee3b066Stb 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
360b36fd3daSbluhm 		if (ifa->ifa_addr->sa_family != AF_INET)
361b36fd3daSbluhm 			continue;
362b36fd3daSbluhm 		/* find first address */
3636ee3b066Stb 		ia = ifatoia(ifa);
3646ee3b066Stb 		break;
3656ee3b066Stb 	}
3666ee3b066Stb 	if (ia == NULL) {
3676ee3b066Stb 		ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
36818a44669Sbluhm 		refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
3696ee3b066Stb 		ia->ia_addr.sin_family = AF_INET;
3706ee3b066Stb 		ia->ia_addr.sin_len = sizeof(ia->ia_addr);
3716ee3b066Stb 		ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
3726ee3b066Stb 		ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
3736ee3b066Stb 		ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
3746ee3b066Stb 		ia->ia_sockmask.sin_len = 8;
3756ee3b066Stb 		if (ifp->if_flags & IFF_BROADCAST) {
3766ee3b066Stb 			ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
3776ee3b066Stb 			ia->ia_broadaddr.sin_family = AF_INET;
3786ee3b066Stb 		}
3796ee3b066Stb 		ia->ia_ifp = ifp;
3806ee3b066Stb 
3816ee3b066Stb 		newifaddr = 1;
3826ee3b066Stb 	} else
3836ee3b066Stb 		newifaddr = 0;
384574f2ebaStb 
385f5492269Smpi 	in_ifscrub(ifp, ia);
386b36fd3daSbluhm 	error = in_ifinit(ifp, ia, sin, newifaddr);
387574f2ebaStb 	if (!error)
388f22742abSdlg 		if_addrhooks_run(ifp);
389df930be7Sderaadt 
39023506624Skn 	KERNEL_UNLOCK();
391*a61bf6f2Sbluhm 	NET_UNLOCK();
392574f2ebaStb 	return error;
393574f2ebaStb }
394574f2ebaStb 
395574f2ebaStb int
in_ioctl_change_ifaddr(u_long cmd,caddr_t data,struct ifnet * ifp)39636d351c1Skn in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp)
397574f2ebaStb {
398574f2ebaStb 	struct ifaddr *ifa;
399574f2ebaStb 	struct in_ifaddr *ia = NULL;
400574f2ebaStb 	struct in_aliasreq *ifra = (struct in_aliasreq *)data;
40171713a9bSbluhm 	struct sockaddr_in *sin = NULL, *dstsin = NULL, *broadsin = NULL;
4028718e781Sbluhm 	struct sockaddr_in *masksin = NULL;
403574f2ebaStb 	int error = 0;
404574f2ebaStb 	int newifaddr;
405574f2ebaStb 
40671713a9bSbluhm 	if (ifra->ifra_addr.sin_family == AF_INET) {
40771713a9bSbluhm 		error = in_sa2sin(sintosa(&ifra->ifra_addr), &sin);
40871713a9bSbluhm 		if (error)
40971713a9bSbluhm 			return (error);
41071713a9bSbluhm 	}
41171713a9bSbluhm 
412574f2ebaStb 	NET_LOCK();
413*a61bf6f2Sbluhm 	KERNEL_LOCK();
414574f2ebaStb 
415574f2ebaStb 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
41671713a9bSbluhm 		if (ifa->ifa_addr->sa_family != AF_INET)
41771713a9bSbluhm 			continue;
41871713a9bSbluhm 		/* find first address, if no exact match wanted */
41971713a9bSbluhm 		if (sin == NULL || sin->sin_addr.s_addr ==
42071713a9bSbluhm 		    ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
421574f2ebaStb 			ia = ifatoia(ifa);
422574f2ebaStb 			break;
423574f2ebaStb 		}
424574f2ebaStb 	}
425574f2ebaStb 
426574f2ebaStb 	switch (cmd) {
42748afad59Smpi 	case SIOCAIFADDR: {
42848afad59Smpi 		int needinit = 0;
42948afad59Smpi 
43071713a9bSbluhm 		if (ifra->ifra_mask.sin_len) {
43171713a9bSbluhm 			if (ifra->ifra_mask.sin_len < 8) {
43271713a9bSbluhm 				error = EINVAL;
43371713a9bSbluhm 				break;
43471713a9bSbluhm 			}
4358718e781Sbluhm 			/* do not check inet family or strict len */
4368718e781Sbluhm 			masksin = &ifra->ifra_mask;
4378718e781Sbluhm 			if (ntohl(masksin->sin_addr.s_addr) &
4388718e781Sbluhm 			    (~ntohl(masksin->sin_addr.s_addr) >> 1)) {
4398718e781Sbluhm 				/* non-contiguous netmask */
4408718e781Sbluhm 				error = EINVAL;
4418718e781Sbluhm 				break;
4428718e781Sbluhm 			}
44371713a9bSbluhm 		}
44471713a9bSbluhm 		if ((ifp->if_flags & IFF_POINTOPOINT) &&
44571713a9bSbluhm 		    ifra->ifra_dstaddr.sin_family == AF_INET) {
44671713a9bSbluhm 			error = in_sa2sin(sintosa(&ifra->ifra_dstaddr),
44771713a9bSbluhm 			    &dstsin);
44871713a9bSbluhm 			if (error)
44971713a9bSbluhm 				break;
45071713a9bSbluhm 		}
45171713a9bSbluhm 		if ((ifp->if_flags & IFF_BROADCAST) &&
45271713a9bSbluhm 		    ifra->ifra_broadaddr.sin_family == AF_INET) {
45371713a9bSbluhm 			error = in_sa2sin(sintosa(&ifra->ifra_broadaddr),
45471713a9bSbluhm 			    &broadsin);
45571713a9bSbluhm 			if (error)
45671713a9bSbluhm 				break;
45771713a9bSbluhm 		}
45871713a9bSbluhm 
459574f2ebaStb 		if (ia == NULL) {
460574f2ebaStb 			ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
46118a44669Sbluhm 			refcnt_init_trace(&ia->ia_ifa.ifa_refcnt,
46218a44669Sbluhm 			    DT_REFCNT_IDX_IFADDR);
463574f2ebaStb 			ia->ia_addr.sin_family = AF_INET;
464574f2ebaStb 			ia->ia_addr.sin_len = sizeof(ia->ia_addr);
465574f2ebaStb 			ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
466574f2ebaStb 			ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
467574f2ebaStb 			ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
468574f2ebaStb 			ia->ia_sockmask.sin_len = 8;
469574f2ebaStb 			if (ifp->if_flags & IFF_BROADCAST) {
470574f2ebaStb 				ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
471574f2ebaStb 				ia->ia_broadaddr.sin_family = AF_INET;
472574f2ebaStb 			}
473574f2ebaStb 			ia->ia_ifp = ifp;
474574f2ebaStb 
475574f2ebaStb 			newifaddr = 1;
476574f2ebaStb 		} else
477574f2ebaStb 			newifaddr = 0;
478574f2ebaStb 
47971713a9bSbluhm 		if (sin == NULL) {
48071713a9bSbluhm 			sin = &ia->ia_addr;
48171713a9bSbluhm 		} else if (newifaddr ||
48271713a9bSbluhm 		    sin->sin_addr.s_addr != ia->ia_addr.sin_addr.s_addr) {
48348afad59Smpi 			needinit = 1;
484df930be7Sderaadt 		}
4858718e781Sbluhm 		if (masksin != NULL) {
486df930be7Sderaadt 			in_ifscrub(ifp, ia);
48771713a9bSbluhm 			ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
4888718e781Sbluhm 			    masksin->sin_addr.s_addr;
48948afad59Smpi 			needinit = 1;
490df930be7Sderaadt 		}
49171713a9bSbluhm 		if (dstsin != NULL) {
492df930be7Sderaadt 			in_ifscrub(ifp, ia);
49371713a9bSbluhm 			ia->ia_dstaddr = *dstsin;
49448afad59Smpi 			needinit = 1;
495df930be7Sderaadt 		}
49671713a9bSbluhm 		if (broadsin != NULL) {
497b86f1ce7Shenning 			if (newifaddr)
49871713a9bSbluhm 				ia->ia_broadaddr = *broadsin;
499b86f1ce7Shenning 			else
500fe19dd8dSbluhm 				ifa_update_broadaddr(ifp, &ia->ia_ifa,
50171713a9bSbluhm 				    sintosa(broadsin));
502b86f1ce7Shenning 		}
50371713a9bSbluhm 		if (needinit) {
50471713a9bSbluhm 			error = in_ifinit(ifp, ia, sin, newifaddr);
50519223f69Stb 			if (error)
50619223f69Stb 				break;
50771713a9bSbluhm 		}
508f22742abSdlg 		if_addrhooks_run(ifp);
50919223f69Stb 		break;
51048afad59Smpi 	    }
5117899d34dSmpi 	case SIOCDIFADDR:
512574f2ebaStb 		if (ia == NULL) {
513574f2ebaStb 			error = EADDRNOTAVAIL;
514574f2ebaStb 			break;
515574f2ebaStb 		}
5163427d89aShenric 		/*
5173427d89aShenric 		 * Even if the individual steps were safe, shouldn't
5183427d89aShenric 		 * these kinds of changes happen atomically?  What
5193427d89aShenric 		 * should happen to a packet that was routed after
5203427d89aShenric 		 * the scrub but before the other steps?
5213427d89aShenric 		 */
5227899d34dSmpi 		in_purgeaddr(&ia->ia_ifa);
523f22742abSdlg 		if_addrhooks_run(ifp);
5247899d34dSmpi 		break;
5256ee3b066Stb 
5266ee3b066Stb 	default:
52740e42c82Snayden 		panic("%s: invalid ioctl %lu", __func__, cmd);
528df930be7Sderaadt 	}
52919223f69Stb 
53023506624Skn 	KERNEL_UNLOCK();
531*a61bf6f2Sbluhm 	NET_UNLOCK();
53219223f69Stb 	return (error);
533df930be7Sderaadt }
53439915755Stb 
53539915755Stb int
in_ioctl_get(u_long cmd,caddr_t data,struct ifnet * ifp)53639915755Stb in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
53739915755Stb {
53839915755Stb 	struct ifreq *ifr = (struct ifreq *)data;
53939915755Stb 	struct ifaddr *ifa;
54039915755Stb 	struct in_ifaddr *ia = NULL;
541baa28055Sjca 	struct sockaddr *sa;
542b36fd3daSbluhm 	struct sockaddr_in *sin = NULL;
54339915755Stb 	int error = 0;
54439915755Stb 
545baa28055Sjca 	sa = &ifr->ifr_addr;
546baa28055Sjca 	if (sa->sa_family == AF_INET) {
547baa28055Sjca 		sa->sa_len = sizeof(struct sockaddr_in);
548baa28055Sjca 		error = in_sa2sin(sa, &sin);
549b36fd3daSbluhm 		if (error)
550b36fd3daSbluhm 			return (error);
551b36fd3daSbluhm 	}
552b36fd3daSbluhm 
5536a1c2aefSbluhm 	NET_LOCK_SHARED();
55439915755Stb 
55539915755Stb 	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
556b36fd3daSbluhm 		if (ifa->ifa_addr->sa_family != AF_INET)
557b36fd3daSbluhm 			continue;
558b36fd3daSbluhm 		/* find first address or exact match */
559b36fd3daSbluhm 		if (ia == NULL)
560b36fd3daSbluhm 			ia = ifatoia(ifa);
561b36fd3daSbluhm 		if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
562b36fd3daSbluhm 			break;
563b36fd3daSbluhm 		if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
564b36fd3daSbluhm 		    sin->sin_addr.s_addr) {
56539915755Stb 			ia = ifatoia(ifa);
56639915755Stb 			break;
56739915755Stb 		}
56839915755Stb 	}
56939915755Stb 	if (ia == NULL) {
57039915755Stb 		error = EADDRNOTAVAIL;
57139915755Stb 		goto err;
57239915755Stb 	}
57339915755Stb 
57439915755Stb 	switch(cmd) {
57539915755Stb 	case SIOCGIFADDR:
57639915755Stb 		*satosin(&ifr->ifr_addr) = ia->ia_addr;
57739915755Stb 		break;
57839915755Stb 
57939915755Stb 	case SIOCGIFBRDADDR:
58039915755Stb 		if ((ifp->if_flags & IFF_BROADCAST) == 0) {
58139915755Stb 			error = EINVAL;
58239915755Stb 			break;
58339915755Stb 		}
58439915755Stb 		*satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
58539915755Stb 		break;
58639915755Stb 
58739915755Stb 	case SIOCGIFDSTADDR:
58839915755Stb 		if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
58939915755Stb 			error = EINVAL;
59039915755Stb 			break;
59139915755Stb 		}
59239915755Stb 		*satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
59339915755Stb 		break;
59439915755Stb 
59539915755Stb 	case SIOCGIFNETMASK:
59639915755Stb 		*satosin(&ifr->ifr_addr) = ia->ia_sockmask;
59739915755Stb 		break;
59839915755Stb 
59939915755Stb 	default:
60040e42c82Snayden 		panic("%s: invalid ioctl %lu", __func__, cmd);
60139915755Stb 	}
60239915755Stb 
60339915755Stb err:
6046a1c2aefSbluhm 	NET_UNLOCK_SHARED();
60539915755Stb 	return (error);
60639915755Stb }
60739915755Stb 
608287546eaSitojun /*
609df930be7Sderaadt  * Delete any existing route for an interface.
610df930be7Sderaadt  */
611df930be7Sderaadt void
in_ifscrub(struct ifnet * ifp,struct in_ifaddr * ia)61280481146Sdlg in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
613df930be7Sderaadt {
614adb45f93Smpi 	if (ISSET(ifp->if_flags, IFF_POINTOPOINT))
615074bbb20Smpi 		in_scrubhost(ia, &ia->ia_dstaddr);
616adb45f93Smpi 	else if (!ISSET(ifp->if_flags, IFF_LOOPBACK))
617cfc71c8bSclaudio 		in_remove_prefix(ia);
618df930be7Sderaadt }
619df930be7Sderaadt 
620df930be7Sderaadt /*
621df930be7Sderaadt  * Initialize an interface's internet address
622df930be7Sderaadt  * and routing table entry.
623df930be7Sderaadt  */
624df930be7Sderaadt int
in_ifinit(struct ifnet * ifp,struct in_ifaddr * ia,struct sockaddr_in * sin,int newaddr)62580481146Sdlg in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
626f5492269Smpi     int newaddr)
627df930be7Sderaadt {
62864aa4cc7Sitojun 	u_int32_t i = sin->sin_addr.s_addr;
629df930be7Sderaadt 	struct sockaddr_in oldaddr;
6304229efd4Sbluhm 	int error = 0, rterror;
63180ec1445Sbluhm 
63266736630Smpi 	NET_ASSERT_LOCKED();
633df930be7Sderaadt 
634311b3a36Smpi 	/*
635311b3a36Smpi 	 * Always remove the address from the tree to make sure its
636311b3a36Smpi 	 * position gets updated in case the key changes.
637311b3a36Smpi 	 */
638caa91aedSmpi 	if (!newaddr) {
639dfa661caSmpi 		rt_ifa_dellocal(&ia->ia_ifa);
640fe19dd8dSbluhm 		ifa_del(ifp, &ia->ia_ifa);
641caa91aedSmpi 	}
642df930be7Sderaadt 	oldaddr = ia->ia_addr;
643df930be7Sderaadt 	ia->ia_addr = *sin;
6440d78322bShenning 
64538603617Srzalamena 	if (ia->ia_netmask == 0) {
64638603617Srzalamena 		if (IN_CLASSA(i))
64738603617Srzalamena 			ia->ia_netmask = IN_CLASSA_NET;
64838603617Srzalamena 		else if (IN_CLASSB(i))
64938603617Srzalamena 			ia->ia_netmask = IN_CLASSB_NET;
65038603617Srzalamena 		else
65138603617Srzalamena 			ia->ia_netmask = IN_CLASSC_NET;
65238603617Srzalamena 		ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
65338603617Srzalamena 	}
65438603617Srzalamena 
655df930be7Sderaadt 	/*
656df930be7Sderaadt 	 * Give the interface a chance to initialize
657df930be7Sderaadt 	 * if this is its first address,
658df930be7Sderaadt 	 * and to validate the address if necessary.
659df930be7Sderaadt 	 */
660dfab256eSmpi 	if ((error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
661df930be7Sderaadt 		ia->ia_addr = oldaddr;
662df930be7Sderaadt 	}
6633427d89aShenric 
664f4def34aSmpi 	/*
665f4def34aSmpi 	 * Add the address to the local list and the global tree.  If an
666678831beSjsg 	 * error occurred, put back the original address.
667f4def34aSmpi 	 */
668f4def34aSmpi 	ifa_add(ifp, &ia->ia_ifa);
6694229efd4Sbluhm 	rterror = rt_ifa_addlocal(&ia->ia_ifa);
670f4def34aSmpi 
6714229efd4Sbluhm 	if (rterror) {
6724229efd4Sbluhm 		if (!newaddr)
6734229efd4Sbluhm 			ifa_del(ifp, &ia->ia_ifa);
6744229efd4Sbluhm 		if (!error)
6754229efd4Sbluhm 			error = rterror;
6764229efd4Sbluhm 		goto out;
6774229efd4Sbluhm 	}
678f4def34aSmpi 	if (error)
679f4def34aSmpi 		goto out;
680f4def34aSmpi 
68106892480Shenning 
682df930be7Sderaadt 	ia->ia_net = i & ia->ia_netmask;
683df930be7Sderaadt 	in_socktrim(&ia->ia_sockmask);
684df930be7Sderaadt 	/*
685df930be7Sderaadt 	 * Add route for the network.
686df930be7Sderaadt 	 */
687df930be7Sderaadt 	ia->ia_ifa.ifa_metric = ifp->if_metric;
688074bbb20Smpi 	if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
68951de5020Sdlg 		if (IN_RFC3021_SUBNET(ia->ia_netmask))
69051de5020Sdlg 			ia->ia_broadaddr.sin_addr.s_addr = 0;
69151de5020Sdlg 		else {
692df930be7Sderaadt 			ia->ia_broadaddr.sin_addr.s_addr =
69306892480Shenning 			    ia->ia_net | ~ia->ia_netmask;
69451de5020Sdlg 		}
695df930be7Sderaadt 	}
696e5876f54Smpi 
697074bbb20Smpi 	if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) {
698074bbb20Smpi 		/* XXX We should not even call in_ifinit() in this case. */
699074bbb20Smpi 		if (ia->ia_dstaddr.sin_family != AF_INET)
700074bbb20Smpi 			goto out;
701074bbb20Smpi 		error = in_addhost(ia, &ia->ia_dstaddr);
702074bbb20Smpi 	} else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) {
703cfc71c8bSclaudio 		error = in_insert_prefix(ia);
704074bbb20Smpi 	}
7050d78322bShenning 
706df930be7Sderaadt 	/*
707df930be7Sderaadt 	 * If the interface supports multicast, join the "all hosts"
708df930be7Sderaadt 	 * multicast group on that interface.
709df930be7Sderaadt 	 */
710be2fc42cSpascoe 	if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
711df930be7Sderaadt 		struct in_addr addr;
712df930be7Sderaadt 
713df930be7Sderaadt 		addr.s_addr = INADDR_ALLHOSTS_GROUP;
714be2fc42cSpascoe 		ia->ia_allhosts = in_addmulti(&addr, ifp);
715df930be7Sderaadt 	}
71676faa554Shenning 
7175edc58b7Smpi out:
7187899d34dSmpi 	if (error && newaddr)
7197899d34dSmpi 		in_purgeaddr(&ia->ia_ifa);
7207899d34dSmpi 
721df930be7Sderaadt 	return (error);
722df930be7Sderaadt }
723df930be7Sderaadt 
7247899d34dSmpi void
in_purgeaddr(struct ifaddr * ifa)7257899d34dSmpi in_purgeaddr(struct ifaddr *ifa)
7267899d34dSmpi {
7277899d34dSmpi 	struct ifnet *ifp = ifa->ifa_ifp;
7287899d34dSmpi 	struct in_ifaddr *ia = ifatoia(ifa);
7297899d34dSmpi 
73066736630Smpi 	NET_ASSERT_LOCKED();
7317899d34dSmpi 
7327899d34dSmpi 	in_ifscrub(ifp, ia);
7337899d34dSmpi 
734dfa661caSmpi 	rt_ifa_dellocal(&ia->ia_ifa);
73503edf7baSmpi 	rt_ifa_purge(&ia->ia_ifa);
7367899d34dSmpi 	ifa_del(ifp, &ia->ia_ifa);
737caa91aedSmpi 
7387899d34dSmpi 	if (ia->ia_allhosts != NULL) {
7397899d34dSmpi 		in_delmulti(ia->ia_allhosts);
7407899d34dSmpi 		ia->ia_allhosts = NULL;
7417899d34dSmpi 	}
7427899d34dSmpi 
7437899d34dSmpi 	ia->ia_ifp = NULL;
7447899d34dSmpi 	ifafree(&ia->ia_ifa);
7457899d34dSmpi }
7467899d34dSmpi 
747e5876f54Smpi int
in_addhost(struct in_ifaddr * ia,struct sockaddr_in * dst)748074bbb20Smpi in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
749e5876f54Smpi {
7508f960e22Sdlg 	return rt_ifa_add(&ia->ia_ifa, RTF_HOST | RTF_MPATH,
7518f960e22Sdlg 	    sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
752e5876f54Smpi }
753e5876f54Smpi 
754e5876f54Smpi int
in_scrubhost(struct in_ifaddr * ia,struct sockaddr_in * dst)755074bbb20Smpi in_scrubhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
756e5876f54Smpi {
7578f960e22Sdlg 	return rt_ifa_del(&ia->ia_ifa, RTF_HOST,
7588f960e22Sdlg 	    sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
759e5876f54Smpi }
760c800a1d2Sitojun 
761c800a1d2Sitojun /*
7625105ae10Smpi  * Insert the cloning and broadcast routes for this subnet.
7635105ae10Smpi  */
7645105ae10Smpi int
in_insert_prefix(struct in_ifaddr * ia)7655105ae10Smpi in_insert_prefix(struct in_ifaddr *ia)
7665105ae10Smpi {
7675105ae10Smpi 	struct ifaddr *ifa = &ia->ia_ifa;
7685105ae10Smpi 	int error;
7695105ae10Smpi 
77062cb75b3Sdlg 	error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED | RTF_MPATH,
7718f960e22Sdlg 	    ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
7725105ae10Smpi 	if (error)
7735105ae10Smpi 		return (error);
7745105ae10Smpi 
7758f960e22Sdlg 	if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
77662cb75b3Sdlg 		error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST | RTF_MPATH,
7778f960e22Sdlg 		    ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
7788f960e22Sdlg 	}
7795105ae10Smpi 
7805105ae10Smpi 	return (error);
7815105ae10Smpi }
7825105ae10Smpi 
7835105ae10Smpi void
in_remove_prefix(struct in_ifaddr * ia)7845105ae10Smpi in_remove_prefix(struct in_ifaddr *ia)
7855105ae10Smpi {
7865105ae10Smpi 	struct ifaddr *ifa = &ia->ia_ifa;
7875105ae10Smpi 
7888f960e22Sdlg 	rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED,
7898f960e22Sdlg 	    ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
7905105ae10Smpi 
7918f960e22Sdlg 	if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
7928f960e22Sdlg 		rt_ifa_del(ifa, RTF_HOST | RTF_BROADCAST,
7938f960e22Sdlg 		    ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
7948f960e22Sdlg 	}
7955105ae10Smpi }
7965105ae10Smpi 
7975105ae10Smpi /*
7983c536e30Smpi  * Return 1 if the address is a local broadcast address.
799df930be7Sderaadt  */
800df930be7Sderaadt int
in_broadcast(struct in_addr in,u_int rtableid)8013c536e30Smpi in_broadcast(struct in_addr in, u_int rtableid)
802df930be7Sderaadt {
8033c536e30Smpi 	struct ifnet *ifn;
80464aa4cc7Sitojun 	struct ifaddr *ifa;
805e26c6cbcSclaudio 	u_int rdomain;
806e26c6cbcSclaudio 
807e26c6cbcSclaudio 	rdomain = rtable_l2(rtableid);
808df930be7Sderaadt 
80985a622a8Sangelos #define ia (ifatoia(ifa))
810ccb45f8eSkn 	TAILQ_FOREACH(ifn, &ifnetlist, if_list) {
811e26c6cbcSclaudio 		if (ifn->if_rdomain != rdomain)
812e26c6cbcSclaudio 			continue;
813d4ee7daeSitojun 		if ((ifn->if_flags & IFF_BROADCAST) == 0)
814d4ee7daeSitojun 			continue;
8151573508eSmiod 		TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
816df930be7Sderaadt 			if (ifa->ifa_addr->sa_family == AF_INET &&
817d4ee7daeSitojun 			    in.s_addr != ia->ia_addr.sin_addr.s_addr &&
818220c0cb9Shenning 			    in.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
819e985a30cSangelos 				return 1;
820e985a30cSangelos 	}
821df930be7Sderaadt 	return (0);
822df930be7Sderaadt #undef ia
823df930be7Sderaadt }
824df930be7Sderaadt 
825df930be7Sderaadt /*
826df930be7Sderaadt  * Add an address to the list of IP multicast addresses for a given interface.
827df930be7Sderaadt  */
828df930be7Sderaadt struct in_multi *
in_addmulti(struct in_addr * ap,struct ifnet * ifp)82980481146Sdlg in_addmulti(struct in_addr *ap, struct ifnet *ifp)
830df930be7Sderaadt {
83164aa4cc7Sitojun 	struct in_multi *inm;
832df930be7Sderaadt 	struct ifreq ifr;
833f2852e57Smpi 
834df930be7Sderaadt 	/*
835df930be7Sderaadt 	 * See if address already in list.
836df930be7Sderaadt 	 */
837df930be7Sderaadt 	IN_LOOKUP_MULTI(*ap, ifp, inm);
838df930be7Sderaadt 	if (inm != NULL) {
839df930be7Sderaadt 		/*
840df930be7Sderaadt 		 * Found it; just increment the reference count.
841df930be7Sderaadt 		 */
842a409c69cSkn 		refcnt_take(&inm->inm_refcnt);
843df930be7Sderaadt 	} else {
844df930be7Sderaadt 		/*
845df930be7Sderaadt 		 * New address; allocate a new multicast record
846df930be7Sderaadt 		 * and link it into the interface's multicast list.
847df930be7Sderaadt 		 */
848cf19868bSbluhm 		inm = malloc(sizeof(*inm), M_IPMADDR, M_WAITOK | M_ZERO);
8492bea58a8Smpi 		inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
8502bea58a8Smpi 		inm->inm_sin.sin_family = AF_INET;
8512bea58a8Smpi 		inm->inm_sin.sin_addr = *ap;
852a409c69cSkn 		refcnt_init_trace(&inm->inm_refcnt, DT_REFCNT_IDX_IFMADDR);
85333082e9fSmpi 		inm->inm_ifidx = ifp->if_index;
8542bea58a8Smpi 		inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
8552bea58a8Smpi 
856df930be7Sderaadt 		/*
857df930be7Sderaadt 		 * Ask the network driver to update its multicast reception
858df930be7Sderaadt 		 * filter appropriately for the new address.
859df930be7Sderaadt 		 */
8609c794535Sbluhm 		memset(&ifr, 0, sizeof(ifr));
8612bea58a8Smpi 		memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
862bfb4dd3fSmvs 		KERNEL_LOCK();
8632bea58a8Smpi 		if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
864bfb4dd3fSmvs 			KERNEL_UNLOCK();
8658df9ba4dStedu 			free(inm, M_IPMADDR, sizeof(*inm));
866df930be7Sderaadt 			return (NULL);
867df930be7Sderaadt 		}
868bfb4dd3fSmvs 		KERNEL_UNLOCK();
8692bea58a8Smpi 
8702bea58a8Smpi 		TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
8712bea58a8Smpi 		    ifma_list);
8722bea58a8Smpi 
873df930be7Sderaadt 		/*
874df930be7Sderaadt 		 * Let IGMP know that we have joined a new IP multicast group.
875df930be7Sderaadt 		 */
876a134c703Sbluhm 		igmp_joingroup(inm, ifp);
877df930be7Sderaadt 	}
8782bea58a8Smpi 
879df930be7Sderaadt 	return (inm);
880df930be7Sderaadt }
881df930be7Sderaadt 
882df930be7Sderaadt /*
883df930be7Sderaadt  * Delete a multicast address record.
884df930be7Sderaadt  */
885b400e158Sniklas void
in_delmulti(struct in_multi * inm)88680481146Sdlg in_delmulti(struct in_multi *inm)
887df930be7Sderaadt {
888df930be7Sderaadt 	struct ifreq ifr;
8895b0dc0ebSclaudio 	struct ifnet *ifp;
890f2852e57Smpi 
89166736630Smpi 	NET_ASSERT_LOCKED();
892df930be7Sderaadt 
893a409c69cSkn 	if (refcnt_rele(&inm->inm_refcnt) == 0)
894a134c703Sbluhm 		return;
895a134c703Sbluhm 
896a134c703Sbluhm 	ifp = if_get(inm->inm_ifidx);
897a134c703Sbluhm 	if (ifp != NULL) {
898df930be7Sderaadt 		/*
899df930be7Sderaadt 		 * No remaining claims to this record; let IGMP know that
900df930be7Sderaadt 		 * we are leaving the multicast group.
901df930be7Sderaadt 		 */
902a134c703Sbluhm 		igmp_leavegroup(inm, ifp);
9035b0dc0ebSclaudio 
904df930be7Sderaadt 		/*
9055b0dc0ebSclaudio 		 * Notify the network driver to update its multicast
9065b0dc0ebSclaudio 		 * reception filter.
907df930be7Sderaadt 		 */
9089c794535Sbluhm 		memset(&ifr, 0, sizeof(ifr));
909a134c703Sbluhm 		satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
910df930be7Sderaadt 		satosin(&ifr.ifr_addr)->sin_family = AF_INET;
911df930be7Sderaadt 		satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
9124b9a5ba9Svisa 		KERNEL_LOCK();
9135b0dc0ebSclaudio 		(*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
9144b9a5ba9Svisa 		KERNEL_UNLOCK();
9152bea58a8Smpi 
916a134c703Sbluhm 		TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list);
91733082e9fSmpi 	}
91800b670e0Sdlg 	if_put(ifp);
9192bea58a8Smpi 
9208df9ba4dStedu 	free(inm, M_IPMADDR, sizeof(*inm));
921df930be7Sderaadt }
922df930be7Sderaadt 
92334dbf6d6Smpi /*
92434dbf6d6Smpi  * Return 1 if the multicast group represented by ``ap'' has been
92534dbf6d6Smpi  * joined by interface ``ifp'', 0 otherwise.
92634dbf6d6Smpi  */
92734dbf6d6Smpi int
in_hasmulti(struct in_addr * ap,struct ifnet * ifp)92834dbf6d6Smpi in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
92934dbf6d6Smpi {
93034dbf6d6Smpi 	struct in_multi *inm;
93134dbf6d6Smpi 	int joined;
93234dbf6d6Smpi 
93334dbf6d6Smpi 	IN_LOOKUP_MULTI(*ap, ifp, inm);
93434dbf6d6Smpi 	joined = (inm != NULL);
93534dbf6d6Smpi 
93634dbf6d6Smpi 	return (joined);
93734dbf6d6Smpi }
93874308e45Smpi 
93974308e45Smpi void
in_ifdetach(struct ifnet * ifp)94074308e45Smpi in_ifdetach(struct ifnet *ifp)
94174308e45Smpi {
94274308e45Smpi 	struct ifaddr *ifa, *next;
94374308e45Smpi 
94474308e45Smpi 	/* nuke any of IPv4 addresses we have */
94574308e45Smpi 	TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
94674308e45Smpi 		if (ifa->ifa_addr->sa_family != AF_INET)
94774308e45Smpi 			continue;
94874308e45Smpi 		in_purgeaddr(ifa);
949f22742abSdlg 		if_addrhooks_run(ifp);
95074308e45Smpi 	}
951367b0a2eSkrw 
952367b0a2eSkrw 	if (ifp->if_xflags & IFXF_AUTOCONF4)
953367b0a2eSkrw 		ifp->if_xflags &= ~IFXF_AUTOCONF4;
95474308e45Smpi }
955ad38292eSmpi 
956ad38292eSmpi void
in_prefixlen2mask(struct in_addr * maskp,int plen)957ad38292eSmpi in_prefixlen2mask(struct in_addr *maskp, int plen)
958ad38292eSmpi {
959ad38292eSmpi 	if (plen == 0)
960ad38292eSmpi 		maskp->s_addr = 0;
961ad38292eSmpi 	else
962ad38292eSmpi 		maskp->s_addr = htonl(0xffffffff << (32 - plen));
963ad38292eSmpi }
964