Line data Source code
1 : /* $OpenBSD: in.c,v 1.160 2018/07/11 21:18:23 nayden Exp $ */
2 : /* $NetBSD: in.c,v 1.26 1996/02/13 23:41:39 christos Exp $ */
3 :
4 : /*
5 : * Copyright (C) 2001 WIDE Project. All rights reserved.
6 : *
7 : * Redistribution and use in source and binary forms, with or without
8 : * modification, are permitted provided that the following conditions
9 : * are met:
10 : * 1. Redistributions of source code must retain the above copyright
11 : * notice, this list of conditions and the following disclaimer.
12 : * 2. Redistributions in binary form must reproduce the above copyright
13 : * notice, this list of conditions and the following disclaimer in the
14 : * documentation and/or other materials provided with the distribution.
15 : * 3. Neither the name of the project nor the names of its contributors
16 : * may be used to endorse or promote products derived from this software
17 : * without specific prior written permission.
18 : *
19 : * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
20 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 : * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
23 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 : * SUCH DAMAGE.
30 : */
31 :
32 : /*
33 : * Copyright (c) 1982, 1986, 1991, 1993
34 : * The Regents of the University of California. All rights reserved.
35 : *
36 : * Redistribution and use in source and binary forms, with or without
37 : * modification, are permitted provided that the following conditions
38 : * are met:
39 : * 1. Redistributions of source code must retain the above copyright
40 : * notice, this list of conditions and the following disclaimer.
41 : * 2. Redistributions in binary form must reproduce the above copyright
42 : * notice, this list of conditions and the following disclaimer in the
43 : * documentation and/or other materials provided with the distribution.
44 : * 3. Neither the name of the University nor the names of its contributors
45 : * may be used to endorse or promote products derived from this software
46 : * without specific prior written permission.
47 : *
48 : * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
49 : * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
50 : * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
51 : * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
52 : * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
53 : * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
54 : * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
55 : * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
56 : * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
57 : * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
58 : * SUCH DAMAGE.
59 : *
60 : * @(#)in.c 8.2 (Berkeley) 11/15/93
61 : */
62 :
63 : #include <sys/param.h>
64 : #include <sys/systm.h>
65 : #include <sys/ioctl.h>
66 : #include <sys/malloc.h>
67 : #include <sys/socket.h>
68 : #include <sys/socketvar.h>
69 :
70 : #include <net/if.h>
71 : #include <net/if_var.h>
72 : #include <net/route.h>
73 :
74 : #include <netinet/in.h>
75 : #include <netinet/in_var.h>
76 : #include <netinet/igmp_var.h>
77 :
78 : #ifdef MROUTING
79 : #include <netinet/ip_mroute.h>
80 : #endif
81 :
82 : #include "ether.h"
83 :
84 :
85 : void in_socktrim(struct sockaddr_in *);
86 :
87 : int in_ioctl_sifaddr(u_long, caddr_t, struct ifnet *, int);
88 : int in_ioctl_change_ifaddr(u_long, caddr_t, struct ifnet *, int);
89 : int in_ioctl_get(u_long, caddr_t, struct ifnet *);
90 : void in_purgeaddr(struct ifaddr *);
91 : int in_addhost(struct in_ifaddr *, struct sockaddr_in *);
92 : int in_scrubhost(struct in_ifaddr *, struct sockaddr_in *);
93 : int in_insert_prefix(struct in_ifaddr *);
94 : void in_remove_prefix(struct in_ifaddr *);
95 :
96 : /*
97 : * Determine whether an IP address is in a reserved set of addresses
98 : * that may not be forwarded, or whether datagrams to that destination
99 : * may be forwarded.
100 : */
101 : int
102 0 : in_canforward(struct in_addr in)
103 : {
104 : u_int32_t net;
105 :
106 0 : if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr))
107 0 : return (0);
108 0 : if (IN_CLASSA(in.s_addr)) {
109 0 : net = in.s_addr & IN_CLASSA_NET;
110 0 : if (net == 0 ||
111 0 : net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
112 0 : return (0);
113 : }
114 0 : return (1);
115 0 : }
116 :
117 : /*
118 : * Trim a mask in a sockaddr
119 : */
120 : void
121 0 : in_socktrim(struct sockaddr_in *ap)
122 : {
123 0 : char *cplim = (char *) &ap->sin_addr;
124 0 : char *cp = (char *) (&ap->sin_addr + 1);
125 :
126 0 : ap->sin_len = 0;
127 0 : while (--cp >= cplim)
128 0 : if (*cp) {
129 0 : (ap)->sin_len = cp - (char *) (ap) + 1;
130 0 : break;
131 : }
132 0 : }
133 :
134 : int
135 0 : in_mask2len(struct in_addr *mask)
136 : {
137 : int x, y;
138 : u_char *p;
139 :
140 0 : p = (u_char *)mask;
141 0 : for (x = 0; x < sizeof(*mask); x++) {
142 0 : if (p[x] != 0xff)
143 : break;
144 : }
145 : y = 0;
146 0 : if (x < sizeof(*mask)) {
147 0 : for (y = 0; y < 8; y++) {
148 0 : if ((p[x] & (0x80 >> y)) == 0)
149 : break;
150 : }
151 : }
152 0 : return x * 8 + y;
153 : }
154 :
155 : void
156 0 : in_len2mask(struct in_addr *mask, int len)
157 : {
158 : int i;
159 : u_char *p;
160 :
161 0 : p = (u_char *)mask;
162 0 : bzero(mask, sizeof(*mask));
163 0 : for (i = 0; i < len / 8; i++)
164 0 : p[i] = 0xff;
165 0 : if (len % 8)
166 0 : p[i] = (0xff00 >> (len % 8)) & 0xff;
167 0 : }
168 :
169 : int
170 0 : in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
171 : {
172 0 : struct sockaddr *sa = mtod(nam, struct sockaddr *);
173 :
174 0 : if (nam->m_len < offsetof(struct sockaddr, sa_data))
175 0 : return EINVAL;
176 0 : if (sa->sa_family != AF_INET)
177 0 : return EAFNOSUPPORT;
178 0 : if (sa->sa_len != nam->m_len)
179 0 : return EINVAL;
180 0 : if (sa->sa_len != sizeof(struct sockaddr_in))
181 0 : return EINVAL;
182 0 : *sin = satosin(sa);
183 :
184 0 : return 0;
185 0 : }
186 :
187 : int
188 0 : in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
189 : {
190 : int privileged;
191 : int error;
192 :
193 : privileged = 0;
194 0 : if ((so->so_state & SS_PRIV) != 0)
195 0 : privileged++;
196 :
197 0 : switch (cmd) {
198 : #ifdef MROUTING
199 : case SIOCGETVIFCNT:
200 : case SIOCGETSGCNT:
201 0 : error = mrt_ioctl(so, cmd, data);
202 0 : break;
203 : #endif /* MROUTING */
204 : default:
205 0 : error = in_ioctl(cmd, data, ifp, privileged);
206 0 : break;
207 : }
208 :
209 0 : return error;
210 : }
211 :
212 : int
213 0 : in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
214 : {
215 0 : struct ifreq *ifr = (struct ifreq *)data;
216 : struct ifaddr *ifa;
217 : struct in_ifaddr *ia = NULL;
218 0 : struct sockaddr_in oldaddr;
219 : int error = 0;
220 :
221 0 : if (ifp == NULL)
222 0 : return (ENXIO);
223 :
224 0 : switch (cmd) {
225 : case SIOCGIFADDR:
226 : case SIOCGIFNETMASK:
227 : case SIOCGIFDSTADDR:
228 : case SIOCGIFBRDADDR:
229 0 : return in_ioctl_get(cmd, data, ifp);
230 : case SIOCSIFADDR:
231 0 : return in_ioctl_sifaddr(cmd, data, ifp, privileged);
232 : case SIOCAIFADDR:
233 : case SIOCDIFADDR:
234 0 : return in_ioctl_change_ifaddr(cmd, data, ifp, privileged);
235 : case SIOCSIFNETMASK:
236 : case SIOCSIFDSTADDR:
237 : case SIOCSIFBRDADDR:
238 : break;
239 : default:
240 0 : return (EOPNOTSUPP);
241 : }
242 :
243 0 : NET_LOCK();
244 :
245 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
246 0 : if (ifa->ifa_addr->sa_family == AF_INET) {
247 0 : ia = ifatoia(ifa);
248 0 : break;
249 : }
250 : }
251 :
252 0 : if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
253 0 : for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
254 0 : if ((ifa->ifa_addr->sa_family == AF_INET) &&
255 0 : ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
256 0 : satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
257 0 : ia = ifatoia(ifa);
258 0 : break;
259 : }
260 : }
261 : }
262 0 : if (ia == NULL) {
263 0 : NET_UNLOCK();
264 0 : return (EADDRNOTAVAIL);
265 : }
266 :
267 0 : switch (cmd) {
268 : case SIOCSIFDSTADDR:
269 0 : if (!privileged) {
270 : error = EPERM;
271 0 : break;
272 : }
273 :
274 0 : if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
275 : error = EINVAL;
276 0 : break;
277 : }
278 0 : oldaddr = ia->ia_dstaddr;
279 0 : ia->ia_dstaddr = *satosin(&ifr->ifr_dstaddr);
280 0 : error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia);
281 0 : if (error) {
282 0 : ia->ia_dstaddr = oldaddr;
283 0 : break;
284 : }
285 0 : in_scrubhost(ia, &oldaddr);
286 0 : in_addhost(ia, &ia->ia_dstaddr);
287 0 : break;
288 :
289 : case SIOCSIFBRDADDR:
290 0 : if (!privileged) {
291 : error = EPERM;
292 0 : break;
293 : }
294 :
295 0 : if ((ifp->if_flags & IFF_BROADCAST) == 0) {
296 : error = EINVAL;
297 0 : break;
298 : }
299 0 : ifa_update_broadaddr(ifp, &ia->ia_ifa, &ifr->ifr_broadaddr);
300 0 : break;
301 :
302 : case SIOCSIFNETMASK:
303 0 : if (!privileged) {
304 : error = EPERM;
305 0 : break;
306 : }
307 :
308 0 : ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
309 0 : satosin(&ifr->ifr_addr)->sin_addr.s_addr;
310 0 : break;
311 : }
312 :
313 0 : NET_UNLOCK();
314 0 : return (error);
315 0 : }
316 :
317 : int
318 0 : in_ioctl_sifaddr(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
319 : {
320 0 : struct ifreq *ifr = (struct ifreq *)data;
321 : struct ifaddr *ifa;
322 : struct in_ifaddr *ia = NULL;
323 : int error = 0;
324 : int newifaddr;
325 :
326 0 : if (cmd != SIOCSIFADDR)
327 0 : panic("%s: invalid ioctl %lu", __func__, cmd);
328 :
329 0 : if (!privileged)
330 0 : return (EPERM);
331 :
332 0 : NET_LOCK();
333 :
334 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
335 0 : if (ifa->ifa_addr->sa_family == AF_INET) {
336 0 : ia = ifatoia(ifa);
337 0 : break;
338 : }
339 : }
340 :
341 0 : if (ia == NULL) {
342 0 : ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
343 0 : ia->ia_addr.sin_family = AF_INET;
344 0 : ia->ia_addr.sin_len = sizeof(ia->ia_addr);
345 0 : ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
346 0 : ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
347 0 : ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
348 0 : ia->ia_sockmask.sin_len = 8;
349 0 : if (ifp->if_flags & IFF_BROADCAST) {
350 0 : ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
351 0 : ia->ia_broadaddr.sin_family = AF_INET;
352 0 : }
353 0 : ia->ia_ifp = ifp;
354 :
355 : newifaddr = 1;
356 0 : } else
357 : newifaddr = 0;
358 :
359 0 : in_ifscrub(ifp, ia);
360 0 : error = in_ifinit(ifp, ia, satosin(&ifr->ifr_addr), newifaddr);
361 0 : if (!error)
362 0 : dohooks(ifp->if_addrhooks, 0);
363 :
364 0 : NET_UNLOCK();
365 0 : return error;
366 0 : }
367 :
368 : int
369 0 : in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
370 : int privileged)
371 : {
372 : struct ifaddr *ifa;
373 : struct in_ifaddr *ia = NULL;
374 0 : struct in_aliasreq *ifra = (struct in_aliasreq *)data;
375 : int error = 0;
376 : int newifaddr;
377 :
378 0 : NET_LOCK();
379 :
380 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
381 0 : if (ifa->ifa_addr->sa_family == AF_INET) {
382 0 : ia = ifatoia(ifa);
383 0 : break;
384 : }
385 : }
386 :
387 0 : if (ifra->ifra_addr.sin_family == AF_INET) {
388 0 : for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
389 0 : if ((ifa->ifa_addr->sa_family == AF_INET) &&
390 0 : ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
391 0 : ifra->ifra_addr.sin_addr.s_addr)
392 : break;
393 : }
394 0 : ia = ifatoia(ifa);
395 0 : }
396 :
397 0 : switch (cmd) {
398 : case SIOCAIFADDR: {
399 : int needinit = 0;
400 :
401 0 : if (!privileged) {
402 : error = EPERM;
403 0 : break;
404 : }
405 :
406 0 : if (ia == NULL) {
407 0 : ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
408 0 : ia->ia_addr.sin_family = AF_INET;
409 0 : ia->ia_addr.sin_len = sizeof(ia->ia_addr);
410 0 : ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
411 0 : ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
412 0 : ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
413 0 : ia->ia_sockmask.sin_len = 8;
414 0 : if (ifp->if_flags & IFF_BROADCAST) {
415 0 : ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
416 0 : ia->ia_broadaddr.sin_family = AF_INET;
417 0 : }
418 0 : ia->ia_ifp = ifp;
419 :
420 : newifaddr = 1;
421 0 : } else
422 : newifaddr = 0;
423 :
424 0 : if (ia->ia_addr.sin_family == AF_INET) {
425 0 : if (ifra->ifra_addr.sin_len == 0)
426 0 : ifra->ifra_addr = ia->ia_addr;
427 0 : else if (ifra->ifra_addr.sin_addr.s_addr !=
428 0 : ia->ia_addr.sin_addr.s_addr || newifaddr)
429 0 : needinit = 1;
430 : }
431 0 : if (ifra->ifra_mask.sin_len) {
432 0 : in_ifscrub(ifp, ia);
433 0 : ia->ia_sockmask = ifra->ifra_mask;
434 0 : ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr;
435 : needinit = 1;
436 0 : }
437 0 : if ((ifp->if_flags & IFF_POINTOPOINT) &&
438 0 : (ifra->ifra_dstaddr.sin_family == AF_INET)) {
439 0 : in_ifscrub(ifp, ia);
440 0 : ia->ia_dstaddr = ifra->ifra_dstaddr;
441 : needinit = 1;
442 0 : }
443 0 : if ((ifp->if_flags & IFF_BROADCAST) &&
444 0 : (ifra->ifra_broadaddr.sin_family == AF_INET)) {
445 0 : if (newifaddr)
446 0 : ia->ia_broadaddr = ifra->ifra_broadaddr;
447 : else
448 0 : ifa_update_broadaddr(ifp, &ia->ia_ifa,
449 0 : sintosa(&ifra->ifra_broadaddr));
450 : }
451 0 : if (ifra->ifra_addr.sin_family == AF_INET && needinit) {
452 0 : error = in_ifinit(ifp, ia, &ifra->ifra_addr, newifaddr);
453 0 : }
454 0 : if (error)
455 0 : break;
456 0 : dohooks(ifp->if_addrhooks, 0);
457 0 : break;
458 : }
459 : case SIOCDIFADDR:
460 0 : if (!privileged) {
461 : error = EPERM;
462 0 : break;
463 : }
464 :
465 0 : if (ia == NULL) {
466 : error = EADDRNOTAVAIL;
467 0 : break;
468 : }
469 : /*
470 : * Even if the individual steps were safe, shouldn't
471 : * these kinds of changes happen atomically? What
472 : * should happen to a packet that was routed after
473 : * the scrub but before the other steps?
474 : */
475 0 : in_purgeaddr(&ia->ia_ifa);
476 0 : dohooks(ifp->if_addrhooks, 0);
477 0 : break;
478 :
479 : default:
480 0 : panic("%s: invalid ioctl %lu", __func__, cmd);
481 : }
482 :
483 0 : NET_UNLOCK();
484 0 : return (error);
485 : }
486 :
487 : int
488 0 : in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
489 : {
490 0 : struct ifreq *ifr = (struct ifreq *)data;
491 : struct ifaddr *ifa;
492 : struct in_ifaddr *ia = NULL;
493 : int error = 0;
494 :
495 0 : NET_RLOCK();
496 :
497 0 : TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
498 0 : if (ifa->ifa_addr->sa_family == AF_INET) {
499 0 : ia = ifatoia(ifa);
500 0 : break;
501 : }
502 : }
503 :
504 0 : if (ia && satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
505 0 : for (; ifa != NULL; ifa = TAILQ_NEXT(ifa, ifa_list)) {
506 0 : if ((ifa->ifa_addr->sa_family == AF_INET) &&
507 0 : ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
508 0 : satosin(&ifr->ifr_addr)->sin_addr.s_addr) {
509 0 : ia = ifatoia(ifa);
510 0 : break;
511 : }
512 : }
513 : }
514 0 : if (ia == NULL) {
515 : error = EADDRNOTAVAIL;
516 0 : goto err;
517 : }
518 :
519 0 : switch(cmd) {
520 : case SIOCGIFADDR:
521 0 : *satosin(&ifr->ifr_addr) = ia->ia_addr;
522 0 : break;
523 :
524 : case SIOCGIFBRDADDR:
525 0 : if ((ifp->if_flags & IFF_BROADCAST) == 0) {
526 : error = EINVAL;
527 0 : break;
528 : }
529 0 : *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
530 0 : break;
531 :
532 : case SIOCGIFDSTADDR:
533 0 : if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
534 : error = EINVAL;
535 0 : break;
536 : }
537 0 : *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
538 0 : break;
539 :
540 : case SIOCGIFNETMASK:
541 0 : *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
542 0 : break;
543 :
544 : default:
545 0 : panic("%s: invalid ioctl %lu", __func__, cmd);
546 : }
547 :
548 : err:
549 0 : NET_RUNLOCK();
550 0 : return (error);
551 : }
552 :
553 : /*
554 : * Delete any existing route for an interface.
555 : */
556 : void
557 0 : in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
558 : {
559 0 : if (ISSET(ifp->if_flags, IFF_POINTOPOINT))
560 0 : in_scrubhost(ia, &ia->ia_dstaddr);
561 0 : else if (!ISSET(ifp->if_flags, IFF_LOOPBACK))
562 0 : in_remove_prefix(ia);
563 0 : }
564 :
565 : /*
566 : * Initialize an interface's internet address
567 : * and routing table entry.
568 : */
569 : int
570 0 : in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
571 : int newaddr)
572 : {
573 0 : u_int32_t i = sin->sin_addr.s_addr;
574 0 : struct sockaddr_in oldaddr;
575 : int error = 0, rterror;
576 :
577 0 : NET_ASSERT_LOCKED();
578 :
579 : /*
580 : * Always remove the address from the tree to make sure its
581 : * position gets updated in case the key changes.
582 : */
583 0 : if (!newaddr) {
584 0 : rt_ifa_dellocal(&ia->ia_ifa);
585 0 : ifa_del(ifp, &ia->ia_ifa);
586 0 : }
587 0 : oldaddr = ia->ia_addr;
588 0 : ia->ia_addr = *sin;
589 :
590 0 : if (ia->ia_netmask == 0) {
591 0 : if (IN_CLASSA(i))
592 0 : ia->ia_netmask = IN_CLASSA_NET;
593 0 : else if (IN_CLASSB(i))
594 0 : ia->ia_netmask = IN_CLASSB_NET;
595 : else
596 0 : ia->ia_netmask = IN_CLASSC_NET;
597 0 : ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
598 0 : }
599 :
600 : /*
601 : * Give the interface a chance to initialize
602 : * if this is its first address,
603 : * and to validate the address if necessary.
604 : */
605 0 : if ((error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
606 0 : ia->ia_addr = oldaddr;
607 0 : }
608 :
609 : /*
610 : * Add the address to the local list and the global tree. If an
611 : * error occured, put back the original address.
612 : */
613 0 : ifa_add(ifp, &ia->ia_ifa);
614 0 : rterror = rt_ifa_addlocal(&ia->ia_ifa);
615 :
616 0 : if (rterror) {
617 0 : if (!newaddr)
618 0 : ifa_del(ifp, &ia->ia_ifa);
619 0 : if (!error)
620 0 : error = rterror;
621 : goto out;
622 : }
623 0 : if (error)
624 : goto out;
625 :
626 :
627 0 : ia->ia_net = i & ia->ia_netmask;
628 0 : in_socktrim(&ia->ia_sockmask);
629 : /*
630 : * Add route for the network.
631 : */
632 0 : ia->ia_ifa.ifa_metric = ifp->if_metric;
633 0 : if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
634 0 : if (IN_RFC3021_SUBNET(ia->ia_netmask))
635 0 : ia->ia_broadaddr.sin_addr.s_addr = 0;
636 : else {
637 0 : ia->ia_broadaddr.sin_addr.s_addr =
638 0 : ia->ia_net | ~ia->ia_netmask;
639 : }
640 : }
641 :
642 0 : if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) {
643 : /* XXX We should not even call in_ifinit() in this case. */
644 0 : if (ia->ia_dstaddr.sin_family != AF_INET)
645 : goto out;
646 0 : error = in_addhost(ia, &ia->ia_dstaddr);
647 0 : } else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) {
648 0 : error = in_insert_prefix(ia);
649 0 : }
650 :
651 : /*
652 : * If the interface supports multicast, join the "all hosts"
653 : * multicast group on that interface.
654 : */
655 0 : if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
656 0 : struct in_addr addr;
657 :
658 0 : addr.s_addr = INADDR_ALLHOSTS_GROUP;
659 0 : ia->ia_allhosts = in_addmulti(&addr, ifp);
660 0 : }
661 :
662 : out:
663 0 : if (error && newaddr)
664 0 : in_purgeaddr(&ia->ia_ifa);
665 :
666 0 : return (error);
667 0 : }
668 :
669 : void
670 0 : in_purgeaddr(struct ifaddr *ifa)
671 : {
672 0 : struct ifnet *ifp = ifa->ifa_ifp;
673 0 : struct in_ifaddr *ia = ifatoia(ifa);
674 : extern int ifatrash;
675 :
676 0 : NET_ASSERT_LOCKED();
677 :
678 0 : in_ifscrub(ifp, ia);
679 :
680 0 : rt_ifa_dellocal(&ia->ia_ifa);
681 0 : rt_ifa_purge(&ia->ia_ifa);
682 0 : ifa_del(ifp, &ia->ia_ifa);
683 :
684 0 : if (ia->ia_allhosts != NULL) {
685 0 : in_delmulti(ia->ia_allhosts);
686 0 : ia->ia_allhosts = NULL;
687 0 : }
688 :
689 0 : ifatrash++;
690 0 : ia->ia_ifp = NULL;
691 0 : ifafree(&ia->ia_ifa);
692 0 : }
693 :
694 : int
695 0 : in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
696 : {
697 0 : return rt_ifa_add(&ia->ia_ifa, RTF_HOST, sintosa(dst));
698 : }
699 :
700 : int
701 0 : in_scrubhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
702 : {
703 0 : return rt_ifa_del(&ia->ia_ifa, RTF_HOST, sintosa(dst));
704 : }
705 :
706 : /*
707 : * Insert the cloning and broadcast routes for this subnet.
708 : */
709 : int
710 0 : in_insert_prefix(struct in_ifaddr *ia)
711 : {
712 0 : struct ifaddr *ifa = &ia->ia_ifa;
713 : int error;
714 :
715 0 : error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr);
716 0 : if (error)
717 0 : return (error);
718 :
719 0 : if (ia->ia_broadaddr.sin_addr.s_addr != 0)
720 0 : error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST,
721 0 : ifa->ifa_broadaddr);
722 :
723 0 : return (error);
724 0 : }
725 :
726 : void
727 0 : in_remove_prefix(struct in_ifaddr *ia)
728 : {
729 0 : struct ifaddr *ifa = &ia->ia_ifa;
730 :
731 0 : rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED, ifa->ifa_addr);
732 :
733 0 : if (ia->ia_broadaddr.sin_addr.s_addr != 0)
734 0 : rt_ifa_del(ifa, RTF_HOST | RTF_BROADCAST, ifa->ifa_broadaddr);
735 0 : }
736 :
737 : /*
738 : * Return 1 if the address is a local broadcast address.
739 : */
740 : int
741 0 : in_broadcast(struct in_addr in, u_int rtableid)
742 : {
743 : struct ifnet *ifn;
744 : struct ifaddr *ifa;
745 : u_int rdomain;
746 :
747 0 : rdomain = rtable_l2(rtableid);
748 :
749 : #define ia (ifatoia(ifa))
750 0 : TAILQ_FOREACH(ifn, &ifnet, if_list) {
751 0 : if (ifn->if_rdomain != rdomain)
752 : continue;
753 0 : if ((ifn->if_flags & IFF_BROADCAST) == 0)
754 : continue;
755 0 : TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
756 0 : if (ifa->ifa_addr->sa_family == AF_INET &&
757 0 : in.s_addr != ia->ia_addr.sin_addr.s_addr &&
758 0 : in.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
759 0 : return 1;
760 : }
761 0 : return (0);
762 : #undef ia
763 0 : }
764 :
765 : /*
766 : * Add an address to the list of IP multicast addresses for a given interface.
767 : */
768 : struct in_multi *
769 0 : in_addmulti(struct in_addr *ap, struct ifnet *ifp)
770 : {
771 : struct in_multi *inm;
772 0 : struct ifreq ifr;
773 :
774 : /*
775 : * See if address already in list.
776 : */
777 0 : IN_LOOKUP_MULTI(*ap, ifp, inm);
778 0 : if (inm != NULL) {
779 : /*
780 : * Found it; just increment the reference count.
781 : */
782 0 : ++inm->inm_refcnt;
783 0 : } else {
784 : /*
785 : * New address; allocate a new multicast record
786 : * and link it into the interface's multicast list.
787 : */
788 0 : inm = malloc(sizeof(*inm), M_IPMADDR, M_NOWAIT | M_ZERO);
789 0 : if (inm == NULL)
790 0 : return (NULL);
791 :
792 0 : inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
793 0 : inm->inm_sin.sin_family = AF_INET;
794 0 : inm->inm_sin.sin_addr = *ap;
795 0 : inm->inm_refcnt = 1;
796 0 : inm->inm_ifidx = ifp->if_index;
797 0 : inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
798 :
799 : /*
800 : * Ask the network driver to update its multicast reception
801 : * filter appropriately for the new address.
802 : */
803 0 : memset(&ifr, 0, sizeof(ifr));
804 0 : memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
805 0 : if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
806 0 : free(inm, M_IPMADDR, sizeof(*inm));
807 0 : return (NULL);
808 : }
809 :
810 0 : TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
811 : ifma_list);
812 :
813 : /*
814 : * Let IGMP know that we have joined a new IP multicast group.
815 : */
816 0 : igmp_joingroup(inm);
817 : }
818 :
819 0 : return (inm);
820 0 : }
821 :
822 : /*
823 : * Delete a multicast address record.
824 : */
825 : void
826 0 : in_delmulti(struct in_multi *inm)
827 : {
828 0 : struct ifreq ifr;
829 : struct ifnet *ifp;
830 :
831 0 : NET_ASSERT_LOCKED();
832 :
833 0 : if (--inm->inm_refcnt == 0) {
834 : /*
835 : * No remaining claims to this record; let IGMP know that
836 : * we are leaving the multicast group.
837 : */
838 0 : igmp_leavegroup(inm);
839 0 : ifp = if_get(inm->inm_ifidx);
840 :
841 : /*
842 : * Notify the network driver to update its multicast
843 : * reception filter.
844 : */
845 0 : if (ifp != NULL) {
846 0 : memset(&ifr, 0, sizeof(ifr));
847 0 : satosin(&ifr.ifr_addr)->sin_len =
848 : sizeof(struct sockaddr_in);
849 0 : satosin(&ifr.ifr_addr)->sin_family = AF_INET;
850 0 : satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
851 0 : (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
852 :
853 0 : TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma,
854 : ifma_list);
855 0 : }
856 0 : if_put(ifp);
857 :
858 0 : free(inm, M_IPMADDR, sizeof(*inm));
859 0 : }
860 0 : }
861 :
862 : /*
863 : * Return 1 if the multicast group represented by ``ap'' has been
864 : * joined by interface ``ifp'', 0 otherwise.
865 : */
866 : int
867 0 : in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
868 : {
869 : struct in_multi *inm;
870 : int joined;
871 :
872 0 : IN_LOOKUP_MULTI(*ap, ifp, inm);
873 0 : joined = (inm != NULL);
874 :
875 0 : return (joined);
876 : }
877 :
878 : void
879 0 : in_ifdetach(struct ifnet *ifp)
880 : {
881 : struct ifaddr *ifa, *next;
882 :
883 : /* nuke any of IPv4 addresses we have */
884 0 : TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
885 0 : if (ifa->ifa_addr->sa_family != AF_INET)
886 : continue;
887 0 : in_purgeaddr(ifa);
888 0 : dohooks(ifp->if_addrhooks, 0);
889 0 : }
890 0 : }
891 :
892 : void
893 0 : in_prefixlen2mask(struct in_addr *maskp, int plen)
894 : {
895 0 : if (plen == 0)
896 0 : maskp->s_addr = 0;
897 : else
898 0 : maskp->s_addr = htonl(0xffffffff << (32 - plen));
899 0 : }
|