in.c revision 1.7 1 /*
2 * Copyright (c) 1982, 1986, 1991 Regents of the University of California.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: @(#)in.c 7.17 (Berkeley) 4/20/91
34 * $Id: in.c,v 1.7 1994/01/08 21:21:36 mycroft Exp $
35 */
36
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/mbuf.h>
40 #include <sys/socket.h>
41 #include <sys/socketvar.h>
42
43 #include <net/if.h>
44 #include <net/route.h>
45 #include <net/af.h>
46
47 #include <netinet/in.h>
48 #include <netinet/in_var.h>
49 #include <netinet/in_systm.h>
50
51 #ifdef INET
52 /*
53 * Formulate an Internet address from network + host.
54 */
55 struct in_addr
56 in_makeaddr(net, host)
57 u_long net, host;
58 {
59 register struct in_ifaddr *ia;
60 register u_long mask;
61 u_long addr;
62
63 if (IN_CLASSA(net))
64 mask = IN_CLASSA_HOST;
65 else if (IN_CLASSB(net))
66 mask = IN_CLASSB_HOST;
67 else
68 mask = IN_CLASSC_HOST;
69 for (ia = in_ifaddr; ia; ia = ia->ia_next)
70 if ((ia->ia_netmask & net) == ia->ia_net) {
71 mask = ~ia->ia_subnetmask;
72 break;
73 }
74 addr = htonl(net | (host & mask));
75 return (*(struct in_addr *)&addr);
76 }
77
78 /*
79 * Return the network number from an internet address.
80 */
81 u_long
82 in_netof(in)
83 struct in_addr in;
84 {
85 register u_long i = ntohl(in.s_addr);
86 register u_long net;
87 register struct in_ifaddr *ia;
88
89 if (IN_CLASSA(i))
90 net = i & IN_CLASSA_NET;
91 else if (IN_CLASSB(i))
92 net = i & IN_CLASSB_NET;
93 #ifdef MULTICAST
94 else if (IN_CLASSD(i))
95 net = i & IN_CLASSD_NET;
96 #endif
97 else if (IN_CLASSC(i))
98 net = i & IN_CLASSC_NET;
99 else
100 return (0);
101
102 /*
103 * Check whether network is a subnet;
104 * if so, return subnet number.
105 */
106 for (ia = in_ifaddr; ia; ia = ia->ia_next)
107 if (net == ia->ia_net)
108 return (i & ia->ia_subnetmask);
109 return (net);
110 }
111
112 /*
113 * Compute and save network mask as sockaddr from an internet address.
114 */
115 in_sockmaskof(in, sockmask)
116 struct in_addr in;
117 register struct sockaddr_in *sockmask;
118 {
119 register u_long net;
120 register u_long mask;
121 {
122 register u_long i = ntohl(in.s_addr);
123
124 if (i == 0)
125 net = 0, mask = 0;
126 else if (IN_CLASSA(i))
127 net = i & IN_CLASSA_NET, mask = IN_CLASSA_NET;
128 else if (IN_CLASSB(i))
129 net = i & IN_CLASSB_NET, mask = IN_CLASSB_NET;
130 else if (IN_CLASSC(i))
131 net = i & IN_CLASSC_NET, mask = IN_CLASSC_NET;
132 else
133 net = i, mask = -1;
134 }
135 {
136 register struct in_ifaddr *ia;
137 /*
138 * Check whether network is a subnet;
139 * if so, return subnet number.
140 */
141 for (ia = in_ifaddr; ia; ia = ia->ia_next)
142 if (net == ia->ia_net)
143 mask = ia->ia_subnetmask;
144 }
145 {
146 register char *cpbase = (char *)&(sockmask->sin_addr);
147 register char *cp = (char *)(1 + &(sockmask->sin_addr));
148
149 sockmask->sin_addr.s_addr = htonl(mask);
150 sockmask->sin_len = 0;
151 while (--cp >= cpbase)
152 if (*cp) {
153 sockmask->sin_len = 1 + cp - (caddr_t)sockmask;
154 break;
155 }
156 }
157 }
158
159 /*
160 * Return the host portion of an internet address.
161 */
162 u_long
163 in_lnaof(in)
164 struct in_addr in;
165 {
166 register u_long i = ntohl(in.s_addr);
167 register u_long net, host;
168 register struct in_ifaddr *ia;
169
170 if (IN_CLASSA(i)) {
171 net = i & IN_CLASSA_NET;
172 host = i & IN_CLASSA_HOST;
173 } else if (IN_CLASSB(i)) {
174 net = i & IN_CLASSB_NET;
175 host = i & IN_CLASSB_HOST;
176 } else if (IN_CLASSC(i)) {
177 net = i & IN_CLASSC_NET;
178 host = i & IN_CLASSC_HOST;
179 #ifdef MULTICAST
180 } else if (IN_CLASSD(i)) {
181 net = i & IN_CLASSD_NET;
182 host = i & IN_CLASSD_HOST;
183 #endif
184 } else
185 return (i);
186
187 /*
188 * Check whether network is a subnet;
189 * if so, use the modified interpretation of `host'.
190 */
191 for (ia = in_ifaddr; ia; ia = ia->ia_next)
192 if (net == ia->ia_net)
193 return (host &~ ia->ia_subnetmask);
194 return (host);
195 }
196
197 #ifndef SUBNETSARELOCAL
198 #define SUBNETSARELOCAL 1
199 #endif
200 int subnetsarelocal = SUBNETSARELOCAL;
201 /*
202 * Return 1 if an internet address is for a ``local'' host
203 * (one to which we have a connection). If subnetsarelocal
204 * is true, this includes other subnets of the local net.
205 * Otherwise, it includes only the directly-connected (sub)nets.
206 */
207 in_localaddr(in)
208 struct in_addr in;
209 {
210 register u_long i = ntohl(in.s_addr);
211 register struct in_ifaddr *ia;
212
213 if (subnetsarelocal) {
214 for (ia = in_ifaddr; ia; ia = ia->ia_next)
215 if ((i & ia->ia_netmask) == ia->ia_net)
216 return (1);
217 } else {
218 for (ia = in_ifaddr; ia; ia = ia->ia_next)
219 if ((i & ia->ia_subnetmask) == ia->ia_subnet)
220 return (1);
221 }
222 return (0);
223 }
224
225 /*
226 * Determine whether an IP address is in a reserved set of addresses
227 * that may not be forwarded, or whether datagrams to that destination
228 * may be forwarded.
229 */
230 in_canforward(in)
231 struct in_addr in;
232 {
233 register u_long i = ntohl(in.s_addr);
234 register u_long net;
235
236 if (IN_EXPERIMENTAL(i))
237 return (0);
238 if (IN_CLASSA(i)) {
239 net = i & IN_CLASSA_NET;
240 if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
241 return (0);
242 }
243 return (1);
244 }
245
246 int in_interfaces; /* number of external internet interfaces */
247 extern struct ifnet loif;
248
249 /*
250 * Generic internet control operations (ioctl's).
251 * Ifp is 0 if not an interface-specific ioctl.
252 */
253 /* ARGSUSED */
254 in_control(so, cmd, data, ifp)
255 struct socket *so;
256 int cmd;
257 caddr_t data;
258 register struct ifnet *ifp;
259 {
260 register struct ifreq *ifr = (struct ifreq *)data;
261 register struct in_ifaddr *ia = 0;
262 register struct ifaddr *ifa;
263 struct in_ifaddr *oia;
264 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
265 struct mbuf *m;
266 struct sockaddr_in oldaddr;
267 int error, hostIsNew, maskIsNew;
268 u_long i;
269
270 /*
271 * Find address for this interface, if it exists.
272 */
273 if (ifp)
274 for (ia = in_ifaddr; ia; ia = ia->ia_next)
275 if (ia->ia_ifp == ifp)
276 break;
277
278 switch (cmd) {
279
280 case SIOCAIFADDR:
281 case SIOCDIFADDR:
282 if (ifra->ifra_addr.sin_family == AF_INET)
283 for (oia = ia; ia; ia = ia->ia_next) {
284 if (ia->ia_ifp == ifp &&
285 ia->ia_addr.sin_addr.s_addr ==
286 ifra->ifra_addr.sin_addr.s_addr)
287 break;
288 }
289 if (cmd == SIOCDIFADDR && ia == 0)
290 return (EADDRNOTAVAIL);
291 /* FALLTHROUGH */
292 case SIOCSIFADDR:
293 case SIOCSIFNETMASK:
294 case SIOCSIFDSTADDR:
295 if ((so->so_state & SS_PRIV) == 0)
296 return (EPERM);
297
298 if (ifp == 0)
299 panic("in_control");
300 if (ia == (struct in_ifaddr *)0) {
301 m = m_getclr(M_WAIT, MT_IFADDR);
302 if (m == (struct mbuf *)NULL)
303 return (ENOBUFS);
304 if (ia = in_ifaddr) {
305 for ( ; ia->ia_next; ia = ia->ia_next)
306 ;
307 ia->ia_next = mtod(m, struct in_ifaddr *);
308 } else
309 in_ifaddr = mtod(m, struct in_ifaddr *);
310 ia = mtod(m, struct in_ifaddr *);
311 if (ifa = ifp->if_addrlist) {
312 for ( ; ifa->ifa_next; ifa = ifa->ifa_next)
313 ;
314 ifa->ifa_next = (struct ifaddr *) ia;
315 } else
316 ifp->if_addrlist = (struct ifaddr *) ia;
317 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
318 ia->ia_ifa.ifa_dstaddr
319 = (struct sockaddr *)&ia->ia_dstaddr;
320 ia->ia_ifa.ifa_netmask
321 = (struct sockaddr *)&ia->ia_sockmask;
322 ia->ia_sockmask.sin_len = 8;
323 if (ifp->if_flags & IFF_BROADCAST) {
324 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
325 ia->ia_broadaddr.sin_family = AF_INET;
326 }
327 ia->ia_ifp = ifp;
328 if (ifp != &loif)
329 in_interfaces++;
330 }
331 break;
332
333 case SIOCSIFBRDADDR:
334 if ((so->so_state & SS_PRIV) == 0)
335 return (EPERM);
336 /* FALLTHROUGH */
337
338 case SIOCGIFADDR:
339 case SIOCGIFNETMASK:
340 case SIOCGIFDSTADDR:
341 case SIOCGIFBRDADDR:
342 if (ia == (struct in_ifaddr *)0)
343 return (EADDRNOTAVAIL);
344 break;
345
346 default:
347 return (EOPNOTSUPP);
348 break;
349 }
350 switch (cmd) {
351
352 case SIOCGIFADDR:
353 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
354 break;
355
356 case SIOCGIFBRDADDR:
357 if ((ifp->if_flags & IFF_BROADCAST) == 0)
358 return (EINVAL);
359 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
360 break;
361
362 case SIOCGIFDSTADDR:
363 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
364 return (EINVAL);
365 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
366 break;
367
368 case SIOCGIFNETMASK:
369 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
370 break;
371
372 case SIOCSIFDSTADDR:
373 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
374 return (EINVAL);
375 oldaddr = ia->ia_dstaddr;
376 ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
377 if (ifp->if_ioctl &&
378 (error = (*ifp->if_ioctl)(ifp, SIOCSIFDSTADDR, ia))) {
379 ia->ia_dstaddr = oldaddr;
380 return (error);
381 }
382 if (ia->ia_flags & IFA_ROUTE) {
383 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
384 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
385 ia->ia_ifa.ifa_dstaddr =
386 (struct sockaddr *)&ia->ia_dstaddr;
387 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
388 }
389 break;
390
391 case SIOCSIFBRDADDR:
392 if ((ifp->if_flags & IFF_BROADCAST) == 0)
393 return (EINVAL);
394 ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
395 break;
396
397 case SIOCSIFADDR:
398 return (in_ifinit(ifp, ia,
399 (struct sockaddr_in *) &ifr->ifr_addr, 1));
400
401 case SIOCSIFNETMASK:
402 i = ifra->ifra_addr.sin_addr.s_addr;
403 ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
404 break;
405
406 case SIOCAIFADDR:
407 maskIsNew = 0;
408 hostIsNew = 1;
409 error = 0;
410 if (ia->ia_addr.sin_family == AF_INET) {
411 if (ifra->ifra_addr.sin_len == 0) {
412 ifra->ifra_addr = ia->ia_addr;
413 hostIsNew = 0;
414 } else if (ifra->ifra_addr.sin_addr.s_addr ==
415 ia->ia_addr.sin_addr.s_addr)
416 hostIsNew = 0;
417 }
418 if (ifra->ifra_mask.sin_len) {
419 in_ifscrub(ifp, ia);
420 ia->ia_sockmask = ifra->ifra_mask;
421 ia->ia_subnetmask =
422 ntohl(ia->ia_sockmask.sin_addr.s_addr);
423 maskIsNew = 1;
424 }
425 if ((ifp->if_flags & IFF_POINTOPOINT) &&
426 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
427 in_ifscrub(ifp, ia);
428 ia->ia_dstaddr = ifra->ifra_dstaddr;
429 maskIsNew = 1; /* We lie; but the effect's the same */
430 }
431 if (ifra->ifra_addr.sin_family == AF_INET &&
432 (hostIsNew || maskIsNew))
433 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
434 if ((ifp->if_flags & IFF_BROADCAST) &&
435 (ifra->ifra_broadaddr.sin_family == AF_INET))
436 ia->ia_broadaddr = ifra->ifra_broadaddr;
437 return (error);
438
439 case SIOCDIFADDR:
440 in_ifscrub(ifp, ia);
441 if ((ifa = ifp->if_addrlist) == (struct ifaddr *)ia)
442 ifp->if_addrlist = ifa->ifa_next;
443 else {
444 while (ifa->ifa_next &&
445 (ifa->ifa_next != (struct ifaddr *)ia))
446 ifa = ifa->ifa_next;
447 if (ifa->ifa_next)
448 ifa->ifa_next = ((struct ifaddr *)ia)->ifa_next;
449 else
450 printf("Couldn't unlink inifaddr from ifp\n");
451 }
452 oia = ia;
453 if (oia == (ia = in_ifaddr))
454 in_ifaddr = ia->ia_next;
455 else {
456 while (ia->ia_next && (ia->ia_next != oia))
457 ia = ia->ia_next;
458 if (ia->ia_next)
459 ia->ia_next = oia->ia_next;
460 else
461 printf("Didn't unlink inifadr from list\n");
462 }
463 (void) m_free(dtom(oia));
464 break;
465
466 default:
467 if (ifp == 0 || ifp->if_ioctl == 0)
468 return (EOPNOTSUPP);
469 return ((*ifp->if_ioctl)(ifp, cmd, data));
470 }
471 return (0);
472 }
473
474 /*
475 * Delete any existing route for an interface.
476 */
477 in_ifscrub(ifp, ia)
478 register struct ifnet *ifp;
479 register struct in_ifaddr *ia;
480 {
481
482 if ((ia->ia_flags & IFA_ROUTE) == 0)
483 return;
484 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
485 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
486 else
487 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
488 ia->ia_flags &= ~IFA_ROUTE;
489 }
490
491 /*
492 * Initialize an interface's internet address
493 * and routing table entry.
494 */
495 in_ifinit(ifp, ia, sin, scrub)
496 register struct ifnet *ifp;
497 register struct in_ifaddr *ia;
498 struct sockaddr_in *sin;
499 {
500 register u_long i = ntohl(sin->sin_addr.s_addr);
501 struct sockaddr_in oldaddr;
502 int s = splimp(), error, flags = RTF_UP;
503
504 oldaddr = ia->ia_addr;
505 ia->ia_addr = *sin;
506 /*
507 * Give the interface a chance to initialize
508 * if this is its first address,
509 * and to validate the address if necessary.
510 */
511 if (ifp->if_ioctl && (error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, ia))) {
512 splx(s);
513 ia->ia_addr = oldaddr;
514 return (error);
515 }
516 splx(s);
517 if (scrub) {
518 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
519 in_ifscrub(ifp, ia);
520 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
521 }
522 if (IN_CLASSA(i))
523 ia->ia_netmask = IN_CLASSA_NET;
524 else if (IN_CLASSB(i))
525 ia->ia_netmask = IN_CLASSB_NET;
526 else
527 ia->ia_netmask = IN_CLASSC_NET;
528 ia->ia_net = i & ia->ia_netmask;
529 /*
530 * The subnet mask includes at least the standard network part,
531 * but may already have been set to a larger value.
532 */
533 ia->ia_subnetmask |= ia->ia_netmask;
534 ia->ia_subnet = i & ia->ia_subnetmask;
535 ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
536 {
537 register char *cp = (char *) (1 + &(ia->ia_sockmask.sin_addr));
538 register char *cpbase = (char *) &(ia->ia_sockmask.sin_addr);
539 while (--cp >= cpbase)
540 if (*cp) {
541 ia->ia_sockmask.sin_len =
542 1 + cp - (char *) &(ia->ia_sockmask);
543 break;
544 }
545 }
546 /*
547 * Add route for the network.
548 */
549 if (ifp->if_flags & IFF_BROADCAST) {
550 ia->ia_broadaddr.sin_addr =
551 in_makeaddr(ia->ia_subnet, INADDR_BROADCAST);
552 ia->ia_netbroadcast.s_addr =
553 htonl(ia->ia_net | (INADDR_BROADCAST &~ ia->ia_netmask));
554 } else if (ifp->if_flags & IFF_LOOPBACK) {
555 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
556 flags |= RTF_HOST;
557 } else if (ifp->if_flags & IFF_POINTOPOINT) {
558 if (ia->ia_dstaddr.sin_family != AF_INET)
559 return (0);
560 flags |= RTF_HOST;
561 }
562 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
563 ia->ia_flags |= IFA_ROUTE;
564 #ifdef MULTICAST
565 /*
566 * If the interface supports multicast, join the "all hosts"
567 * multicast group on that interface.
568 */
569 if (ifp->if_flags & IFF_MULTICAST) {
570 struct in_addr addr;
571
572 addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
573 in_addmulti(&addr, ifp);
574 }
575 #endif
576 return (error);
577 }
578
579 /*
580 * Return address info for specified internet network.
581 */
582 struct in_ifaddr *
583 in_iaonnetof(net)
584 u_long net;
585 {
586 register struct in_ifaddr *ia;
587
588 for (ia = in_ifaddr; ia; ia = ia->ia_next)
589 if (ia->ia_subnet == net)
590 return (ia);
591 return ((struct in_ifaddr *)0);
592 }
593
594 /*
595 * Return 1 if the address might be a local broadcast address.
596 */
597 in_broadcast(in)
598 struct in_addr in;
599 {
600 register struct in_ifaddr *ia;
601 u_long t;
602
603 /*
604 * Look through the list of addresses for a match
605 * with a broadcast address.
606 */
607 for (ia = in_ifaddr; ia; ia = ia->ia_next)
608 if (ia->ia_ifp->if_flags & IFF_BROADCAST) {
609 if (ia->ia_broadaddr.sin_addr.s_addr == in.s_addr)
610 return (1);
611 /*
612 * Check for old-style (host 0) broadcast.
613 */
614 if ((t = ntohl(in.s_addr)) == ia->ia_subnet || t == ia->ia_net)
615 return (1);
616 }
617 if (in.s_addr == INADDR_BROADCAST || in.s_addr == INADDR_ANY)
618 return (1);
619 return (0);
620 }
621
622 #ifdef MULTICAST
623 /*
624 * Add an address to the list of IP multicast addresses for a given interface.
625 */
626 struct in_multi *
627 in_addmulti(ap, ifp)
628 register struct in_addr *ap;
629 register struct ifnet *ifp;
630 {
631 register struct in_multi *inm;
632 struct ifreq ifr;
633 struct in_ifaddr *ia;
634 int s = splnet();
635
636 /*
637 * See if address already in list.
638 */
639 IN_LOOKUP_MULTI(*ap, ifp, inm);
640 if (inm != NULL) {
641 /*
642 * Found it; just increment the reference count.
643 */
644 ++inm->inm_refcount;
645 }
646 else {
647 /*
648 * New address; allocate a new multicast record
649 * and link it into the interface's multicast list.
650 */
651 inm = (struct in_multi *)malloc(sizeof(*inm),
652 M_IPMADDR, M_NOWAIT);
653 if (inm == NULL) {
654 splx(s);
655 return (NULL);
656 }
657 inm->inm_addr = *ap;
658 inm->inm_ifp = ifp;
659 inm->inm_refcount = 1;
660 IFP_TO_IA(ifp, ia);
661 if (ia == NULL) {
662 free(inm, M_IPMADDR);
663 splx(s);
664 return (NULL);
665 }
666 inm->inm_ia = ia;
667 inm->inm_next = ia->ia_multiaddrs;
668 ia->ia_multiaddrs = inm;
669 /*
670 * Ask the network driver to update its multicast reception
671 * filter appropriately for the new address.
672 */
673 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_family = AF_INET;
674 ((struct sockaddr_in *)&ifr.ifr_addr)->sin_addr = *ap;
675 if (ifp->if_ioctl == NULL ||
676 (*ifp->if_ioctl)(ifp, SIOCADDMULTI,(caddr_t)&ifr) != 0) {
677 ia->ia_multiaddrs = inm->inm_next;
678 free(inm, M_IPMADDR);
679 splx(s);
680 return (NULL);
681 }
682 /*
683 * Let IGMP know that we have joined a new IP multicast group.
684 */
685 igmp_joingroup(inm);
686 }
687 splx(s);
688 return (inm);
689 }
690
691 /*
692 * Delete a multicast address record.
693 */
694 int
695 in_delmulti(inm)
696 register struct in_multi *inm;
697 {
698 register struct in_multi **p;
699 struct ifreq ifr;
700 int s = splnet();
701
702 if (--inm->inm_refcount == 0) {
703 /*
704 * No remaining claims to this record; let IGMP know that
705 * we are leaving the multicast group.
706 */
707 igmp_leavegroup(inm);
708 /*
709 * Unlink from list.
710 */
711 for (p = &inm->inm_ia->ia_multiaddrs;
712 *p != inm;
713 p = &(*p)->inm_next)
714 continue;
715 *p = (*p)->inm_next;
716 /*
717 * Notify the network driver to update its multicast reception
718 * filter.
719 */
720 ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_family = AF_INET;
721 ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr =
722 inm->inm_addr;
723 (*inm->inm_ifp->if_ioctl)(inm->inm_ifp, SIOCDELMULTI,
724 (caddr_t)&ifr);
725 free(inm, M_IPMADDR);
726 }
727 splx(s);
728 }
729 #endif
730 #endif
731