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