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