]> git.saurik.com Git - apple/xnu.git/blob - bsd/netinet/in.c
b26199f21589ffa48aabb6999444c6c0244fd55c
[apple/xnu.git] / bsd / netinet / in.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
13 * file.
14 *
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * Copyright (c) 1982, 1986, 1991, 1993
27 * The Regents of the University of California. All rights reserved.
28 *
29 * Redistribution and use in source and binary forms, with or without
30 * modification, are permitted provided that the following conditions
31 * are met:
32 * 1. Redistributions of source code must retain the above copyright
33 * notice, this list of conditions and the following disclaimer.
34 * 2. Redistributions in binary form must reproduce the above copyright
35 * notice, this list of conditions and the following disclaimer in the
36 * documentation and/or other materials provided with the distribution.
37 * 3. All advertising materials mentioning features or use of this software
38 * must display the following acknowledgement:
39 * This product includes software developed by the University of
40 * California, Berkeley and its contributors.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 *
57 * @(#)in.c 8.4 (Berkeley) 1/9/95
58 * $FreeBSD: src/sys/netinet/in.c,v 1.44.2.5 2001/08/13 16:26:17 ume Exp $
59 */
60
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/sockio.h>
64 #include <sys/socketvar.h>
65 #include <sys/malloc.h>
66 #include <sys/proc.h>
67 #include <sys/socket.h>
68 #include <sys/kernel.h>
69 #include <sys/sysctl.h>
70 #include <sys/kern_event.h>
71
72 #include <net/if.h>
73 #include <net/if_types.h>
74 #include <net/route.h>
75
76 #include <netinet/in.h>
77 #include <netinet/in_var.h>
78 #include <netinet/in_pcb.h>
79
80 #include <netinet/igmp_var.h>
81 #include <net/dlil.h>
82
83 #include <netinet/ip_var.h>
84
85 #include <netinet/tcp.h>
86 #include <netinet/tcp_timer.h>
87 #include <netinet/tcp_var.h>
88
89 #include <sys/file.h>
90
91
92 static int in_mask2len __P((struct in_addr *));
93 static void in_len2mask __P((struct in_addr *, int));
94 static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t,
95 struct ifnet *, struct proc *));
96
97 static void in_socktrim __P((struct sockaddr_in *));
98 static int in_ifinit __P((struct ifnet *,
99 struct in_ifaddr *, struct sockaddr_in *, int));
100
101 static int subnetsarelocal = 0;
102 SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW,
103 &subnetsarelocal, 0, "");
104
105 struct in_multihead in_multihead; /* XXX BSS initialization */
106
107 extern void arp_rtrequest();
108 extern int ether_detach_inet(struct ifnet *ifp);
109
110 #if INET6
111 extern int ip6_auto_on;
112 #endif
113
114 /*
115 * Return 1 if an internet address is for a ``local'' host
116 * (one to which we have a connection). If subnetsarelocal
117 * is true, this includes other subnets of the local net.
118 * Otherwise, it includes only the directly-connected (sub)nets.
119 */
120 int
121 in_localaddr(in)
122 struct in_addr in;
123 {
124 register u_long i = ntohl(in.s_addr);
125 register struct in_ifaddr *ia;
126
127 if (subnetsarelocal) {
128 for (ia = in_ifaddrhead.tqh_first; ia;
129 ia = ia->ia_link.tqe_next)
130 if ((i & ia->ia_netmask) == ia->ia_net)
131 return (1);
132 } else {
133 for (ia = in_ifaddrhead.tqh_first; ia;
134 ia = ia->ia_link.tqe_next)
135 if ((i & ia->ia_subnetmask) == ia->ia_subnet)
136 return (1);
137 }
138 return (0);
139 }
140
141 /*
142 * Determine whether an IP address is in a reserved set of addresses
143 * that may not be forwarded, or whether datagrams to that destination
144 * may be forwarded.
145 */
146 int
147 in_canforward(in)
148 struct in_addr in;
149 {
150 register u_long i = ntohl(in.s_addr);
151 register u_long net;
152
153 if (IN_EXPERIMENTAL(i) || IN_MULTICAST(i))
154 return (0);
155 if (IN_CLASSA(i)) {
156 net = i & IN_CLASSA_NET;
157 if (net == 0 || net == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT))
158 return (0);
159 }
160 return (1);
161 }
162
163 /*
164 * Trim a mask in a sockaddr
165 */
166 static void
167 in_socktrim(ap)
168 struct sockaddr_in *ap;
169 {
170 register char *cplim = (char *) &ap->sin_addr;
171 register char *cp = (char *) (&ap->sin_addr + 1);
172
173 ap->sin_len = 0;
174 while (--cp >= cplim)
175 if (*cp) {
176 (ap)->sin_len = cp - (char *) (ap) + 1;
177 break;
178 }
179 }
180
181 static int
182 in_mask2len(mask)
183 struct in_addr *mask;
184 {
185 int x, y;
186 u_char *p;
187
188 p = (u_char *)mask;
189 for (x = 0; x < sizeof(*mask); x++) {
190 if (p[x] != 0xff)
191 break;
192 }
193 y = 0;
194 if (x < sizeof(*mask)) {
195 for (y = 0; y < 8; y++) {
196 if ((p[x] & (0x80 >> y)) == 0)
197 break;
198 }
199 }
200 return x * 8 + y;
201 }
202
203 static void
204 in_len2mask(mask, len)
205 struct in_addr *mask;
206 int len;
207 {
208 int i;
209 u_char *p;
210
211 p = (u_char *)mask;
212 bzero(mask, sizeof(*mask));
213 for (i = 0; i < len / 8; i++)
214 p[i] = 0xff;
215 if (len % 8)
216 p[i] = (0xff00 >> (len % 8)) & 0xff;
217 }
218
219 static int in_interfaces; /* number of external internet interfaces */
220
221 /*
222 * Generic internet control operations (ioctl's).
223 * Ifp is 0 if not an interface-specific ioctl.
224 */
225 /* ARGSUSED */
226 int
227 in_control(so, cmd, data, ifp, p)
228 struct socket *so;
229 u_long cmd;
230 caddr_t data;
231 register struct ifnet *ifp;
232 struct proc *p;
233 {
234 register struct ifreq *ifr = (struct ifreq *)data;
235 register struct in_ifaddr *ia = 0, *iap;
236 register struct ifaddr *ifa;
237 struct in_ifaddr *oia;
238 struct in_aliasreq *ifra = (struct in_aliasreq *)data;
239 struct sockaddr_in oldaddr;
240 int error, hostIsNew, maskIsNew, s;
241 u_long i, dl_tag;
242 struct kev_msg ev_msg;
243 struct kev_in_data in_event_data;
244
245
246 switch (cmd) {
247 case SIOCALIFADDR:
248 case SIOCDLIFADDR:
249 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
250 return error;
251 /*fall through*/
252 case SIOCGLIFADDR:
253 if (!ifp)
254 return EINVAL;
255 return in_lifaddr_ioctl(so, cmd, data, ifp, p);
256 }
257
258 /*
259 * Find address for this interface, if it exists.
260 *
261 * If an alias address was specified, find that one instead of
262 * the first one on the interface.
263 */
264 if (ifp)
265 for (iap = in_ifaddrhead.tqh_first; iap;
266 iap = iap->ia_link.tqe_next)
267 if (iap->ia_ifp == ifp) {
268 if (((struct sockaddr_in *)&ifr->ifr_addr)->sin_addr.s_addr ==
269 iap->ia_addr.sin_addr.s_addr) {
270 ia = iap;
271 break;
272 } else if (ia == NULL) {
273 ia = iap;
274 if (ifr->ifr_addr.sa_family != AF_INET)
275 break;
276 }
277 }
278
279 switch (cmd) {
280 case SIOCAUTOADDR:
281 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
282 return error;
283 break;
284
285 case SIOCAIFADDR:
286 case SIOCDIFADDR:
287 if (ifp == 0)
288 return (EADDRNOTAVAIL);
289 if (ifra->ifra_addr.sin_family == AF_INET) {
290 for (oia = ia; ia; ia = ia->ia_link.tqe_next) {
291 if (ia->ia_ifp == ifp &&
292 ia->ia_addr.sin_addr.s_addr ==
293 ifra->ifra_addr.sin_addr.s_addr)
294 break;
295 }
296 if ((ifp->if_flags & IFF_POINTOPOINT)
297 && (cmd == SIOCAIFADDR)
298 && (ifra->ifra_dstaddr.sin_addr.s_addr
299 == INADDR_ANY)) {
300 return EDESTADDRREQ;
301 }
302 }
303 else if (cmd == SIOCAIFADDR)
304 return (EINVAL);
305 if (cmd == SIOCDIFADDR && ia == 0)
306 return (EADDRNOTAVAIL);
307 /* FALLTHROUGH */
308 case SIOCSIFADDR:
309 case SIOCSIFNETMASK:
310 case SIOCSIFDSTADDR:
311 #ifdef __APPLE__
312 if ((so->so_state & SS_PRIV) == 0)
313 return (EPERM);
314 #else
315 if (p && (error = suser(p)) != 0)
316 return error;
317 #endif
318
319 if (ifp == 0)
320 return (EADDRNOTAVAIL);
321 if (ifra->ifra_addr.sin_family != AF_INET && cmd == SIOCSIFADDR)
322 return (EINVAL);
323 if (ia == (struct in_ifaddr *)0) {
324 ia = (struct in_ifaddr *)
325 _MALLOC(sizeof *ia, M_IFADDR, M_WAITOK);
326 if (ia == (struct in_ifaddr *)NULL)
327 return (ENOBUFS);
328 bzero((caddr_t)ia, sizeof *ia);
329 /*
330 * Protect from ipintr() traversing address list
331 * while we're modifying it.
332 */
333 s = splnet();
334
335 TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_link);
336 ifa = &ia->ia_ifa;
337 TAILQ_INSERT_TAIL(&ifp->if_addrhead, ifa, ifa_link);
338
339 /*
340 * Temorary code for protocol attachment XXX
341 */
342
343 if (ifp->if_type == IFT_ETHER)
344 dl_tag = ether_attach_inet(ifp);
345
346 if (ifp->if_type == IFT_LOOP)
347 dl_tag = lo_attach_inet(ifp);
348 #if NFAITH
349 /* Is this right? */
350 if (ifp && ifp->if_type == IFT_FAITH)
351 dl_tag = faith_attach_inet(ifp);
352 #endif
353 #if NGIF
354 /* Is this right? */
355 if (ifp && ifp->if_type == IFT_GIF)
356 dl_tag = gif_attach_proto_family(ifp, PF_INET);
357 #endif
358 /* End of temp code */
359
360 ifa->ifa_dlt = dl_tag;
361 ifa->ifa_addr = (struct sockaddr *)&ia->ia_addr;
362 ifa->ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
363 ifa->ifa_netmask = (struct sockaddr *)&ia->ia_sockmask;
364 ia->ia_sockmask.sin_len = 8;
365 if (ifp->if_flags & IFF_BROADCAST) {
366 ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr);
367 ia->ia_broadaddr.sin_family = AF_INET;
368 }
369 ia->ia_ifp = ifp;
370 if (!(ifp->if_flags & IFF_LOOPBACK))
371 in_interfaces++;
372 splx(s);
373 }
374 break;
375
376 case SIOCPROTOATTACH:
377 case SIOCPROTODETACH:
378 if (p && (error = suser(p->p_ucred, &p->p_acflag)) != 0)
379 return error;
380 if (ifp == 0)
381 return (EADDRNOTAVAIL);
382 if (strcmp(ifp->if_name, "en"))
383 return ENODEV;
384 break;
385
386 case SIOCSIFBRDADDR:
387 #ifdef __APPLE__
388 if ((so->so_state & SS_PRIV) == 0)
389 return (EPERM);
390 #else
391 if (p && (error = suser(p)) != 0)
392 return error;
393 #endif
394 /* FALLTHROUGH */
395
396 case SIOCGIFADDR:
397 case SIOCGIFNETMASK:
398 case SIOCGIFDSTADDR:
399 case SIOCGIFBRDADDR:
400 if (ia == (struct in_ifaddr *)0)
401 return (EADDRNOTAVAIL);
402 break;
403 }
404 switch (cmd) {
405 case SIOCAUTOADDR:
406 if (ifp == 0)
407 return (EADDRNOTAVAIL);
408 if (ifr->ifr_data)
409 ifp->if_eflags |= IFEF_AUTOCONFIGURING;
410 else
411 ifp->if_eflags &= ~IFEF_AUTOCONFIGURING;
412 break;
413
414 case SIOCGIFADDR:
415 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_addr;
416 break;
417
418 case SIOCGIFBRDADDR:
419 if ((ifp->if_flags & IFF_BROADCAST) == 0)
420 return (EINVAL);
421 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_broadaddr;
422 break;
423
424 case SIOCGIFDSTADDR:
425 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
426 return (EINVAL);
427 *((struct sockaddr_in *)&ifr->ifr_dstaddr) = ia->ia_dstaddr;
428 break;
429
430 case SIOCGIFNETMASK:
431 *((struct sockaddr_in *)&ifr->ifr_addr) = ia->ia_sockmask;
432 break;
433
434 case SIOCSIFDSTADDR:
435 if ((ifp->if_flags & IFF_POINTOPOINT) == 0)
436 return (EINVAL);
437 oldaddr = ia->ia_dstaddr;
438 ia->ia_dstaddr = *(struct sockaddr_in *)&ifr->ifr_dstaddr;
439 error = dlil_ioctl(PF_INET, ifp, SIOCSIFDSTADDR, (caddr_t)ia);
440 if (error == EOPNOTSUPP)
441 error = 0;
442
443 if (error) {
444 ia->ia_dstaddr = oldaddr;
445 return error;
446 }
447
448 ev_msg.vendor_code = KEV_VENDOR_APPLE;
449 ev_msg.kev_class = KEV_NETWORK_CLASS;
450 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
451
452 ev_msg.event_code = KEV_INET_SIFDSTADDR;
453
454 if (ia->ia_ifa.ifa_dstaddr)
455 in_event_data.ia_dstaddr =
456 ((struct sockaddr_in *)ia->ia_ifa.ifa_dstaddr)->sin_addr;
457 else
458 in_event_data.ia_dstaddr.s_addr = 0;
459
460 in_event_data.ia_addr = ia->ia_addr.sin_addr;
461 in_event_data.ia_net = ia->ia_net;
462 in_event_data.ia_netmask = ia->ia_netmask;
463 in_event_data.ia_subnet = ia->ia_subnet;
464 in_event_data.ia_subnetmask = ia->ia_subnetmask;
465 in_event_data.ia_netbroadcast = ia->ia_netbroadcast;
466 strncpy(&in_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
467 in_event_data.link_data.if_family = ifp->if_family;
468 in_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
469
470 ev_msg.dv[0].data_ptr = &in_event_data;
471 ev_msg.dv[0].data_length = sizeof(struct kev_in_data);
472 ev_msg.dv[1].data_length = 0;
473
474 kev_post_msg(&ev_msg);
475
476
477 if (ia->ia_flags & IFA_ROUTE) {
478 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&oldaddr;
479 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
480 ia->ia_ifa.ifa_dstaddr =
481 (struct sockaddr *)&ia->ia_dstaddr;
482 rtinit(&(ia->ia_ifa), (int)RTM_ADD, RTF_HOST|RTF_UP);
483 }
484 break;
485
486 case SIOCSIFBRDADDR:
487 if ((ifp->if_flags & IFF_BROADCAST) == 0)
488 return (EINVAL);
489 ia->ia_broadaddr = *(struct sockaddr_in *)&ifr->ifr_broadaddr;
490
491 ev_msg.vendor_code = KEV_VENDOR_APPLE;
492 ev_msg.kev_class = KEV_NETWORK_CLASS;
493 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
494
495 ev_msg.event_code = KEV_INET_SIFBRDADDR;
496
497 if (ia->ia_ifa.ifa_dstaddr)
498 in_event_data.ia_dstaddr =
499 ((struct sockaddr_in *)ia->ia_ifa.ifa_dstaddr)->sin_addr;
500 else
501 in_event_data.ia_dstaddr.s_addr = 0;
502
503 in_event_data.ia_addr = ia->ia_addr.sin_addr;
504 in_event_data.ia_net = ia->ia_net;
505 in_event_data.ia_netmask = ia->ia_netmask;
506 in_event_data.ia_subnet = ia->ia_subnet;
507 in_event_data.ia_subnetmask = ia->ia_subnetmask;
508 in_event_data.ia_netbroadcast = ia->ia_netbroadcast;
509 strncpy(&in_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
510 in_event_data.link_data.if_family = ifp->if_family;
511 in_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
512
513 ev_msg.dv[0].data_ptr = &in_event_data;
514 ev_msg.dv[0].data_length = sizeof(struct kev_in_data);
515 ev_msg.dv[1].data_length = 0;
516
517 kev_post_msg(&ev_msg);
518
519 break;
520
521 case SIOCSIFADDR:
522 return (in_ifinit(ifp, ia,
523 (struct sockaddr_in *) &ifr->ifr_addr, 1));
524
525 case SIOCPROTOATTACH:
526 ether_attach_inet(ifp);
527 #if INET6
528 if (ip6_auto_on) /* FreeBSD compat mode: Acquire linklocal addresses for IPv6 for if */
529 in6_if_up(ifp);
530 #endif
531 break;
532
533 case SIOCPROTODETACH:
534 // if an ip address is still present, refuse to detach
535 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
536 if (ifa->ifa_addr->sa_family == AF_INET)
537 return EBUSY;
538 error = ether_detach_inet(ifp);
539 if (error)
540 return(error);
541 #if INET6
542 if (ip6_auto_on) { /* if we linked ipv6 addresses to v4, remove them now */
543 in6_purgeif(ifp);
544 error = ether_detach_inet6(ifp);
545 if (error)
546 return(error);
547 }
548 #endif
549 break;
550
551
552 case SIOCSIFNETMASK:
553 i = ifra->ifra_addr.sin_addr.s_addr;
554 ia->ia_subnetmask = ntohl(ia->ia_sockmask.sin_addr.s_addr = i);
555 ev_msg.vendor_code = KEV_VENDOR_APPLE;
556 ev_msg.kev_class = KEV_NETWORK_CLASS;
557 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
558
559 ev_msg.event_code = KEV_INET_SIFNETMASK;
560
561 if (ia->ia_ifa.ifa_dstaddr)
562 in_event_data.ia_dstaddr =
563 ((struct sockaddr_in *)ia->ia_ifa.ifa_dstaddr)->sin_addr;
564 else
565 in_event_data.ia_dstaddr.s_addr = 0;
566
567 in_event_data.ia_addr = ia->ia_addr.sin_addr;
568 in_event_data.ia_net = ia->ia_net;
569 in_event_data.ia_netmask = ia->ia_netmask;
570 in_event_data.ia_subnet = ia->ia_subnet;
571 in_event_data.ia_subnetmask = ia->ia_subnetmask;
572 in_event_data.ia_netbroadcast = ia->ia_netbroadcast;
573 strncpy(&in_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
574 in_event_data.link_data.if_family = ifp->if_family;
575 in_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
576
577 ev_msg.dv[0].data_ptr = &in_event_data;
578 ev_msg.dv[0].data_length = sizeof(struct kev_in_data);
579 ev_msg.dv[1].data_length = 0;
580
581 kev_post_msg(&ev_msg);
582
583 break;
584
585 case SIOCAIFADDR:
586 maskIsNew = 0;
587 hostIsNew = 1;
588 error = 0;
589 if (ia->ia_addr.sin_family == AF_INET) {
590 if (ifra->ifra_addr.sin_len == 0) {
591 ifra->ifra_addr = ia->ia_addr;
592 hostIsNew = 0;
593 } else if (ifra->ifra_addr.sin_addr.s_addr ==
594 ia->ia_addr.sin_addr.s_addr)
595 hostIsNew = 0;
596 }
597 if (ifra->ifra_mask.sin_len) {
598 in_ifscrub(ifp, ia);
599 ia->ia_sockmask = ifra->ifra_mask;
600 ia->ia_subnetmask =
601 ntohl(ia->ia_sockmask.sin_addr.s_addr);
602 maskIsNew = 1;
603 }
604 if ((ifp->if_flags & IFF_POINTOPOINT) &&
605 (ifra->ifra_dstaddr.sin_family == AF_INET)) {
606 in_ifscrub(ifp, ia);
607 ia->ia_dstaddr = ifra->ifra_dstaddr;
608 maskIsNew = 1; /* We lie; but the effect's the same */
609 }
610 if (ifra->ifra_addr.sin_family == AF_INET &&
611 (hostIsNew || maskIsNew)) {
612 error = in_ifinit(ifp, ia, &ifra->ifra_addr, 0);
613 }
614 if ((ifp->if_flags & IFF_BROADCAST) &&
615 (ifra->ifra_broadaddr.sin_family == AF_INET))
616 ia->ia_broadaddr = ifra->ifra_broadaddr;
617
618 /*
619 * Report event.
620 */
621
622 if ((error == 0) || (error == EEXIST)) {
623 ev_msg.vendor_code = KEV_VENDOR_APPLE;
624 ev_msg.kev_class = KEV_NETWORK_CLASS;
625 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
626
627 if (hostIsNew)
628 ev_msg.event_code = KEV_INET_NEW_ADDR;
629 else
630 ev_msg.event_code = KEV_INET_CHANGED_ADDR;
631
632 if (ia->ia_ifa.ifa_dstaddr)
633 in_event_data.ia_dstaddr =
634 ((struct sockaddr_in *)ia->ia_ifa.ifa_dstaddr)->sin_addr;
635 else
636 in_event_data.ia_dstaddr.s_addr = 0;
637
638 in_event_data.ia_addr = ia->ia_addr.sin_addr;
639 in_event_data.ia_net = ia->ia_net;
640 in_event_data.ia_netmask = ia->ia_netmask;
641 in_event_data.ia_subnet = ia->ia_subnet;
642 in_event_data.ia_subnetmask = ia->ia_subnetmask;
643 in_event_data.ia_netbroadcast = ia->ia_netbroadcast;
644 strncpy(&in_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
645 in_event_data.link_data.if_family = ifp->if_family;
646 in_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
647
648 ev_msg.dv[0].data_ptr = &in_event_data;
649 ev_msg.dv[0].data_length = sizeof(struct kev_in_data);
650 ev_msg.dv[1].data_length = 0;
651
652 kev_post_msg(&ev_msg);
653 }
654
655 return (error);
656
657 case SIOCDIFADDR:
658 error = dlil_ioctl(PF_INET, ifp, SIOCDIFADDR, (caddr_t)ia);
659 if (error == EOPNOTSUPP)
660 error = 0;
661 if (error)
662 return error;
663
664 ev_msg.vendor_code = KEV_VENDOR_APPLE;
665 ev_msg.kev_class = KEV_NETWORK_CLASS;
666 ev_msg.kev_subclass = KEV_INET_SUBCLASS;
667
668 ev_msg.event_code = KEV_INET_ADDR_DELETED;
669
670 if (ia->ia_ifa.ifa_dstaddr)
671 in_event_data.ia_dstaddr =
672 ((struct sockaddr_in *)ia->ia_ifa.ifa_dstaddr)->sin_addr;
673 else
674 in_event_data.ia_dstaddr.s_addr = 0;
675
676 in_event_data.ia_addr = ia->ia_addr.sin_addr;
677 in_event_data.ia_net = ia->ia_net;
678 in_event_data.ia_netmask = ia->ia_netmask;
679 in_event_data.ia_subnet = ia->ia_subnet;
680 in_event_data.ia_subnetmask = ia->ia_subnetmask;
681 in_event_data.ia_netbroadcast = ia->ia_netbroadcast;
682 strncpy(&in_event_data.link_data.if_name[0], ifp->if_name, IFNAMSIZ);
683 in_event_data.link_data.if_family = ifp->if_family;
684 in_event_data.link_data.if_unit = (unsigned long) ifp->if_unit;
685
686 ev_msg.dv[0].data_ptr = &in_event_data;
687 ev_msg.dv[0].data_length = sizeof(struct kev_in_data);
688 ev_msg.dv[1].data_length = 0;
689
690 kev_post_msg(&ev_msg);
691
692 /*
693 * in_ifscrub kills the interface route.
694 */
695 in_ifscrub(ifp, ia);
696 #ifndef __APPLE__
697 /*
698 * in_ifadown gets rid of all the rest of
699 * the routes. This is not quite the right
700 * thing to do, but at least if we are running
701 * a routing process they will come back.
702 */
703 in_ifadown(&ia->ia_ifa, 1);
704 /*
705 * XXX horrible hack to detect that we are being called
706 * from if_detach()
707 */
708 if (!ifnet_addrs[ifp->if_index - 1]) {
709 in_pcbpurgeif0(LIST_FIRST(ripcbinfo.listhead), ifp);
710 in_pcbpurgeif0(LIST_FIRST(udbinfo.listhead), ifp);
711 }
712 #endif
713
714 /*
715 * Protect from ipintr() traversing address list
716 * while we're modifying it.
717 */
718 s = splnet();
719
720 ifa = &ia->ia_ifa;
721 TAILQ_REMOVE(&ifp->if_addrhead, ifa, ifa_link);
722 oia = ia;
723 TAILQ_REMOVE(&in_ifaddrhead, oia, ia_link);
724 ifafree(&oia->ia_ifa);
725
726 #ifdef __APPLE__
727 /*
728 * If the interface supports multicast, and no address is left,
729 * remove the "all hosts" multicast group from that interface.
730 */
731 if (ifp->if_flags & IFF_MULTICAST) {
732 struct in_addr addr;
733 struct in_multi *inm;
734
735 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link)
736 if (ifa->ifa_addr->sa_family == AF_INET)
737 break;
738
739 if (ifa == 0) {
740 addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
741 IN_LOOKUP_MULTI(addr, ifp, inm);
742 if (inm)
743 in_delmulti(inm);
744 }
745 }
746 #endif
747 splx(s);
748 break;
749
750 #ifdef __APPLE__
751 case SIOCSETOT: {
752 /*
753 * Inspiration from tcp_ctloutput() and ip_ctloutput()
754 * Special ioctl for OpenTransport sockets
755 */
756 struct inpcb *inp, *cloned_inp;
757 int error = 0;
758 int cloned_fd = *(int *)data;
759
760 s = splnet(); /* XXX */
761 inp = sotoinpcb(so);
762 if (inp == NULL) {
763 splx(s);
764 break;
765 }
766
767 /* let's make sure it's either -1 or a valid file descriptor */
768 if (cloned_fd != -1) {
769 struct socket *cloned_so;
770 struct file *cloned_fp;
771 error = getsock(p->p_fd, cloned_fd, &cloned_fp);
772 if (error){
773 splx(s);
774 break;
775 }
776 cloned_so = (struct socket *)cloned_fp->f_data;
777 cloned_inp = sotoinpcb(cloned_so);
778 } else {
779 cloned_inp = NULL;
780 }
781
782 if (cloned_inp == NULL) {
783 /* OT always uses IP_PORTRANGE_HIGH */
784 inp->inp_flags &= ~(INP_LOWPORT);
785 inp->inp_flags |= INP_HIGHPORT;
786 /* For UDP, OT allows broadcast by default */
787 if (so->so_type == SOCK_DGRAM)
788 so->so_options |= SO_BROADCAST;
789 /* For TCP we want to see MSG_OOB when receive urgent data */
790 else if (so->so_type == SOCK_STREAM)
791 so->so_options |= SO_WANTOOBFLAG;
792 } else {
793 inp->inp_ip_tos = cloned_inp->inp_ip_tos;
794 inp->inp_ip_ttl = cloned_inp->inp_ip_ttl;
795 inp->inp_flags = cloned_inp->inp_flags;
796
797 /* Multicast options */
798 if (cloned_inp->inp_moptions != NULL) {
799 int i;
800 struct ip_moptions *cloned_imo = cloned_inp->inp_moptions;
801 struct ip_moptions *imo = inp->inp_moptions;
802
803 if (imo == NULL) {
804 /*
805 * No multicast option buffer attached to the pcb;
806 * allocate one.
807 */
808 splx();
809 imo = (struct ip_moptions*)
810 _MALLOC(sizeof(*imo), M_IPMOPTS, M_WAITOK);
811 if (imo == NULL) {
812 error = ENOBUFS;
813 break;
814 }
815 s = splnet(); /* XXX */
816 inp->inp_moptions = imo;
817 }
818 imo->imo_multicast_ifp = cloned_imo->imo_multicast_ifp;
819 imo->imo_multicast_vif = cloned_imo->imo_multicast_vif;
820 imo->imo_multicast_ttl = cloned_imo->imo_multicast_ttl;
821 imo->imo_multicast_loop = cloned_imo->imo_multicast_loop;
822 imo->imo_num_memberships = cloned_imo->imo_num_memberships;
823 for (i = 0; i < cloned_imo->imo_num_memberships; i++) {
824 imo->imo_membership[i] =
825 in_addmulti(&cloned_imo->imo_membership[i]->inm_addr,
826 cloned_imo->imo_membership[i]->inm_ifp);
827 if (imo->imo_membership[i] == NULL) {
828 error = ENOBUFS;
829 break;
830 }
831 }
832 if (i < cloned_imo->imo_num_memberships) {
833 /* Failed, perform cleanup */
834 for (i--; i >= 0; i--)
835 in_delmulti(imo->imo_membership[i]);
836 break;
837 }
838 }
839 }
840 splx(s);
841 break;
842 }
843 #endif /* __APPLE__ */
844
845 default:
846 return EOPNOTSUPP;
847 /* Darwin: dlil_ioctl called from ifioctl */
848 #ifndef __APPLE__
849 return ((*ifp->if_ioctl)(ifp, cmd, data));
850 #endif
851 }
852 return (0);
853 }
854
855 /*
856 * SIOC[GAD]LIFADDR.
857 * SIOCGLIFADDR: get first address. (?!?)
858 * SIOCGLIFADDR with IFLR_PREFIX:
859 * get first address that matches the specified prefix.
860 * SIOCALIFADDR: add the specified address.
861 * SIOCALIFADDR with IFLR_PREFIX:
862 * EINVAL since we can't deduce hostid part of the address.
863 * SIOCDLIFADDR: delete the specified address.
864 * SIOCDLIFADDR with IFLR_PREFIX:
865 * delete the first address that matches the specified prefix.
866 * return values:
867 * EINVAL on invalid parameters
868 * EADDRNOTAVAIL on prefix match failed/specified address not found
869 * other values may be returned from in_ioctl()
870 */
871 static int
872 in_lifaddr_ioctl(so, cmd, data, ifp, p)
873 struct socket *so;
874 u_long cmd;
875 caddr_t data;
876 struct ifnet *ifp;
877 struct proc *p;
878 {
879 struct if_laddrreq *iflr = (struct if_laddrreq *)data;
880 struct ifaddr *ifa;
881
882 /* sanity checks */
883 if (!data || !ifp) {
884 panic("invalid argument to in_lifaddr_ioctl");
885 /*NOTRECHED*/
886 }
887
888 switch (cmd) {
889 case SIOCGLIFADDR:
890 /* address must be specified on GET with IFLR_PREFIX */
891 if ((iflr->flags & IFLR_PREFIX) == 0)
892 break;
893 /*FALLTHROUGH*/
894 case SIOCALIFADDR:
895 case SIOCDLIFADDR:
896 /* address must be specified on ADD and DELETE */
897 if (iflr->addr.ss_family != AF_INET)
898 return EINVAL;
899 if (iflr->addr.ss_len != sizeof(struct sockaddr_in))
900 return EINVAL;
901 /* XXX need improvement */
902 if (iflr->dstaddr.ss_family
903 && iflr->dstaddr.ss_family != AF_INET)
904 return EINVAL;
905 if (iflr->dstaddr.ss_family
906 && iflr->dstaddr.ss_len != sizeof(struct sockaddr_in))
907 return EINVAL;
908 break;
909 default: /*shouldn't happen*/
910 return EOPNOTSUPP;
911 }
912 if (sizeof(struct in_addr) * 8 < iflr->prefixlen)
913 return EINVAL;
914
915 switch (cmd) {
916 case SIOCALIFADDR:
917 {
918 struct in_aliasreq ifra;
919
920 if (iflr->flags & IFLR_PREFIX)
921 return EINVAL;
922
923 /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */
924 bzero(&ifra, sizeof(ifra));
925 bcopy(iflr->iflr_name, ifra.ifra_name,
926 sizeof(ifra.ifra_name));
927
928 bcopy(&iflr->addr, &ifra.ifra_addr, iflr->addr.ss_len);
929
930 if (iflr->dstaddr.ss_family) { /*XXX*/
931 bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr,
932 iflr->dstaddr.ss_len);
933 }
934
935 ifra.ifra_mask.sin_family = AF_INET;
936 ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in);
937 in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen);
938
939 return in_control(so, SIOCAIFADDR, (caddr_t)&ifra, ifp, p);
940 }
941 case SIOCGLIFADDR:
942 case SIOCDLIFADDR:
943 {
944 struct in_ifaddr *ia;
945 struct in_addr mask, candidate, match;
946 struct sockaddr_in *sin;
947 int cmp;
948
949 bzero(&mask, sizeof(mask));
950 if (iflr->flags & IFLR_PREFIX) {
951 /* lookup a prefix rather than address. */
952 in_len2mask(&mask, iflr->prefixlen);
953
954 sin = (struct sockaddr_in *)&iflr->addr;
955 match.s_addr = sin->sin_addr.s_addr;
956 match.s_addr &= mask.s_addr;
957
958 /* if you set extra bits, that's wrong */
959 if (match.s_addr != sin->sin_addr.s_addr)
960 return EINVAL;
961
962 cmp = 1;
963 } else {
964 if (cmd == SIOCGLIFADDR) {
965 /* on getting an address, take the 1st match */
966 cmp = 0; /*XXX*/
967 } else {
968 /* on deleting an address, do exact match */
969 in_len2mask(&mask, 32);
970 sin = (struct sockaddr_in *)&iflr->addr;
971 match.s_addr = sin->sin_addr.s_addr;
972
973 cmp = 1;
974 }
975 }
976
977 TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) {
978 if (ifa->ifa_addr->sa_family != AF_INET6)
979 continue;
980 if (!cmp)
981 break;
982 candidate.s_addr = ((struct sockaddr_in *)&ifa->ifa_addr)->sin_addr.s_addr;
983 candidate.s_addr &= mask.s_addr;
984 if (candidate.s_addr == match.s_addr)
985 break;
986 }
987 if (!ifa)
988 return EADDRNOTAVAIL;
989 ia = (struct in_ifaddr *)ifa;
990
991 if (cmd == SIOCGLIFADDR) {
992 /* fill in the if_laddrreq structure */
993 bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin_len);
994
995 if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
996 bcopy(&ia->ia_dstaddr, &iflr->dstaddr,
997 ia->ia_dstaddr.sin_len);
998 } else
999 bzero(&iflr->dstaddr, sizeof(iflr->dstaddr));
1000
1001 iflr->prefixlen =
1002 in_mask2len(&ia->ia_sockmask.sin_addr);
1003
1004 iflr->flags = 0; /*XXX*/
1005
1006 return 0;
1007 } else {
1008 struct in_aliasreq ifra;
1009
1010 /* fill in_aliasreq and do ioctl(SIOCDIFADDR_IN6) */
1011 bzero(&ifra, sizeof(ifra));
1012 bcopy(iflr->iflr_name, ifra.ifra_name,
1013 sizeof(ifra.ifra_name));
1014
1015 bcopy(&ia->ia_addr, &ifra.ifra_addr,
1016 ia->ia_addr.sin_len);
1017 if ((ifp->if_flags & IFF_POINTOPOINT) != 0) {
1018 bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr,
1019 ia->ia_dstaddr.sin_len);
1020 }
1021 bcopy(&ia->ia_sockmask, &ifra.ifra_dstaddr,
1022 ia->ia_sockmask.sin_len);
1023
1024 return in_control(so, SIOCDIFADDR, (caddr_t)&ifra,
1025 ifp, p);
1026 }
1027 }
1028 }
1029
1030 return EOPNOTSUPP; /*just for safety*/
1031 }
1032
1033 /*
1034 * Delete any existing route for an interface.
1035 */
1036 void
1037 in_ifscrub(ifp, ia)
1038 register struct ifnet *ifp;
1039 register struct in_ifaddr *ia;
1040 {
1041
1042 if ((ia->ia_flags & IFA_ROUTE) == 0)
1043 return;
1044 if (ifp->if_flags & (IFF_LOOPBACK|IFF_POINTOPOINT))
1045 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST);
1046 else
1047 rtinit(&(ia->ia_ifa), (int)RTM_DELETE, 0);
1048 ia->ia_flags &= ~IFA_ROUTE;
1049 }
1050
1051 /*
1052 * Initialize an interface's internet address
1053 * and routing table entry.
1054 */
1055 static int
1056 in_ifinit(ifp, ia, sin, scrub)
1057 register struct ifnet *ifp;
1058 register struct in_ifaddr *ia;
1059 struct sockaddr_in *sin;
1060 int scrub;
1061 {
1062 register u_long i = ntohl(sin->sin_addr.s_addr);
1063 struct sockaddr_in oldaddr;
1064 int s = splimp(), flags = RTF_UP, error;
1065 u_long dl_tag;
1066
1067 oldaddr = ia->ia_addr;
1068 ia->ia_addr = *sin;
1069
1070 /*
1071 * Give the interface a chance to initialize
1072 * if this is its first address,
1073 * and to validate the address if necessary.
1074 */
1075 error = dlil_ioctl(PF_INET, ifp, SIOCSIFADDR, (caddr_t)ia);
1076 if (error == EOPNOTSUPP)
1077 error = 0;
1078 if (error) {
1079 splx(s);
1080 ia->ia_addr = oldaddr;
1081 return (error);
1082 }
1083 splx(s);
1084 if (scrub) {
1085 ia->ia_ifa.ifa_addr = (struct sockaddr *)&oldaddr;
1086 in_ifscrub(ifp, ia);
1087 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
1088 }
1089 if (IN_CLASSA(i))
1090 ia->ia_netmask = IN_CLASSA_NET;
1091 else if (IN_CLASSB(i))
1092 ia->ia_netmask = IN_CLASSB_NET;
1093 else
1094 ia->ia_netmask = IN_CLASSC_NET;
1095 /*
1096 * The subnet mask usually includes at least the standard network part,
1097 * but may may be smaller in the case of supernetting.
1098 * If it is set, we believe it.
1099 */
1100 if (ia->ia_subnetmask == 0) {
1101 ia->ia_subnetmask = ia->ia_netmask;
1102 ia->ia_sockmask.sin_addr.s_addr = htonl(ia->ia_subnetmask);
1103 } else
1104 ia->ia_netmask &= ia->ia_subnetmask;
1105 ia->ia_net = i & ia->ia_netmask;
1106 ia->ia_subnet = i & ia->ia_subnetmask;
1107 in_socktrim(&ia->ia_sockmask);
1108 /*
1109 * Add route for the network.
1110 */
1111 ia->ia_ifa.ifa_metric = ifp->if_metric;
1112 if (ifp->if_flags & IFF_BROADCAST) {
1113 ia->ia_broadaddr.sin_addr.s_addr =
1114 htonl(ia->ia_subnet | ~ia->ia_subnetmask);
1115 ia->ia_netbroadcast.s_addr =
1116 htonl(ia->ia_net | ~ ia->ia_netmask);
1117 } else if (ifp->if_flags & IFF_LOOPBACK) {
1118 ia->ia_ifa.ifa_dstaddr = ia->ia_ifa.ifa_addr;
1119 flags |= RTF_HOST;
1120 } else if (ifp->if_flags & IFF_POINTOPOINT) {
1121 if (ia->ia_dstaddr.sin_family != AF_INET)
1122 return (0);
1123 flags |= RTF_HOST;
1124 }
1125 if ((error = rtinit(&(ia->ia_ifa), (int)RTM_ADD, flags)) == 0)
1126 ia->ia_flags |= IFA_ROUTE;
1127 /* XXX check if the subnet route points to the same interface */
1128 if (error == EEXIST)
1129 error = 0;
1130
1131 /*
1132 * If the interface supports multicast, join the "all hosts"
1133 * multicast group on that interface.
1134 */
1135 if (ifp->if_flags & IFF_MULTICAST) {
1136 struct in_multi *inm;
1137 struct in_addr addr;
1138
1139 addr.s_addr = htonl(INADDR_ALLHOSTS_GROUP);
1140 IN_LOOKUP_MULTI(addr, ifp, inm);
1141 if (inm == 0)
1142 in_addmulti(&addr, ifp);
1143 }
1144 return (error);
1145 }
1146
1147
1148 /*
1149 * Return 1 if the address might be a local broadcast address.
1150 */
1151 int
1152 in_broadcast(in, ifp)
1153 struct in_addr in;
1154 struct ifnet *ifp;
1155 {
1156 register struct ifaddr *ifa;
1157 u_long t;
1158
1159 if (in.s_addr == INADDR_BROADCAST ||
1160 in.s_addr == INADDR_ANY)
1161 return 1;
1162 if ((ifp->if_flags & IFF_BROADCAST) == 0)
1163 return 0;
1164 t = ntohl(in.s_addr);
1165 /*
1166 * Look through the list of addresses for a match
1167 * with a broadcast address.
1168 */
1169 #define ia ((struct in_ifaddr *)ifa)
1170 for (ifa = ifp->if_addrhead.tqh_first; ifa;
1171 ifa = ifa->ifa_link.tqe_next) {
1172 if (ifa->ifa_addr == NULL)
1173 return (0);
1174 if (ifa->ifa_addr->sa_family == AF_INET &&
1175 (in.s_addr == ia->ia_broadaddr.sin_addr.s_addr ||
1176 in.s_addr == ia->ia_netbroadcast.s_addr ||
1177 /*
1178 * Check for old-style (host 0) broadcast.
1179 */
1180 t == ia->ia_subnet || t == ia->ia_net) &&
1181 /*
1182 * Check for an all one subnetmask. These
1183 * only exist when an interface gets a secondary
1184 * address.
1185 */
1186 ia->ia_subnetmask != (u_long)0xffffffff)
1187 return 1;
1188 }
1189 return (0);
1190 #undef ia
1191 }
1192 /*
1193 * Add an address to the list of IP multicast addresses for a given interface.
1194 */
1195 struct in_multi *
1196 in_addmulti(ap, ifp)
1197 register struct in_addr *ap;
1198 register struct ifnet *ifp;
1199 {
1200 register struct in_multi *inm;
1201 int error;
1202 struct sockaddr_in sin;
1203 struct ifmultiaddr *ifma;
1204 int s = splnet();
1205
1206 /*
1207 * Call generic routine to add membership or increment
1208 * refcount. It wants addresses in the form of a sockaddr,
1209 * so we build one here (being careful to zero the unused bytes).
1210 */
1211 bzero(&sin, sizeof sin);
1212 sin.sin_family = AF_INET;
1213 sin.sin_len = sizeof sin;
1214 sin.sin_addr = *ap;
1215 error = if_addmulti(ifp, (struct sockaddr *)&sin, &ifma);
1216 if (error) {
1217 splx(s);
1218 return 0;
1219 }
1220
1221 /*
1222 * If ifma->ifma_protospec is null, then if_addmulti() created
1223 * a new record. Otherwise, we are done.
1224 */
1225 if (ifma->ifma_protospec != 0) {
1226 splx(s);
1227 return ifma->ifma_protospec;
1228 }
1229
1230 inm = (struct in_multi *) _MALLOC(sizeof(*inm), M_IPMADDR, M_WAITOK);
1231 if (inm == NULL) {
1232 splx(s);
1233 return (NULL);
1234 }
1235
1236 bzero(inm, sizeof *inm);
1237 inm->inm_addr = *ap;
1238 inm->inm_ifp = ifp;
1239 inm->inm_ifma = ifma;
1240 ifma->ifma_protospec = inm;
1241 LIST_INSERT_HEAD(&in_multihead, inm, inm_link);
1242
1243 /*
1244 * Let IGMP know that we have joined a new IP multicast group.
1245 */
1246 igmp_joingroup(inm);
1247 splx(s);
1248 return (inm);
1249 }
1250
1251 /*
1252 * Delete a multicast address record.
1253 */
1254 void
1255 in_delmulti(inm)
1256 register struct in_multi *inm;
1257 {
1258 struct ifmultiaddr *ifma = inm->inm_ifma;
1259 int s = splnet();
1260
1261 /* We intentionally do this a bit differently than BSD */
1262
1263 if (ifma->ifma_refcount == 1) {
1264 /*
1265 * No remaining claims to this record; let IGMP know that
1266 * we are leaving the multicast group.
1267 */
1268 igmp_leavegroup(inm);
1269 ifma->ifma_protospec = 0;
1270 LIST_REMOVE(inm, inm_link);
1271 FREE(inm, M_IPMADDR);
1272 }
1273 /* XXX - should be separate API for when we have an ifma? */
1274 if_delmulti(ifma->ifma_ifp, ifma->ifma_addr);
1275 splx(s);
1276 }