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