FreeBSD/Linux Kernel Cross Reference
sys/netinet/in.c
1 /* $OpenBSD: in.c,v 1.179 2022/12/06 22:19:39 mvs 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_set_ifaddr(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 in_canforward(struct in_addr in)
103 {
104 u_int32_t net;
105
106 if (IN_MULTICAST(in.s_addr))
107 return (0);
108 if (IN_CLASSA(in.s_addr)) {
109 net = in.s_addr & IN_CLASSA_NET;
110 if (net == 0 ||
111 net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
112 return (0);
113 }
114 return (1);
115 }
116
117 /*
118 * Trim a mask in a sockaddr
119 */
120 void
121 in_socktrim(struct sockaddr_in *ap)
122 {
123 char *cplim = (char *) &ap->sin_addr;
124 char *cp = (char *) (&ap->sin_addr + 1);
125
126 ap->sin_len = 0;
127 while (--cp >= cplim)
128 if (*cp) {
129 (ap)->sin_len = cp - (char *) (ap) + 1;
130 break;
131 }
132 }
133
134 int
135 in_mask2len(struct in_addr *mask)
136 {
137 int x, y;
138 u_char *p;
139
140 p = (u_char *)mask;
141 for (x = 0; x < sizeof(*mask); x++) {
142 if (p[x] != 0xff)
143 break;
144 }
145 y = 0;
146 if (x < sizeof(*mask)) {
147 for (y = 0; y < 8; y++) {
148 if ((p[x] & (0x80 >> y)) == 0)
149 break;
150 }
151 }
152 return x * 8 + y;
153 }
154
155 void
156 in_len2mask(struct in_addr *mask, int len)
157 {
158 int i;
159 u_char *p;
160
161 p = (u_char *)mask;
162 bzero(mask, sizeof(*mask));
163 for (i = 0; i < len / 8; i++)
164 p[i] = 0xff;
165 if (len % 8)
166 p[i] = (0xff00 >> (len % 8)) & 0xff;
167 }
168
169 int
170 in_nam2sin(const struct mbuf *nam, struct sockaddr_in **sin)
171 {
172 struct sockaddr *sa = mtod(nam, struct sockaddr *);
173
174 if (nam->m_len < offsetof(struct sockaddr, sa_data))
175 return EINVAL;
176 if (sa->sa_family != AF_INET)
177 return EAFNOSUPPORT;
178 if (sa->sa_len != nam->m_len)
179 return EINVAL;
180 if (sa->sa_len != sizeof(struct sockaddr_in))
181 return EINVAL;
182 *sin = satosin(sa);
183
184 return 0;
185 }
186
187 int
188 in_sa2sin(struct sockaddr *sa, struct sockaddr_in **sin)
189 {
190 if (sa->sa_family != AF_INET)
191 return EAFNOSUPPORT;
192 if (sa->sa_len != sizeof(struct sockaddr_in))
193 return EINVAL;
194 *sin = satosin(sa);
195
196 return 0;
197 }
198
199 int
200 in_control(struct socket *so, u_long cmd, caddr_t data, struct ifnet *ifp)
201 {
202 int privileged;
203 int error;
204
205 privileged = 0;
206 if ((so->so_state & SS_PRIV) != 0)
207 privileged++;
208
209 switch (cmd) {
210 #ifdef MROUTING
211 case SIOCGETVIFCNT:
212 case SIOCGETSGCNT:
213 KERNEL_LOCK();
214 error = mrt_ioctl(so, cmd, data);
215 KERNEL_UNLOCK();
216 break;
217 #endif /* MROUTING */
218 default:
219 KERNEL_LOCK();
220 error = in_ioctl(cmd, data, ifp, privileged);
221 KERNEL_UNLOCK();
222 break;
223 }
224
225 return error;
226 }
227
228 int
229 in_ioctl(u_long cmd, caddr_t data, struct ifnet *ifp, int privileged)
230 {
231 struct ifreq *ifr = (struct ifreq *)data;
232 struct ifaddr *ifa;
233 struct in_ifaddr *ia = NULL;
234 struct sockaddr_in *sin = NULL, oldaddr;
235 int error = 0;
236
237 if (ifp == NULL)
238 return (ENXIO);
239
240 switch (cmd) {
241 case SIOCGIFADDR:
242 case SIOCGIFNETMASK:
243 case SIOCGIFDSTADDR:
244 case SIOCGIFBRDADDR:
245 return in_ioctl_get(cmd, data, ifp);
246 case SIOCSIFADDR:
247 return in_ioctl_set_ifaddr(cmd, data, ifp, privileged);
248 case SIOCAIFADDR:
249 case SIOCDIFADDR:
250 return in_ioctl_change_ifaddr(cmd, data, ifp, privileged);
251 case SIOCSIFNETMASK:
252 case SIOCSIFDSTADDR:
253 case SIOCSIFBRDADDR:
254 break;
255 default:
256 return (EOPNOTSUPP);
257 }
258
259 if (ifr->ifr_addr.sa_family == AF_INET) {
260 error = in_sa2sin(&ifr->ifr_addr, &sin);
261 if (error)
262 return (error);
263 }
264
265 NET_LOCK();
266
267 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
268 if (ifa->ifa_addr->sa_family != AF_INET)
269 continue;
270 /* find first address or exact match */
271 if (ia == NULL)
272 ia = ifatoia(ifa);
273 if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
274 break;
275 if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
276 sin->sin_addr.s_addr) {
277 ia = ifatoia(ifa);
278 break;
279 }
280 }
281 if (ia == NULL) {
282 error = EADDRNOTAVAIL;
283 goto err;
284 }
285
286 switch (cmd) {
287 case SIOCSIFDSTADDR:
288 if (!privileged) {
289 error = EPERM;
290 break;
291 }
292
293 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
294 error = EINVAL;
295 break;
296 }
297 error = in_sa2sin(&ifr->ifr_dstaddr, &sin);
298 if (error)
299 break;
300 oldaddr = ia->ia_dstaddr;
301 ia->ia_dstaddr = *sin;
302 error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, (caddr_t)ia);
303 if (error) {
304 ia->ia_dstaddr = oldaddr;
305 break;
306 }
307 in_scrubhost(ia, &oldaddr);
308 in_addhost(ia, &ia->ia_dstaddr);
309 break;
310
311 case SIOCSIFBRDADDR:
312 if (!privileged) {
313 error = EPERM;
314 break;
315 }
316
317 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
318 error = EINVAL;
319 break;
320 }
321 error = in_sa2sin(&ifr->ifr_broadaddr, &sin);
322 if (error)
323 break;
324 ifa_update_broadaddr(ifp, &ia->ia_ifa, sintosa(sin));
325 break;
326
327 case SIOCSIFNETMASK:
328 if (!privileged) {
329 error = EPERM;
330 break;
331 }
332
333 if (ifr->ifr_addr.sa_len < 8) {
334 error = EINVAL;
335 break;
336 }
337 /* do not check inet family or strict len */
338 sin = satosin(&ifr->ifr_addr);
339 if (ntohl(sin->sin_addr.s_addr) &
340 (~ntohl(sin->sin_addr.s_addr) >> 1)) {
341 /* non-contiguous netmask */
342 error = EINVAL;
343 break;
344 }
345 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
346 sin->sin_addr.s_addr;
347 break;
348 }
349 err:
350 NET_UNLOCK();
351 return (error);
352 }
353
354 int
355 in_ioctl_set_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
356 int privileged)
357 {
358 struct ifreq *ifr = (struct ifreq *)data;
359 struct ifaddr *ifa;
360 struct in_ifaddr *ia = NULL;
361 struct sockaddr_in *sin;
362 int error = 0;
363 int newifaddr;
364
365 if (cmd != SIOCSIFADDR)
366 panic("%s: invalid ioctl %lu", __func__, cmd);
367
368 if (!privileged)
369 return (EPERM);
370
371 error = in_sa2sin(&ifr->ifr_addr, &sin);
372 if (error)
373 return (error);
374
375 NET_LOCK();
376
377 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
378 if (ifa->ifa_addr->sa_family != AF_INET)
379 continue;
380 /* find first address */
381 ia = ifatoia(ifa);
382 break;
383 }
384 if (ia == NULL) {
385 ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
386 refcnt_init_trace(&ia->ia_ifa.ifa_refcnt, DT_REFCNT_IDX_IFADDR);
387 ia->ia_addr.sin_family = AF_INET;
388 ia->ia_addr.sin_len = sizeof(ia->ia_addr);
389 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
390 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
391 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
392 ia->ia_sockmask.sin_len = 8;
393 if (ifp->if_flags & IFF_BROADCAST) {
394 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
395 ia->ia_broadaddr.sin_family = AF_INET;
396 }
397 ia->ia_ifp = ifp;
398
399 newifaddr = 1;
400 } else
401 newifaddr = 0;
402
403 in_ifscrub(ifp, ia);
404 error = in_ifinit(ifp, ia, sin, newifaddr);
405 if (!error)
406 if_addrhooks_run(ifp);
407
408 NET_UNLOCK();
409 return error;
410 }
411
412 int
413 in_ioctl_change_ifaddr(u_long cmd, caddr_t data, struct ifnet *ifp,
414 int privileged)
415 {
416 struct ifaddr *ifa;
417 struct in_ifaddr *ia = NULL;
418 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
419 struct sockaddr_in *sin = NULL, *dstsin = NULL, *broadsin = NULL;
420 struct sockaddr_in *masksin = NULL;
421 int error = 0;
422 int newifaddr;
423
424 if (ifra->ifra_addr.sin_family == AF_INET) {
425 error = in_sa2sin(sintosa(&ifra->ifra_addr), &sin);
426 if (error)
427 return (error);
428 }
429
430 NET_LOCK();
431
432 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
433 if (ifa->ifa_addr->sa_family != AF_INET)
434 continue;
435 /* find first address, if no exact match wanted */
436 if (sin == NULL || sin->sin_addr.s_addr ==
437 ifatoia(ifa)->ia_addr.sin_addr.s_addr) {
438 ia = ifatoia(ifa);
439 break;
440 }
441 }
442
443 switch (cmd) {
444 case SIOCAIFADDR: {
445 int needinit = 0;
446
447 if (!privileged) {
448 error = EPERM;
449 break;
450 }
451
452 if (ifra->ifra_mask.sin_len) {
453 if (ifra->ifra_mask.sin_len < 8) {
454 error = EINVAL;
455 break;
456 }
457 /* do not check inet family or strict len */
458 masksin = &ifra->ifra_mask;
459 if (ntohl(masksin->sin_addr.s_addr) &
460 (~ntohl(masksin->sin_addr.s_addr) >> 1)) {
461 /* non-contiguous netmask */
462 error = EINVAL;
463 break;
464 }
465 }
466 if ((ifp->if_flags & IFF_POINTOPOINT) &&
467 ifra->ifra_dstaddr.sin_family == AF_INET) {
468 error = in_sa2sin(sintosa(&ifra->ifra_dstaddr),
469 &dstsin);
470 if (error)
471 break;
472 }
473 if ((ifp->if_flags & IFF_BROADCAST) &&
474 ifra->ifra_broadaddr.sin_family == AF_INET) {
475 error = in_sa2sin(sintosa(&ifra->ifra_broadaddr),
476 &broadsin);
477 if (error)
478 break;
479 }
480
481 if (ia == NULL) {
482 ia = malloc(sizeof *ia, M_IFADDR, M_WAITOK | M_ZERO);
483 refcnt_init_trace(&ia->ia_ifa.ifa_refcnt,
484 DT_REFCNT_IDX_IFADDR);
485 ia->ia_addr.sin_family = AF_INET;
486 ia->ia_addr.sin_len = sizeof(ia->ia_addr);
487 ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr);
488 ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr);
489 ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask);
490 ia->ia_sockmask.sin_len = 8;
491 if (ifp->if_flags & IFF_BROADCAST) {
492 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
493 ia->ia_broadaddr.sin_family = AF_INET;
494 }
495 ia->ia_ifp = ifp;
496
497 newifaddr = 1;
498 } else
499 newifaddr = 0;
500
501 if (sin == NULL) {
502 sin = &ia->ia_addr;
503 } else if (newifaddr ||
504 sin->sin_addr.s_addr != ia->ia_addr.sin_addr.s_addr) {
505 needinit = 1;
506 }
507 if (masksin != NULL) {
508 in_ifscrub(ifp, ia);
509 ia->ia_netmask = ia->ia_sockmask.sin_addr.s_addr =
510 masksin->sin_addr.s_addr;
511 needinit = 1;
512 }
513 if (dstsin != NULL) {
514 in_ifscrub(ifp, ia);
515 ia->ia_dstaddr = *dstsin;
516 needinit = 1;
517 }
518 if (broadsin != NULL) {
519 if (newifaddr)
520 ia->ia_broadaddr = *broadsin;
521 else
522 ifa_update_broadaddr(ifp, &ia->ia_ifa,
523 sintosa(broadsin));
524 }
525 if (needinit) {
526 error = in_ifinit(ifp, ia, sin, newifaddr);
527 if (error)
528 break;
529 }
530 if_addrhooks_run(ifp);
531 break;
532 }
533 case SIOCDIFADDR:
534 if (!privileged) {
535 error = EPERM;
536 break;
537 }
538
539 if (ia == NULL) {
540 error = EADDRNOTAVAIL;
541 break;
542 }
543 /*
544 * Even if the individual steps were safe, shouldn't
545 * these kinds of changes happen atomically? What
546 * should happen to a packet that was routed after
547 * the scrub but before the other steps?
548 */
549 in_purgeaddr(&ia->ia_ifa);
550 if_addrhooks_run(ifp);
551 break;
552
553 default:
554 panic("%s: invalid ioctl %lu", __func__, cmd);
555 }
556
557 NET_UNLOCK();
558 return (error);
559 }
560
561 int
562 in_ioctl_get(u_long cmd, caddr_t data, struct ifnet *ifp)
563 {
564 struct ifreq *ifr = (struct ifreq *)data;
565 struct ifaddr *ifa;
566 struct in_ifaddr *ia = NULL;
567 struct sockaddr *sa;
568 struct sockaddr_in *sin = NULL;
569 int error = 0;
570
571 sa = &ifr->ifr_addr;
572 if (sa->sa_family == AF_INET) {
573 sa->sa_len = sizeof(struct sockaddr_in);
574 error = in_sa2sin(sa, &sin);
575 if (error)
576 return (error);
577 }
578
579 NET_LOCK_SHARED();
580
581 TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
582 if (ifa->ifa_addr->sa_family != AF_INET)
583 continue;
584 /* find first address or exact match */
585 if (ia == NULL)
586 ia = ifatoia(ifa);
587 if (sin == NULL || sin->sin_addr.s_addr == INADDR_ANY)
588 break;
589 if (ifatoia(ifa)->ia_addr.sin_addr.s_addr ==
590 sin->sin_addr.s_addr) {
591 ia = ifatoia(ifa);
592 break;
593 }
594 }
595 if (ia == NULL) {
596 error = EADDRNOTAVAIL;
597 goto err;
598 }
599
600 switch(cmd) {
601 case SIOCGIFADDR:
602 *satosin(&ifr->ifr_addr) = ia->ia_addr;
603 break;
604
605 case SIOCGIFBRDADDR:
606 if ((ifp->if_flags & IFF_BROADCAST) == 0) {
607 error = EINVAL;
608 break;
609 }
610 *satosin(&ifr->ifr_dstaddr) = ia->ia_broadaddr;
611 break;
612
613 case SIOCGIFDSTADDR:
614 if ((ifp->if_flags & IFF_POINTOPOINT) == 0) {
615 error = EINVAL;
616 break;
617 }
618 *satosin(&ifr->ifr_dstaddr) = ia->ia_dstaddr;
619 break;
620
621 case SIOCGIFNETMASK:
622 *satosin(&ifr->ifr_addr) = ia->ia_sockmask;
623 break;
624
625 default:
626 panic("%s: invalid ioctl %lu", __func__, cmd);
627 }
628
629 err:
630 NET_UNLOCK_SHARED();
631 return (error);
632 }
633
634 /*
635 * Delete any existing route for an interface.
636 */
637 void
638 in_ifscrub(struct ifnet *ifp, struct in_ifaddr *ia)
639 {
640 if (ISSET(ifp->if_flags, IFF_POINTOPOINT))
641 in_scrubhost(ia, &ia->ia_dstaddr);
642 else if (!ISSET(ifp->if_flags, IFF_LOOPBACK))
643 in_remove_prefix(ia);
644 }
645
646 /*
647 * Initialize an interface's internet address
648 * and routing table entry.
649 */
650 int
651 in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, struct sockaddr_in *sin,
652 int newaddr)
653 {
654 u_int32_t i = sin->sin_addr.s_addr;
655 struct sockaddr_in oldaddr;
656 int error = 0, rterror;
657
658 NET_ASSERT_LOCKED();
659
660 /*
661 * Always remove the address from the tree to make sure its
662 * position gets updated in case the key changes.
663 */
664 if (!newaddr) {
665 rt_ifa_dellocal(&ia->ia_ifa);
666 ifa_del(ifp, &ia->ia_ifa);
667 }
668 oldaddr = ia->ia_addr;
669 ia->ia_addr = *sin;
670
671 if (ia->ia_netmask == 0) {
672 if (IN_CLASSA(i))
673 ia->ia_netmask = IN_CLASSA_NET;
674 else if (IN_CLASSB(i))
675 ia->ia_netmask = IN_CLASSB_NET;
676 else
677 ia->ia_netmask = IN_CLASSC_NET;
678 ia->ia_sockmask.sin_addr.s_addr = ia->ia_netmask;
679 }
680
681 /*
682 * Give the interface a chance to initialize
683 * if this is its first address,
684 * and to validate the address if necessary.
685 */
686 if ((error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia))) {
687 ia->ia_addr = oldaddr;
688 }
689
690 /*
691 * Add the address to the local list and the global tree. If an
692 * error occurred, put back the original address.
693 */
694 ifa_add(ifp, &ia->ia_ifa);
695 rterror = rt_ifa_addlocal(&ia->ia_ifa);
696
697 if (rterror) {
698 if (!newaddr)
699 ifa_del(ifp, &ia->ia_ifa);
700 if (!error)
701 error = rterror;
702 goto out;
703 }
704 if (error)
705 goto out;
706
707
708 ia->ia_net = i & ia->ia_netmask;
709 in_socktrim(&ia->ia_sockmask);
710 /*
711 * Add route for the network.
712 */
713 ia->ia_ifa.ifa_metric = ifp->if_metric;
714 if (ISSET(ifp->if_flags, IFF_BROADCAST)) {
715 if (IN_RFC3021_SUBNET(ia->ia_netmask))
716 ia->ia_broadaddr.sin_addr.s_addr = 0;
717 else {
718 ia->ia_broadaddr.sin_addr.s_addr =
719 ia->ia_net | ~ia->ia_netmask;
720 }
721 }
722
723 if (ISSET(ifp->if_flags, IFF_POINTOPOINT)) {
724 /* XXX We should not even call in_ifinit() in this case. */
725 if (ia->ia_dstaddr.sin_family != AF_INET)
726 goto out;
727 error = in_addhost(ia, &ia->ia_dstaddr);
728 } else if (!ISSET(ifp->if_flags, IFF_LOOPBACK)) {
729 error = in_insert_prefix(ia);
730 }
731
732 /*
733 * If the interface supports multicast, join the "all hosts"
734 * multicast group on that interface.
735 */
736 if ((ifp->if_flags & IFF_MULTICAST) && ia->ia_allhosts == NULL) {
737 struct in_addr addr;
738
739 addr.s_addr = INADDR_ALLHOSTS_GROUP;
740 ia->ia_allhosts = in_addmulti(&addr, ifp);
741 }
742
743 out:
744 if (error && newaddr)
745 in_purgeaddr(&ia->ia_ifa);
746
747 return (error);
748 }
749
750 void
751 in_purgeaddr(struct ifaddr *ifa)
752 {
753 struct ifnet *ifp = ifa->ifa_ifp;
754 struct in_ifaddr *ia = ifatoia(ifa);
755
756 NET_ASSERT_LOCKED();
757
758 in_ifscrub(ifp, ia);
759
760 rt_ifa_dellocal(&ia->ia_ifa);
761 rt_ifa_purge(&ia->ia_ifa);
762 ifa_del(ifp, &ia->ia_ifa);
763
764 if (ia->ia_allhosts != NULL) {
765 in_delmulti(ia->ia_allhosts);
766 ia->ia_allhosts = NULL;
767 }
768
769 ia->ia_ifp = NULL;
770 ifafree(&ia->ia_ifa);
771 }
772
773 int
774 in_addhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
775 {
776 return rt_ifa_add(&ia->ia_ifa, RTF_HOST | RTF_MPATH,
777 sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
778 }
779
780 int
781 in_scrubhost(struct in_ifaddr *ia, struct sockaddr_in *dst)
782 {
783 return rt_ifa_del(&ia->ia_ifa, RTF_HOST,
784 sintosa(dst), ia->ia_ifa.ifa_ifp->if_rdomain);
785 }
786
787 /*
788 * Insert the cloning and broadcast routes for this subnet.
789 */
790 int
791 in_insert_prefix(struct in_ifaddr *ia)
792 {
793 struct ifaddr *ifa = &ia->ia_ifa;
794 int error;
795
796 error = rt_ifa_add(ifa, RTF_CLONING | RTF_CONNECTED | RTF_MPATH,
797 ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
798 if (error)
799 return (error);
800
801 if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
802 error = rt_ifa_add(ifa, RTF_HOST | RTF_BROADCAST | RTF_MPATH,
803 ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
804 }
805
806 return (error);
807 }
808
809 void
810 in_remove_prefix(struct in_ifaddr *ia)
811 {
812 struct ifaddr *ifa = &ia->ia_ifa;
813
814 rt_ifa_del(ifa, RTF_CLONING | RTF_CONNECTED,
815 ifa->ifa_addr, ifa->ifa_ifp->if_rdomain);
816
817 if (ia->ia_broadaddr.sin_addr.s_addr != 0) {
818 rt_ifa_del(ifa, RTF_HOST | RTF_BROADCAST,
819 ifa->ifa_broadaddr, ifa->ifa_ifp->if_rdomain);
820 }
821 }
822
823 /*
824 * Return 1 if the address is a local broadcast address.
825 */
826 int
827 in_broadcast(struct in_addr in, u_int rtableid)
828 {
829 struct ifnet *ifn;
830 struct ifaddr *ifa;
831 u_int rdomain;
832
833 rdomain = rtable_l2(rtableid);
834
835 #define ia (ifatoia(ifa))
836 TAILQ_FOREACH(ifn, &ifnetlist, if_list) {
837 if (ifn->if_rdomain != rdomain)
838 continue;
839 if ((ifn->if_flags & IFF_BROADCAST) == 0)
840 continue;
841 TAILQ_FOREACH(ifa, &ifn->if_addrlist, ifa_list)
842 if (ifa->ifa_addr->sa_family == AF_INET &&
843 in.s_addr != ia->ia_addr.sin_addr.s_addr &&
844 in.s_addr == ia->ia_broadaddr.sin_addr.s_addr)
845 return 1;
846 }
847 return (0);
848 #undef ia
849 }
850
851 /*
852 * Add an address to the list of IP multicast addresses for a given interface.
853 */
854 struct in_multi *
855 in_addmulti(struct in_addr *ap, struct ifnet *ifp)
856 {
857 struct in_multi *inm;
858 struct ifreq ifr;
859
860 /*
861 * See if address already in list.
862 */
863 IN_LOOKUP_MULTI(*ap, ifp, inm);
864 if (inm != NULL) {
865 /*
866 * Found it; just increment the reference count.
867 */
868 ++inm->inm_refcnt;
869 } else {
870 /*
871 * New address; allocate a new multicast record
872 * and link it into the interface's multicast list.
873 */
874 inm = malloc(sizeof(*inm), M_IPMADDR, M_WAITOK | M_ZERO);
875 inm->inm_sin.sin_len = sizeof(struct sockaddr_in);
876 inm->inm_sin.sin_family = AF_INET;
877 inm->inm_sin.sin_addr = *ap;
878 inm->inm_refcnt = 1;
879 inm->inm_ifidx = ifp->if_index;
880 inm->inm_ifma.ifma_addr = sintosa(&inm->inm_sin);
881
882 /*
883 * Ask the network driver to update its multicast reception
884 * filter appropriately for the new address.
885 */
886 memset(&ifr, 0, sizeof(ifr));
887 memcpy(&ifr.ifr_addr, &inm->inm_sin, sizeof(inm->inm_sin));
888 KERNEL_LOCK();
889 if ((*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
890 KERNEL_UNLOCK();
891 free(inm, M_IPMADDR, sizeof(*inm));
892 return (NULL);
893 }
894 KERNEL_UNLOCK();
895
896 TAILQ_INSERT_HEAD(&ifp->if_maddrlist, &inm->inm_ifma,
897 ifma_list);
898
899 /*
900 * Let IGMP know that we have joined a new IP multicast group.
901 */
902 igmp_joingroup(inm, ifp);
903 }
904
905 return (inm);
906 }
907
908 /*
909 * Delete a multicast address record.
910 */
911 void
912 in_delmulti(struct in_multi *inm)
913 {
914 struct ifreq ifr;
915 struct ifnet *ifp;
916
917 NET_ASSERT_LOCKED();
918
919 if (--inm->inm_refcnt != 0)
920 return;
921
922 ifp = if_get(inm->inm_ifidx);
923 if (ifp != NULL) {
924 /*
925 * No remaining claims to this record; let IGMP know that
926 * we are leaving the multicast group.
927 */
928 igmp_leavegroup(inm, ifp);
929
930 /*
931 * Notify the network driver to update its multicast
932 * reception filter.
933 */
934 memset(&ifr, 0, sizeof(ifr));
935 satosin(&ifr.ifr_addr)->sin_len = sizeof(struct sockaddr_in);
936 satosin(&ifr.ifr_addr)->sin_family = AF_INET;
937 satosin(&ifr.ifr_addr)->sin_addr = inm->inm_addr;
938 KERNEL_LOCK();
939 (*ifp->if_ioctl)(ifp, SIOCDELMULTI, (caddr_t)&ifr);
940 KERNEL_UNLOCK();
941
942 TAILQ_REMOVE(&ifp->if_maddrlist, &inm->inm_ifma, ifma_list);
943 }
944 if_put(ifp);
945
946 free(inm, M_IPMADDR, sizeof(*inm));
947 }
948
949 /*
950 * Return 1 if the multicast group represented by ``ap'' has been
951 * joined by interface ``ifp'', 0 otherwise.
952 */
953 int
954 in_hasmulti(struct in_addr *ap, struct ifnet *ifp)
955 {
956 struct in_multi *inm;
957 int joined;
958
959 IN_LOOKUP_MULTI(*ap, ifp, inm);
960 joined = (inm != NULL);
961
962 return (joined);
963 }
964
965 void
966 in_ifdetach(struct ifnet *ifp)
967 {
968 struct ifaddr *ifa, *next;
969
970 /* nuke any of IPv4 addresses we have */
971 TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
972 if (ifa->ifa_addr->sa_family != AF_INET)
973 continue;
974 in_purgeaddr(ifa);
975 if_addrhooks_run(ifp);
976 }
977
978 if (ifp->if_xflags & IFXF_AUTOCONF4)
979 ifp->if_xflags &= ~IFXF_AUTOCONF4;
980 }
981
982 void
983 in_prefixlen2mask(struct in_addr *maskp, int plen)
984 {
985 if (plen == 0)
986 maskp->s_addr = 0;
987 else
988 maskp->s_addr = htonl(0xffffffff << (32 - plen));
989 }
Cache object: 88eb0be17beb06d164f6b9e7d26701ec
|