]>
Commit | Line | Data |
---|---|---|
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 | ||
89 | static int in_mask2len __P((struct in_addr *)); | |
90 | static void in_len2mask __P((struct in_addr *, int)); | |
91 | static int in_lifaddr_ioctl __P((struct socket *, u_long, caddr_t, | |
92 | struct ifnet *, struct proc *)); | |
93 | ||
94 | static void in_socktrim __P((struct sockaddr_in *)); | |
95 | static int in_ifinit __P((struct ifnet *, | |
96 | struct in_ifaddr *, struct sockaddr_in *, int)); | |
97 | ||
98 | static int subnetsarelocal = 0; | |
99 | SYSCTL_INT(_net_inet_ip, OID_AUTO, subnets_are_local, CTLFLAG_RW, | |
100 | &subnetsarelocal, 0, ""); | |
101 | ||
102 | struct in_multihead in_multihead; /* XXX BSS initialization */ | |
103 | ||
104 | extern void arp_rtrequest(); | |
0b4e3aa0 | 105 | extern int ether_detach_inet(struct ifnet *ifp); |
1c79356b | 106 | |
9bccf70c A |
107 | #if INET6 |
108 | extern 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 | */ | |
117 | int | |
118 | in_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 | */ | |
143 | int | |
144 | in_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 | */ | |
163 | static void | |
164 | in_socktrim(ap) | |
165 | struct 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 | ||
178 | static int | |
179 | in_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 | ||
200 | static void | |
201 | in_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 | ||
216 | static 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 */ | |
223 | int | |
224 | in_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 | */ | |
868 | static int | |
869 | in_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 | */ | |
1033 | void | |
1034 | in_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 | */ | |
1052 | static int | |
1053 | in_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 | */ | |
1148 | int | |
1149 | in_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 | */ | |
1192 | struct in_multi * | |
1193 | in_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 | */ | |
1251 | void | |
1252 | in_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 | } |