1 | /* $NetBSD: in.c,v 1.188 2016/11/18 10:38:55 knakahara Exp $ */ |
2 | |
3 | /* |
4 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. |
5 | * All rights reserved. |
6 | * |
7 | * Redistribution and use in source and binary forms, with or without |
8 | * modification, are permitted provided that the following conditions |
9 | * are met: |
10 | * 1. Redistributions of source code must retain the above copyright |
11 | * notice, this list of conditions and the following disclaimer. |
12 | * 2. Redistributions in binary form must reproduce the above copyright |
13 | * notice, this list of conditions and the following disclaimer in the |
14 | * documentation and/or other materials provided with the distribution. |
15 | * 3. Neither the name of the project nor the names of its contributors |
16 | * may be used to endorse or promote products derived from this software |
17 | * without specific prior written permission. |
18 | * |
19 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND |
20 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
21 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
22 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE |
23 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
24 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
25 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
26 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
27 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
28 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
29 | * SUCH DAMAGE. |
30 | */ |
31 | |
32 | /*- |
33 | * Copyright (c) 1998 The NetBSD Foundation, Inc. |
34 | * All rights reserved. |
35 | * |
36 | * This code is derived from software contributed to The NetBSD Foundation |
37 | * by Public Access Networks Corporation ("Panix"). It was developed under |
38 | * contract to Panix by Eric Haszlakiewicz and Thor Lancelot Simon. |
39 | * |
40 | * Redistribution and use in source and binary forms, with or without |
41 | * modification, are permitted provided that the following conditions |
42 | * are met: |
43 | * 1. Redistributions of source code must retain the above copyright |
44 | * notice, this list of conditions and the following disclaimer. |
45 | * 2. Redistributions in binary form must reproduce the above copyright |
46 | * notice, this list of conditions and the following disclaimer in the |
47 | * documentation and/or other materials provided with the distribution. |
48 | * |
49 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS |
50 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED |
51 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
52 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS |
53 | * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
54 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
55 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
56 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
57 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
58 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
59 | * POSSIBILITY OF SUCH DAMAGE. |
60 | */ |
61 | |
62 | /* |
63 | * Copyright (c) 1982, 1986, 1991, 1993 |
64 | * The Regents of the University of California. All rights reserved. |
65 | * |
66 | * Redistribution and use in source and binary forms, with or without |
67 | * modification, are permitted provided that the following conditions |
68 | * are met: |
69 | * 1. Redistributions of source code must retain the above copyright |
70 | * notice, this list of conditions and the following disclaimer. |
71 | * 2. Redistributions in binary form must reproduce the above copyright |
72 | * notice, this list of conditions and the following disclaimer in the |
73 | * documentation and/or other materials provided with the distribution. |
74 | * 3. Neither the name of the University nor the names of its contributors |
75 | * may be used to endorse or promote products derived from this software |
76 | * without specific prior written permission. |
77 | * |
78 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
79 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
80 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
81 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
82 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
83 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
84 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
85 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
86 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
87 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
88 | * SUCH DAMAGE. |
89 | * |
90 | * @(#)in.c 8.4 (Berkeley) 1/9/95 |
91 | */ |
92 | |
93 | #include <sys/cdefs.h> |
94 | __KERNEL_RCSID(0, "$NetBSD: in.c,v 1.188 2016/11/18 10:38:55 knakahara Exp $" ); |
95 | |
96 | #include "arp.h" |
97 | |
98 | #ifdef _KERNEL_OPT |
99 | #include "opt_inet.h" |
100 | #include "opt_inet_conf.h" |
101 | #include "opt_mrouting.h" |
102 | #include "opt_net_mpsafe.h" |
103 | #endif |
104 | |
105 | #include <sys/param.h> |
106 | #include <sys/ioctl.h> |
107 | #include <sys/errno.h> |
108 | #include <sys/kernel.h> |
109 | #include <sys/malloc.h> |
110 | #include <sys/socket.h> |
111 | #include <sys/socketvar.h> |
112 | #include <sys/sysctl.h> |
113 | #include <sys/systm.h> |
114 | #include <sys/proc.h> |
115 | #include <sys/syslog.h> |
116 | #include <sys/kauth.h> |
117 | #include <sys/kmem.h> |
118 | |
119 | #include <sys/cprng.h> |
120 | |
121 | #include <net/if.h> |
122 | #include <net/route.h> |
123 | #include <net/pfil.h> |
124 | |
125 | #include <net/if_arp.h> |
126 | #include <net/if_ether.h> |
127 | #include <net/if_types.h> |
128 | #include <net/if_llatbl.h> |
129 | #include <net/if_dl.h> |
130 | |
131 | #include <netinet/in_systm.h> |
132 | #include <netinet/in.h> |
133 | #include <netinet/in_var.h> |
134 | #include <netinet/ip.h> |
135 | #include <netinet/ip_var.h> |
136 | #include <netinet/in_ifattach.h> |
137 | #include <netinet/in_pcb.h> |
138 | #include <netinet/in_selsrc.h> |
139 | #include <netinet/if_inarp.h> |
140 | #include <netinet/ip_mroute.h> |
141 | #include <netinet/igmp_var.h> |
142 | |
143 | #ifdef IPSELSRC |
144 | #include <netinet/in_selsrc.h> |
145 | #endif |
146 | |
147 | static u_int in_mask2len(struct in_addr *); |
148 | static void in_len2mask(struct in_addr *, u_int); |
149 | static int in_lifaddr_ioctl(struct socket *, u_long, void *, |
150 | struct ifnet *); |
151 | |
152 | static int in_addprefix(struct in_ifaddr *, int); |
153 | static void in_scrubaddr(struct in_ifaddr *); |
154 | static int in_scrubprefix(struct in_ifaddr *); |
155 | static void in_sysctl_init(struct sysctllog **); |
156 | |
157 | #ifndef SUBNETSARELOCAL |
158 | #define SUBNETSARELOCAL 1 |
159 | #endif |
160 | |
161 | #ifndef HOSTZEROBROADCAST |
162 | #define HOSTZEROBROADCAST 0 |
163 | #endif |
164 | |
165 | /* Note: 61, 127, 251, 509, 1021, 2039 are good. */ |
166 | #ifndef IN_MULTI_HASH_SIZE |
167 | #define IN_MULTI_HASH_SIZE 509 |
168 | #endif |
169 | |
170 | static int subnetsarelocal = SUBNETSARELOCAL; |
171 | static int hostzeroisbroadcast = HOSTZEROBROADCAST; |
172 | |
173 | /* |
174 | * This list is used to keep track of in_multi chains which belong to |
175 | * deleted interface addresses. We use in_ifaddr so that a chain head |
176 | * won't be deallocated until all multicast address record are deleted. |
177 | */ |
178 | |
179 | LIST_HEAD(in_multihashhead, in_multi); /* Type of the hash head */ |
180 | |
181 | static struct pool inmulti_pool; |
182 | static u_int in_multientries; |
183 | static struct in_multihashhead *in_multihashtbl; |
184 | static u_long in_multihash; |
185 | static krwlock_t in_multilock; |
186 | |
187 | #define IN_MULTI_HASH(x, ifp) \ |
188 | (in_multihashtbl[(u_long)((x) ^ (ifp->if_index)) % IN_MULTI_HASH_SIZE]) |
189 | |
190 | /* XXX DEPRECATED. Keep them to avoid breaking kvm(3) users. */ |
191 | struct in_ifaddrhashhead * in_ifaddrhashtbl; |
192 | u_long in_ifaddrhash; |
193 | struct in_ifaddrhead in_ifaddrhead; |
194 | static kmutex_t in_ifaddr_lock; |
195 | |
196 | pserialize_t in_ifaddrhash_psz; |
197 | struct pslist_head * in_ifaddrhashtbl_pslist; |
198 | u_long in_ifaddrhash_pslist; |
199 | struct pslist_head in_ifaddrhead_pslist; |
200 | |
201 | void |
202 | in_init(void) |
203 | { |
204 | pool_init(&inmulti_pool, sizeof(struct in_multi), 0, 0, 0, "inmltpl" , |
205 | NULL, IPL_SOFTNET); |
206 | TAILQ_INIT(&in_ifaddrhead); |
207 | PSLIST_INIT(&in_ifaddrhead_pslist); |
208 | |
209 | in_ifaddrhashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, |
210 | &in_ifaddrhash); |
211 | |
212 | in_ifaddrhash_psz = pserialize_create(); |
213 | in_ifaddrhashtbl_pslist = hashinit(IN_IFADDR_HASH_SIZE, HASH_PSLIST, |
214 | true, &in_ifaddrhash_pslist); |
215 | mutex_init(&in_ifaddr_lock, MUTEX_DEFAULT, IPL_NONE); |
216 | |
217 | in_multihashtbl = hashinit(IN_IFADDR_HASH_SIZE, HASH_LIST, true, |
218 | &in_multihash); |
219 | rw_init(&in_multilock); |
220 | |
221 | in_sysctl_init(NULL); |
222 | } |
223 | |
224 | /* |
225 | * Return 1 if an internet address is for a ``local'' host |
226 | * (one to which we have a connection). If subnetsarelocal |
227 | * is true, this includes other subnets of the local net. |
228 | * Otherwise, it includes only the directly-connected (sub)nets. |
229 | */ |
230 | int |
231 | in_localaddr(struct in_addr in) |
232 | { |
233 | struct in_ifaddr *ia; |
234 | int localaddr = 0; |
235 | int s = pserialize_read_enter(); |
236 | |
237 | if (subnetsarelocal) { |
238 | IN_ADDRLIST_READER_FOREACH(ia) { |
239 | if ((in.s_addr & ia->ia_netmask) == ia->ia_net) { |
240 | localaddr = 1; |
241 | break; |
242 | } |
243 | } |
244 | } else { |
245 | IN_ADDRLIST_READER_FOREACH(ia) { |
246 | if ((in.s_addr & ia->ia_subnetmask) == ia->ia_subnet) { |
247 | localaddr = 1; |
248 | break; |
249 | } |
250 | } |
251 | } |
252 | pserialize_read_exit(s); |
253 | |
254 | return localaddr; |
255 | } |
256 | |
257 | /* |
258 | * Determine whether an IP address is in a reserved set of addresses |
259 | * that may not be forwarded, or whether datagrams to that destination |
260 | * may be forwarded. |
261 | */ |
262 | int |
263 | in_canforward(struct in_addr in) |
264 | { |
265 | u_int32_t net; |
266 | |
267 | if (IN_EXPERIMENTAL(in.s_addr) || IN_MULTICAST(in.s_addr)) |
268 | return (0); |
269 | if (IN_CLASSA(in.s_addr)) { |
270 | net = in.s_addr & IN_CLASSA_NET; |
271 | if (net == 0 || net == htonl(IN_LOOPBACKNET << IN_CLASSA_NSHIFT)) |
272 | return (0); |
273 | } |
274 | return (1); |
275 | } |
276 | |
277 | /* |
278 | * Trim a mask in a sockaddr |
279 | */ |
280 | void |
281 | in_socktrim(struct sockaddr_in *ap) |
282 | { |
283 | char *cplim = (char *) &ap->sin_addr; |
284 | char *cp = (char *) (&ap->sin_addr + 1); |
285 | |
286 | ap->sin_len = 0; |
287 | while (--cp >= cplim) |
288 | if (*cp) { |
289 | (ap)->sin_len = cp - (char *) (ap) + 1; |
290 | break; |
291 | } |
292 | } |
293 | |
294 | /* |
295 | * Routine to take an Internet address and convert into a |
296 | * "dotted quad" representation for printing. |
297 | */ |
298 | const char * |
299 | in_fmtaddr(struct in_addr addr) |
300 | { |
301 | static char buf[sizeof("123.456.789.123" )]; |
302 | |
303 | addr.s_addr = ntohl(addr.s_addr); |
304 | |
305 | snprintf(buf, sizeof(buf), "%d.%d.%d.%d" , |
306 | (addr.s_addr >> 24) & 0xFF, |
307 | (addr.s_addr >> 16) & 0xFF, |
308 | (addr.s_addr >> 8) & 0xFF, |
309 | (addr.s_addr >> 0) & 0xFF); |
310 | return buf; |
311 | } |
312 | |
313 | /* |
314 | * Maintain the "in_maxmtu" variable, which is the largest |
315 | * mtu for non-local interfaces with AF_INET addresses assigned |
316 | * to them that are up. |
317 | */ |
318 | unsigned long in_maxmtu; |
319 | |
320 | void |
321 | in_setmaxmtu(void) |
322 | { |
323 | struct in_ifaddr *ia; |
324 | struct ifnet *ifp; |
325 | unsigned long maxmtu = 0; |
326 | int s = pserialize_read_enter(); |
327 | |
328 | IN_ADDRLIST_READER_FOREACH(ia) { |
329 | if ((ifp = ia->ia_ifp) == 0) |
330 | continue; |
331 | if ((ifp->if_flags & (IFF_UP|IFF_LOOPBACK)) != IFF_UP) |
332 | continue; |
333 | if (ifp->if_mtu > maxmtu) |
334 | maxmtu = ifp->if_mtu; |
335 | } |
336 | if (maxmtu) |
337 | in_maxmtu = maxmtu; |
338 | pserialize_read_exit(s); |
339 | } |
340 | |
341 | static u_int |
342 | in_mask2len(struct in_addr *mask) |
343 | { |
344 | u_int x, y; |
345 | u_char *p; |
346 | |
347 | p = (u_char *)mask; |
348 | for (x = 0; x < sizeof(*mask); x++) { |
349 | if (p[x] != 0xff) |
350 | break; |
351 | } |
352 | y = 0; |
353 | if (x < sizeof(*mask)) { |
354 | for (y = 0; y < NBBY; y++) { |
355 | if ((p[x] & (0x80 >> y)) == 0) |
356 | break; |
357 | } |
358 | } |
359 | return x * NBBY + y; |
360 | } |
361 | |
362 | static void |
363 | in_len2mask(struct in_addr *mask, u_int len) |
364 | { |
365 | u_int i; |
366 | u_char *p; |
367 | |
368 | p = (u_char *)mask; |
369 | memset(mask, 0, sizeof(*mask)); |
370 | for (i = 0; i < len / NBBY; i++) |
371 | p[i] = 0xff; |
372 | if (len % NBBY) |
373 | p[i] = (0xff00 >> (len % NBBY)) & 0xff; |
374 | } |
375 | |
376 | /* |
377 | * Generic internet control operations (ioctl's). |
378 | * Ifp is 0 if not an interface-specific ioctl. |
379 | */ |
380 | /* ARGSUSED */ |
381 | static int |
382 | in_control0(struct socket *so, u_long cmd, void *data, struct ifnet *ifp) |
383 | { |
384 | struct ifreq *ifr = (struct ifreq *)data; |
385 | struct in_ifaddr *ia = NULL; |
386 | struct in_aliasreq *ifra = (struct in_aliasreq *)data; |
387 | struct sockaddr_in oldaddr, *new_dstaddr; |
388 | int error, hostIsNew, maskIsNew; |
389 | int newifaddr = 0; |
390 | bool run_hook = false; |
391 | bool need_reinsert = false; |
392 | struct psref psref; |
393 | int bound; |
394 | |
395 | switch (cmd) { |
396 | case SIOCALIFADDR: |
397 | case SIOCDLIFADDR: |
398 | case SIOCGLIFADDR: |
399 | if (ifp == NULL) |
400 | return EINVAL; |
401 | return in_lifaddr_ioctl(so, cmd, data, ifp); |
402 | case SIOCGIFADDRPREF: |
403 | case SIOCSIFADDRPREF: |
404 | if (ifp == NULL) |
405 | return EINVAL; |
406 | return ifaddrpref_ioctl(so, cmd, data, ifp); |
407 | } |
408 | |
409 | bound = curlwp_bind(); |
410 | /* |
411 | * Find address for this interface, if it exists. |
412 | */ |
413 | if (ifp != NULL) |
414 | ia = in_get_ia_from_ifp_psref(ifp, &psref); |
415 | |
416 | hostIsNew = 1; /* moved here to appease gcc */ |
417 | switch (cmd) { |
418 | case SIOCAIFADDR: |
419 | case SIOCDIFADDR: |
420 | case SIOCGIFALIAS: |
421 | case SIOCGIFAFLAG_IN: |
422 | if (ifra->ifra_addr.sin_family == AF_INET) { |
423 | int s; |
424 | |
425 | if (ia != NULL) |
426 | ia4_release(ia, &psref); |
427 | s = pserialize_read_enter(); |
428 | IN_ADDRHASH_READER_FOREACH(ia, |
429 | ifra->ifra_addr.sin_addr.s_addr) { |
430 | if (ia->ia_ifp == ifp && |
431 | in_hosteq(ia->ia_addr.sin_addr, |
432 | ifra->ifra_addr.sin_addr)) |
433 | break; |
434 | } |
435 | if (ia != NULL) |
436 | ia4_acquire(ia, &psref); |
437 | pserialize_read_exit(s); |
438 | } |
439 | if ((cmd == SIOCDIFADDR || |
440 | cmd == SIOCGIFALIAS || |
441 | cmd == SIOCGIFAFLAG_IN) && |
442 | ia == NULL) { |
443 | error = EADDRNOTAVAIL; |
444 | goto out; |
445 | } |
446 | |
447 | if (cmd == SIOCDIFADDR && |
448 | ifra->ifra_addr.sin_family == AF_UNSPEC) { |
449 | ifra->ifra_addr.sin_family = AF_INET; |
450 | } |
451 | /* FALLTHROUGH */ |
452 | case SIOCSIFADDR: |
453 | if (ia == NULL || ia->ia_addr.sin_family != AF_INET) |
454 | ; |
455 | else if (ifra->ifra_addr.sin_len == 0) { |
456 | ifra->ifra_addr = ia->ia_addr; |
457 | hostIsNew = 0; |
458 | } else if (in_hosteq(ia->ia_addr.sin_addr, |
459 | ifra->ifra_addr.sin_addr)) |
460 | hostIsNew = 0; |
461 | /* FALLTHROUGH */ |
462 | case SIOCSIFDSTADDR: |
463 | if (ifra->ifra_addr.sin_family != AF_INET) { |
464 | error = EAFNOSUPPORT; |
465 | goto out; |
466 | } |
467 | /* FALLTHROUGH */ |
468 | case SIOCSIFNETMASK: |
469 | if (ifp == NULL) |
470 | panic("in_control" ); |
471 | |
472 | if (cmd == SIOCGIFALIAS || cmd == SIOCGIFAFLAG_IN) |
473 | break; |
474 | |
475 | if (ia == NULL && |
476 | (cmd == SIOCSIFNETMASK || cmd == SIOCSIFDSTADDR)) { |
477 | error = EADDRNOTAVAIL; |
478 | goto out; |
479 | } |
480 | |
481 | if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE, |
482 | KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, |
483 | NULL) != 0) { |
484 | error = EPERM; |
485 | goto out; |
486 | } |
487 | |
488 | if (ia == NULL) { |
489 | ia = malloc(sizeof(*ia), M_IFADDR, M_WAITOK|M_ZERO); |
490 | if (ia == NULL) { |
491 | error = ENOBUFS; |
492 | goto out; |
493 | } |
494 | ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr); |
495 | ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); |
496 | ia->ia_ifa.ifa_netmask = sintosa(&ia->ia_sockmask); |
497 | #ifdef IPSELSRC |
498 | ia->ia_ifa.ifa_getifa = in_getifa; |
499 | #else /* IPSELSRC */ |
500 | ia->ia_ifa.ifa_getifa = NULL; |
501 | #endif /* IPSELSRC */ |
502 | ia->ia_sockmask.sin_len = 8; |
503 | ia->ia_sockmask.sin_family = AF_INET; |
504 | if (ifp->if_flags & IFF_BROADCAST) { |
505 | ia->ia_broadaddr.sin_len = sizeof(ia->ia_addr); |
506 | ia->ia_broadaddr.sin_family = AF_INET; |
507 | } |
508 | ia->ia_ifp = ifp; |
509 | ia->ia_idsalt = cprng_fast32() % 65535; |
510 | LIST_INIT(&ia->ia_multiaddrs); |
511 | IN_ADDRHASH_ENTRY_INIT(ia); |
512 | IN_ADDRLIST_ENTRY_INIT(ia); |
513 | ifa_psref_init(&ia->ia_ifa); |
514 | |
515 | newifaddr = 1; |
516 | } |
517 | break; |
518 | |
519 | case SIOCSIFBRDADDR: |
520 | if (kauth_authorize_network(curlwp->l_cred, KAUTH_NETWORK_INTERFACE, |
521 | KAUTH_REQ_NETWORK_INTERFACE_SETPRIV, ifp, (void *)cmd, |
522 | NULL) != 0) { |
523 | error = EPERM; |
524 | goto out; |
525 | } |
526 | /* FALLTHROUGH */ |
527 | |
528 | case SIOCGIFADDR: |
529 | case SIOCGIFNETMASK: |
530 | case SIOCGIFDSTADDR: |
531 | case SIOCGIFBRDADDR: |
532 | if (ia == NULL) { |
533 | error = EADDRNOTAVAIL; |
534 | goto out; |
535 | } |
536 | break; |
537 | } |
538 | error = 0; |
539 | switch (cmd) { |
540 | |
541 | case SIOCGIFADDR: |
542 | ifreq_setaddr(cmd, ifr, sintocsa(&ia->ia_addr)); |
543 | break; |
544 | |
545 | case SIOCGIFBRDADDR: |
546 | if ((ifp->if_flags & IFF_BROADCAST) == 0) { |
547 | error = EINVAL; |
548 | goto out; |
549 | } |
550 | ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_broadaddr)); |
551 | break; |
552 | |
553 | case SIOCGIFDSTADDR: |
554 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { |
555 | error = EINVAL; |
556 | goto out; |
557 | } |
558 | ifreq_setdstaddr(cmd, ifr, sintocsa(&ia->ia_dstaddr)); |
559 | break; |
560 | |
561 | case SIOCGIFNETMASK: |
562 | /* |
563 | * We keep the number of trailing zero bytes the sin_len field |
564 | * of ia_sockmask, so we fix this before we pass it back to |
565 | * userland. |
566 | */ |
567 | oldaddr = ia->ia_sockmask; |
568 | oldaddr.sin_len = sizeof(struct sockaddr_in); |
569 | ifreq_setaddr(cmd, ifr, (const void *)&oldaddr); |
570 | break; |
571 | |
572 | case SIOCSIFDSTADDR: |
573 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { |
574 | error = EINVAL; |
575 | goto out; |
576 | } |
577 | oldaddr = ia->ia_dstaddr; |
578 | ia->ia_dstaddr = *satocsin(ifreq_getdstaddr(cmd, ifr)); |
579 | if ((error = if_addr_init(ifp, &ia->ia_ifa, false)) != 0) { |
580 | ia->ia_dstaddr = oldaddr; |
581 | goto out; |
582 | } |
583 | if (ia->ia_flags & IFA_ROUTE) { |
584 | ia->ia_ifa.ifa_dstaddr = sintosa(&oldaddr); |
585 | rtinit(&ia->ia_ifa, RTM_DELETE, RTF_HOST); |
586 | ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); |
587 | rtinit(&ia->ia_ifa, RTM_ADD, RTF_HOST|RTF_UP); |
588 | } |
589 | break; |
590 | |
591 | case SIOCSIFBRDADDR: |
592 | if ((ifp->if_flags & IFF_BROADCAST) == 0) { |
593 | error = EINVAL; |
594 | goto out; |
595 | } |
596 | ia->ia_broadaddr = *satocsin(ifreq_getbroadaddr(cmd, ifr)); |
597 | break; |
598 | |
599 | case SIOCSIFADDR: |
600 | if (!newifaddr) { |
601 | mutex_enter(&in_ifaddr_lock); |
602 | LIST_REMOVE(ia, ia_hash); |
603 | IN_ADDRHASH_WRITER_REMOVE(ia); |
604 | mutex_exit(&in_ifaddr_lock); |
605 | #ifdef NET_MPSAFE |
606 | pserialize_perform(in_ifaddrhash_psz); |
607 | #endif |
608 | IN_ADDRHASH_ENTRY_DESTROY(ia); |
609 | need_reinsert = true; |
610 | } |
611 | error = in_ifinit(ifp, ia, satocsin(ifreq_getaddr(cmd, ifr)), |
612 | NULL, 1); |
613 | |
614 | run_hook = true; |
615 | break; |
616 | |
617 | case SIOCSIFNETMASK: |
618 | in_scrubprefix(ia); |
619 | ia->ia_sockmask = *satocsin(ifreq_getaddr(cmd, ifr)); |
620 | ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr; |
621 | if (!newifaddr) { |
622 | mutex_enter(&in_ifaddr_lock); |
623 | LIST_REMOVE(ia, ia_hash); |
624 | IN_ADDRHASH_WRITER_REMOVE(ia); |
625 | mutex_exit(&in_ifaddr_lock); |
626 | #ifdef NET_MPSAFE |
627 | pserialize_perform(in_ifaddrhash_psz); |
628 | #endif |
629 | IN_ADDRHASH_ENTRY_DESTROY(ia); |
630 | need_reinsert = true; |
631 | } |
632 | error = in_ifinit(ifp, ia, NULL, NULL, 0); |
633 | break; |
634 | |
635 | case SIOCAIFADDR: |
636 | maskIsNew = 0; |
637 | if (ifra->ifra_mask.sin_len) { |
638 | in_scrubprefix(ia); |
639 | ia->ia_sockmask = ifra->ifra_mask; |
640 | ia->ia_subnetmask = ia->ia_sockmask.sin_addr.s_addr; |
641 | maskIsNew = 1; |
642 | } |
643 | if ((ifp->if_flags & IFF_POINTOPOINT) && |
644 | (ifra->ifra_dstaddr.sin_family == AF_INET)) { |
645 | new_dstaddr = &ifra->ifra_dstaddr; |
646 | maskIsNew = 1; /* We lie; but the effect's the same */ |
647 | } else |
648 | new_dstaddr = NULL; |
649 | if (ifra->ifra_addr.sin_family == AF_INET && |
650 | (hostIsNew || maskIsNew)) { |
651 | if (!newifaddr) { |
652 | mutex_enter(&in_ifaddr_lock); |
653 | LIST_REMOVE(ia, ia_hash); |
654 | IN_ADDRHASH_WRITER_REMOVE(ia); |
655 | mutex_exit(&in_ifaddr_lock); |
656 | #ifdef NET_MPSAFE |
657 | pserialize_perform(in_ifaddrhash_psz); |
658 | #endif |
659 | IN_ADDRHASH_ENTRY_DESTROY(ia); |
660 | need_reinsert = true; |
661 | } |
662 | error = in_ifinit(ifp, ia, &ifra->ifra_addr, |
663 | new_dstaddr, 0); |
664 | } |
665 | if ((ifp->if_flags & IFF_BROADCAST) && |
666 | (ifra->ifra_broadaddr.sin_family == AF_INET)) |
667 | ia->ia_broadaddr = ifra->ifra_broadaddr; |
668 | run_hook = true; |
669 | break; |
670 | |
671 | case SIOCGIFALIAS: |
672 | ifra->ifra_mask = ia->ia_sockmask; |
673 | if ((ifp->if_flags & IFF_POINTOPOINT) && |
674 | (ia->ia_dstaddr.sin_family == AF_INET)) |
675 | ifra->ifra_dstaddr = ia->ia_dstaddr; |
676 | else if ((ifp->if_flags & IFF_BROADCAST) && |
677 | (ia->ia_broadaddr.sin_family == AF_INET)) |
678 | ifra->ifra_broadaddr = ia->ia_broadaddr; |
679 | else |
680 | memset(&ifra->ifra_broadaddr, 0, |
681 | sizeof(ifra->ifra_broadaddr)); |
682 | break; |
683 | |
684 | case SIOCGIFAFLAG_IN: |
685 | ifr->ifr_addrflags = ia->ia4_flags; |
686 | break; |
687 | |
688 | case SIOCDIFADDR: |
689 | ia4_release(ia, &psref); |
690 | in_purgeaddr(&ia->ia_ifa); |
691 | ia = NULL; |
692 | run_hook = true; |
693 | break; |
694 | |
695 | #ifdef MROUTING |
696 | case SIOCGETVIFCNT: |
697 | case SIOCGETSGCNT: |
698 | error = mrt_ioctl(so, cmd, data); |
699 | break; |
700 | #endif /* MROUTING */ |
701 | |
702 | default: |
703 | error = ENOTTY; |
704 | goto out; |
705 | } |
706 | |
707 | /* |
708 | * XXX insert regardless of error to make in_purgeaddr below work. |
709 | * Need to improve. |
710 | */ |
711 | if (newifaddr) { |
712 | ifaref(&ia->ia_ifa); |
713 | ifa_insert(ifp, &ia->ia_ifa); |
714 | |
715 | mutex_enter(&in_ifaddr_lock); |
716 | TAILQ_INSERT_TAIL(&in_ifaddrhead, ia, ia_list); |
717 | IN_ADDRLIST_WRITER_INSERT_TAIL(ia); |
718 | LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr), |
719 | ia, ia_hash); |
720 | IN_ADDRHASH_WRITER_INSERT_HEAD(ia); |
721 | mutex_exit(&in_ifaddr_lock); |
722 | } else if (need_reinsert) { |
723 | mutex_enter(&in_ifaddr_lock); |
724 | LIST_INSERT_HEAD(&IN_IFADDR_HASH(ia->ia_addr.sin_addr.s_addr), |
725 | ia, ia_hash); |
726 | IN_ADDRHASH_ENTRY_INIT(ia); |
727 | IN_ADDRHASH_WRITER_INSERT_HEAD(ia); |
728 | mutex_exit(&in_ifaddr_lock); |
729 | } |
730 | |
731 | if (error == 0) { |
732 | if (run_hook) |
733 | (void)pfil_run_hooks(if_pfil, |
734 | (struct mbuf **)cmd, ifp, PFIL_IFADDR); |
735 | } else if (newifaddr) { |
736 | KASSERT(ia != NULL); |
737 | in_purgeaddr(&ia->ia_ifa); |
738 | ia = NULL; |
739 | } |
740 | |
741 | out: |
742 | if (!newifaddr && ia != NULL) |
743 | ia4_release(ia, &psref); |
744 | curlwp_bindx(bound); |
745 | return error; |
746 | } |
747 | |
748 | int |
749 | in_control(struct socket *so, u_long cmd, void *data, struct ifnet *ifp) |
750 | { |
751 | int error; |
752 | |
753 | #ifndef NET_MPSAFE |
754 | mutex_enter(softnet_lock); |
755 | #endif |
756 | error = in_control0(so, cmd, data, ifp); |
757 | #ifndef NET_MPSAFE |
758 | mutex_exit(softnet_lock); |
759 | #endif |
760 | |
761 | return error; |
762 | } |
763 | |
764 | /* Add ownaddr as loopback rtentry. */ |
765 | static void |
766 | in_ifaddlocal(struct ifaddr *ifa) |
767 | { |
768 | struct in_ifaddr *ia; |
769 | |
770 | ia = (struct in_ifaddr *)ifa; |
771 | if (ia->ia_addr.sin_addr.s_addr == INADDR_ANY || |
772 | (ia->ia_ifp->if_flags & IFF_POINTOPOINT && |
773 | in_hosteq(ia->ia_dstaddr.sin_addr, ia->ia_addr.sin_addr))) |
774 | { |
775 | rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); |
776 | return; |
777 | } |
778 | |
779 | rt_ifa_addlocal(ifa); |
780 | } |
781 | |
782 | /* Remove loopback entry of ownaddr */ |
783 | static void |
784 | in_ifremlocal(struct ifaddr *ifa) |
785 | { |
786 | struct in_ifaddr *ia, *p; |
787 | struct ifaddr *alt_ifa = NULL; |
788 | int ia_count = 0; |
789 | int s; |
790 | struct psref psref; |
791 | int bound = curlwp_bind(); |
792 | |
793 | ia = (struct in_ifaddr *)ifa; |
794 | /* Delete the entry if exactly one ifaddr matches the |
795 | * address, ifa->ifa_addr. */ |
796 | s = pserialize_read_enter(); |
797 | IN_ADDRLIST_READER_FOREACH(p) { |
798 | if (!in_hosteq(p->ia_addr.sin_addr, ia->ia_addr.sin_addr)) |
799 | continue; |
800 | if (p->ia_ifp != ia->ia_ifp) |
801 | alt_ifa = &p->ia_ifa; |
802 | if (++ia_count > 1 && alt_ifa != NULL) |
803 | break; |
804 | } |
805 | if (alt_ifa != NULL && ia_count > 1) |
806 | ifa_acquire(alt_ifa, &psref); |
807 | pserialize_read_exit(s); |
808 | |
809 | if (ia_count == 0) |
810 | goto out; |
811 | |
812 | rt_ifa_remlocal(ifa, ia_count == 1 ? NULL : alt_ifa); |
813 | if (alt_ifa != NULL && ia_count > 1) |
814 | ifa_release(alt_ifa, &psref); |
815 | out: |
816 | curlwp_bindx(bound); |
817 | } |
818 | |
819 | static void |
820 | in_scrubaddr(struct in_ifaddr *ia) |
821 | { |
822 | |
823 | /* stop DAD processing */ |
824 | if (ia->ia_dad_stop != NULL) |
825 | ia->ia_dad_stop(&ia->ia_ifa); |
826 | |
827 | in_scrubprefix(ia); |
828 | in_ifremlocal(&ia->ia_ifa); |
829 | |
830 | if (ia->ia_allhosts != NULL) { |
831 | in_delmulti(ia->ia_allhosts); |
832 | ia->ia_allhosts = NULL; |
833 | } |
834 | } |
835 | |
836 | /* |
837 | * Depends on it isn't called in concurrent. It should be guaranteed |
838 | * by ifa->ifa_ifp's ioctl lock. The possible callers are in_control |
839 | * and if_purgeaddrs; the former is called iva ifa->ifa_ifp's ioctl |
840 | * and the latter is called via ifa->ifa_ifp's if_detach. The functions |
841 | * never be executed in concurrent. |
842 | */ |
843 | void |
844 | in_purgeaddr(struct ifaddr *ifa) |
845 | { |
846 | struct in_ifaddr *ia = (void *) ifa; |
847 | struct ifnet *ifp = ifa->ifa_ifp; |
848 | |
849 | KASSERT(!ifa_held(ifa)); |
850 | |
851 | in_scrubaddr(ia); |
852 | |
853 | mutex_enter(&in_ifaddr_lock); |
854 | LIST_REMOVE(ia, ia_hash); |
855 | IN_ADDRHASH_WRITER_REMOVE(ia); |
856 | TAILQ_REMOVE(&in_ifaddrhead, ia, ia_list); |
857 | IN_ADDRLIST_WRITER_REMOVE(ia); |
858 | ifa_remove(ifp, &ia->ia_ifa); |
859 | mutex_exit(&in_ifaddr_lock); |
860 | |
861 | #ifdef NET_MPSAFE |
862 | pserialize_perform(in_ifaddrhash_psz); |
863 | #endif |
864 | IN_ADDRHASH_ENTRY_DESTROY(ia); |
865 | IN_ADDRLIST_ENTRY_DESTROY(ia); |
866 | ifafree(&ia->ia_ifa); |
867 | in_setmaxmtu(); |
868 | } |
869 | |
870 | void |
871 | in_purgeif(struct ifnet *ifp) /* MUST be called at splsoftnet() */ |
872 | { |
873 | if_purgeaddrs(ifp, AF_INET, in_purgeaddr); |
874 | igmp_purgeif(ifp); /* manipulates pools */ |
875 | #ifdef MROUTING |
876 | ip_mrouter_detach(ifp); |
877 | #endif |
878 | } |
879 | |
880 | /* |
881 | * SIOC[GAD]LIFADDR. |
882 | * SIOCGLIFADDR: get first address. (???) |
883 | * SIOCGLIFADDR with IFLR_PREFIX: |
884 | * get first address that matches the specified prefix. |
885 | * SIOCALIFADDR: add the specified address. |
886 | * SIOCALIFADDR with IFLR_PREFIX: |
887 | * EINVAL since we can't deduce hostid part of the address. |
888 | * SIOCDLIFADDR: delete the specified address. |
889 | * SIOCDLIFADDR with IFLR_PREFIX: |
890 | * delete the first address that matches the specified prefix. |
891 | * return values: |
892 | * EINVAL on invalid parameters |
893 | * EADDRNOTAVAIL on prefix match failed/specified address not found |
894 | * other values may be returned from in_ioctl() |
895 | */ |
896 | static int |
897 | in_lifaddr_ioctl(struct socket *so, u_long cmd, void *data, |
898 | struct ifnet *ifp) |
899 | { |
900 | struct if_laddrreq *iflr = (struct if_laddrreq *)data; |
901 | struct ifaddr *ifa; |
902 | struct sockaddr *sa; |
903 | |
904 | /* sanity checks */ |
905 | if (data == NULL || ifp == NULL) { |
906 | panic("invalid argument to in_lifaddr_ioctl" ); |
907 | /*NOTRECHED*/ |
908 | } |
909 | |
910 | switch (cmd) { |
911 | case SIOCGLIFADDR: |
912 | /* address must be specified on GET with IFLR_PREFIX */ |
913 | if ((iflr->flags & IFLR_PREFIX) == 0) |
914 | break; |
915 | /*FALLTHROUGH*/ |
916 | case SIOCALIFADDR: |
917 | case SIOCDLIFADDR: |
918 | /* address must be specified on ADD and DELETE */ |
919 | sa = (struct sockaddr *)&iflr->addr; |
920 | if (sa->sa_family != AF_INET) |
921 | return EINVAL; |
922 | if (sa->sa_len != sizeof(struct sockaddr_in)) |
923 | return EINVAL; |
924 | /* XXX need improvement */ |
925 | sa = (struct sockaddr *)&iflr->dstaddr; |
926 | if (sa->sa_family != AF_UNSPEC && sa->sa_family != AF_INET) |
927 | return EINVAL; |
928 | if (sa->sa_len != 0 && sa->sa_len != sizeof(struct sockaddr_in)) |
929 | return EINVAL; |
930 | break; |
931 | default: /*shouldn't happen*/ |
932 | #if 0 |
933 | panic("invalid cmd to in_lifaddr_ioctl" ); |
934 | /*NOTREACHED*/ |
935 | #else |
936 | return EOPNOTSUPP; |
937 | #endif |
938 | } |
939 | if (sizeof(struct in_addr) * NBBY < iflr->prefixlen) |
940 | return EINVAL; |
941 | |
942 | switch (cmd) { |
943 | case SIOCALIFADDR: |
944 | { |
945 | struct in_aliasreq ifra; |
946 | |
947 | if (iflr->flags & IFLR_PREFIX) |
948 | return EINVAL; |
949 | |
950 | /* copy args to in_aliasreq, perform ioctl(SIOCAIFADDR). */ |
951 | memset(&ifra, 0, sizeof(ifra)); |
952 | memcpy(ifra.ifra_name, iflr->iflr_name, |
953 | sizeof(ifra.ifra_name)); |
954 | |
955 | memcpy(&ifra.ifra_addr, &iflr->addr, |
956 | ((struct sockaddr *)&iflr->addr)->sa_len); |
957 | |
958 | if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /*XXX*/ |
959 | memcpy(&ifra.ifra_dstaddr, &iflr->dstaddr, |
960 | ((struct sockaddr *)&iflr->dstaddr)->sa_len); |
961 | } |
962 | |
963 | ifra.ifra_mask.sin_family = AF_INET; |
964 | ifra.ifra_mask.sin_len = sizeof(struct sockaddr_in); |
965 | in_len2mask(&ifra.ifra_mask.sin_addr, iflr->prefixlen); |
966 | |
967 | return in_control(so, SIOCAIFADDR, &ifra, ifp); |
968 | } |
969 | case SIOCGLIFADDR: |
970 | case SIOCDLIFADDR: |
971 | { |
972 | struct in_ifaddr *ia; |
973 | struct in_addr mask, candidate, match; |
974 | struct sockaddr_in *sin; |
975 | int cmp, s; |
976 | |
977 | memset(&mask, 0, sizeof(mask)); |
978 | memset(&match, 0, sizeof(match)); /* XXX gcc */ |
979 | if (iflr->flags & IFLR_PREFIX) { |
980 | /* lookup a prefix rather than address. */ |
981 | in_len2mask(&mask, iflr->prefixlen); |
982 | |
983 | sin = (struct sockaddr_in *)&iflr->addr; |
984 | match.s_addr = sin->sin_addr.s_addr; |
985 | match.s_addr &= mask.s_addr; |
986 | |
987 | /* if you set extra bits, that's wrong */ |
988 | if (match.s_addr != sin->sin_addr.s_addr) |
989 | return EINVAL; |
990 | |
991 | cmp = 1; |
992 | } else { |
993 | if (cmd == SIOCGLIFADDR) { |
994 | /* on getting an address, take the 1st match */ |
995 | cmp = 0; /*XXX*/ |
996 | } else { |
997 | /* on deleting an address, do exact match */ |
998 | in_len2mask(&mask, 32); |
999 | sin = (struct sockaddr_in *)&iflr->addr; |
1000 | match.s_addr = sin->sin_addr.s_addr; |
1001 | |
1002 | cmp = 1; |
1003 | } |
1004 | } |
1005 | |
1006 | s = pserialize_read_enter(); |
1007 | IFADDR_READER_FOREACH(ifa, ifp) { |
1008 | if (ifa->ifa_addr->sa_family != AF_INET) |
1009 | continue; |
1010 | if (cmp == 0) |
1011 | break; |
1012 | candidate.s_addr = ((struct sockaddr_in *)ifa->ifa_addr)->sin_addr.s_addr; |
1013 | candidate.s_addr &= mask.s_addr; |
1014 | if (candidate.s_addr == match.s_addr) |
1015 | break; |
1016 | } |
1017 | if (ifa == NULL) { |
1018 | pserialize_read_exit(s); |
1019 | return EADDRNOTAVAIL; |
1020 | } |
1021 | ia = (struct in_ifaddr *)ifa; |
1022 | |
1023 | if (cmd == SIOCGLIFADDR) { |
1024 | /* fill in the if_laddrreq structure */ |
1025 | memcpy(&iflr->addr, &ia->ia_addr, ia->ia_addr.sin_len); |
1026 | |
1027 | if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { |
1028 | memcpy(&iflr->dstaddr, &ia->ia_dstaddr, |
1029 | ia->ia_dstaddr.sin_len); |
1030 | } else |
1031 | memset(&iflr->dstaddr, 0, sizeof(iflr->dstaddr)); |
1032 | |
1033 | iflr->prefixlen = |
1034 | in_mask2len(&ia->ia_sockmask.sin_addr); |
1035 | |
1036 | iflr->flags = 0; /*XXX*/ |
1037 | pserialize_read_exit(s); |
1038 | |
1039 | return 0; |
1040 | } else { |
1041 | struct in_aliasreq ifra; |
1042 | |
1043 | /* fill in_aliasreq and do ioctl(SIOCDIFADDR) */ |
1044 | memset(&ifra, 0, sizeof(ifra)); |
1045 | memcpy(ifra.ifra_name, iflr->iflr_name, |
1046 | sizeof(ifra.ifra_name)); |
1047 | |
1048 | memcpy(&ifra.ifra_addr, &ia->ia_addr, |
1049 | ia->ia_addr.sin_len); |
1050 | if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { |
1051 | memcpy(&ifra.ifra_dstaddr, &ia->ia_dstaddr, |
1052 | ia->ia_dstaddr.sin_len); |
1053 | } |
1054 | memcpy(&ifra.ifra_dstaddr, &ia->ia_sockmask, |
1055 | ia->ia_sockmask.sin_len); |
1056 | pserialize_read_exit(s); |
1057 | |
1058 | return in_control(so, SIOCDIFADDR, &ifra, ifp); |
1059 | } |
1060 | } |
1061 | } |
1062 | |
1063 | return EOPNOTSUPP; /*just for safety*/ |
1064 | } |
1065 | |
1066 | /* |
1067 | * Initialize an interface's internet address |
1068 | * and routing table entry. |
1069 | */ |
1070 | int |
1071 | in_ifinit(struct ifnet *ifp, struct in_ifaddr *ia, |
1072 | const struct sockaddr_in *sin, const struct sockaddr_in *dst, int scrub) |
1073 | { |
1074 | u_int32_t i; |
1075 | struct sockaddr_in oldaddr, olddst; |
1076 | int s, oldflags, flags = RTF_UP, error, hostIsNew; |
1077 | |
1078 | if (sin == NULL) |
1079 | sin = &ia->ia_addr; |
1080 | if (dst == NULL) |
1081 | dst = &ia->ia_dstaddr; |
1082 | |
1083 | /* |
1084 | * Set up new addresses. |
1085 | */ |
1086 | oldaddr = ia->ia_addr; |
1087 | olddst = ia->ia_dstaddr; |
1088 | oldflags = ia->ia4_flags; |
1089 | ia->ia_addr = *sin; |
1090 | ia->ia_dstaddr = *dst; |
1091 | hostIsNew = oldaddr.sin_family != AF_INET || |
1092 | !in_hosteq(ia->ia_addr.sin_addr, oldaddr.sin_addr); |
1093 | if (!scrub) |
1094 | scrub = oldaddr.sin_family != ia->ia_dstaddr.sin_family || |
1095 | !in_hosteq(ia->ia_dstaddr.sin_addr, olddst.sin_addr); |
1096 | |
1097 | /* |
1098 | * Configure address flags. |
1099 | * We need to do this early because they maybe adjusted |
1100 | * by if_addr_init depending on the address. |
1101 | */ |
1102 | if (ia->ia4_flags & IN_IFF_DUPLICATED) { |
1103 | ia->ia4_flags &= ~IN_IFF_DUPLICATED; |
1104 | hostIsNew = 1; |
1105 | } |
1106 | if (ifp->if_link_state == LINK_STATE_DOWN) { |
1107 | ia->ia4_flags |= IN_IFF_DETACHED; |
1108 | ia->ia4_flags &= ~IN_IFF_TENTATIVE; |
1109 | } else if (hostIsNew && if_do_dad(ifp)) |
1110 | ia->ia4_flags |= IN_IFF_TRYTENTATIVE; |
1111 | |
1112 | /* |
1113 | * Give the interface a chance to initialize |
1114 | * if this is its first address, |
1115 | * and to validate the address if necessary. |
1116 | */ |
1117 | s = splnet(); |
1118 | error = if_addr_init(ifp, &ia->ia_ifa, true); |
1119 | splx(s); |
1120 | /* Now clear the try tentative flag, it's job is done. */ |
1121 | ia->ia4_flags &= ~IN_IFF_TRYTENTATIVE; |
1122 | if (error != 0) { |
1123 | ia->ia_addr = oldaddr; |
1124 | ia->ia_dstaddr = olddst; |
1125 | ia->ia4_flags = oldflags; |
1126 | return error; |
1127 | } |
1128 | |
1129 | if (scrub || hostIsNew) { |
1130 | int newflags = ia->ia4_flags; |
1131 | |
1132 | ia->ia_ifa.ifa_addr = sintosa(&oldaddr); |
1133 | ia->ia_ifa.ifa_dstaddr = sintosa(&olddst); |
1134 | ia->ia4_flags = oldflags; |
1135 | if (hostIsNew) |
1136 | in_scrubaddr(ia); |
1137 | else if (scrub) |
1138 | in_scrubprefix(ia); |
1139 | ia->ia_ifa.ifa_addr = sintosa(&ia->ia_addr); |
1140 | ia->ia_ifa.ifa_dstaddr = sintosa(&ia->ia_dstaddr); |
1141 | ia->ia4_flags = newflags; |
1142 | } |
1143 | |
1144 | /* Add the local route to the address */ |
1145 | in_ifaddlocal(&ia->ia_ifa); |
1146 | |
1147 | i = ia->ia_addr.sin_addr.s_addr; |
1148 | if (ifp->if_flags & IFF_POINTOPOINT) |
1149 | ia->ia_netmask = INADDR_BROADCAST; /* default to /32 */ |
1150 | else if (IN_CLASSA(i)) |
1151 | ia->ia_netmask = IN_CLASSA_NET; |
1152 | else if (IN_CLASSB(i)) |
1153 | ia->ia_netmask = IN_CLASSB_NET; |
1154 | else |
1155 | ia->ia_netmask = IN_CLASSC_NET; |
1156 | /* |
1157 | * The subnet mask usually includes at least the standard network part, |
1158 | * but may may be smaller in the case of supernetting. |
1159 | * If it is set, we believe it. |
1160 | */ |
1161 | if (ia->ia_subnetmask == 0) { |
1162 | ia->ia_subnetmask = ia->ia_netmask; |
1163 | ia->ia_sockmask.sin_addr.s_addr = ia->ia_subnetmask; |
1164 | } else |
1165 | ia->ia_netmask &= ia->ia_subnetmask; |
1166 | |
1167 | ia->ia_net = i & ia->ia_netmask; |
1168 | ia->ia_subnet = i & ia->ia_subnetmask; |
1169 | in_socktrim(&ia->ia_sockmask); |
1170 | /* re-calculate the "in_maxmtu" value */ |
1171 | in_setmaxmtu(); |
1172 | /* |
1173 | * Add route for the network. |
1174 | */ |
1175 | ia->ia_ifa.ifa_metric = ifp->if_metric; |
1176 | if (ifp->if_flags & IFF_BROADCAST) { |
1177 | ia->ia_broadaddr.sin_addr.s_addr = |
1178 | ia->ia_subnet | ~ia->ia_subnetmask; |
1179 | ia->ia_netbroadcast.s_addr = |
1180 | ia->ia_net | ~ia->ia_netmask; |
1181 | } else if (ifp->if_flags & IFF_LOOPBACK) { |
1182 | ia->ia_dstaddr = ia->ia_addr; |
1183 | flags |= RTF_HOST; |
1184 | } else if (ifp->if_flags & IFF_POINTOPOINT) { |
1185 | if (ia->ia_dstaddr.sin_family != AF_INET) |
1186 | return (0); |
1187 | flags |= RTF_HOST; |
1188 | } |
1189 | error = in_addprefix(ia, flags); |
1190 | /* |
1191 | * If the interface supports multicast, join the "all hosts" |
1192 | * multicast group on that interface. |
1193 | */ |
1194 | if ((ifp->if_flags & IFF_MULTICAST) != 0 && ia->ia_allhosts == NULL) { |
1195 | struct in_addr addr; |
1196 | |
1197 | addr.s_addr = INADDR_ALLHOSTS_GROUP; |
1198 | ia->ia_allhosts = in_addmulti(&addr, ifp); |
1199 | } |
1200 | |
1201 | if (hostIsNew && |
1202 | ia->ia4_flags & IN_IFF_TENTATIVE && |
1203 | if_do_dad(ifp)) |
1204 | ia->ia_dad_start((struct ifaddr *)ia); |
1205 | |
1206 | return error; |
1207 | } |
1208 | |
1209 | #define rtinitflags(x) \ |
1210 | ((((x)->ia_ifp->if_flags & (IFF_LOOPBACK | IFF_POINTOPOINT)) != 0) \ |
1211 | ? RTF_HOST : 0) |
1212 | |
1213 | /* |
1214 | * add a route to prefix ("connected route" in cisco terminology). |
1215 | * does nothing if there's some interface address with the same prefix already. |
1216 | */ |
1217 | static int |
1218 | in_addprefix(struct in_ifaddr *target, int flags) |
1219 | { |
1220 | struct in_ifaddr *ia; |
1221 | struct in_addr prefix, mask, p; |
1222 | int error; |
1223 | int s; |
1224 | |
1225 | if ((flags & RTF_HOST) != 0) |
1226 | prefix = target->ia_dstaddr.sin_addr; |
1227 | else { |
1228 | prefix = target->ia_addr.sin_addr; |
1229 | mask = target->ia_sockmask.sin_addr; |
1230 | prefix.s_addr &= mask.s_addr; |
1231 | } |
1232 | |
1233 | s = pserialize_read_enter(); |
1234 | IN_ADDRLIST_READER_FOREACH(ia) { |
1235 | if (rtinitflags(ia)) |
1236 | p = ia->ia_dstaddr.sin_addr; |
1237 | else { |
1238 | p = ia->ia_addr.sin_addr; |
1239 | p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; |
1240 | } |
1241 | |
1242 | if (prefix.s_addr != p.s_addr) |
1243 | continue; |
1244 | |
1245 | /* |
1246 | * if we got a matching prefix route inserted by other |
1247 | * interface address, we don't need to bother |
1248 | * |
1249 | * XXX RADIX_MPATH implications here? -dyoung |
1250 | */ |
1251 | if (ia->ia_flags & IFA_ROUTE) { |
1252 | pserialize_read_exit(s); |
1253 | return 0; |
1254 | } |
1255 | } |
1256 | pserialize_read_exit(s); |
1257 | |
1258 | /* |
1259 | * noone seem to have prefix route. insert it. |
1260 | */ |
1261 | error = rtinit(&target->ia_ifa, RTM_ADD, flags); |
1262 | if (error == 0) |
1263 | target->ia_flags |= IFA_ROUTE; |
1264 | else if (error == EEXIST) { |
1265 | /* |
1266 | * the fact the route already exists is not an error. |
1267 | */ |
1268 | error = 0; |
1269 | } |
1270 | return error; |
1271 | } |
1272 | |
1273 | /* |
1274 | * remove a route to prefix ("connected route" in cisco terminology). |
1275 | * re-installs the route by using another interface address, if there's one |
1276 | * with the same prefix (otherwise we lose the route mistakenly). |
1277 | */ |
1278 | static int |
1279 | in_scrubprefix(struct in_ifaddr *target) |
1280 | { |
1281 | struct in_ifaddr *ia; |
1282 | struct in_addr prefix, mask, p; |
1283 | int error; |
1284 | int s; |
1285 | |
1286 | /* If we don't have IFA_ROUTE we have nothing to do */ |
1287 | if ((target->ia_flags & IFA_ROUTE) == 0) |
1288 | return 0; |
1289 | |
1290 | if (rtinitflags(target)) |
1291 | prefix = target->ia_dstaddr.sin_addr; |
1292 | else { |
1293 | prefix = target->ia_addr.sin_addr; |
1294 | mask = target->ia_sockmask.sin_addr; |
1295 | prefix.s_addr &= mask.s_addr; |
1296 | } |
1297 | |
1298 | s = pserialize_read_enter(); |
1299 | IN_ADDRLIST_READER_FOREACH(ia) { |
1300 | if (rtinitflags(ia)) |
1301 | p = ia->ia_dstaddr.sin_addr; |
1302 | else { |
1303 | p = ia->ia_addr.sin_addr; |
1304 | p.s_addr &= ia->ia_sockmask.sin_addr.s_addr; |
1305 | } |
1306 | |
1307 | if (prefix.s_addr != p.s_addr) |
1308 | continue; |
1309 | |
1310 | /* |
1311 | * if we got a matching prefix route, move IFA_ROUTE to him |
1312 | */ |
1313 | if ((ia->ia_flags & IFA_ROUTE) == 0) { |
1314 | struct psref psref; |
1315 | int bound = curlwp_bind(); |
1316 | |
1317 | ia4_acquire(ia, &psref); |
1318 | pserialize_read_exit(s); |
1319 | |
1320 | rtinit(&target->ia_ifa, RTM_DELETE, |
1321 | rtinitflags(target)); |
1322 | target->ia_flags &= ~IFA_ROUTE; |
1323 | |
1324 | error = rtinit(&ia->ia_ifa, RTM_ADD, |
1325 | rtinitflags(ia) | RTF_UP); |
1326 | if (error == 0) |
1327 | ia->ia_flags |= IFA_ROUTE; |
1328 | |
1329 | ia4_release(ia, &psref); |
1330 | curlwp_bindx(bound); |
1331 | |
1332 | return error; |
1333 | } |
1334 | } |
1335 | pserialize_read_exit(s); |
1336 | |
1337 | /* |
1338 | * noone seem to have prefix route. remove it. |
1339 | */ |
1340 | rtinit(&target->ia_ifa, RTM_DELETE, rtinitflags(target)); |
1341 | target->ia_flags &= ~IFA_ROUTE; |
1342 | return 0; |
1343 | } |
1344 | |
1345 | #undef rtinitflags |
1346 | |
1347 | /* |
1348 | * Return 1 if the address might be a local broadcast address. |
1349 | */ |
1350 | int |
1351 | in_broadcast(struct in_addr in, struct ifnet *ifp) |
1352 | { |
1353 | struct ifaddr *ifa; |
1354 | int s; |
1355 | |
1356 | KASSERT(ifp != NULL); |
1357 | |
1358 | if (in.s_addr == INADDR_BROADCAST || |
1359 | in_nullhost(in)) |
1360 | return 1; |
1361 | if ((ifp->if_flags & IFF_BROADCAST) == 0) |
1362 | return 0; |
1363 | /* |
1364 | * Look through the list of addresses for a match |
1365 | * with a broadcast address. |
1366 | */ |
1367 | #define ia (ifatoia(ifa)) |
1368 | s = pserialize_read_enter(); |
1369 | IFADDR_READER_FOREACH(ifa, ifp) { |
1370 | if (ifa->ifa_addr->sa_family == AF_INET && |
1371 | !in_hosteq(in, ia->ia_addr.sin_addr) && |
1372 | (in_hosteq(in, ia->ia_broadaddr.sin_addr) || |
1373 | in_hosteq(in, ia->ia_netbroadcast) || |
1374 | (hostzeroisbroadcast && |
1375 | /* |
1376 | * Check for old-style (host 0) broadcast. |
1377 | */ |
1378 | (in.s_addr == ia->ia_subnet || |
1379 | in.s_addr == ia->ia_net)))) { |
1380 | pserialize_read_exit(s); |
1381 | return 1; |
1382 | } |
1383 | } |
1384 | pserialize_read_exit(s); |
1385 | return (0); |
1386 | #undef ia |
1387 | } |
1388 | |
1389 | /* |
1390 | * perform DAD when interface becomes IFF_UP. |
1391 | */ |
1392 | void |
1393 | in_if_link_up(struct ifnet *ifp) |
1394 | { |
1395 | struct ifaddr *ifa; |
1396 | struct in_ifaddr *ia; |
1397 | int s, bound; |
1398 | |
1399 | /* Ensure it's sane to run DAD */ |
1400 | if (ifp->if_link_state == LINK_STATE_DOWN) |
1401 | return; |
1402 | if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) |
1403 | return; |
1404 | |
1405 | bound = curlwp_bind(); |
1406 | s = pserialize_read_enter(); |
1407 | IFADDR_READER_FOREACH(ifa, ifp) { |
1408 | struct psref psref; |
1409 | |
1410 | if (ifa->ifa_addr->sa_family != AF_INET) |
1411 | continue; |
1412 | ifa_acquire(ifa, &psref); |
1413 | pserialize_read_exit(s); |
1414 | |
1415 | ia = (struct in_ifaddr *)ifa; |
1416 | |
1417 | /* If detached then mark as tentative */ |
1418 | if (ia->ia4_flags & IN_IFF_DETACHED) { |
1419 | ia->ia4_flags &= ~IN_IFF_DETACHED; |
1420 | if (if_do_dad(ifp) && ia->ia_dad_start != NULL) |
1421 | ia->ia4_flags |= IN_IFF_TENTATIVE; |
1422 | else if ((ia->ia4_flags & IN_IFF_TENTATIVE) == 0) |
1423 | rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); |
1424 | } |
1425 | |
1426 | if (ia->ia4_flags & IN_IFF_TENTATIVE) { |
1427 | /* Clear the duplicated flag as we're starting DAD. */ |
1428 | ia->ia4_flags &= ~IN_IFF_DUPLICATED; |
1429 | ia->ia_dad_start(ifa); |
1430 | } |
1431 | |
1432 | s = pserialize_read_enter(); |
1433 | ifa_release(ifa, &psref); |
1434 | } |
1435 | pserialize_read_exit(s); |
1436 | curlwp_bindx(bound); |
1437 | } |
1438 | |
1439 | void |
1440 | in_if_up(struct ifnet *ifp) |
1441 | { |
1442 | |
1443 | /* interface may not support link state, so bring it up also */ |
1444 | in_if_link_up(ifp); |
1445 | } |
1446 | |
1447 | /* |
1448 | * Mark all addresses as detached. |
1449 | */ |
1450 | void |
1451 | in_if_link_down(struct ifnet *ifp) |
1452 | { |
1453 | struct ifaddr *ifa; |
1454 | struct in_ifaddr *ia; |
1455 | int s, bound; |
1456 | |
1457 | bound = curlwp_bind(); |
1458 | s = pserialize_read_enter(); |
1459 | IFADDR_READER_FOREACH(ifa, ifp) { |
1460 | struct psref psref; |
1461 | |
1462 | if (ifa->ifa_addr->sa_family != AF_INET) |
1463 | continue; |
1464 | ifa_acquire(ifa, &psref); |
1465 | pserialize_read_exit(s); |
1466 | |
1467 | ia = (struct in_ifaddr *)ifa; |
1468 | |
1469 | /* Stop DAD processing */ |
1470 | if (ia->ia_dad_stop != NULL) |
1471 | ia->ia_dad_stop(ifa); |
1472 | |
1473 | /* |
1474 | * Mark the address as detached. |
1475 | */ |
1476 | if (!(ia->ia4_flags & IN_IFF_DETACHED)) { |
1477 | ia->ia4_flags |= IN_IFF_DETACHED; |
1478 | ia->ia4_flags &= |
1479 | ~(IN_IFF_TENTATIVE | IN_IFF_DUPLICATED); |
1480 | rt_newaddrmsg(RTM_NEWADDR, ifa, 0, NULL); |
1481 | } |
1482 | |
1483 | s = pserialize_read_enter(); |
1484 | ifa_release(ifa, &psref); |
1485 | } |
1486 | pserialize_read_exit(s); |
1487 | curlwp_bindx(bound); |
1488 | } |
1489 | |
1490 | void |
1491 | in_if_down(struct ifnet *ifp) |
1492 | { |
1493 | |
1494 | in_if_link_down(ifp); |
1495 | } |
1496 | |
1497 | void |
1498 | in_if_link_state_change(struct ifnet *ifp, int link_state) |
1499 | { |
1500 | |
1501 | switch (link_state) { |
1502 | case LINK_STATE_DOWN: |
1503 | in_if_link_down(ifp); |
1504 | break; |
1505 | case LINK_STATE_UP: |
1506 | in_if_link_up(ifp); |
1507 | break; |
1508 | } |
1509 | } |
1510 | |
1511 | /* |
1512 | * in_lookup_multi: look up the in_multi record for a given IP |
1513 | * multicast address on a given interface. If no matching record is |
1514 | * found, return NULL. |
1515 | */ |
1516 | struct in_multi * |
1517 | in_lookup_multi(struct in_addr addr, ifnet_t *ifp) |
1518 | { |
1519 | struct in_multi *inm; |
1520 | |
1521 | KASSERT(rw_lock_held(&in_multilock)); |
1522 | |
1523 | LIST_FOREACH(inm, &IN_MULTI_HASH(addr.s_addr, ifp), inm_list) { |
1524 | if (in_hosteq(inm->inm_addr, addr) && inm->inm_ifp == ifp) |
1525 | break; |
1526 | } |
1527 | return inm; |
1528 | } |
1529 | |
1530 | /* |
1531 | * in_multi_group: check whether the address belongs to an IP multicast |
1532 | * group we are joined on this interface. Returns true or false. |
1533 | */ |
1534 | bool |
1535 | in_multi_group(struct in_addr addr, ifnet_t *ifp, int flags) |
1536 | { |
1537 | bool ingroup; |
1538 | |
1539 | if (__predict_true(flags & IP_IGMP_MCAST) == 0) { |
1540 | rw_enter(&in_multilock, RW_READER); |
1541 | ingroup = in_lookup_multi(addr, ifp) != NULL; |
1542 | rw_exit(&in_multilock); |
1543 | } else { |
1544 | /* XXX Recursive call from ip_output(). */ |
1545 | KASSERT(rw_lock_held(&in_multilock)); |
1546 | ingroup = in_lookup_multi(addr, ifp) != NULL; |
1547 | } |
1548 | return ingroup; |
1549 | } |
1550 | |
1551 | /* |
1552 | * Add an address to the list of IP multicast addresses for a given interface. |
1553 | */ |
1554 | struct in_multi * |
1555 | in_addmulti(struct in_addr *ap, ifnet_t *ifp) |
1556 | { |
1557 | struct sockaddr_in sin; |
1558 | struct in_multi *inm; |
1559 | |
1560 | /* |
1561 | * See if address already in list. |
1562 | */ |
1563 | rw_enter(&in_multilock, RW_WRITER); |
1564 | inm = in_lookup_multi(*ap, ifp); |
1565 | if (inm != NULL) { |
1566 | /* |
1567 | * Found it; just increment the reference count. |
1568 | */ |
1569 | inm->inm_refcount++; |
1570 | rw_exit(&in_multilock); |
1571 | return inm; |
1572 | } |
1573 | |
1574 | /* |
1575 | * New address; allocate a new multicast record. |
1576 | */ |
1577 | inm = pool_get(&inmulti_pool, PR_NOWAIT); |
1578 | if (inm == NULL) { |
1579 | rw_exit(&in_multilock); |
1580 | return NULL; |
1581 | } |
1582 | inm->inm_addr = *ap; |
1583 | inm->inm_ifp = ifp; |
1584 | inm->inm_refcount = 1; |
1585 | |
1586 | /* |
1587 | * Ask the network driver to update its multicast reception |
1588 | * filter appropriately for the new address. |
1589 | */ |
1590 | sockaddr_in_init(&sin, ap, 0); |
1591 | if (if_mcast_op(ifp, SIOCADDMULTI, sintosa(&sin)) != 0) { |
1592 | rw_exit(&in_multilock); |
1593 | pool_put(&inmulti_pool, inm); |
1594 | return NULL; |
1595 | } |
1596 | |
1597 | /* |
1598 | * Let IGMP know that we have joined a new IP multicast group. |
1599 | */ |
1600 | if (igmp_joingroup(inm) != 0) { |
1601 | rw_exit(&in_multilock); |
1602 | pool_put(&inmulti_pool, inm); |
1603 | return NULL; |
1604 | } |
1605 | LIST_INSERT_HEAD( |
1606 | &IN_MULTI_HASH(inm->inm_addr.s_addr, ifp), |
1607 | inm, inm_list); |
1608 | in_multientries++; |
1609 | rw_exit(&in_multilock); |
1610 | |
1611 | return inm; |
1612 | } |
1613 | |
1614 | /* |
1615 | * Delete a multicast address record. |
1616 | */ |
1617 | void |
1618 | in_delmulti(struct in_multi *inm) |
1619 | { |
1620 | struct sockaddr_in sin; |
1621 | |
1622 | rw_enter(&in_multilock, RW_WRITER); |
1623 | if (--inm->inm_refcount > 0) { |
1624 | rw_exit(&in_multilock); |
1625 | return; |
1626 | } |
1627 | |
1628 | /* |
1629 | * No remaining claims to this record; let IGMP know that |
1630 | * we are leaving the multicast group. |
1631 | */ |
1632 | igmp_leavegroup(inm); |
1633 | |
1634 | /* |
1635 | * Notify the network driver to update its multicast reception |
1636 | * filter. |
1637 | */ |
1638 | sockaddr_in_init(&sin, &inm->inm_addr, 0); |
1639 | if_mcast_op(inm->inm_ifp, SIOCDELMULTI, sintosa(&sin)); |
1640 | |
1641 | /* |
1642 | * Unlink from list. |
1643 | */ |
1644 | LIST_REMOVE(inm, inm_list); |
1645 | in_multientries--; |
1646 | rw_exit(&in_multilock); |
1647 | |
1648 | pool_put(&inmulti_pool, inm); |
1649 | } |
1650 | |
1651 | /* |
1652 | * in_next_multi: step through all of the in_multi records, one at a time. |
1653 | * The current position is remembered in "step", which the caller must |
1654 | * provide. in_first_multi(), below, must be called to initialize "step" |
1655 | * and get the first record. Both macros return a NULL "inm" when there |
1656 | * are no remaining records. |
1657 | */ |
1658 | struct in_multi * |
1659 | in_next_multi(struct in_multistep *step) |
1660 | { |
1661 | struct in_multi *inm; |
1662 | |
1663 | KASSERT(rw_lock_held(&in_multilock)); |
1664 | |
1665 | while (step->i_inm == NULL && step->i_n < IN_MULTI_HASH_SIZE) { |
1666 | step->i_inm = LIST_FIRST(&in_multihashtbl[++step->i_n]); |
1667 | } |
1668 | if ((inm = step->i_inm) != NULL) { |
1669 | step->i_inm = LIST_NEXT(inm, inm_list); |
1670 | } |
1671 | return inm; |
1672 | } |
1673 | |
1674 | struct in_multi * |
1675 | in_first_multi(struct in_multistep *step) |
1676 | { |
1677 | KASSERT(rw_lock_held(&in_multilock)); |
1678 | |
1679 | step->i_n = 0; |
1680 | step->i_inm = LIST_FIRST(&in_multihashtbl[0]); |
1681 | return in_next_multi(step); |
1682 | } |
1683 | |
1684 | void |
1685 | in_multi_lock(int op) |
1686 | { |
1687 | rw_enter(&in_multilock, op); |
1688 | } |
1689 | |
1690 | void |
1691 | in_multi_unlock(void) |
1692 | { |
1693 | rw_exit(&in_multilock); |
1694 | } |
1695 | |
1696 | int |
1697 | in_multi_lock_held(void) |
1698 | { |
1699 | return rw_lock_held(&in_multilock); |
1700 | } |
1701 | |
1702 | struct in_ifaddr * |
1703 | in_selectsrc(struct sockaddr_in *sin, struct route *ro, |
1704 | int soopts, struct ip_moptions *mopts, int *errorp, struct psref *psref) |
1705 | { |
1706 | struct rtentry *rt = NULL; |
1707 | struct in_ifaddr *ia = NULL; |
1708 | |
1709 | KASSERT(ISSET(curlwp->l_pflag, LP_BOUND)); |
1710 | /* |
1711 | * If route is known or can be allocated now, take the |
1712 | * source address from the interface. Otherwise, punt. |
1713 | */ |
1714 | if ((soopts & SO_DONTROUTE) != 0) |
1715 | rtcache_free(ro); |
1716 | else { |
1717 | union { |
1718 | struct sockaddr dst; |
1719 | struct sockaddr_in dst4; |
1720 | } u; |
1721 | |
1722 | sockaddr_in_init(&u.dst4, &sin->sin_addr, 0); |
1723 | rt = rtcache_lookup(ro, &u.dst); |
1724 | } |
1725 | /* |
1726 | * If we found a route, use the address |
1727 | * corresponding to the outgoing interface |
1728 | * unless it is the loopback (in case a route |
1729 | * to our address on another net goes to loopback). |
1730 | * |
1731 | * XXX Is this still true? Do we care? |
1732 | */ |
1733 | if (rt != NULL && (rt->rt_ifp->if_flags & IFF_LOOPBACK) == 0) { |
1734 | int s; |
1735 | struct ifaddr *ifa; |
1736 | /* |
1737 | * Just in case. May not need to do this workaround. |
1738 | * Revisit when working on rtentry MP-ification. |
1739 | */ |
1740 | s = pserialize_read_enter(); |
1741 | IFADDR_READER_FOREACH(ifa, rt->rt_ifp) { |
1742 | if (ifa == rt->rt_ifa) |
1743 | break; |
1744 | } |
1745 | if (ifa != NULL) |
1746 | ifa_acquire(ifa, psref); |
1747 | pserialize_read_exit(s); |
1748 | |
1749 | ia = ifatoia(ifa); |
1750 | } |
1751 | if (ia == NULL) { |
1752 | u_int16_t fport = sin->sin_port; |
1753 | struct ifaddr *ifa; |
1754 | int s; |
1755 | |
1756 | sin->sin_port = 0; |
1757 | ifa = ifa_ifwithladdr_psref(sintosa(sin), psref); |
1758 | sin->sin_port = fport; |
1759 | if (ifa == NULL) { |
1760 | /* Find 1st non-loopback AF_INET address */ |
1761 | s = pserialize_read_enter(); |
1762 | IN_ADDRLIST_READER_FOREACH(ia) { |
1763 | if (!(ia->ia_ifp->if_flags & IFF_LOOPBACK)) |
1764 | break; |
1765 | } |
1766 | if (ia != NULL) |
1767 | ia4_acquire(ia, psref); |
1768 | pserialize_read_exit(s); |
1769 | } else { |
1770 | /* ia is already referenced by psref */ |
1771 | ia = ifatoia(ifa); |
1772 | } |
1773 | if (ia == NULL) { |
1774 | *errorp = EADDRNOTAVAIL; |
1775 | return NULL; |
1776 | } |
1777 | } |
1778 | /* |
1779 | * If the destination address is multicast and an outgoing |
1780 | * interface has been set as a multicast option, use the |
1781 | * address of that interface as our source address. |
1782 | */ |
1783 | if (IN_MULTICAST(sin->sin_addr.s_addr) && mopts != NULL) { |
1784 | struct ip_moptions *imo; |
1785 | |
1786 | imo = mopts; |
1787 | if (imo->imo_multicast_if_index != 0) { |
1788 | struct ifnet *ifp; |
1789 | int s; |
1790 | |
1791 | if (ia != NULL) |
1792 | ia4_release(ia, psref); |
1793 | s = pserialize_read_enter(); |
1794 | ifp = if_byindex(imo->imo_multicast_if_index); |
1795 | if (ifp != NULL) { |
1796 | /* XXX */ |
1797 | ia = in_get_ia_from_ifp_psref(ifp, psref); |
1798 | } else |
1799 | ia = NULL; |
1800 | if (ia == NULL || ia->ia4_flags & IN_IFF_NOTREADY) { |
1801 | pserialize_read_exit(s); |
1802 | if (ia != NULL) |
1803 | ia4_release(ia, psref); |
1804 | *errorp = EADDRNOTAVAIL; |
1805 | return NULL; |
1806 | } |
1807 | pserialize_read_exit(s); |
1808 | } |
1809 | } |
1810 | if (ia->ia_ifa.ifa_getifa != NULL) { |
1811 | ia = ifatoia((*ia->ia_ifa.ifa_getifa)(&ia->ia_ifa, |
1812 | sintosa(sin))); |
1813 | if (ia == NULL) { |
1814 | *errorp = EADDRNOTAVAIL; |
1815 | return NULL; |
1816 | } |
1817 | /* FIXME NOMPSAFE */ |
1818 | ia4_acquire(ia, psref); |
1819 | } |
1820 | #ifdef GETIFA_DEBUG |
1821 | else |
1822 | printf("%s: missing ifa_getifa\n" , __func__); |
1823 | #endif |
1824 | return ia; |
1825 | } |
1826 | |
1827 | #if NARP > 0 |
1828 | |
1829 | struct in_llentry { |
1830 | struct llentry base; |
1831 | }; |
1832 | |
1833 | #define IN_LLTBL_DEFAULT_HSIZE 32 |
1834 | #define IN_LLTBL_HASH(k, h) \ |
1835 | (((((((k >> 8) ^ k) >> 8) ^ k) >> 8) ^ k) & ((h) - 1)) |
1836 | |
1837 | /* |
1838 | * Do actual deallocation of @lle. |
1839 | * Called by LLE_FREE_LOCKED when number of references |
1840 | * drops to zero. |
1841 | */ |
1842 | static void |
1843 | in_lltable_destroy_lle(struct llentry *lle) |
1844 | { |
1845 | |
1846 | LLE_WUNLOCK(lle); |
1847 | LLE_LOCK_DESTROY(lle); |
1848 | kmem_intr_free(lle, sizeof(*lle)); |
1849 | } |
1850 | |
1851 | static struct llentry * |
1852 | in_lltable_new(struct in_addr addr4, u_int flags) |
1853 | { |
1854 | struct in_llentry *lle; |
1855 | |
1856 | lle = kmem_intr_zalloc(sizeof(*lle), KM_NOSLEEP); |
1857 | if (lle == NULL) /* NB: caller generates msg */ |
1858 | return NULL; |
1859 | |
1860 | /* |
1861 | * For IPv4 this will trigger "arpresolve" to generate |
1862 | * an ARP request. |
1863 | */ |
1864 | lle->base.la_expire = time_uptime; /* mark expired */ |
1865 | lle->base.r_l3addr.addr4 = addr4; |
1866 | lle->base.lle_refcnt = 1; |
1867 | lle->base.lle_free = in_lltable_destroy_lle; |
1868 | LLE_LOCK_INIT(&lle->base); |
1869 | callout_init(&lle->base.la_timer, CALLOUT_MPSAFE); |
1870 | |
1871 | return (&lle->base); |
1872 | } |
1873 | |
1874 | #define IN_ARE_MASKED_ADDR_EQUAL(d, a, m) ( \ |
1875 | (((ntohl((d).s_addr) ^ (a)->sin_addr.s_addr) & (m)->sin_addr.s_addr)) == 0 ) |
1876 | |
1877 | static int |
1878 | in_lltable_match_prefix(const struct sockaddr *prefix, |
1879 | const struct sockaddr *mask, u_int flags, struct llentry *lle) |
1880 | { |
1881 | const struct sockaddr_in *pfx = (const struct sockaddr_in *)prefix; |
1882 | const struct sockaddr_in *msk = (const struct sockaddr_in *)mask; |
1883 | |
1884 | /* |
1885 | * (flags & LLE_STATIC) means deleting all entries |
1886 | * including static ARP entries. |
1887 | */ |
1888 | if (IN_ARE_MASKED_ADDR_EQUAL(lle->r_l3addr.addr4, pfx, msk) && |
1889 | ((flags & LLE_STATIC) || !(lle->la_flags & LLE_STATIC))) |
1890 | return (1); |
1891 | |
1892 | return (0); |
1893 | } |
1894 | |
1895 | static void |
1896 | in_lltable_free_entry(struct lltable *llt, struct llentry *lle) |
1897 | { |
1898 | struct ifnet *ifp __diagused; |
1899 | size_t pkts_dropped; |
1900 | |
1901 | LLE_WLOCK_ASSERT(lle); |
1902 | KASSERT(llt != NULL); |
1903 | |
1904 | /* Unlink entry from table if not already */ |
1905 | if ((lle->la_flags & LLE_LINKED) != 0) { |
1906 | ifp = llt->llt_ifp; |
1907 | IF_AFDATA_WLOCK_ASSERT(ifp); |
1908 | lltable_unlink_entry(llt, lle); |
1909 | } |
1910 | |
1911 | /* cancel timer */ |
1912 | if (callout_halt(&lle->lle_timer, &lle->lle_lock)) |
1913 | LLE_REMREF(lle); |
1914 | |
1915 | /* Drop hold queue */ |
1916 | pkts_dropped = llentry_free(lle); |
1917 | arp_stat_add(ARP_STAT_DFRDROPPED, (uint64_t)pkts_dropped); |
1918 | } |
1919 | |
1920 | static int |
1921 | in_lltable_rtcheck(struct ifnet *ifp, u_int flags, const struct sockaddr *l3addr) |
1922 | { |
1923 | struct rtentry *rt; |
1924 | int error = EINVAL; |
1925 | |
1926 | KASSERTMSG(l3addr->sa_family == AF_INET, |
1927 | "sin_family %d" , l3addr->sa_family); |
1928 | |
1929 | rt = rtalloc1(l3addr, 0); |
1930 | if (rt == NULL) |
1931 | return error; |
1932 | |
1933 | /* |
1934 | * If the gateway for an existing host route matches the target L3 |
1935 | * address, which is a special route inserted by some implementation |
1936 | * such as MANET, and the interface is of the correct type, then |
1937 | * allow for ARP to proceed. |
1938 | */ |
1939 | if (rt->rt_flags & RTF_GATEWAY) { |
1940 | if (!(rt->rt_flags & RTF_HOST) || !rt->rt_ifp || |
1941 | rt->rt_ifp->if_type != IFT_ETHER || |
1942 | #ifdef __FreeBSD__ |
1943 | (rt->rt_ifp->if_flags & (IFF_NOARP | IFF_STATICARP)) != 0 || |
1944 | #else |
1945 | (rt->rt_ifp->if_flags & IFF_NOARP) != 0 || |
1946 | #endif |
1947 | memcmp(rt->rt_gateway->sa_data, l3addr->sa_data, |
1948 | sizeof(in_addr_t)) != 0) { |
1949 | goto error; |
1950 | } |
1951 | } |
1952 | |
1953 | /* |
1954 | * Make sure that at least the destination address is covered |
1955 | * by the route. This is for handling the case where 2 or more |
1956 | * interfaces have the same prefix. An incoming packet arrives |
1957 | * on one interface and the corresponding outgoing packet leaves |
1958 | * another interface. |
1959 | */ |
1960 | if (!(rt->rt_flags & RTF_HOST) && rt->rt_ifp != ifp) { |
1961 | const char *sa, *mask, *addr, *lim; |
1962 | int len; |
1963 | |
1964 | mask = (const char *)rt_mask(rt); |
1965 | /* |
1966 | * Just being extra cautious to avoid some custom |
1967 | * code getting into trouble. |
1968 | */ |
1969 | if (mask == NULL) |
1970 | goto error; |
1971 | |
1972 | sa = (const char *)rt_getkey(rt); |
1973 | addr = (const char *)l3addr; |
1974 | len = ((const struct sockaddr_in *)l3addr)->sin_len; |
1975 | lim = addr + len; |
1976 | |
1977 | for ( ; addr < lim; sa++, mask++, addr++) { |
1978 | if ((*sa ^ *addr) & *mask) { |
1979 | #ifdef DIAGNOSTIC |
1980 | log(LOG_INFO, "IPv4 address: \"%s\" is not on the network\n" , |
1981 | inet_ntoa(((const struct sockaddr_in *)l3addr)->sin_addr)); |
1982 | #endif |
1983 | goto error; |
1984 | } |
1985 | } |
1986 | } |
1987 | |
1988 | error = 0; |
1989 | error: |
1990 | rtfree(rt); |
1991 | return error; |
1992 | } |
1993 | |
1994 | static inline uint32_t |
1995 | in_lltable_hash_dst(const struct in_addr dst, uint32_t hsize) |
1996 | { |
1997 | |
1998 | return (IN_LLTBL_HASH(dst.s_addr, hsize)); |
1999 | } |
2000 | |
2001 | static uint32_t |
2002 | in_lltable_hash(const struct llentry *lle, uint32_t hsize) |
2003 | { |
2004 | |
2005 | return (in_lltable_hash_dst(lle->r_l3addr.addr4, hsize)); |
2006 | } |
2007 | |
2008 | static void |
2009 | in_lltable_fill_sa_entry(const struct llentry *lle, struct sockaddr *sa) |
2010 | { |
2011 | struct sockaddr_in *sin; |
2012 | |
2013 | sin = (struct sockaddr_in *)sa; |
2014 | memset(sin, 0, sizeof(*sin)); |
2015 | sin->sin_family = AF_INET; |
2016 | sin->sin_len = sizeof(*sin); |
2017 | sin->sin_addr = lle->r_l3addr.addr4; |
2018 | } |
2019 | |
2020 | static inline struct llentry * |
2021 | in_lltable_find_dst(struct lltable *llt, struct in_addr dst) |
2022 | { |
2023 | struct llentry *lle; |
2024 | struct llentries *lleh; |
2025 | u_int hashidx; |
2026 | |
2027 | hashidx = in_lltable_hash_dst(dst, llt->llt_hsize); |
2028 | lleh = &llt->lle_head[hashidx]; |
2029 | LIST_FOREACH(lle, lleh, lle_next) { |
2030 | if (lle->la_flags & LLE_DELETED) |
2031 | continue; |
2032 | if (lle->r_l3addr.addr4.s_addr == dst.s_addr) |
2033 | break; |
2034 | } |
2035 | |
2036 | return (lle); |
2037 | } |
2038 | |
2039 | static int |
2040 | in_lltable_delete(struct lltable *llt, u_int flags, |
2041 | const struct sockaddr *l3addr) |
2042 | { |
2043 | const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; |
2044 | struct ifnet *ifp __diagused = llt->llt_ifp; |
2045 | struct llentry *lle; |
2046 | |
2047 | IF_AFDATA_WLOCK_ASSERT(ifp); |
2048 | KASSERTMSG(l3addr->sa_family == AF_INET, |
2049 | "sin_family %d" , l3addr->sa_family); |
2050 | |
2051 | lle = in_lltable_find_dst(llt, sin->sin_addr); |
2052 | if (lle == NULL) { |
2053 | #ifdef DIAGNOSTIC |
2054 | log(LOG_INFO, "interface address is missing from cache = %p in delete\n" , lle); |
2055 | #endif |
2056 | return (ENOENT); |
2057 | } |
2058 | |
2059 | LLE_WLOCK(lle); |
2060 | lle->la_flags |= LLE_DELETED; |
2061 | #ifdef DIAGNOSTIC |
2062 | log(LOG_INFO, "ifaddr cache = %p is deleted\n" , lle); |
2063 | #endif |
2064 | if ((lle->la_flags & (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) |
2065 | llentry_free(lle); |
2066 | else |
2067 | LLE_WUNLOCK(lle); |
2068 | |
2069 | return (0); |
2070 | } |
2071 | |
2072 | static struct llentry * |
2073 | in_lltable_create(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) |
2074 | { |
2075 | const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; |
2076 | struct ifnet *ifp = llt->llt_ifp; |
2077 | struct llentry *lle; |
2078 | |
2079 | IF_AFDATA_WLOCK_ASSERT(ifp); |
2080 | KASSERTMSG(l3addr->sa_family == AF_INET, |
2081 | "sin_family %d" , l3addr->sa_family); |
2082 | |
2083 | lle = in_lltable_find_dst(llt, sin->sin_addr); |
2084 | |
2085 | if (lle != NULL) { |
2086 | LLE_WLOCK(lle); |
2087 | return (lle); |
2088 | } |
2089 | |
2090 | /* no existing record, we need to create new one */ |
2091 | |
2092 | /* |
2093 | * A route that covers the given address must have |
2094 | * been installed 1st because we are doing a resolution, |
2095 | * verify this. |
2096 | */ |
2097 | if (!(flags & LLE_IFADDR) && |
2098 | in_lltable_rtcheck(ifp, flags, l3addr) != 0) |
2099 | return (NULL); |
2100 | |
2101 | lle = in_lltable_new(sin->sin_addr, flags); |
2102 | if (lle == NULL) { |
2103 | log(LOG_INFO, "lla_lookup: new lle malloc failed\n" ); |
2104 | return (NULL); |
2105 | } |
2106 | lle->la_flags = flags; |
2107 | if ((flags & LLE_IFADDR) == LLE_IFADDR) { |
2108 | memcpy(&lle->ll_addr, CLLADDR(ifp->if_sadl), ifp->if_addrlen); |
2109 | lle->la_flags |= (LLE_VALID | LLE_STATIC); |
2110 | } |
2111 | |
2112 | lltable_link_entry(llt, lle); |
2113 | LLE_WLOCK(lle); |
2114 | |
2115 | return (lle); |
2116 | } |
2117 | |
2118 | /* |
2119 | * Return NULL if not found or marked for deletion. |
2120 | * If found return lle read locked. |
2121 | */ |
2122 | static struct llentry * |
2123 | in_lltable_lookup(struct lltable *llt, u_int flags, const struct sockaddr *l3addr) |
2124 | { |
2125 | const struct sockaddr_in *sin = (const struct sockaddr_in *)l3addr; |
2126 | struct llentry *lle; |
2127 | |
2128 | IF_AFDATA_LOCK_ASSERT(llt->llt_ifp); |
2129 | KASSERTMSG(l3addr->sa_family == AF_INET, |
2130 | "sin_family %d" , l3addr->sa_family); |
2131 | |
2132 | lle = in_lltable_find_dst(llt, sin->sin_addr); |
2133 | |
2134 | if (lle == NULL) |
2135 | return NULL; |
2136 | |
2137 | if (flags & LLE_EXCLUSIVE) |
2138 | LLE_WLOCK(lle); |
2139 | else |
2140 | LLE_RLOCK(lle); |
2141 | |
2142 | return lle; |
2143 | } |
2144 | |
2145 | static int |
2146 | in_lltable_dump_entry(struct lltable *llt, struct llentry *lle, |
2147 | struct rt_walkarg *w) |
2148 | { |
2149 | struct sockaddr_in sin; |
2150 | |
2151 | LLTABLE_LOCK_ASSERT(); |
2152 | |
2153 | /* skip deleted entries */ |
2154 | if (lle->la_flags & LLE_DELETED) |
2155 | return 0; |
2156 | |
2157 | sockaddr_in_init(&sin, &lle->r_l3addr.addr4, 0); |
2158 | |
2159 | return lltable_dump_entry(llt, lle, w, sintosa(&sin)); |
2160 | } |
2161 | |
2162 | #endif /* NARP > 0 */ |
2163 | |
2164 | static int |
2165 | in_multicast_sysctl(SYSCTLFN_ARGS) |
2166 | { |
2167 | struct ifnet *ifp; |
2168 | struct ifaddr *ifa; |
2169 | struct in_ifaddr *ifa4; |
2170 | struct in_multi *inm; |
2171 | uint32_t tmp; |
2172 | int error; |
2173 | size_t written; |
2174 | struct psref psref; |
2175 | int bound; |
2176 | |
2177 | if (namelen != 1) |
2178 | return EINVAL; |
2179 | |
2180 | bound = curlwp_bind(); |
2181 | ifp = if_get_byindex(name[0], &psref); |
2182 | if (ifp == NULL) { |
2183 | curlwp_bindx(bound); |
2184 | return ENODEV; |
2185 | } |
2186 | |
2187 | if (oldp == NULL) { |
2188 | *oldlenp = 0; |
2189 | IFADDR_FOREACH(ifa, ifp) { |
2190 | if (ifa->ifa_addr->sa_family != AF_INET) |
2191 | continue; |
2192 | ifa4 = (void *)ifa; |
2193 | LIST_FOREACH(inm, &ifa4->ia_multiaddrs, inm_list) { |
2194 | *oldlenp += 2 * sizeof(struct in_addr) + |
2195 | sizeof(uint32_t); |
2196 | } |
2197 | } |
2198 | if_put(ifp, &psref); |
2199 | curlwp_bindx(bound); |
2200 | return 0; |
2201 | } |
2202 | |
2203 | error = 0; |
2204 | written = 0; |
2205 | IFADDR_FOREACH(ifa, ifp) { |
2206 | if (ifa->ifa_addr->sa_family != AF_INET) |
2207 | continue; |
2208 | ifa4 = (void *)ifa; |
2209 | LIST_FOREACH(inm, &ifa4->ia_multiaddrs, inm_list) { |
2210 | if (written + 2 * sizeof(struct in_addr) + |
2211 | sizeof(uint32_t) > *oldlenp) |
2212 | goto done; |
2213 | error = sysctl_copyout(l, &ifa4->ia_addr.sin_addr, |
2214 | oldp, sizeof(struct in_addr)); |
2215 | if (error) |
2216 | goto done; |
2217 | oldp = (char *)oldp + sizeof(struct in_addr); |
2218 | written += sizeof(struct in_addr); |
2219 | error = sysctl_copyout(l, &inm->inm_addr, |
2220 | oldp, sizeof(struct in_addr)); |
2221 | if (error) |
2222 | goto done; |
2223 | oldp = (char *)oldp + sizeof(struct in_addr); |
2224 | written += sizeof(struct in_addr); |
2225 | tmp = inm->inm_refcount; |
2226 | error = sysctl_copyout(l, &tmp, oldp, sizeof(tmp)); |
2227 | if (error) |
2228 | goto done; |
2229 | oldp = (char *)oldp + sizeof(tmp); |
2230 | written += sizeof(tmp); |
2231 | } |
2232 | } |
2233 | done: |
2234 | if_put(ifp, &psref); |
2235 | curlwp_bindx(bound); |
2236 | *oldlenp = written; |
2237 | return error; |
2238 | } |
2239 | |
2240 | static void |
2241 | in_sysctl_init(struct sysctllog **clog) |
2242 | { |
2243 | sysctl_createv(clog, 0, NULL, NULL, |
2244 | CTLFLAG_PERMANENT, |
2245 | CTLTYPE_NODE, "inet" , |
2246 | SYSCTL_DESCR("PF_INET related settings" ), |
2247 | NULL, 0, NULL, 0, |
2248 | CTL_NET, PF_INET, CTL_EOL); |
2249 | sysctl_createv(clog, 0, NULL, NULL, |
2250 | CTLFLAG_PERMANENT, |
2251 | CTLTYPE_NODE, "multicast" , |
2252 | SYSCTL_DESCR("Multicast information" ), |
2253 | in_multicast_sysctl, 0, NULL, 0, |
2254 | CTL_NET, PF_INET, CTL_CREATE, CTL_EOL); |
2255 | sysctl_createv(clog, 0, NULL, NULL, |
2256 | CTLFLAG_PERMANENT, |
2257 | CTLTYPE_NODE, "ip" , |
2258 | SYSCTL_DESCR("IPv4 related settings" ), |
2259 | NULL, 0, NULL, 0, |
2260 | CTL_NET, PF_INET, IPPROTO_IP, CTL_EOL); |
2261 | |
2262 | sysctl_createv(clog, 0, NULL, NULL, |
2263 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
2264 | CTLTYPE_INT, "subnetsarelocal" , |
2265 | SYSCTL_DESCR("Whether logical subnets are considered " |
2266 | "local" ), |
2267 | NULL, 0, &subnetsarelocal, 0, |
2268 | CTL_NET, PF_INET, IPPROTO_IP, |
2269 | IPCTL_SUBNETSARELOCAL, CTL_EOL); |
2270 | sysctl_createv(clog, 0, NULL, NULL, |
2271 | CTLFLAG_PERMANENT|CTLFLAG_READWRITE, |
2272 | CTLTYPE_INT, "hostzerobroadcast" , |
2273 | SYSCTL_DESCR("All zeroes address is broadcast address" ), |
2274 | NULL, 0, &hostzeroisbroadcast, 0, |
2275 | CTL_NET, PF_INET, IPPROTO_IP, |
2276 | IPCTL_HOSTZEROBROADCAST, CTL_EOL); |
2277 | } |
2278 | |
2279 | #if NARP > 0 |
2280 | |
2281 | static struct lltable * |
2282 | in_lltattach(struct ifnet *ifp) |
2283 | { |
2284 | struct lltable *llt; |
2285 | |
2286 | llt = lltable_allocate_htbl(IN_LLTBL_DEFAULT_HSIZE); |
2287 | llt->llt_af = AF_INET; |
2288 | llt->llt_ifp = ifp; |
2289 | |
2290 | llt->llt_lookup = in_lltable_lookup; |
2291 | llt->llt_create = in_lltable_create; |
2292 | llt->llt_delete = in_lltable_delete; |
2293 | llt->llt_dump_entry = in_lltable_dump_entry; |
2294 | llt->llt_hash = in_lltable_hash; |
2295 | llt->llt_fill_sa_entry = in_lltable_fill_sa_entry; |
2296 | llt->llt_free_entry = in_lltable_free_entry; |
2297 | llt->llt_match_prefix = in_lltable_match_prefix; |
2298 | lltable_link(llt); |
2299 | |
2300 | return (llt); |
2301 | } |
2302 | |
2303 | #endif /* NARP > 0 */ |
2304 | |
2305 | void * |
2306 | in_domifattach(struct ifnet *ifp) |
2307 | { |
2308 | struct in_ifinfo *ii; |
2309 | |
2310 | ii = kmem_zalloc(sizeof(struct in_ifinfo), KM_SLEEP); |
2311 | KASSERT(ii != NULL); |
2312 | |
2313 | #if NARP > 0 |
2314 | ii->ii_llt = in_lltattach(ifp); |
2315 | #endif |
2316 | |
2317 | #ifdef IPSELSRC |
2318 | ii->ii_selsrc = in_selsrc_domifattach(ifp); |
2319 | KASSERT(ii->ii_selsrc != NULL); |
2320 | #endif |
2321 | |
2322 | return ii; |
2323 | } |
2324 | |
2325 | void |
2326 | in_domifdetach(struct ifnet *ifp, void *aux) |
2327 | { |
2328 | struct in_ifinfo *ii = aux; |
2329 | |
2330 | #ifdef IPSELSRC |
2331 | in_selsrc_domifdetach(ifp, ii->ii_selsrc); |
2332 | #endif |
2333 | #if NARP > 0 |
2334 | lltable_free(ii->ii_llt); |
2335 | #endif |
2336 | kmem_free(ii, sizeof(struct in_ifinfo)); |
2337 | } |
2338 | |