1 | #include <machine/rtems-bsd-kernel-space.h> |
---|
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 | * $KAME: in6.c,v 1.259 2002/01/21 11:37:50 keiichi Exp $ |
---|
32 | */ |
---|
33 | |
---|
34 | /*- |
---|
35 | * Copyright (c) 1982, 1986, 1991, 1993 |
---|
36 | * The Regents of the University of California. All rights reserved. |
---|
37 | * |
---|
38 | * Redistribution and use in source and binary forms, with or without |
---|
39 | * modification, are permitted provided that the following conditions |
---|
40 | * are met: |
---|
41 | * 1. Redistributions of source code must retain the above copyright |
---|
42 | * notice, this list of conditions and the following disclaimer. |
---|
43 | * 2. Redistributions in binary form must reproduce the above copyright |
---|
44 | * notice, this list of conditions and the following disclaimer in the |
---|
45 | * documentation and/or other materials provided with the distribution. |
---|
46 | * 4. Neither the name of the University nor the names of its contributors |
---|
47 | * may be used to endorse or promote products derived from this software |
---|
48 | * without specific prior written permission. |
---|
49 | * |
---|
50 | * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
---|
51 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
---|
52 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
---|
53 | * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
---|
54 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
---|
55 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
---|
56 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
---|
57 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
---|
58 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
---|
59 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
---|
60 | * SUCH DAMAGE. |
---|
61 | * |
---|
62 | * @(#)in.c 8.2 (Berkeley) 11/15/93 |
---|
63 | */ |
---|
64 | |
---|
65 | #include <sys/cdefs.h> |
---|
66 | __FBSDID("$FreeBSD$"); |
---|
67 | |
---|
68 | #include <rtems/bsd/local/opt_compat.h> |
---|
69 | #include <rtems/bsd/local/opt_inet.h> |
---|
70 | #include <rtems/bsd/local/opt_inet6.h> |
---|
71 | |
---|
72 | #include <rtems/bsd/sys/param.h> |
---|
73 | #include <rtems/bsd/sys/errno.h> |
---|
74 | #include <sys/jail.h> |
---|
75 | #include <sys/malloc.h> |
---|
76 | #include <sys/socket.h> |
---|
77 | #include <sys/socketvar.h> |
---|
78 | #include <sys/sockio.h> |
---|
79 | #include <sys/systm.h> |
---|
80 | #include <sys/priv.h> |
---|
81 | #include <sys/proc.h> |
---|
82 | #include <rtems/bsd/sys/time.h> |
---|
83 | #include <sys/kernel.h> |
---|
84 | #include <sys/syslog.h> |
---|
85 | |
---|
86 | #include <net/if.h> |
---|
87 | #include <net/if_var.h> |
---|
88 | #include <net/if_types.h> |
---|
89 | #include <net/route.h> |
---|
90 | #include <net/if_dl.h> |
---|
91 | #include <net/vnet.h> |
---|
92 | |
---|
93 | #include <netinet/in.h> |
---|
94 | #include <netinet/in_var.h> |
---|
95 | #include <net/if_llatbl.h> |
---|
96 | #include <netinet/if_ether.h> |
---|
97 | #include <netinet/in_systm.h> |
---|
98 | #include <netinet/ip.h> |
---|
99 | #include <netinet/in_pcb.h> |
---|
100 | |
---|
101 | #include <netinet/ip6.h> |
---|
102 | #include <netinet6/ip6_var.h> |
---|
103 | #include <netinet6/nd6.h> |
---|
104 | #include <netinet6/mld6_var.h> |
---|
105 | #include <netinet6/ip6_mroute.h> |
---|
106 | #include <netinet6/in6_ifattach.h> |
---|
107 | #include <netinet6/scope6_var.h> |
---|
108 | #include <netinet6/in6_pcb.h> |
---|
109 | |
---|
110 | VNET_DECLARE(int, icmp6_nodeinfo_oldmcprefix); |
---|
111 | #define V_icmp6_nodeinfo_oldmcprefix VNET(icmp6_nodeinfo_oldmcprefix) |
---|
112 | |
---|
113 | /* |
---|
114 | * Definitions of some costant IP6 addresses. |
---|
115 | */ |
---|
116 | const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT; |
---|
117 | const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT; |
---|
118 | const struct in6_addr in6addr_nodelocal_allnodes = |
---|
119 | IN6ADDR_NODELOCAL_ALLNODES_INIT; |
---|
120 | const struct in6_addr in6addr_linklocal_allnodes = |
---|
121 | IN6ADDR_LINKLOCAL_ALLNODES_INIT; |
---|
122 | const struct in6_addr in6addr_linklocal_allrouters = |
---|
123 | IN6ADDR_LINKLOCAL_ALLROUTERS_INIT; |
---|
124 | const struct in6_addr in6addr_linklocal_allv2routers = |
---|
125 | IN6ADDR_LINKLOCAL_ALLV2ROUTERS_INIT; |
---|
126 | |
---|
127 | const struct in6_addr in6mask0 = IN6MASK0; |
---|
128 | const struct in6_addr in6mask32 = IN6MASK32; |
---|
129 | const struct in6_addr in6mask64 = IN6MASK64; |
---|
130 | const struct in6_addr in6mask96 = IN6MASK96; |
---|
131 | const struct in6_addr in6mask128 = IN6MASK128; |
---|
132 | |
---|
133 | const struct sockaddr_in6 sa6_any = |
---|
134 | { sizeof(sa6_any), AF_INET6, 0, 0, IN6ADDR_ANY_INIT, 0 }; |
---|
135 | |
---|
136 | static int in6_lifaddr_ioctl(struct socket *, u_long, caddr_t, |
---|
137 | struct ifnet *, struct thread *); |
---|
138 | static int in6_ifinit(struct ifnet *, struct in6_ifaddr *, |
---|
139 | struct sockaddr_in6 *, int); |
---|
140 | static void in6_unlink_ifa(struct in6_ifaddr *, struct ifnet *); |
---|
141 | |
---|
142 | int (*faithprefix_p)(struct in6_addr *); |
---|
143 | |
---|
144 | #define ifa2ia6(ifa) ((struct in6_ifaddr *)(ifa)) |
---|
145 | #define ia62ifa(ia6) (&((ia6)->ia_ifa)) |
---|
146 | |
---|
147 | void |
---|
148 | in6_ifaddloop(struct ifaddr *ifa) |
---|
149 | { |
---|
150 | struct sockaddr_dl gateway; |
---|
151 | struct sockaddr_in6 mask, addr; |
---|
152 | struct rtentry rt; |
---|
153 | struct in6_ifaddr *ia; |
---|
154 | struct ifnet *ifp; |
---|
155 | struct llentry *ln; |
---|
156 | |
---|
157 | ia = ifa2ia6(ifa); |
---|
158 | ifp = ifa->ifa_ifp; |
---|
159 | IF_AFDATA_LOCK(ifp); |
---|
160 | ifa->ifa_rtrequest = nd6_rtrequest; |
---|
161 | ln = lla_lookup(LLTABLE6(ifp), (LLE_CREATE | LLE_IFADDR | |
---|
162 | LLE_EXCLUSIVE), (struct sockaddr *)&ia->ia_addr); |
---|
163 | IF_AFDATA_UNLOCK(ifp); |
---|
164 | if (ln != NULL) { |
---|
165 | ln->la_expire = 0; /* for IPv6 this means permanent */ |
---|
166 | ln->ln_state = ND6_LLINFO_REACHABLE; |
---|
167 | /* |
---|
168 | * initialize for rtmsg generation |
---|
169 | */ |
---|
170 | bzero(&gateway, sizeof(gateway)); |
---|
171 | gateway.sdl_len = sizeof(gateway); |
---|
172 | gateway.sdl_family = AF_LINK; |
---|
173 | gateway.sdl_nlen = 0; |
---|
174 | gateway.sdl_alen = 6; |
---|
175 | memcpy(gateway.sdl_data, &ln->ll_addr.mac_aligned, |
---|
176 | sizeof(ln->ll_addr)); |
---|
177 | LLE_WUNLOCK(ln); |
---|
178 | } |
---|
179 | |
---|
180 | bzero(&rt, sizeof(rt)); |
---|
181 | rt.rt_gateway = (struct sockaddr *)&gateway; |
---|
182 | memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); |
---|
183 | memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); |
---|
184 | rt_mask(&rt) = (struct sockaddr *)&mask; |
---|
185 | rt_key(&rt) = (struct sockaddr *)&addr; |
---|
186 | rt.rt_flags = RTF_UP | RTF_HOST | RTF_STATIC; |
---|
187 | /* Announce arrival of local address to all FIBs. */ |
---|
188 | rt_newaddrmsg(RTM_ADD, ifa, 0, &rt); |
---|
189 | } |
---|
190 | |
---|
191 | void |
---|
192 | in6_ifremloop(struct ifaddr *ifa) |
---|
193 | { |
---|
194 | struct sockaddr_dl gateway; |
---|
195 | struct sockaddr_in6 mask, addr; |
---|
196 | struct rtentry rt0; |
---|
197 | struct in6_ifaddr *ia; |
---|
198 | struct ifnet *ifp; |
---|
199 | |
---|
200 | ia = ifa2ia6(ifa); |
---|
201 | ifp = ifa->ifa_ifp; |
---|
202 | memcpy(&addr, &ia->ia_addr, sizeof(ia->ia_addr)); |
---|
203 | memcpy(&mask, &ia->ia_prefixmask, sizeof(ia->ia_prefixmask)); |
---|
204 | lltable_prefix_free(AF_INET6, (struct sockaddr *)&addr, |
---|
205 | (struct sockaddr *)&mask, LLE_STATIC); |
---|
206 | |
---|
207 | /* |
---|
208 | * initialize for rtmsg generation |
---|
209 | */ |
---|
210 | bzero(&gateway, sizeof(gateway)); |
---|
211 | gateway.sdl_len = sizeof(gateway); |
---|
212 | gateway.sdl_family = AF_LINK; |
---|
213 | gateway.sdl_nlen = 0; |
---|
214 | gateway.sdl_alen = ifp->if_addrlen; |
---|
215 | bzero(&rt0, sizeof(rt0)); |
---|
216 | rt0.rt_gateway = (struct sockaddr *)&gateway; |
---|
217 | rt_mask(&rt0) = (struct sockaddr *)&mask; |
---|
218 | rt_key(&rt0) = (struct sockaddr *)&addr; |
---|
219 | rt0.rt_flags = RTF_HOST | RTF_STATIC; |
---|
220 | /* Announce removal of local address to all FIBs. */ |
---|
221 | rt_newaddrmsg(RTM_DELETE, ifa, 0, &rt0); |
---|
222 | } |
---|
223 | |
---|
224 | int |
---|
225 | in6_mask2len(struct in6_addr *mask, u_char *lim0) |
---|
226 | { |
---|
227 | int x = 0, y; |
---|
228 | u_char *lim = lim0, *p; |
---|
229 | |
---|
230 | /* ignore the scope_id part */ |
---|
231 | if (lim0 == NULL || lim0 - (u_char *)mask > sizeof(*mask)) |
---|
232 | lim = (u_char *)mask + sizeof(*mask); |
---|
233 | for (p = (u_char *)mask; p < lim; x++, p++) { |
---|
234 | if (*p != 0xff) |
---|
235 | break; |
---|
236 | } |
---|
237 | y = 0; |
---|
238 | if (p < lim) { |
---|
239 | for (y = 0; y < 8; y++) { |
---|
240 | if ((*p & (0x80 >> y)) == 0) |
---|
241 | break; |
---|
242 | } |
---|
243 | } |
---|
244 | |
---|
245 | /* |
---|
246 | * when the limit pointer is given, do a stricter check on the |
---|
247 | * remaining bits. |
---|
248 | */ |
---|
249 | if (p < lim) { |
---|
250 | if (y != 0 && (*p & (0x00ff >> y)) != 0) |
---|
251 | return (-1); |
---|
252 | for (p = p + 1; p < lim; p++) |
---|
253 | if (*p != 0) |
---|
254 | return (-1); |
---|
255 | } |
---|
256 | |
---|
257 | return x * 8 + y; |
---|
258 | } |
---|
259 | |
---|
260 | #ifdef COMPAT_FREEBSD32 |
---|
261 | struct in6_ndifreq32 { |
---|
262 | char ifname[IFNAMSIZ]; |
---|
263 | uint32_t ifindex; |
---|
264 | }; |
---|
265 | #define SIOCGDEFIFACE32_IN6 _IOWR('i', 86, struct in6_ndifreq32) |
---|
266 | #endif |
---|
267 | |
---|
268 | int |
---|
269 | in6_control(struct socket *so, u_long cmd, caddr_t data, |
---|
270 | struct ifnet *ifp, struct thread *td) |
---|
271 | { |
---|
272 | struct in6_ifreq *ifr = (struct in6_ifreq *)data; |
---|
273 | struct in6_ifaddr *ia = NULL; |
---|
274 | struct in6_aliasreq *ifra = (struct in6_aliasreq *)data; |
---|
275 | struct sockaddr_in6 *sa6; |
---|
276 | int error; |
---|
277 | |
---|
278 | switch (cmd) { |
---|
279 | case SIOCGETSGCNT_IN6: |
---|
280 | case SIOCGETMIFCNT_IN6: |
---|
281 | /* |
---|
282 | * XXX mrt_ioctl has a 3rd, unused, FIB argument in route.c. |
---|
283 | * We cannot see how that would be needed, so do not adjust the |
---|
284 | * KPI blindly; more likely should clean up the IPv4 variant. |
---|
285 | */ |
---|
286 | return (mrt6_ioctl ? mrt6_ioctl(cmd, data) : EOPNOTSUPP); |
---|
287 | } |
---|
288 | |
---|
289 | switch (cmd) { |
---|
290 | case SIOCAADDRCTL_POLICY: |
---|
291 | case SIOCDADDRCTL_POLICY: |
---|
292 | if (td != NULL) { |
---|
293 | error = priv_check(td, PRIV_NETINET_ADDRCTRL6); |
---|
294 | if (error) |
---|
295 | return (error); |
---|
296 | } |
---|
297 | return (in6_src_ioctl(cmd, data)); |
---|
298 | } |
---|
299 | |
---|
300 | if (ifp == NULL) |
---|
301 | return (EOPNOTSUPP); |
---|
302 | |
---|
303 | switch (cmd) { |
---|
304 | case SIOCSNDFLUSH_IN6: |
---|
305 | case SIOCSPFXFLUSH_IN6: |
---|
306 | case SIOCSRTRFLUSH_IN6: |
---|
307 | case SIOCSDEFIFACE_IN6: |
---|
308 | case SIOCSIFINFO_FLAGS: |
---|
309 | case SIOCSIFINFO_IN6: |
---|
310 | if (td != NULL) { |
---|
311 | error = priv_check(td, PRIV_NETINET_ND6); |
---|
312 | if (error) |
---|
313 | return (error); |
---|
314 | } |
---|
315 | /* FALLTHROUGH */ |
---|
316 | case OSIOCGIFINFO_IN6: |
---|
317 | case SIOCGIFINFO_IN6: |
---|
318 | case SIOCGDRLST_IN6: |
---|
319 | case SIOCGPRLST_IN6: |
---|
320 | case SIOCGNBRINFO_IN6: |
---|
321 | case SIOCGDEFIFACE_IN6: |
---|
322 | return (nd6_ioctl(cmd, data, ifp)); |
---|
323 | |
---|
324 | #ifdef COMPAT_FREEBSD32 |
---|
325 | case SIOCGDEFIFACE32_IN6: |
---|
326 | { |
---|
327 | struct in6_ndifreq ndif; |
---|
328 | struct in6_ndifreq32 *ndif32; |
---|
329 | |
---|
330 | error = nd6_ioctl(SIOCGDEFIFACE_IN6, (caddr_t)&ndif, |
---|
331 | ifp); |
---|
332 | if (error) |
---|
333 | return (error); |
---|
334 | ndif32 = (struct in6_ndifreq32 *)data; |
---|
335 | ndif32->ifindex = ndif.ifindex; |
---|
336 | return (0); |
---|
337 | } |
---|
338 | #endif |
---|
339 | } |
---|
340 | |
---|
341 | switch (cmd) { |
---|
342 | case SIOCSIFPREFIX_IN6: |
---|
343 | case SIOCDIFPREFIX_IN6: |
---|
344 | case SIOCAIFPREFIX_IN6: |
---|
345 | case SIOCCIFPREFIX_IN6: |
---|
346 | case SIOCSGIFPREFIX_IN6: |
---|
347 | case SIOCGIFPREFIX_IN6: |
---|
348 | log(LOG_NOTICE, |
---|
349 | "prefix ioctls are now invalidated. " |
---|
350 | "please use ifconfig.\n"); |
---|
351 | return (EOPNOTSUPP); |
---|
352 | } |
---|
353 | |
---|
354 | switch (cmd) { |
---|
355 | case SIOCSSCOPE6: |
---|
356 | if (td != NULL) { |
---|
357 | error = priv_check(td, PRIV_NETINET_SCOPE6); |
---|
358 | if (error) |
---|
359 | return (error); |
---|
360 | } |
---|
361 | /* FALLTHROUGH */ |
---|
362 | case SIOCGSCOPE6: |
---|
363 | case SIOCGSCOPE6DEF: |
---|
364 | return (scope6_ioctl(cmd, data, ifp)); |
---|
365 | } |
---|
366 | |
---|
367 | switch (cmd) { |
---|
368 | case SIOCALIFADDR: |
---|
369 | if (td != NULL) { |
---|
370 | error = priv_check(td, PRIV_NET_ADDIFADDR); |
---|
371 | if (error) |
---|
372 | return (error); |
---|
373 | } |
---|
374 | return in6_lifaddr_ioctl(so, cmd, data, ifp, td); |
---|
375 | |
---|
376 | case SIOCDLIFADDR: |
---|
377 | if (td != NULL) { |
---|
378 | error = priv_check(td, PRIV_NET_DELIFADDR); |
---|
379 | if (error) |
---|
380 | return (error); |
---|
381 | } |
---|
382 | /* FALLTHROUGH */ |
---|
383 | case SIOCGLIFADDR: |
---|
384 | return in6_lifaddr_ioctl(so, cmd, data, ifp, td); |
---|
385 | } |
---|
386 | |
---|
387 | /* |
---|
388 | * Find address for this interface, if it exists. |
---|
389 | * |
---|
390 | * In netinet code, we have checked ifra_addr in SIOCSIF*ADDR operation |
---|
391 | * only, and used the first interface address as the target of other |
---|
392 | * operations (without checking ifra_addr). This was because netinet |
---|
393 | * code/API assumed at most 1 interface address per interface. |
---|
394 | * Since IPv6 allows a node to assign multiple addresses |
---|
395 | * on a single interface, we almost always look and check the |
---|
396 | * presence of ifra_addr, and reject invalid ones here. |
---|
397 | * It also decreases duplicated code among SIOC*_IN6 operations. |
---|
398 | */ |
---|
399 | switch (cmd) { |
---|
400 | case SIOCAIFADDR_IN6: |
---|
401 | case SIOCSIFPHYADDR_IN6: |
---|
402 | sa6 = &ifra->ifra_addr; |
---|
403 | break; |
---|
404 | case SIOCSIFADDR_IN6: |
---|
405 | case SIOCGIFADDR_IN6: |
---|
406 | case SIOCSIFDSTADDR_IN6: |
---|
407 | case SIOCSIFNETMASK_IN6: |
---|
408 | case SIOCGIFDSTADDR_IN6: |
---|
409 | case SIOCGIFNETMASK_IN6: |
---|
410 | case SIOCDIFADDR_IN6: |
---|
411 | case SIOCGIFPSRCADDR_IN6: |
---|
412 | case SIOCGIFPDSTADDR_IN6: |
---|
413 | case SIOCGIFAFLAG_IN6: |
---|
414 | case SIOCSNDFLUSH_IN6: |
---|
415 | case SIOCSPFXFLUSH_IN6: |
---|
416 | case SIOCSRTRFLUSH_IN6: |
---|
417 | case SIOCGIFALIFETIME_IN6: |
---|
418 | case SIOCSIFALIFETIME_IN6: |
---|
419 | case SIOCGIFSTAT_IN6: |
---|
420 | case SIOCGIFSTAT_ICMP6: |
---|
421 | sa6 = &ifr->ifr_addr; |
---|
422 | break; |
---|
423 | case SIOCSIFADDR: |
---|
424 | case SIOCSIFBRDADDR: |
---|
425 | case SIOCSIFDSTADDR: |
---|
426 | case SIOCSIFNETMASK: |
---|
427 | /* |
---|
428 | * Although we should pass any non-INET6 ioctl requests |
---|
429 | * down to driver, we filter some legacy INET requests. |
---|
430 | * Drivers trust SIOCSIFADDR et al to come from an already |
---|
431 | * privileged layer, and do not perform any credentials |
---|
432 | * checks or input validation. |
---|
433 | */ |
---|
434 | return (EINVAL); |
---|
435 | default: |
---|
436 | sa6 = NULL; |
---|
437 | break; |
---|
438 | } |
---|
439 | if (sa6 && sa6->sin6_family == AF_INET6) { |
---|
440 | if (sa6->sin6_scope_id != 0) |
---|
441 | error = sa6_embedscope(sa6, 0); |
---|
442 | else |
---|
443 | error = in6_setscope(&sa6->sin6_addr, ifp, NULL); |
---|
444 | if (error != 0) |
---|
445 | return (error); |
---|
446 | if (td != NULL && (error = prison_check_ip6(td->td_ucred, |
---|
447 | &sa6->sin6_addr)) != 0) |
---|
448 | return (error); |
---|
449 | ia = in6ifa_ifpwithaddr(ifp, &sa6->sin6_addr); |
---|
450 | } else |
---|
451 | ia = NULL; |
---|
452 | |
---|
453 | switch (cmd) { |
---|
454 | case SIOCSIFADDR_IN6: |
---|
455 | case SIOCSIFDSTADDR_IN6: |
---|
456 | case SIOCSIFNETMASK_IN6: |
---|
457 | /* |
---|
458 | * Since IPv6 allows a node to assign multiple addresses |
---|
459 | * on a single interface, SIOCSIFxxx ioctls are deprecated. |
---|
460 | */ |
---|
461 | /* we decided to obsolete this command (20000704) */ |
---|
462 | error = EINVAL; |
---|
463 | goto out; |
---|
464 | |
---|
465 | case SIOCDIFADDR_IN6: |
---|
466 | /* |
---|
467 | * for IPv4, we look for existing in_ifaddr here to allow |
---|
468 | * "ifconfig if0 delete" to remove the first IPv4 address on |
---|
469 | * the interface. For IPv6, as the spec allows multiple |
---|
470 | * interface address from the day one, we consider "remove the |
---|
471 | * first one" semantics to be not preferable. |
---|
472 | */ |
---|
473 | if (ia == NULL) { |
---|
474 | error = EADDRNOTAVAIL; |
---|
475 | goto out; |
---|
476 | } |
---|
477 | /* FALLTHROUGH */ |
---|
478 | case SIOCAIFADDR_IN6: |
---|
479 | /* |
---|
480 | * We always require users to specify a valid IPv6 address for |
---|
481 | * the corresponding operation. |
---|
482 | */ |
---|
483 | if (ifra->ifra_addr.sin6_family != AF_INET6 || |
---|
484 | ifra->ifra_addr.sin6_len != sizeof(struct sockaddr_in6)) { |
---|
485 | error = EAFNOSUPPORT; |
---|
486 | goto out; |
---|
487 | } |
---|
488 | |
---|
489 | if (td != NULL) { |
---|
490 | error = priv_check(td, (cmd == SIOCDIFADDR_IN6) ? |
---|
491 | PRIV_NET_DELIFADDR : PRIV_NET_ADDIFADDR); |
---|
492 | if (error) |
---|
493 | goto out; |
---|
494 | } |
---|
495 | /* FALLTHROUGH */ |
---|
496 | case SIOCGIFSTAT_IN6: |
---|
497 | case SIOCGIFSTAT_ICMP6: |
---|
498 | if (ifp->if_afdata[AF_INET6] == NULL) { |
---|
499 | error = EPFNOSUPPORT; |
---|
500 | goto out; |
---|
501 | } |
---|
502 | break; |
---|
503 | |
---|
504 | case SIOCGIFADDR_IN6: |
---|
505 | /* This interface is basically deprecated. use SIOCGIFCONF. */ |
---|
506 | /* FALLTHROUGH */ |
---|
507 | case SIOCGIFAFLAG_IN6: |
---|
508 | case SIOCGIFNETMASK_IN6: |
---|
509 | case SIOCGIFDSTADDR_IN6: |
---|
510 | case SIOCGIFALIFETIME_IN6: |
---|
511 | /* must think again about its semantics */ |
---|
512 | if (ia == NULL) { |
---|
513 | error = EADDRNOTAVAIL; |
---|
514 | goto out; |
---|
515 | } |
---|
516 | break; |
---|
517 | |
---|
518 | case SIOCSIFALIFETIME_IN6: |
---|
519 | { |
---|
520 | struct in6_addrlifetime *lt; |
---|
521 | |
---|
522 | if (td != NULL) { |
---|
523 | error = priv_check(td, PRIV_NETINET_ALIFETIME6); |
---|
524 | if (error) |
---|
525 | goto out; |
---|
526 | } |
---|
527 | if (ia == NULL) { |
---|
528 | error = EADDRNOTAVAIL; |
---|
529 | goto out; |
---|
530 | } |
---|
531 | /* sanity for overflow - beware unsigned */ |
---|
532 | lt = &ifr->ifr_ifru.ifru_lifetime; |
---|
533 | if (lt->ia6t_vltime != ND6_INFINITE_LIFETIME && |
---|
534 | lt->ia6t_vltime + time_second < time_second) { |
---|
535 | error = EINVAL; |
---|
536 | goto out; |
---|
537 | } |
---|
538 | if (lt->ia6t_pltime != ND6_INFINITE_LIFETIME && |
---|
539 | lt->ia6t_pltime + time_second < time_second) { |
---|
540 | error = EINVAL; |
---|
541 | goto out; |
---|
542 | } |
---|
543 | break; |
---|
544 | } |
---|
545 | } |
---|
546 | |
---|
547 | switch (cmd) { |
---|
548 | case SIOCGIFADDR_IN6: |
---|
549 | ifr->ifr_addr = ia->ia_addr; |
---|
550 | if ((error = sa6_recoverscope(&ifr->ifr_addr)) != 0) |
---|
551 | goto out; |
---|
552 | break; |
---|
553 | |
---|
554 | case SIOCGIFDSTADDR_IN6: |
---|
555 | if ((ifp->if_flags & IFF_POINTOPOINT) == 0) { |
---|
556 | error = EINVAL; |
---|
557 | goto out; |
---|
558 | } |
---|
559 | /* |
---|
560 | * XXX: should we check if ifa_dstaddr is NULL and return |
---|
561 | * an error? |
---|
562 | */ |
---|
563 | ifr->ifr_dstaddr = ia->ia_dstaddr; |
---|
564 | if ((error = sa6_recoverscope(&ifr->ifr_dstaddr)) != 0) |
---|
565 | goto out; |
---|
566 | break; |
---|
567 | |
---|
568 | case SIOCGIFNETMASK_IN6: |
---|
569 | ifr->ifr_addr = ia->ia_prefixmask; |
---|
570 | break; |
---|
571 | |
---|
572 | case SIOCGIFAFLAG_IN6: |
---|
573 | ifr->ifr_ifru.ifru_flags6 = ia->ia6_flags; |
---|
574 | break; |
---|
575 | |
---|
576 | case SIOCGIFSTAT_IN6: |
---|
577 | bzero(&ifr->ifr_ifru.ifru_stat, |
---|
578 | sizeof(ifr->ifr_ifru.ifru_stat)); |
---|
579 | ifr->ifr_ifru.ifru_stat = |
---|
580 | *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->in6_ifstat; |
---|
581 | break; |
---|
582 | |
---|
583 | case SIOCGIFSTAT_ICMP6: |
---|
584 | bzero(&ifr->ifr_ifru.ifru_icmp6stat, |
---|
585 | sizeof(ifr->ifr_ifru.ifru_icmp6stat)); |
---|
586 | ifr->ifr_ifru.ifru_icmp6stat = |
---|
587 | *((struct in6_ifextra *)ifp->if_afdata[AF_INET6])->icmp6_ifstat; |
---|
588 | break; |
---|
589 | |
---|
590 | case SIOCGIFALIFETIME_IN6: |
---|
591 | ifr->ifr_ifru.ifru_lifetime = ia->ia6_lifetime; |
---|
592 | if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { |
---|
593 | time_t maxexpire; |
---|
594 | struct in6_addrlifetime *retlt = |
---|
595 | &ifr->ifr_ifru.ifru_lifetime; |
---|
596 | |
---|
597 | /* |
---|
598 | * XXX: adjust expiration time assuming time_t is |
---|
599 | * signed. |
---|
600 | */ |
---|
601 | maxexpire = (-1) & |
---|
602 | ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); |
---|
603 | if (ia->ia6_lifetime.ia6t_vltime < |
---|
604 | maxexpire - ia->ia6_updatetime) { |
---|
605 | retlt->ia6t_expire = ia->ia6_updatetime + |
---|
606 | ia->ia6_lifetime.ia6t_vltime; |
---|
607 | } else |
---|
608 | retlt->ia6t_expire = maxexpire; |
---|
609 | } |
---|
610 | if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { |
---|
611 | time_t maxexpire; |
---|
612 | struct in6_addrlifetime *retlt = |
---|
613 | &ifr->ifr_ifru.ifru_lifetime; |
---|
614 | |
---|
615 | /* |
---|
616 | * XXX: adjust expiration time assuming time_t is |
---|
617 | * signed. |
---|
618 | */ |
---|
619 | maxexpire = (-1) & |
---|
620 | ~((time_t)1 << ((sizeof(maxexpire) * 8) - 1)); |
---|
621 | if (ia->ia6_lifetime.ia6t_pltime < |
---|
622 | maxexpire - ia->ia6_updatetime) { |
---|
623 | retlt->ia6t_preferred = ia->ia6_updatetime + |
---|
624 | ia->ia6_lifetime.ia6t_pltime; |
---|
625 | } else |
---|
626 | retlt->ia6t_preferred = maxexpire; |
---|
627 | } |
---|
628 | break; |
---|
629 | |
---|
630 | case SIOCSIFALIFETIME_IN6: |
---|
631 | ia->ia6_lifetime = ifr->ifr_ifru.ifru_lifetime; |
---|
632 | /* for sanity */ |
---|
633 | if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { |
---|
634 | ia->ia6_lifetime.ia6t_expire = |
---|
635 | time_second + ia->ia6_lifetime.ia6t_vltime; |
---|
636 | } else |
---|
637 | ia->ia6_lifetime.ia6t_expire = 0; |
---|
638 | if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { |
---|
639 | ia->ia6_lifetime.ia6t_preferred = |
---|
640 | time_second + ia->ia6_lifetime.ia6t_pltime; |
---|
641 | } else |
---|
642 | ia->ia6_lifetime.ia6t_preferred = 0; |
---|
643 | break; |
---|
644 | |
---|
645 | case SIOCAIFADDR_IN6: |
---|
646 | { |
---|
647 | int i; |
---|
648 | struct nd_prefixctl pr0; |
---|
649 | struct nd_prefix *pr; |
---|
650 | |
---|
651 | /* |
---|
652 | * first, make or update the interface address structure, |
---|
653 | * and link it to the list. |
---|
654 | */ |
---|
655 | if ((error = in6_update_ifa(ifp, ifra, ia, 0)) != 0) |
---|
656 | goto out; |
---|
657 | if (ia != NULL) |
---|
658 | ifa_free(&ia->ia_ifa); |
---|
659 | if ((ia = in6ifa_ifpwithaddr(ifp, &ifra->ifra_addr.sin6_addr)) |
---|
660 | == NULL) { |
---|
661 | /* |
---|
662 | * this can happen when the user specify the 0 valid |
---|
663 | * lifetime. |
---|
664 | */ |
---|
665 | break; |
---|
666 | } |
---|
667 | |
---|
668 | /* |
---|
669 | * then, make the prefix on-link on the interface. |
---|
670 | * XXX: we'd rather create the prefix before the address, but |
---|
671 | * we need at least one address to install the corresponding |
---|
672 | * interface route, so we configure the address first. |
---|
673 | */ |
---|
674 | |
---|
675 | /* |
---|
676 | * convert mask to prefix length (prefixmask has already |
---|
677 | * been validated in in6_update_ifa(). |
---|
678 | */ |
---|
679 | bzero(&pr0, sizeof(pr0)); |
---|
680 | pr0.ndpr_ifp = ifp; |
---|
681 | pr0.ndpr_plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, |
---|
682 | NULL); |
---|
683 | if (pr0.ndpr_plen == 128) { |
---|
684 | break; /* we don't need to install a host route. */ |
---|
685 | } |
---|
686 | pr0.ndpr_prefix = ifra->ifra_addr; |
---|
687 | /* apply the mask for safety. */ |
---|
688 | for (i = 0; i < 4; i++) { |
---|
689 | pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= |
---|
690 | ifra->ifra_prefixmask.sin6_addr.s6_addr32[i]; |
---|
691 | } |
---|
692 | /* |
---|
693 | * XXX: since we don't have an API to set prefix (not address) |
---|
694 | * lifetimes, we just use the same lifetimes as addresses. |
---|
695 | * The (temporarily) installed lifetimes can be overridden by |
---|
696 | * later advertised RAs (when accept_rtadv is non 0), which is |
---|
697 | * an intended behavior. |
---|
698 | */ |
---|
699 | pr0.ndpr_raf_onlink = 1; /* should be configurable? */ |
---|
700 | pr0.ndpr_raf_auto = |
---|
701 | ((ifra->ifra_flags & IN6_IFF_AUTOCONF) != 0); |
---|
702 | pr0.ndpr_vltime = ifra->ifra_lifetime.ia6t_vltime; |
---|
703 | pr0.ndpr_pltime = ifra->ifra_lifetime.ia6t_pltime; |
---|
704 | |
---|
705 | /* add the prefix if not yet. */ |
---|
706 | if ((pr = nd6_prefix_lookup(&pr0)) == NULL) { |
---|
707 | /* |
---|
708 | * nd6_prelist_add will install the corresponding |
---|
709 | * interface route. |
---|
710 | */ |
---|
711 | if ((error = nd6_prelist_add(&pr0, NULL, &pr)) != 0) |
---|
712 | goto out; |
---|
713 | if (pr == NULL) { |
---|
714 | log(LOG_ERR, "nd6_prelist_add succeeded but " |
---|
715 | "no prefix\n"); |
---|
716 | error = EINVAL; |
---|
717 | goto out; |
---|
718 | } |
---|
719 | } |
---|
720 | |
---|
721 | /* relate the address to the prefix */ |
---|
722 | if (ia->ia6_ndpr == NULL) { |
---|
723 | ia->ia6_ndpr = pr; |
---|
724 | pr->ndpr_refcnt++; |
---|
725 | |
---|
726 | /* |
---|
727 | * If this is the first autoconf address from the |
---|
728 | * prefix, create a temporary address as well |
---|
729 | * (when required). |
---|
730 | */ |
---|
731 | if ((ia->ia6_flags & IN6_IFF_AUTOCONF) && |
---|
732 | V_ip6_use_tempaddr && pr->ndpr_refcnt == 1) { |
---|
733 | int e; |
---|
734 | if ((e = in6_tmpifadd(ia, 1, 0)) != 0) { |
---|
735 | log(LOG_NOTICE, "in6_control: failed " |
---|
736 | "to create a temporary address, " |
---|
737 | "errno=%d\n", e); |
---|
738 | } |
---|
739 | } |
---|
740 | } |
---|
741 | |
---|
742 | /* |
---|
743 | * this might affect the status of autoconfigured addresses, |
---|
744 | * that is, this address might make other addresses detached. |
---|
745 | */ |
---|
746 | pfxlist_onlink_check(); |
---|
747 | if (error == 0 && ia) { |
---|
748 | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) { |
---|
749 | /* |
---|
750 | * Try to clear the flag when a new |
---|
751 | * IPv6 address is added onto an |
---|
752 | * IFDISABLED interface and it |
---|
753 | * succeeds. |
---|
754 | */ |
---|
755 | struct in6_ndireq nd; |
---|
756 | |
---|
757 | memset(&nd, 0, sizeof(nd)); |
---|
758 | nd.ndi.flags = ND_IFINFO(ifp)->flags; |
---|
759 | nd.ndi.flags &= ~ND6_IFF_IFDISABLED; |
---|
760 | if (nd6_ioctl(SIOCSIFINFO_FLAGS, |
---|
761 | (caddr_t)&nd, ifp) < 0) |
---|
762 | log(LOG_NOTICE, "SIOCAIFADDR_IN6: " |
---|
763 | "SIOCSIFINFO_FLAGS for -ifdisabled " |
---|
764 | "failed."); |
---|
765 | /* |
---|
766 | * Ignore failure of clearing the flag |
---|
767 | * intentionally. The failure means |
---|
768 | * address duplication was detected. |
---|
769 | */ |
---|
770 | } |
---|
771 | EVENTHANDLER_INVOKE(ifaddr_event, ifp); |
---|
772 | } |
---|
773 | break; |
---|
774 | } |
---|
775 | |
---|
776 | case SIOCDIFADDR_IN6: |
---|
777 | { |
---|
778 | struct nd_prefix *pr; |
---|
779 | |
---|
780 | /* |
---|
781 | * If the address being deleted is the only one that owns |
---|
782 | * the corresponding prefix, expire the prefix as well. |
---|
783 | * XXX: theoretically, we don't have to worry about such |
---|
784 | * relationship, since we separate the address management |
---|
785 | * and the prefix management. We do this, however, to provide |
---|
786 | * as much backward compatibility as possible in terms of |
---|
787 | * the ioctl operation. |
---|
788 | * Note that in6_purgeaddr() will decrement ndpr_refcnt. |
---|
789 | */ |
---|
790 | pr = ia->ia6_ndpr; |
---|
791 | in6_purgeaddr(&ia->ia_ifa); |
---|
792 | if (pr && pr->ndpr_refcnt == 0) |
---|
793 | prelist_remove(pr); |
---|
794 | EVENTHANDLER_INVOKE(ifaddr_event, ifp); |
---|
795 | break; |
---|
796 | } |
---|
797 | |
---|
798 | default: |
---|
799 | if (ifp->if_ioctl == NULL) { |
---|
800 | error = EOPNOTSUPP; |
---|
801 | goto out; |
---|
802 | } |
---|
803 | error = (*ifp->if_ioctl)(ifp, cmd, data); |
---|
804 | goto out; |
---|
805 | } |
---|
806 | |
---|
807 | error = 0; |
---|
808 | out: |
---|
809 | if (ia != NULL) |
---|
810 | ifa_free(&ia->ia_ifa); |
---|
811 | return (error); |
---|
812 | } |
---|
813 | |
---|
814 | |
---|
815 | /* |
---|
816 | * Join necessary multicast groups. Factored out from in6_update_ifa(). |
---|
817 | * This entire work should only be done once, for the default FIB. |
---|
818 | */ |
---|
819 | static int |
---|
820 | in6_update_ifa_join_mc(struct ifnet *ifp, struct in6_aliasreq *ifra, |
---|
821 | struct in6_ifaddr *ia, int flags, struct in6_multi **in6m_sol) |
---|
822 | { |
---|
823 | char ip6buf[INET6_ADDRSTRLEN]; |
---|
824 | struct sockaddr_in6 mltaddr, mltmask; |
---|
825 | struct in6_addr llsol; |
---|
826 | struct in6_multi_mship *imm; |
---|
827 | struct rtentry *rt; |
---|
828 | int delay, error; |
---|
829 | |
---|
830 | KASSERT(in6m_sol != NULL, ("%s: in6m_sol is NULL", __func__)); |
---|
831 | |
---|
832 | /* Join solicited multicast addr for new host id. */ |
---|
833 | bzero(&llsol, sizeof(struct in6_addr)); |
---|
834 | llsol.s6_addr32[0] = IPV6_ADDR_INT32_MLL; |
---|
835 | llsol.s6_addr32[1] = 0; |
---|
836 | llsol.s6_addr32[2] = htonl(1); |
---|
837 | llsol.s6_addr32[3] = ifra->ifra_addr.sin6_addr.s6_addr32[3]; |
---|
838 | llsol.s6_addr8[12] = 0xff; |
---|
839 | if ((error = in6_setscope(&llsol, ifp, NULL)) != 0) { |
---|
840 | /* XXX: should not happen */ |
---|
841 | log(LOG_ERR, "%s: in6_setscope failed\n", __func__); |
---|
842 | goto cleanup; |
---|
843 | } |
---|
844 | delay = 0; |
---|
845 | if ((flags & IN6_IFAUPDATE_DADDELAY)) { |
---|
846 | /* |
---|
847 | * We need a random delay for DAD on the address being |
---|
848 | * configured. It also means delaying transmission of the |
---|
849 | * corresponding MLD report to avoid report collision. |
---|
850 | * [RFC 4861, Section 6.3.7] |
---|
851 | */ |
---|
852 | delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); |
---|
853 | } |
---|
854 | imm = in6_joingroup(ifp, &llsol, &error, delay); |
---|
855 | if (imm == NULL) { |
---|
856 | nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " |
---|
857 | "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, &llsol), |
---|
858 | if_name(ifp), error)); |
---|
859 | goto cleanup; |
---|
860 | } |
---|
861 | LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); |
---|
862 | *in6m_sol = imm->i6mm_maddr; |
---|
863 | |
---|
864 | bzero(&mltmask, sizeof(mltmask)); |
---|
865 | mltmask.sin6_len = sizeof(struct sockaddr_in6); |
---|
866 | mltmask.sin6_family = AF_INET6; |
---|
867 | mltmask.sin6_addr = in6mask32; |
---|
868 | #define MLTMASK_LEN 4 /* mltmask's masklen (=32bit=4octet) */ |
---|
869 | |
---|
870 | /* |
---|
871 | * Join link-local all-nodes address. |
---|
872 | */ |
---|
873 | bzero(&mltaddr, sizeof(mltaddr)); |
---|
874 | mltaddr.sin6_len = sizeof(struct sockaddr_in6); |
---|
875 | mltaddr.sin6_family = AF_INET6; |
---|
876 | mltaddr.sin6_addr = in6addr_linklocal_allnodes; |
---|
877 | if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) |
---|
878 | goto cleanup; /* XXX: should not fail */ |
---|
879 | |
---|
880 | /* |
---|
881 | * XXX: do we really need this automatic routes? We should probably |
---|
882 | * reconsider this stuff. Most applications actually do not need the |
---|
883 | * routes, since they usually specify the outgoing interface. |
---|
884 | */ |
---|
885 | rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); |
---|
886 | if (rt != NULL) { |
---|
887 | /* XXX: only works in !SCOPEDROUTING case. */ |
---|
888 | if (memcmp(&mltaddr.sin6_addr, |
---|
889 | &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, |
---|
890 | MLTMASK_LEN)) { |
---|
891 | RTFREE_LOCKED(rt); |
---|
892 | rt = NULL; |
---|
893 | } |
---|
894 | } |
---|
895 | if (rt == NULL) { |
---|
896 | error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, |
---|
897 | (struct sockaddr *)&ia->ia_addr, |
---|
898 | (struct sockaddr *)&mltmask, RTF_UP, |
---|
899 | (struct rtentry **)0, RT_DEFAULT_FIB); |
---|
900 | if (error) |
---|
901 | goto cleanup; |
---|
902 | } else |
---|
903 | RTFREE_LOCKED(rt); |
---|
904 | |
---|
905 | imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); |
---|
906 | if (imm == NULL) { |
---|
907 | nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " |
---|
908 | "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, |
---|
909 | &mltaddr.sin6_addr), if_name(ifp), error)); |
---|
910 | goto cleanup; |
---|
911 | } |
---|
912 | LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); |
---|
913 | |
---|
914 | /* |
---|
915 | * Join node information group address. |
---|
916 | */ |
---|
917 | delay = 0; |
---|
918 | if ((flags & IN6_IFAUPDATE_DADDELAY)) { |
---|
919 | /* |
---|
920 | * The spec does not say anything about delay for this group, |
---|
921 | * but the same logic should apply. |
---|
922 | */ |
---|
923 | delay = arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz); |
---|
924 | } |
---|
925 | if (in6_nigroup(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { |
---|
926 | /* XXX jinmei */ |
---|
927 | imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); |
---|
928 | if (imm == NULL) |
---|
929 | nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " |
---|
930 | "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, |
---|
931 | &mltaddr.sin6_addr), if_name(ifp), error)); |
---|
932 | /* XXX not very fatal, go on... */ |
---|
933 | else |
---|
934 | LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); |
---|
935 | } |
---|
936 | if (V_icmp6_nodeinfo_oldmcprefix && |
---|
937 | in6_nigroup_oldmcprefix(ifp, NULL, -1, &mltaddr.sin6_addr) == 0) { |
---|
938 | imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, delay); |
---|
939 | if (imm == NULL) |
---|
940 | nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " |
---|
941 | "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, |
---|
942 | &mltaddr.sin6_addr), if_name(ifp), error)); |
---|
943 | /* XXX not very fatal, go on... */ |
---|
944 | else |
---|
945 | LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); |
---|
946 | } |
---|
947 | |
---|
948 | /* |
---|
949 | * Join interface-local all-nodes address. |
---|
950 | * (ff01::1%ifN, and ff01::%ifN/32) |
---|
951 | */ |
---|
952 | mltaddr.sin6_addr = in6addr_nodelocal_allnodes; |
---|
953 | if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) |
---|
954 | goto cleanup; /* XXX: should not fail */ |
---|
955 | /* XXX: again, do we really need the route? */ |
---|
956 | rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); |
---|
957 | if (rt != NULL) { |
---|
958 | if (memcmp(&mltaddr.sin6_addr, |
---|
959 | &((struct sockaddr_in6 *)rt_key(rt))->sin6_addr, |
---|
960 | MLTMASK_LEN)) { |
---|
961 | RTFREE_LOCKED(rt); |
---|
962 | rt = NULL; |
---|
963 | } |
---|
964 | } |
---|
965 | if (rt == NULL) { |
---|
966 | error = in6_rtrequest(RTM_ADD, (struct sockaddr *)&mltaddr, |
---|
967 | (struct sockaddr *)&ia->ia_addr, |
---|
968 | (struct sockaddr *)&mltmask, RTF_UP, |
---|
969 | (struct rtentry **)0, RT_DEFAULT_FIB); |
---|
970 | if (error) |
---|
971 | goto cleanup; |
---|
972 | } else |
---|
973 | RTFREE_LOCKED(rt); |
---|
974 | |
---|
975 | imm = in6_joingroup(ifp, &mltaddr.sin6_addr, &error, 0); |
---|
976 | if (imm == NULL) { |
---|
977 | nd6log((LOG_WARNING, "%s: addmulti failed for %s on %s " |
---|
978 | "(errno=%d)\n", __func__, ip6_sprintf(ip6buf, |
---|
979 | &mltaddr.sin6_addr), if_name(ifp), error)); |
---|
980 | goto cleanup; |
---|
981 | } |
---|
982 | LIST_INSERT_HEAD(&ia->ia6_memberships, imm, i6mm_chain); |
---|
983 | #undef MLTMASK_LEN |
---|
984 | |
---|
985 | cleanup: |
---|
986 | return (error); |
---|
987 | } |
---|
988 | |
---|
989 | /* |
---|
990 | * Update parameters of an IPv6 interface address. |
---|
991 | * If necessary, a new entry is created and linked into address chains. |
---|
992 | * This function is separated from in6_control(). |
---|
993 | * XXX: should this be performed under splnet()? |
---|
994 | */ |
---|
995 | int |
---|
996 | in6_update_ifa(struct ifnet *ifp, struct in6_aliasreq *ifra, |
---|
997 | struct in6_ifaddr *ia, int flags) |
---|
998 | { |
---|
999 | int error = 0, hostIsNew = 0, plen = -1; |
---|
1000 | struct sockaddr_in6 dst6; |
---|
1001 | struct in6_addrlifetime *lt; |
---|
1002 | struct in6_multi *in6m_sol; |
---|
1003 | int delay; |
---|
1004 | char ip6buf[INET6_ADDRSTRLEN]; |
---|
1005 | |
---|
1006 | /* Validate parameters */ |
---|
1007 | if (ifp == NULL || ifra == NULL) /* this maybe redundant */ |
---|
1008 | return (EINVAL); |
---|
1009 | |
---|
1010 | /* |
---|
1011 | * The destination address for a p2p link must have a family |
---|
1012 | * of AF_UNSPEC or AF_INET6. |
---|
1013 | */ |
---|
1014 | if ((ifp->if_flags & IFF_POINTOPOINT) != 0 && |
---|
1015 | ifra->ifra_dstaddr.sin6_family != AF_INET6 && |
---|
1016 | ifra->ifra_dstaddr.sin6_family != AF_UNSPEC) |
---|
1017 | return (EAFNOSUPPORT); |
---|
1018 | /* |
---|
1019 | * validate ifra_prefixmask. don't check sin6_family, netmask |
---|
1020 | * does not carry fields other than sin6_len. |
---|
1021 | */ |
---|
1022 | if (ifra->ifra_prefixmask.sin6_len > sizeof(struct sockaddr_in6)) |
---|
1023 | return (EINVAL); |
---|
1024 | /* |
---|
1025 | * Because the IPv6 address architecture is classless, we require |
---|
1026 | * users to specify a (non 0) prefix length (mask) for a new address. |
---|
1027 | * We also require the prefix (when specified) mask is valid, and thus |
---|
1028 | * reject a non-consecutive mask. |
---|
1029 | */ |
---|
1030 | if (ia == NULL && ifra->ifra_prefixmask.sin6_len == 0) |
---|
1031 | return (EINVAL); |
---|
1032 | if (ifra->ifra_prefixmask.sin6_len != 0) { |
---|
1033 | plen = in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, |
---|
1034 | (u_char *)&ifra->ifra_prefixmask + |
---|
1035 | ifra->ifra_prefixmask.sin6_len); |
---|
1036 | if (plen <= 0) |
---|
1037 | return (EINVAL); |
---|
1038 | } else { |
---|
1039 | /* |
---|
1040 | * In this case, ia must not be NULL. We just use its prefix |
---|
1041 | * length. |
---|
1042 | */ |
---|
1043 | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); |
---|
1044 | } |
---|
1045 | /* |
---|
1046 | * If the destination address on a p2p interface is specified, |
---|
1047 | * and the address is a scoped one, validate/set the scope |
---|
1048 | * zone identifier. |
---|
1049 | */ |
---|
1050 | dst6 = ifra->ifra_dstaddr; |
---|
1051 | if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) != 0 && |
---|
1052 | (dst6.sin6_family == AF_INET6)) { |
---|
1053 | struct in6_addr in6_tmp; |
---|
1054 | u_int32_t zoneid; |
---|
1055 | |
---|
1056 | in6_tmp = dst6.sin6_addr; |
---|
1057 | if (in6_setscope(&in6_tmp, ifp, &zoneid)) |
---|
1058 | return (EINVAL); /* XXX: should be impossible */ |
---|
1059 | |
---|
1060 | if (dst6.sin6_scope_id != 0) { |
---|
1061 | if (dst6.sin6_scope_id != zoneid) |
---|
1062 | return (EINVAL); |
---|
1063 | } else /* user omit to specify the ID. */ |
---|
1064 | dst6.sin6_scope_id = zoneid; |
---|
1065 | |
---|
1066 | /* convert into the internal form */ |
---|
1067 | if (sa6_embedscope(&dst6, 0)) |
---|
1068 | return (EINVAL); /* XXX: should be impossible */ |
---|
1069 | } |
---|
1070 | /* |
---|
1071 | * The destination address can be specified only for a p2p or a |
---|
1072 | * loopback interface. If specified, the corresponding prefix length |
---|
1073 | * must be 128. |
---|
1074 | */ |
---|
1075 | if (ifra->ifra_dstaddr.sin6_family == AF_INET6) { |
---|
1076 | if ((ifp->if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK)) == 0) { |
---|
1077 | /* XXX: noisy message */ |
---|
1078 | nd6log((LOG_INFO, "in6_update_ifa: a destination can " |
---|
1079 | "be specified for a p2p or a loopback IF only\n")); |
---|
1080 | return (EINVAL); |
---|
1081 | } |
---|
1082 | if (plen != 128) { |
---|
1083 | nd6log((LOG_INFO, "in6_update_ifa: prefixlen should " |
---|
1084 | "be 128 when dstaddr is specified\n")); |
---|
1085 | return (EINVAL); |
---|
1086 | } |
---|
1087 | } |
---|
1088 | /* lifetime consistency check */ |
---|
1089 | lt = &ifra->ifra_lifetime; |
---|
1090 | if (lt->ia6t_pltime > lt->ia6t_vltime) |
---|
1091 | return (EINVAL); |
---|
1092 | if (lt->ia6t_vltime == 0) { |
---|
1093 | /* |
---|
1094 | * the following log might be noisy, but this is a typical |
---|
1095 | * configuration mistake or a tool's bug. |
---|
1096 | */ |
---|
1097 | nd6log((LOG_INFO, |
---|
1098 | "in6_update_ifa: valid lifetime is 0 for %s\n", |
---|
1099 | ip6_sprintf(ip6buf, &ifra->ifra_addr.sin6_addr))); |
---|
1100 | |
---|
1101 | if (ia == NULL) |
---|
1102 | return (0); /* there's nothing to do */ |
---|
1103 | } |
---|
1104 | |
---|
1105 | /* |
---|
1106 | * If this is a new address, allocate a new ifaddr and link it |
---|
1107 | * into chains. |
---|
1108 | */ |
---|
1109 | if (ia == NULL) { |
---|
1110 | hostIsNew = 1; |
---|
1111 | /* |
---|
1112 | * When in6_update_ifa() is called in a process of a received |
---|
1113 | * RA, it is called under an interrupt context. So, we should |
---|
1114 | * call malloc with M_NOWAIT. |
---|
1115 | */ |
---|
1116 | ia = (struct in6_ifaddr *) malloc(sizeof(*ia), M_IFADDR, |
---|
1117 | M_NOWAIT); |
---|
1118 | if (ia == NULL) |
---|
1119 | return (ENOBUFS); |
---|
1120 | bzero((caddr_t)ia, sizeof(*ia)); |
---|
1121 | ifa_init(&ia->ia_ifa); |
---|
1122 | LIST_INIT(&ia->ia6_memberships); |
---|
1123 | /* Initialize the address and masks, and put time stamp */ |
---|
1124 | ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr; |
---|
1125 | ia->ia_addr.sin6_family = AF_INET6; |
---|
1126 | ia->ia_addr.sin6_len = sizeof(ia->ia_addr); |
---|
1127 | ia->ia6_createtime = time_second; |
---|
1128 | if ((ifp->if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) != 0) { |
---|
1129 | /* |
---|
1130 | * XXX: some functions expect that ifa_dstaddr is not |
---|
1131 | * NULL for p2p interfaces. |
---|
1132 | */ |
---|
1133 | ia->ia_ifa.ifa_dstaddr = |
---|
1134 | (struct sockaddr *)&ia->ia_dstaddr; |
---|
1135 | } else { |
---|
1136 | ia->ia_ifa.ifa_dstaddr = NULL; |
---|
1137 | } |
---|
1138 | ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask; |
---|
1139 | ia->ia_ifp = ifp; |
---|
1140 | ifa_ref(&ia->ia_ifa); /* if_addrhead */ |
---|
1141 | IF_ADDR_WLOCK(ifp); |
---|
1142 | TAILQ_INSERT_TAIL(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); |
---|
1143 | IF_ADDR_WUNLOCK(ifp); |
---|
1144 | |
---|
1145 | ifa_ref(&ia->ia_ifa); /* in6_ifaddrhead */ |
---|
1146 | IN6_IFADDR_WLOCK(); |
---|
1147 | TAILQ_INSERT_TAIL(&V_in6_ifaddrhead, ia, ia_link); |
---|
1148 | IN6_IFADDR_WUNLOCK(); |
---|
1149 | } |
---|
1150 | |
---|
1151 | /* update timestamp */ |
---|
1152 | ia->ia6_updatetime = time_second; |
---|
1153 | |
---|
1154 | /* set prefix mask */ |
---|
1155 | if (ifra->ifra_prefixmask.sin6_len) { |
---|
1156 | /* |
---|
1157 | * We prohibit changing the prefix length of an existing |
---|
1158 | * address, because |
---|
1159 | * + such an operation should be rare in IPv6, and |
---|
1160 | * + the operation would confuse prefix management. |
---|
1161 | */ |
---|
1162 | if (ia->ia_prefixmask.sin6_len && |
---|
1163 | in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL) != plen) { |
---|
1164 | nd6log((LOG_INFO, "in6_update_ifa: the prefix length of an" |
---|
1165 | " existing (%s) address should not be changed\n", |
---|
1166 | ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); |
---|
1167 | error = EINVAL; |
---|
1168 | goto unlink; |
---|
1169 | } |
---|
1170 | ia->ia_prefixmask = ifra->ifra_prefixmask; |
---|
1171 | } |
---|
1172 | |
---|
1173 | /* |
---|
1174 | * If a new destination address is specified, scrub the old one and |
---|
1175 | * install the new destination. Note that the interface must be |
---|
1176 | * p2p or loopback (see the check above.) |
---|
1177 | */ |
---|
1178 | if (dst6.sin6_family == AF_INET6 && |
---|
1179 | !IN6_ARE_ADDR_EQUAL(&dst6.sin6_addr, &ia->ia_dstaddr.sin6_addr)) { |
---|
1180 | int e; |
---|
1181 | |
---|
1182 | if ((ia->ia_flags & IFA_ROUTE) != 0 && |
---|
1183 | (e = rtinit(&(ia->ia_ifa), (int)RTM_DELETE, RTF_HOST)) != 0) { |
---|
1184 | nd6log((LOG_ERR, "in6_update_ifa: failed to remove " |
---|
1185 | "a route to the old destination: %s\n", |
---|
1186 | ip6_sprintf(ip6buf, &ia->ia_addr.sin6_addr))); |
---|
1187 | /* proceed anyway... */ |
---|
1188 | } else |
---|
1189 | ia->ia_flags &= ~IFA_ROUTE; |
---|
1190 | ia->ia_dstaddr = dst6; |
---|
1191 | } |
---|
1192 | |
---|
1193 | /* |
---|
1194 | * Set lifetimes. We do not refer to ia6t_expire and ia6t_preferred |
---|
1195 | * to see if the address is deprecated or invalidated, but initialize |
---|
1196 | * these members for applications. |
---|
1197 | */ |
---|
1198 | ia->ia6_lifetime = ifra->ifra_lifetime; |
---|
1199 | if (ia->ia6_lifetime.ia6t_vltime != ND6_INFINITE_LIFETIME) { |
---|
1200 | ia->ia6_lifetime.ia6t_expire = |
---|
1201 | time_second + ia->ia6_lifetime.ia6t_vltime; |
---|
1202 | } else |
---|
1203 | ia->ia6_lifetime.ia6t_expire = 0; |
---|
1204 | if (ia->ia6_lifetime.ia6t_pltime != ND6_INFINITE_LIFETIME) { |
---|
1205 | ia->ia6_lifetime.ia6t_preferred = |
---|
1206 | time_second + ia->ia6_lifetime.ia6t_pltime; |
---|
1207 | } else |
---|
1208 | ia->ia6_lifetime.ia6t_preferred = 0; |
---|
1209 | |
---|
1210 | /* reset the interface and routing table appropriately. */ |
---|
1211 | if ((error = in6_ifinit(ifp, ia, &ifra->ifra_addr, hostIsNew)) != 0) |
---|
1212 | goto unlink; |
---|
1213 | |
---|
1214 | /* |
---|
1215 | * configure address flags. |
---|
1216 | */ |
---|
1217 | ia->ia6_flags = ifra->ifra_flags; |
---|
1218 | /* |
---|
1219 | * backward compatibility - if IN6_IFF_DEPRECATED is set from the |
---|
1220 | * userland, make it deprecated. |
---|
1221 | */ |
---|
1222 | if ((ifra->ifra_flags & IN6_IFF_DEPRECATED) != 0) { |
---|
1223 | ia->ia6_lifetime.ia6t_pltime = 0; |
---|
1224 | ia->ia6_lifetime.ia6t_preferred = time_second; |
---|
1225 | } |
---|
1226 | /* |
---|
1227 | * Make the address tentative before joining multicast addresses, |
---|
1228 | * so that corresponding MLD responses would not have a tentative |
---|
1229 | * source address. |
---|
1230 | */ |
---|
1231 | ia->ia6_flags &= ~IN6_IFF_DUPLICATED; /* safety */ |
---|
1232 | if (hostIsNew && in6if_do_dad(ifp)) |
---|
1233 | ia->ia6_flags |= IN6_IFF_TENTATIVE; |
---|
1234 | |
---|
1235 | /* DAD should be performed after ND6_IFF_IFDISABLED is cleared. */ |
---|
1236 | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) |
---|
1237 | ia->ia6_flags |= IN6_IFF_TENTATIVE; |
---|
1238 | |
---|
1239 | /* |
---|
1240 | * We are done if we have simply modified an existing address. |
---|
1241 | */ |
---|
1242 | if (!hostIsNew) |
---|
1243 | return (error); |
---|
1244 | |
---|
1245 | /* |
---|
1246 | * Beyond this point, we should call in6_purgeaddr upon an error, |
---|
1247 | * not just go to unlink. |
---|
1248 | */ |
---|
1249 | |
---|
1250 | /* Join necessary multicast groups. */ |
---|
1251 | in6m_sol = NULL; |
---|
1252 | if ((ifp->if_flags & IFF_MULTICAST) != 0) { |
---|
1253 | error = in6_update_ifa_join_mc(ifp, ifra, ia, flags, &in6m_sol); |
---|
1254 | if (error) |
---|
1255 | goto cleanup; |
---|
1256 | } |
---|
1257 | |
---|
1258 | /* |
---|
1259 | * Perform DAD, if needed. |
---|
1260 | * XXX It may be of use, if we can administratively disable DAD. |
---|
1261 | */ |
---|
1262 | if (in6if_do_dad(ifp) && ((ifra->ifra_flags & IN6_IFF_NODAD) == 0) && |
---|
1263 | (ia->ia6_flags & IN6_IFF_TENTATIVE)) |
---|
1264 | { |
---|
1265 | int mindelay, maxdelay; |
---|
1266 | |
---|
1267 | delay = 0; |
---|
1268 | if ((flags & IN6_IFAUPDATE_DADDELAY)) { |
---|
1269 | /* |
---|
1270 | * We need to impose a delay before sending an NS |
---|
1271 | * for DAD. Check if we also needed a delay for the |
---|
1272 | * corresponding MLD message. If we did, the delay |
---|
1273 | * should be larger than the MLD delay (this could be |
---|
1274 | * relaxed a bit, but this simple logic is at least |
---|
1275 | * safe). |
---|
1276 | * XXX: Break data hiding guidelines and look at |
---|
1277 | * state for the solicited multicast group. |
---|
1278 | */ |
---|
1279 | mindelay = 0; |
---|
1280 | if (in6m_sol != NULL && |
---|
1281 | in6m_sol->in6m_state == MLD_REPORTING_MEMBER) { |
---|
1282 | mindelay = in6m_sol->in6m_timer; |
---|
1283 | } |
---|
1284 | maxdelay = MAX_RTR_SOLICITATION_DELAY * hz; |
---|
1285 | if (maxdelay - mindelay == 0) |
---|
1286 | delay = 0; |
---|
1287 | else { |
---|
1288 | delay = |
---|
1289 | (arc4random() % (maxdelay - mindelay)) + |
---|
1290 | mindelay; |
---|
1291 | } |
---|
1292 | } |
---|
1293 | nd6_dad_start((struct ifaddr *)ia, delay); |
---|
1294 | } |
---|
1295 | |
---|
1296 | KASSERT(hostIsNew, ("in6_update_ifa: !hostIsNew")); |
---|
1297 | ifa_free(&ia->ia_ifa); |
---|
1298 | return (error); |
---|
1299 | |
---|
1300 | unlink: |
---|
1301 | /* |
---|
1302 | * XXX: if a change of an existing address failed, keep the entry |
---|
1303 | * anyway. |
---|
1304 | */ |
---|
1305 | if (hostIsNew) { |
---|
1306 | in6_unlink_ifa(ia, ifp); |
---|
1307 | ifa_free(&ia->ia_ifa); |
---|
1308 | } |
---|
1309 | return (error); |
---|
1310 | |
---|
1311 | cleanup: |
---|
1312 | KASSERT(hostIsNew, ("in6_update_ifa: cleanup: !hostIsNew")); |
---|
1313 | ifa_free(&ia->ia_ifa); |
---|
1314 | in6_purgeaddr(&ia->ia_ifa); |
---|
1315 | return error; |
---|
1316 | } |
---|
1317 | |
---|
1318 | /* |
---|
1319 | * Leave multicast groups. Factored out from in6_purgeaddr(). |
---|
1320 | * This entire work should only be done once, for the default FIB. |
---|
1321 | */ |
---|
1322 | static int |
---|
1323 | in6_purgeaddr_mc(struct ifnet *ifp, struct in6_ifaddr *ia, struct ifaddr *ifa0) |
---|
1324 | { |
---|
1325 | struct sockaddr_in6 mltaddr, mltmask; |
---|
1326 | struct in6_multi_mship *imm; |
---|
1327 | struct rtentry *rt; |
---|
1328 | struct sockaddr_in6 sin6; |
---|
1329 | int error; |
---|
1330 | |
---|
1331 | /* |
---|
1332 | * Leave from multicast groups we have joined for the interface. |
---|
1333 | */ |
---|
1334 | while ((imm = LIST_FIRST(&ia->ia6_memberships)) != NULL) { |
---|
1335 | LIST_REMOVE(imm, i6mm_chain); |
---|
1336 | in6_leavegroup(imm); |
---|
1337 | } |
---|
1338 | |
---|
1339 | /* |
---|
1340 | * Remove the link-local all-nodes address. |
---|
1341 | */ |
---|
1342 | bzero(&mltmask, sizeof(mltmask)); |
---|
1343 | mltmask.sin6_len = sizeof(struct sockaddr_in6); |
---|
1344 | mltmask.sin6_family = AF_INET6; |
---|
1345 | mltmask.sin6_addr = in6mask32; |
---|
1346 | |
---|
1347 | bzero(&mltaddr, sizeof(mltaddr)); |
---|
1348 | mltaddr.sin6_len = sizeof(struct sockaddr_in6); |
---|
1349 | mltaddr.sin6_family = AF_INET6; |
---|
1350 | mltaddr.sin6_addr = in6addr_linklocal_allnodes; |
---|
1351 | |
---|
1352 | if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) |
---|
1353 | return (error); |
---|
1354 | |
---|
1355 | /* |
---|
1356 | * As for the mltaddr above, proactively prepare the sin6 to avoid |
---|
1357 | * rtentry un- and re-locking. |
---|
1358 | */ |
---|
1359 | if (ifa0 != NULL) { |
---|
1360 | bzero(&sin6, sizeof(sin6)); |
---|
1361 | sin6.sin6_len = sizeof(sin6); |
---|
1362 | sin6.sin6_family = AF_INET6; |
---|
1363 | memcpy(&sin6.sin6_addr, &satosin6(ifa0->ifa_addr)->sin6_addr, |
---|
1364 | sizeof(sin6.sin6_addr)); |
---|
1365 | error = in6_setscope(&sin6.sin6_addr, ifa0->ifa_ifp, NULL); |
---|
1366 | if (error != 0) |
---|
1367 | return (error); |
---|
1368 | } |
---|
1369 | |
---|
1370 | rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); |
---|
1371 | if (rt != NULL && rt->rt_gateway != NULL && |
---|
1372 | (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, |
---|
1373 | &ia->ia_addr.sin6_addr, |
---|
1374 | sizeof(ia->ia_addr.sin6_addr)) == 0)) { |
---|
1375 | /* |
---|
1376 | * If no more IPv6 address exists on this interface then |
---|
1377 | * remove the multicast address route. |
---|
1378 | */ |
---|
1379 | if (ifa0 == NULL) { |
---|
1380 | memcpy(&mltaddr.sin6_addr, |
---|
1381 | &satosin6(rt_key(rt))->sin6_addr, |
---|
1382 | sizeof(mltaddr.sin6_addr)); |
---|
1383 | RTFREE_LOCKED(rt); |
---|
1384 | error = in6_rtrequest(RTM_DELETE, |
---|
1385 | (struct sockaddr *)&mltaddr, |
---|
1386 | (struct sockaddr *)&ia->ia_addr, |
---|
1387 | (struct sockaddr *)&mltmask, RTF_UP, |
---|
1388 | (struct rtentry **)0, RT_DEFAULT_FIB); |
---|
1389 | if (error) |
---|
1390 | log(LOG_INFO, "%s: link-local all-nodes " |
---|
1391 | "multicast address deletion error\n", |
---|
1392 | __func__); |
---|
1393 | } else { |
---|
1394 | /* |
---|
1395 | * Replace the gateway of the route. |
---|
1396 | */ |
---|
1397 | memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); |
---|
1398 | RTFREE_LOCKED(rt); |
---|
1399 | } |
---|
1400 | } else { |
---|
1401 | if (rt != NULL) |
---|
1402 | RTFREE_LOCKED(rt); |
---|
1403 | } |
---|
1404 | |
---|
1405 | /* |
---|
1406 | * Remove the node-local all-nodes address. |
---|
1407 | */ |
---|
1408 | mltaddr.sin6_addr = in6addr_nodelocal_allnodes; |
---|
1409 | if ((error = in6_setscope(&mltaddr.sin6_addr, ifp, NULL)) != 0) |
---|
1410 | return (error); |
---|
1411 | |
---|
1412 | rt = in6_rtalloc1((struct sockaddr *)&mltaddr, 0, 0UL, RT_DEFAULT_FIB); |
---|
1413 | if (rt != NULL && rt->rt_gateway != NULL && |
---|
1414 | (memcmp(&satosin6(rt->rt_gateway)->sin6_addr, |
---|
1415 | &ia->ia_addr.sin6_addr, |
---|
1416 | sizeof(ia->ia_addr.sin6_addr)) == 0)) { |
---|
1417 | /* |
---|
1418 | * If no more IPv6 address exists on this interface then |
---|
1419 | * remove the multicast address route. |
---|
1420 | */ |
---|
1421 | if (ifa0 == NULL) { |
---|
1422 | memcpy(&mltaddr.sin6_addr, |
---|
1423 | &satosin6(rt_key(rt))->sin6_addr, |
---|
1424 | sizeof(mltaddr.sin6_addr)); |
---|
1425 | |
---|
1426 | RTFREE_LOCKED(rt); |
---|
1427 | error = in6_rtrequest(RTM_DELETE, |
---|
1428 | (struct sockaddr *)&mltaddr, |
---|
1429 | (struct sockaddr *)&ia->ia_addr, |
---|
1430 | (struct sockaddr *)&mltmask, RTF_UP, |
---|
1431 | (struct rtentry **)0, RT_DEFAULT_FIB); |
---|
1432 | if (error) |
---|
1433 | log(LOG_INFO, "%s: node-local all-nodes" |
---|
1434 | "multicast address deletion error\n", |
---|
1435 | __func__); |
---|
1436 | } else { |
---|
1437 | /* |
---|
1438 | * Replace the gateway of the route. |
---|
1439 | */ |
---|
1440 | memcpy(rt->rt_gateway, &sin6, sizeof(sin6)); |
---|
1441 | RTFREE_LOCKED(rt); |
---|
1442 | } |
---|
1443 | } else { |
---|
1444 | if (rt != NULL) |
---|
1445 | RTFREE_LOCKED(rt); |
---|
1446 | } |
---|
1447 | |
---|
1448 | return (0); |
---|
1449 | } |
---|
1450 | |
---|
1451 | void |
---|
1452 | in6_purgeaddr(struct ifaddr *ifa) |
---|
1453 | { |
---|
1454 | struct ifnet *ifp = ifa->ifa_ifp; |
---|
1455 | struct in6_ifaddr *ia = (struct in6_ifaddr *) ifa; |
---|
1456 | int plen, error; |
---|
1457 | struct ifaddr *ifa0; |
---|
1458 | |
---|
1459 | /* |
---|
1460 | * find another IPv6 address as the gateway for the |
---|
1461 | * link-local and node-local all-nodes multicast |
---|
1462 | * address routes |
---|
1463 | */ |
---|
1464 | IF_ADDR_RLOCK(ifp); |
---|
1465 | TAILQ_FOREACH(ifa0, &ifp->if_addrhead, ifa_link) { |
---|
1466 | if ((ifa0->ifa_addr->sa_family != AF_INET6) || |
---|
1467 | memcmp(&satosin6(ifa0->ifa_addr)->sin6_addr, |
---|
1468 | &ia->ia_addr.sin6_addr, sizeof(struct in6_addr)) == 0) |
---|
1469 | continue; |
---|
1470 | else |
---|
1471 | break; |
---|
1472 | } |
---|
1473 | if (ifa0 != NULL) |
---|
1474 | ifa_ref(ifa0); |
---|
1475 | IF_ADDR_RUNLOCK(ifp); |
---|
1476 | |
---|
1477 | /* |
---|
1478 | * Remove the loopback route to the interface address. |
---|
1479 | * The check for the current setting of "nd6_useloopback" |
---|
1480 | * is not needed. |
---|
1481 | */ |
---|
1482 | if (ia->ia_flags & IFA_RTSELF) { |
---|
1483 | error = ifa_del_loopback_route((struct ifaddr *)ia, |
---|
1484 | (struct sockaddr *)&ia->ia_addr); |
---|
1485 | if (error == 0) |
---|
1486 | ia->ia_flags &= ~IFA_RTSELF; |
---|
1487 | } |
---|
1488 | |
---|
1489 | /* stop DAD processing */ |
---|
1490 | nd6_dad_stop(ifa); |
---|
1491 | |
---|
1492 | /* Remove local address entry from lltable. */ |
---|
1493 | in6_ifremloop(ifa); |
---|
1494 | |
---|
1495 | /* Leave multicast groups. */ |
---|
1496 | error = in6_purgeaddr_mc(ifp, ia, ifa0); |
---|
1497 | |
---|
1498 | if (ifa0 != NULL) |
---|
1499 | ifa_free(ifa0); |
---|
1500 | |
---|
1501 | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ |
---|
1502 | if ((ia->ia_flags & IFA_ROUTE) && plen == 128) { |
---|
1503 | error = rtinit(&(ia->ia_ifa), RTM_DELETE, ia->ia_flags | |
---|
1504 | (ia->ia_dstaddr.sin6_family == AF_INET6) ? RTF_HOST : 0); |
---|
1505 | if (error != 0) |
---|
1506 | log(LOG_INFO, "%s: err=%d, destination address delete " |
---|
1507 | "failed\n", __func__, error); |
---|
1508 | ia->ia_flags &= ~IFA_ROUTE; |
---|
1509 | } |
---|
1510 | |
---|
1511 | in6_unlink_ifa(ia, ifp); |
---|
1512 | } |
---|
1513 | |
---|
1514 | static void |
---|
1515 | in6_unlink_ifa(struct in6_ifaddr *ia, struct ifnet *ifp) |
---|
1516 | { |
---|
1517 | int s = splnet(); |
---|
1518 | |
---|
1519 | IF_ADDR_WLOCK(ifp); |
---|
1520 | TAILQ_REMOVE(&ifp->if_addrhead, &ia->ia_ifa, ifa_link); |
---|
1521 | IF_ADDR_WUNLOCK(ifp); |
---|
1522 | ifa_free(&ia->ia_ifa); /* if_addrhead */ |
---|
1523 | |
---|
1524 | /* |
---|
1525 | * Defer the release of what might be the last reference to the |
---|
1526 | * in6_ifaddr so that it can't be freed before the remainder of the |
---|
1527 | * cleanup. |
---|
1528 | */ |
---|
1529 | IN6_IFADDR_WLOCK(); |
---|
1530 | TAILQ_REMOVE(&V_in6_ifaddrhead, ia, ia_link); |
---|
1531 | IN6_IFADDR_WUNLOCK(); |
---|
1532 | |
---|
1533 | /* |
---|
1534 | * Release the reference to the base prefix. There should be a |
---|
1535 | * positive reference. |
---|
1536 | */ |
---|
1537 | if (ia->ia6_ndpr == NULL) { |
---|
1538 | nd6log((LOG_NOTICE, |
---|
1539 | "in6_unlink_ifa: autoconf'ed address " |
---|
1540 | "%p has no prefix\n", ia)); |
---|
1541 | } else { |
---|
1542 | ia->ia6_ndpr->ndpr_refcnt--; |
---|
1543 | ia->ia6_ndpr = NULL; |
---|
1544 | } |
---|
1545 | |
---|
1546 | /* |
---|
1547 | * Also, if the address being removed is autoconf'ed, call |
---|
1548 | * pfxlist_onlink_check() since the release might affect the status of |
---|
1549 | * other (detached) addresses. |
---|
1550 | */ |
---|
1551 | if ((ia->ia6_flags & IN6_IFF_AUTOCONF)) { |
---|
1552 | pfxlist_onlink_check(); |
---|
1553 | } |
---|
1554 | ifa_free(&ia->ia_ifa); /* in6_ifaddrhead */ |
---|
1555 | splx(s); |
---|
1556 | } |
---|
1557 | |
---|
1558 | void |
---|
1559 | in6_purgeif(struct ifnet *ifp) |
---|
1560 | { |
---|
1561 | struct ifaddr *ifa, *nifa; |
---|
1562 | |
---|
1563 | TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrhead, ifa_link, nifa) { |
---|
1564 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1565 | continue; |
---|
1566 | in6_purgeaddr(ifa); |
---|
1567 | } |
---|
1568 | |
---|
1569 | in6_ifdetach(ifp); |
---|
1570 | } |
---|
1571 | |
---|
1572 | /* |
---|
1573 | * SIOC[GAD]LIFADDR. |
---|
1574 | * SIOCGLIFADDR: get first address. (?) |
---|
1575 | * SIOCGLIFADDR with IFLR_PREFIX: |
---|
1576 | * get first address that matches the specified prefix. |
---|
1577 | * SIOCALIFADDR: add the specified address. |
---|
1578 | * SIOCALIFADDR with IFLR_PREFIX: |
---|
1579 | * add the specified prefix, filling hostid part from |
---|
1580 | * the first link-local address. prefixlen must be <= 64. |
---|
1581 | * SIOCDLIFADDR: delete the specified address. |
---|
1582 | * SIOCDLIFADDR with IFLR_PREFIX: |
---|
1583 | * delete the first address that matches the specified prefix. |
---|
1584 | * return values: |
---|
1585 | * EINVAL on invalid parameters |
---|
1586 | * EADDRNOTAVAIL on prefix match failed/specified address not found |
---|
1587 | * other values may be returned from in6_ioctl() |
---|
1588 | * |
---|
1589 | * NOTE: SIOCALIFADDR(with IFLR_PREFIX set) allows prefixlen less than 64. |
---|
1590 | * this is to accomodate address naming scheme other than RFC2374, |
---|
1591 | * in the future. |
---|
1592 | * RFC2373 defines interface id to be 64bit, but it allows non-RFC2374 |
---|
1593 | * address encoding scheme. (see figure on page 8) |
---|
1594 | */ |
---|
1595 | static int |
---|
1596 | in6_lifaddr_ioctl(struct socket *so, u_long cmd, caddr_t data, |
---|
1597 | struct ifnet *ifp, struct thread *td) |
---|
1598 | { |
---|
1599 | struct if_laddrreq *iflr = (struct if_laddrreq *)data; |
---|
1600 | struct ifaddr *ifa; |
---|
1601 | struct sockaddr *sa; |
---|
1602 | |
---|
1603 | /* sanity checks */ |
---|
1604 | if (!data || !ifp) { |
---|
1605 | panic("invalid argument to in6_lifaddr_ioctl"); |
---|
1606 | /* NOTREACHED */ |
---|
1607 | } |
---|
1608 | |
---|
1609 | switch (cmd) { |
---|
1610 | case SIOCGLIFADDR: |
---|
1611 | /* address must be specified on GET with IFLR_PREFIX */ |
---|
1612 | if ((iflr->flags & IFLR_PREFIX) == 0) |
---|
1613 | break; |
---|
1614 | /* FALLTHROUGH */ |
---|
1615 | case SIOCALIFADDR: |
---|
1616 | case SIOCDLIFADDR: |
---|
1617 | /* address must be specified on ADD and DELETE */ |
---|
1618 | sa = (struct sockaddr *)&iflr->addr; |
---|
1619 | if (sa->sa_family != AF_INET6) |
---|
1620 | return EINVAL; |
---|
1621 | if (sa->sa_len != sizeof(struct sockaddr_in6)) |
---|
1622 | return EINVAL; |
---|
1623 | /* XXX need improvement */ |
---|
1624 | sa = (struct sockaddr *)&iflr->dstaddr; |
---|
1625 | if (sa->sa_family && sa->sa_family != AF_INET6) |
---|
1626 | return EINVAL; |
---|
1627 | if (sa->sa_len && sa->sa_len != sizeof(struct sockaddr_in6)) |
---|
1628 | return EINVAL; |
---|
1629 | break; |
---|
1630 | default: /* shouldn't happen */ |
---|
1631 | #if 0 |
---|
1632 | panic("invalid cmd to in6_lifaddr_ioctl"); |
---|
1633 | /* NOTREACHED */ |
---|
1634 | #else |
---|
1635 | return EOPNOTSUPP; |
---|
1636 | #endif |
---|
1637 | } |
---|
1638 | if (sizeof(struct in6_addr) * 8 < iflr->prefixlen) |
---|
1639 | return EINVAL; |
---|
1640 | |
---|
1641 | switch (cmd) { |
---|
1642 | case SIOCALIFADDR: |
---|
1643 | { |
---|
1644 | struct in6_aliasreq ifra; |
---|
1645 | struct in6_addr *hostid = NULL; |
---|
1646 | int prefixlen; |
---|
1647 | |
---|
1648 | ifa = NULL; |
---|
1649 | if ((iflr->flags & IFLR_PREFIX) != 0) { |
---|
1650 | struct sockaddr_in6 *sin6; |
---|
1651 | |
---|
1652 | /* |
---|
1653 | * hostid is to fill in the hostid part of the |
---|
1654 | * address. hostid points to the first link-local |
---|
1655 | * address attached to the interface. |
---|
1656 | */ |
---|
1657 | ifa = (struct ifaddr *)in6ifa_ifpforlinklocal(ifp, 0); |
---|
1658 | if (!ifa) |
---|
1659 | return EADDRNOTAVAIL; |
---|
1660 | hostid = IFA_IN6(ifa); |
---|
1661 | |
---|
1662 | /* prefixlen must be <= 64. */ |
---|
1663 | if (64 < iflr->prefixlen) { |
---|
1664 | if (ifa != NULL) |
---|
1665 | ifa_free(ifa); |
---|
1666 | return EINVAL; |
---|
1667 | } |
---|
1668 | prefixlen = iflr->prefixlen; |
---|
1669 | |
---|
1670 | /* hostid part must be zero. */ |
---|
1671 | sin6 = (struct sockaddr_in6 *)&iflr->addr; |
---|
1672 | if (sin6->sin6_addr.s6_addr32[2] != 0 || |
---|
1673 | sin6->sin6_addr.s6_addr32[3] != 0) { |
---|
1674 | if (ifa != NULL) |
---|
1675 | ifa_free(ifa); |
---|
1676 | return EINVAL; |
---|
1677 | } |
---|
1678 | } else |
---|
1679 | prefixlen = iflr->prefixlen; |
---|
1680 | |
---|
1681 | /* copy args to in6_aliasreq, perform ioctl(SIOCAIFADDR_IN6). */ |
---|
1682 | bzero(&ifra, sizeof(ifra)); |
---|
1683 | bcopy(iflr->iflr_name, ifra.ifra_name, sizeof(ifra.ifra_name)); |
---|
1684 | |
---|
1685 | bcopy(&iflr->addr, &ifra.ifra_addr, |
---|
1686 | ((struct sockaddr *)&iflr->addr)->sa_len); |
---|
1687 | if (hostid) { |
---|
1688 | /* fill in hostid part */ |
---|
1689 | ifra.ifra_addr.sin6_addr.s6_addr32[2] = |
---|
1690 | hostid->s6_addr32[2]; |
---|
1691 | ifra.ifra_addr.sin6_addr.s6_addr32[3] = |
---|
1692 | hostid->s6_addr32[3]; |
---|
1693 | } |
---|
1694 | |
---|
1695 | if (((struct sockaddr *)&iflr->dstaddr)->sa_family) { /* XXX */ |
---|
1696 | bcopy(&iflr->dstaddr, &ifra.ifra_dstaddr, |
---|
1697 | ((struct sockaddr *)&iflr->dstaddr)->sa_len); |
---|
1698 | if (hostid) { |
---|
1699 | ifra.ifra_dstaddr.sin6_addr.s6_addr32[2] = |
---|
1700 | hostid->s6_addr32[2]; |
---|
1701 | ifra.ifra_dstaddr.sin6_addr.s6_addr32[3] = |
---|
1702 | hostid->s6_addr32[3]; |
---|
1703 | } |
---|
1704 | } |
---|
1705 | if (ifa != NULL) |
---|
1706 | ifa_free(ifa); |
---|
1707 | |
---|
1708 | ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); |
---|
1709 | in6_prefixlen2mask(&ifra.ifra_prefixmask.sin6_addr, prefixlen); |
---|
1710 | |
---|
1711 | ifra.ifra_flags = iflr->flags & ~IFLR_PREFIX; |
---|
1712 | return in6_control(so, SIOCAIFADDR_IN6, (caddr_t)&ifra, ifp, td); |
---|
1713 | } |
---|
1714 | case SIOCGLIFADDR: |
---|
1715 | case SIOCDLIFADDR: |
---|
1716 | { |
---|
1717 | struct in6_ifaddr *ia; |
---|
1718 | struct in6_addr mask, candidate, match; |
---|
1719 | struct sockaddr_in6 *sin6; |
---|
1720 | int cmp; |
---|
1721 | |
---|
1722 | bzero(&mask, sizeof(mask)); |
---|
1723 | if (iflr->flags & IFLR_PREFIX) { |
---|
1724 | /* lookup a prefix rather than address. */ |
---|
1725 | in6_prefixlen2mask(&mask, iflr->prefixlen); |
---|
1726 | |
---|
1727 | sin6 = (struct sockaddr_in6 *)&iflr->addr; |
---|
1728 | bcopy(&sin6->sin6_addr, &match, sizeof(match)); |
---|
1729 | match.s6_addr32[0] &= mask.s6_addr32[0]; |
---|
1730 | match.s6_addr32[1] &= mask.s6_addr32[1]; |
---|
1731 | match.s6_addr32[2] &= mask.s6_addr32[2]; |
---|
1732 | match.s6_addr32[3] &= mask.s6_addr32[3]; |
---|
1733 | |
---|
1734 | /* if you set extra bits, that's wrong */ |
---|
1735 | if (bcmp(&match, &sin6->sin6_addr, sizeof(match))) |
---|
1736 | return EINVAL; |
---|
1737 | |
---|
1738 | cmp = 1; |
---|
1739 | } else { |
---|
1740 | if (cmd == SIOCGLIFADDR) { |
---|
1741 | /* on getting an address, take the 1st match */ |
---|
1742 | cmp = 0; /* XXX */ |
---|
1743 | } else { |
---|
1744 | /* on deleting an address, do exact match */ |
---|
1745 | in6_prefixlen2mask(&mask, 128); |
---|
1746 | sin6 = (struct sockaddr_in6 *)&iflr->addr; |
---|
1747 | bcopy(&sin6->sin6_addr, &match, sizeof(match)); |
---|
1748 | |
---|
1749 | cmp = 1; |
---|
1750 | } |
---|
1751 | } |
---|
1752 | |
---|
1753 | IF_ADDR_RLOCK(ifp); |
---|
1754 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
1755 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1756 | continue; |
---|
1757 | if (!cmp) |
---|
1758 | break; |
---|
1759 | |
---|
1760 | /* |
---|
1761 | * XXX: this is adhoc, but is necessary to allow |
---|
1762 | * a user to specify fe80::/64 (not /10) for a |
---|
1763 | * link-local address. |
---|
1764 | */ |
---|
1765 | bcopy(IFA_IN6(ifa), &candidate, sizeof(candidate)); |
---|
1766 | in6_clearscope(&candidate); |
---|
1767 | candidate.s6_addr32[0] &= mask.s6_addr32[0]; |
---|
1768 | candidate.s6_addr32[1] &= mask.s6_addr32[1]; |
---|
1769 | candidate.s6_addr32[2] &= mask.s6_addr32[2]; |
---|
1770 | candidate.s6_addr32[3] &= mask.s6_addr32[3]; |
---|
1771 | if (IN6_ARE_ADDR_EQUAL(&candidate, &match)) |
---|
1772 | break; |
---|
1773 | } |
---|
1774 | if (ifa != NULL) |
---|
1775 | ifa_ref(ifa); |
---|
1776 | IF_ADDR_RUNLOCK(ifp); |
---|
1777 | if (!ifa) |
---|
1778 | return EADDRNOTAVAIL; |
---|
1779 | ia = ifa2ia6(ifa); |
---|
1780 | |
---|
1781 | if (cmd == SIOCGLIFADDR) { |
---|
1782 | int error; |
---|
1783 | |
---|
1784 | /* fill in the if_laddrreq structure */ |
---|
1785 | bcopy(&ia->ia_addr, &iflr->addr, ia->ia_addr.sin6_len); |
---|
1786 | error = sa6_recoverscope( |
---|
1787 | (struct sockaddr_in6 *)&iflr->addr); |
---|
1788 | if (error != 0) { |
---|
1789 | ifa_free(ifa); |
---|
1790 | return (error); |
---|
1791 | } |
---|
1792 | |
---|
1793 | if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { |
---|
1794 | bcopy(&ia->ia_dstaddr, &iflr->dstaddr, |
---|
1795 | ia->ia_dstaddr.sin6_len); |
---|
1796 | error = sa6_recoverscope( |
---|
1797 | (struct sockaddr_in6 *)&iflr->dstaddr); |
---|
1798 | if (error != 0) { |
---|
1799 | ifa_free(ifa); |
---|
1800 | return (error); |
---|
1801 | } |
---|
1802 | } else |
---|
1803 | bzero(&iflr->dstaddr, sizeof(iflr->dstaddr)); |
---|
1804 | |
---|
1805 | iflr->prefixlen = |
---|
1806 | in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); |
---|
1807 | |
---|
1808 | iflr->flags = ia->ia6_flags; /* XXX */ |
---|
1809 | ifa_free(ifa); |
---|
1810 | |
---|
1811 | return 0; |
---|
1812 | } else { |
---|
1813 | struct in6_aliasreq ifra; |
---|
1814 | |
---|
1815 | /* fill in6_aliasreq and do ioctl(SIOCDIFADDR_IN6) */ |
---|
1816 | bzero(&ifra, sizeof(ifra)); |
---|
1817 | bcopy(iflr->iflr_name, ifra.ifra_name, |
---|
1818 | sizeof(ifra.ifra_name)); |
---|
1819 | |
---|
1820 | bcopy(&ia->ia_addr, &ifra.ifra_addr, |
---|
1821 | ia->ia_addr.sin6_len); |
---|
1822 | if ((ifp->if_flags & IFF_POINTOPOINT) != 0) { |
---|
1823 | bcopy(&ia->ia_dstaddr, &ifra.ifra_dstaddr, |
---|
1824 | ia->ia_dstaddr.sin6_len); |
---|
1825 | } else { |
---|
1826 | bzero(&ifra.ifra_dstaddr, |
---|
1827 | sizeof(ifra.ifra_dstaddr)); |
---|
1828 | } |
---|
1829 | bcopy(&ia->ia_prefixmask, &ifra.ifra_dstaddr, |
---|
1830 | ia->ia_prefixmask.sin6_len); |
---|
1831 | |
---|
1832 | ifra.ifra_flags = ia->ia6_flags; |
---|
1833 | ifa_free(ifa); |
---|
1834 | return in6_control(so, SIOCDIFADDR_IN6, (caddr_t)&ifra, |
---|
1835 | ifp, td); |
---|
1836 | } |
---|
1837 | } |
---|
1838 | } |
---|
1839 | |
---|
1840 | return EOPNOTSUPP; /* just for safety */ |
---|
1841 | } |
---|
1842 | |
---|
1843 | /* |
---|
1844 | * Initialize an interface's IPv6 address and routing table entry. |
---|
1845 | */ |
---|
1846 | static int |
---|
1847 | in6_ifinit(struct ifnet *ifp, struct in6_ifaddr *ia, |
---|
1848 | struct sockaddr_in6 *sin6, int newhost) |
---|
1849 | { |
---|
1850 | int error = 0, plen, ifacount = 0; |
---|
1851 | int s = splimp(); |
---|
1852 | struct ifaddr *ifa; |
---|
1853 | |
---|
1854 | /* |
---|
1855 | * Give the interface a chance to initialize |
---|
1856 | * if this is its first address, |
---|
1857 | * and to validate the address if necessary. |
---|
1858 | */ |
---|
1859 | IF_ADDR_RLOCK(ifp); |
---|
1860 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
1861 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1862 | continue; |
---|
1863 | ifacount++; |
---|
1864 | } |
---|
1865 | IF_ADDR_RUNLOCK(ifp); |
---|
1866 | |
---|
1867 | ia->ia_addr = *sin6; |
---|
1868 | |
---|
1869 | if (ifacount <= 1 && ifp->if_ioctl) { |
---|
1870 | error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia); |
---|
1871 | if (error) { |
---|
1872 | splx(s); |
---|
1873 | return (error); |
---|
1874 | } |
---|
1875 | } |
---|
1876 | splx(s); |
---|
1877 | |
---|
1878 | ia->ia_ifa.ifa_metric = ifp->if_metric; |
---|
1879 | |
---|
1880 | /* we could do in(6)_socktrim here, but just omit it at this moment. */ |
---|
1881 | |
---|
1882 | /* |
---|
1883 | * Special case: |
---|
1884 | * If a new destination address is specified for a point-to-point |
---|
1885 | * interface, install a route to the destination as an interface |
---|
1886 | * direct route. |
---|
1887 | * XXX: the logic below rejects assigning multiple addresses on a p2p |
---|
1888 | * interface that share the same destination. |
---|
1889 | */ |
---|
1890 | plen = in6_mask2len(&ia->ia_prefixmask.sin6_addr, NULL); /* XXX */ |
---|
1891 | if (!(ia->ia_flags & IFA_ROUTE) && plen == 128 && |
---|
1892 | ia->ia_dstaddr.sin6_family == AF_INET6) { |
---|
1893 | int rtflags = RTF_UP | RTF_HOST; |
---|
1894 | error = rtinit(&ia->ia_ifa, RTM_ADD, ia->ia_flags | rtflags); |
---|
1895 | if (error) |
---|
1896 | return (error); |
---|
1897 | ia->ia_flags |= IFA_ROUTE; |
---|
1898 | /* |
---|
1899 | * Handle the case for ::1 . |
---|
1900 | */ |
---|
1901 | if (ifp->if_flags & IFF_LOOPBACK) |
---|
1902 | ia->ia_flags |= IFA_RTSELF; |
---|
1903 | } |
---|
1904 | |
---|
1905 | /* |
---|
1906 | * add a loopback route to self |
---|
1907 | */ |
---|
1908 | if (!(ia->ia_flags & IFA_RTSELF) && V_nd6_useloopback) { |
---|
1909 | error = ifa_add_loopback_route((struct ifaddr *)ia, |
---|
1910 | (struct sockaddr *)&ia->ia_addr); |
---|
1911 | if (error == 0) |
---|
1912 | ia->ia_flags |= IFA_RTSELF; |
---|
1913 | } |
---|
1914 | |
---|
1915 | /* Add local address to lltable, if necessary (ex. on p2p link). */ |
---|
1916 | if (newhost) |
---|
1917 | in6_ifaddloop(&(ia->ia_ifa)); |
---|
1918 | |
---|
1919 | return (error); |
---|
1920 | } |
---|
1921 | |
---|
1922 | /* |
---|
1923 | * Find an IPv6 interface link-local address specific to an interface. |
---|
1924 | * ifaddr is returned referenced. |
---|
1925 | */ |
---|
1926 | struct in6_ifaddr * |
---|
1927 | in6ifa_ifpforlinklocal(struct ifnet *ifp, int ignoreflags) |
---|
1928 | { |
---|
1929 | struct ifaddr *ifa; |
---|
1930 | |
---|
1931 | IF_ADDR_RLOCK(ifp); |
---|
1932 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
1933 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1934 | continue; |
---|
1935 | if (IN6_IS_ADDR_LINKLOCAL(IFA_IN6(ifa))) { |
---|
1936 | if ((((struct in6_ifaddr *)ifa)->ia6_flags & |
---|
1937 | ignoreflags) != 0) |
---|
1938 | continue; |
---|
1939 | ifa_ref(ifa); |
---|
1940 | break; |
---|
1941 | } |
---|
1942 | } |
---|
1943 | IF_ADDR_RUNLOCK(ifp); |
---|
1944 | |
---|
1945 | return ((struct in6_ifaddr *)ifa); |
---|
1946 | } |
---|
1947 | |
---|
1948 | |
---|
1949 | /* |
---|
1950 | * find the internet address corresponding to a given interface and address. |
---|
1951 | * ifaddr is returned referenced. |
---|
1952 | */ |
---|
1953 | struct in6_ifaddr * |
---|
1954 | in6ifa_ifpwithaddr(struct ifnet *ifp, struct in6_addr *addr) |
---|
1955 | { |
---|
1956 | struct ifaddr *ifa; |
---|
1957 | |
---|
1958 | IF_ADDR_RLOCK(ifp); |
---|
1959 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
1960 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1961 | continue; |
---|
1962 | if (IN6_ARE_ADDR_EQUAL(addr, IFA_IN6(ifa))) { |
---|
1963 | ifa_ref(ifa); |
---|
1964 | break; |
---|
1965 | } |
---|
1966 | } |
---|
1967 | IF_ADDR_RUNLOCK(ifp); |
---|
1968 | |
---|
1969 | return ((struct in6_ifaddr *)ifa); |
---|
1970 | } |
---|
1971 | |
---|
1972 | /* |
---|
1973 | * Find a link-local scoped address on ifp and return it if any. |
---|
1974 | */ |
---|
1975 | struct in6_ifaddr * |
---|
1976 | in6ifa_llaonifp(struct ifnet *ifp) |
---|
1977 | { |
---|
1978 | struct sockaddr_in6 *sin6; |
---|
1979 | struct ifaddr *ifa; |
---|
1980 | |
---|
1981 | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) |
---|
1982 | return (NULL); |
---|
1983 | if_addr_rlock(ifp); |
---|
1984 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
1985 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
1986 | continue; |
---|
1987 | sin6 = (struct sockaddr_in6 *)ifa->ifa_addr; |
---|
1988 | if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr) || |
---|
1989 | IN6_IS_ADDR_MC_INTFACELOCAL(&sin6->sin6_addr) || |
---|
1990 | IN6_IS_ADDR_MC_NODELOCAL(&sin6->sin6_addr)) |
---|
1991 | break; |
---|
1992 | } |
---|
1993 | if_addr_runlock(ifp); |
---|
1994 | |
---|
1995 | return ((struct in6_ifaddr *)ifa); |
---|
1996 | } |
---|
1997 | |
---|
1998 | /* |
---|
1999 | * Convert IP6 address to printable (loggable) representation. Caller |
---|
2000 | * has to make sure that ip6buf is at least INET6_ADDRSTRLEN long. |
---|
2001 | */ |
---|
2002 | static char digits[] = "0123456789abcdef"; |
---|
2003 | char * |
---|
2004 | ip6_sprintf(char *ip6buf, const struct in6_addr *addr) |
---|
2005 | { |
---|
2006 | int i, cnt = 0, maxcnt = 0, idx = 0, index = 0; |
---|
2007 | char *cp; |
---|
2008 | const u_int16_t *a = (const u_int16_t *)addr; |
---|
2009 | const u_int8_t *d; |
---|
2010 | int dcolon = 0, zero = 0; |
---|
2011 | |
---|
2012 | cp = ip6buf; |
---|
2013 | |
---|
2014 | for (i = 0; i < 8; i++) { |
---|
2015 | if (*(a + i) == 0) { |
---|
2016 | cnt++; |
---|
2017 | if (cnt == 1) |
---|
2018 | idx = i; |
---|
2019 | } |
---|
2020 | else if (maxcnt < cnt) { |
---|
2021 | maxcnt = cnt; |
---|
2022 | index = idx; |
---|
2023 | cnt = 0; |
---|
2024 | } |
---|
2025 | } |
---|
2026 | if (maxcnt < cnt) { |
---|
2027 | maxcnt = cnt; |
---|
2028 | index = idx; |
---|
2029 | } |
---|
2030 | |
---|
2031 | for (i = 0; i < 8; i++) { |
---|
2032 | if (dcolon == 1) { |
---|
2033 | if (*a == 0) { |
---|
2034 | if (i == 7) |
---|
2035 | *cp++ = ':'; |
---|
2036 | a++; |
---|
2037 | continue; |
---|
2038 | } else |
---|
2039 | dcolon = 2; |
---|
2040 | } |
---|
2041 | if (*a == 0) { |
---|
2042 | if (dcolon == 0 && *(a + 1) == 0 && i == index) { |
---|
2043 | if (i == 0) |
---|
2044 | *cp++ = ':'; |
---|
2045 | *cp++ = ':'; |
---|
2046 | dcolon = 1; |
---|
2047 | } else { |
---|
2048 | *cp++ = '0'; |
---|
2049 | *cp++ = ':'; |
---|
2050 | } |
---|
2051 | a++; |
---|
2052 | continue; |
---|
2053 | } |
---|
2054 | d = (const u_char *)a; |
---|
2055 | /* Try to eliminate leading zeros in printout like in :0001. */ |
---|
2056 | zero = 1; |
---|
2057 | *cp = digits[*d >> 4]; |
---|
2058 | if (*cp != '0') { |
---|
2059 | zero = 0; |
---|
2060 | cp++; |
---|
2061 | } |
---|
2062 | *cp = digits[*d++ & 0xf]; |
---|
2063 | if (zero == 0 || (*cp != '0')) { |
---|
2064 | zero = 0; |
---|
2065 | cp++; |
---|
2066 | } |
---|
2067 | *cp = digits[*d >> 4]; |
---|
2068 | if (zero == 0 || (*cp != '0')) { |
---|
2069 | zero = 0; |
---|
2070 | cp++; |
---|
2071 | } |
---|
2072 | *cp++ = digits[*d & 0xf]; |
---|
2073 | *cp++ = ':'; |
---|
2074 | a++; |
---|
2075 | } |
---|
2076 | *--cp = '\0'; |
---|
2077 | return (ip6buf); |
---|
2078 | } |
---|
2079 | |
---|
2080 | int |
---|
2081 | in6_localaddr(struct in6_addr *in6) |
---|
2082 | { |
---|
2083 | struct in6_ifaddr *ia; |
---|
2084 | |
---|
2085 | if (IN6_IS_ADDR_LOOPBACK(in6) || IN6_IS_ADDR_LINKLOCAL(in6)) |
---|
2086 | return 1; |
---|
2087 | |
---|
2088 | IN6_IFADDR_RLOCK(); |
---|
2089 | TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { |
---|
2090 | if (IN6_ARE_MASKED_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr, |
---|
2091 | &ia->ia_prefixmask.sin6_addr)) { |
---|
2092 | IN6_IFADDR_RUNLOCK(); |
---|
2093 | return 1; |
---|
2094 | } |
---|
2095 | } |
---|
2096 | IN6_IFADDR_RUNLOCK(); |
---|
2097 | |
---|
2098 | return (0); |
---|
2099 | } |
---|
2100 | |
---|
2101 | /* |
---|
2102 | * Return 1 if an internet address is for the local host and configured |
---|
2103 | * on one of its interfaces. |
---|
2104 | */ |
---|
2105 | int |
---|
2106 | in6_localip(struct in6_addr *in6) |
---|
2107 | { |
---|
2108 | struct in6_ifaddr *ia; |
---|
2109 | |
---|
2110 | IN6_IFADDR_RLOCK(); |
---|
2111 | TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { |
---|
2112 | if (IN6_ARE_ADDR_EQUAL(in6, &ia->ia_addr.sin6_addr)) { |
---|
2113 | IN6_IFADDR_RUNLOCK(); |
---|
2114 | return (1); |
---|
2115 | } |
---|
2116 | } |
---|
2117 | IN6_IFADDR_RUNLOCK(); |
---|
2118 | return (0); |
---|
2119 | } |
---|
2120 | |
---|
2121 | |
---|
2122 | int |
---|
2123 | in6_is_addr_deprecated(struct sockaddr_in6 *sa6) |
---|
2124 | { |
---|
2125 | struct in6_ifaddr *ia; |
---|
2126 | |
---|
2127 | IN6_IFADDR_RLOCK(); |
---|
2128 | TAILQ_FOREACH(ia, &V_in6_ifaddrhead, ia_link) { |
---|
2129 | if (IN6_ARE_ADDR_EQUAL(&ia->ia_addr.sin6_addr, |
---|
2130 | &sa6->sin6_addr) && |
---|
2131 | (ia->ia6_flags & IN6_IFF_DEPRECATED) != 0) { |
---|
2132 | IN6_IFADDR_RUNLOCK(); |
---|
2133 | return (1); /* true */ |
---|
2134 | } |
---|
2135 | |
---|
2136 | /* XXX: do we still have to go thru the rest of the list? */ |
---|
2137 | } |
---|
2138 | IN6_IFADDR_RUNLOCK(); |
---|
2139 | |
---|
2140 | return (0); /* false */ |
---|
2141 | } |
---|
2142 | |
---|
2143 | /* |
---|
2144 | * return length of part which dst and src are equal |
---|
2145 | * hard coding... |
---|
2146 | */ |
---|
2147 | int |
---|
2148 | in6_matchlen(struct in6_addr *src, struct in6_addr *dst) |
---|
2149 | { |
---|
2150 | int match = 0; |
---|
2151 | u_char *s = (u_char *)src, *d = (u_char *)dst; |
---|
2152 | u_char *lim = s + 16, r; |
---|
2153 | |
---|
2154 | while (s < lim) |
---|
2155 | if ((r = (*d++ ^ *s++)) != 0) { |
---|
2156 | while (r < 128) { |
---|
2157 | match++; |
---|
2158 | r <<= 1; |
---|
2159 | } |
---|
2160 | break; |
---|
2161 | } else |
---|
2162 | match += 8; |
---|
2163 | return match; |
---|
2164 | } |
---|
2165 | |
---|
2166 | /* XXX: to be scope conscious */ |
---|
2167 | int |
---|
2168 | in6_are_prefix_equal(struct in6_addr *p1, struct in6_addr *p2, int len) |
---|
2169 | { |
---|
2170 | int bytelen, bitlen; |
---|
2171 | |
---|
2172 | /* sanity check */ |
---|
2173 | if (0 > len || len > 128) { |
---|
2174 | log(LOG_ERR, "in6_are_prefix_equal: invalid prefix length(%d)\n", |
---|
2175 | len); |
---|
2176 | return (0); |
---|
2177 | } |
---|
2178 | |
---|
2179 | bytelen = len / 8; |
---|
2180 | bitlen = len % 8; |
---|
2181 | |
---|
2182 | if (bcmp(&p1->s6_addr, &p2->s6_addr, bytelen)) |
---|
2183 | return (0); |
---|
2184 | if (bitlen != 0 && |
---|
2185 | p1->s6_addr[bytelen] >> (8 - bitlen) != |
---|
2186 | p2->s6_addr[bytelen] >> (8 - bitlen)) |
---|
2187 | return (0); |
---|
2188 | |
---|
2189 | return (1); |
---|
2190 | } |
---|
2191 | |
---|
2192 | void |
---|
2193 | in6_prefixlen2mask(struct in6_addr *maskp, int len) |
---|
2194 | { |
---|
2195 | u_char maskarray[8] = {0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; |
---|
2196 | int bytelen, bitlen, i; |
---|
2197 | |
---|
2198 | /* sanity check */ |
---|
2199 | if (0 > len || len > 128) { |
---|
2200 | log(LOG_ERR, "in6_prefixlen2mask: invalid prefix length(%d)\n", |
---|
2201 | len); |
---|
2202 | return; |
---|
2203 | } |
---|
2204 | |
---|
2205 | bzero(maskp, sizeof(*maskp)); |
---|
2206 | bytelen = len / 8; |
---|
2207 | bitlen = len % 8; |
---|
2208 | for (i = 0; i < bytelen; i++) |
---|
2209 | maskp->s6_addr[i] = 0xff; |
---|
2210 | if (bitlen) |
---|
2211 | maskp->s6_addr[bytelen] = maskarray[bitlen - 1]; |
---|
2212 | } |
---|
2213 | |
---|
2214 | /* |
---|
2215 | * return the best address out of the same scope. if no address was |
---|
2216 | * found, return the first valid address from designated IF. |
---|
2217 | */ |
---|
2218 | struct in6_ifaddr * |
---|
2219 | in6_ifawithifp(struct ifnet *ifp, struct in6_addr *dst) |
---|
2220 | { |
---|
2221 | int dst_scope = in6_addrscope(dst), blen = -1, tlen; |
---|
2222 | struct ifaddr *ifa; |
---|
2223 | struct in6_ifaddr *besta = 0; |
---|
2224 | struct in6_ifaddr *dep[2]; /* last-resort: deprecated */ |
---|
2225 | |
---|
2226 | dep[0] = dep[1] = NULL; |
---|
2227 | |
---|
2228 | /* |
---|
2229 | * We first look for addresses in the same scope. |
---|
2230 | * If there is one, return it. |
---|
2231 | * If two or more, return one which matches the dst longest. |
---|
2232 | * If none, return one of global addresses assigned other ifs. |
---|
2233 | */ |
---|
2234 | IF_ADDR_RLOCK(ifp); |
---|
2235 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
2236 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
2237 | continue; |
---|
2238 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) |
---|
2239 | continue; /* XXX: is there any case to allow anycast? */ |
---|
2240 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) |
---|
2241 | continue; /* don't use this interface */ |
---|
2242 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) |
---|
2243 | continue; |
---|
2244 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { |
---|
2245 | if (V_ip6_use_deprecated) |
---|
2246 | dep[0] = (struct in6_ifaddr *)ifa; |
---|
2247 | continue; |
---|
2248 | } |
---|
2249 | |
---|
2250 | if (dst_scope == in6_addrscope(IFA_IN6(ifa))) { |
---|
2251 | /* |
---|
2252 | * call in6_matchlen() as few as possible |
---|
2253 | */ |
---|
2254 | if (besta) { |
---|
2255 | if (blen == -1) |
---|
2256 | blen = in6_matchlen(&besta->ia_addr.sin6_addr, dst); |
---|
2257 | tlen = in6_matchlen(IFA_IN6(ifa), dst); |
---|
2258 | if (tlen > blen) { |
---|
2259 | blen = tlen; |
---|
2260 | besta = (struct in6_ifaddr *)ifa; |
---|
2261 | } |
---|
2262 | } else |
---|
2263 | besta = (struct in6_ifaddr *)ifa; |
---|
2264 | } |
---|
2265 | } |
---|
2266 | if (besta) { |
---|
2267 | ifa_ref(&besta->ia_ifa); |
---|
2268 | IF_ADDR_RUNLOCK(ifp); |
---|
2269 | return (besta); |
---|
2270 | } |
---|
2271 | |
---|
2272 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
2273 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
2274 | continue; |
---|
2275 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_ANYCAST) |
---|
2276 | continue; /* XXX: is there any case to allow anycast? */ |
---|
2277 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_NOTREADY) |
---|
2278 | continue; /* don't use this interface */ |
---|
2279 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DETACHED) |
---|
2280 | continue; |
---|
2281 | if (((struct in6_ifaddr *)ifa)->ia6_flags & IN6_IFF_DEPRECATED) { |
---|
2282 | if (V_ip6_use_deprecated) |
---|
2283 | dep[1] = (struct in6_ifaddr *)ifa; |
---|
2284 | continue; |
---|
2285 | } |
---|
2286 | |
---|
2287 | if (ifa != NULL) |
---|
2288 | ifa_ref(ifa); |
---|
2289 | IF_ADDR_RUNLOCK(ifp); |
---|
2290 | return (struct in6_ifaddr *)ifa; |
---|
2291 | } |
---|
2292 | |
---|
2293 | /* use the last-resort values, that are, deprecated addresses */ |
---|
2294 | if (dep[0]) { |
---|
2295 | ifa_ref((struct ifaddr *)dep[0]); |
---|
2296 | IF_ADDR_RUNLOCK(ifp); |
---|
2297 | return dep[0]; |
---|
2298 | } |
---|
2299 | if (dep[1]) { |
---|
2300 | ifa_ref((struct ifaddr *)dep[1]); |
---|
2301 | IF_ADDR_RUNLOCK(ifp); |
---|
2302 | return dep[1]; |
---|
2303 | } |
---|
2304 | |
---|
2305 | IF_ADDR_RUNLOCK(ifp); |
---|
2306 | return NULL; |
---|
2307 | } |
---|
2308 | |
---|
2309 | /* |
---|
2310 | * perform DAD when interface becomes IFF_UP. |
---|
2311 | */ |
---|
2312 | void |
---|
2313 | in6_if_up(struct ifnet *ifp) |
---|
2314 | { |
---|
2315 | struct ifaddr *ifa; |
---|
2316 | struct in6_ifaddr *ia; |
---|
2317 | |
---|
2318 | IF_ADDR_RLOCK(ifp); |
---|
2319 | TAILQ_FOREACH(ifa, &ifp->if_addrhead, ifa_link) { |
---|
2320 | if (ifa->ifa_addr->sa_family != AF_INET6) |
---|
2321 | continue; |
---|
2322 | ia = (struct in6_ifaddr *)ifa; |
---|
2323 | if (ia->ia6_flags & IN6_IFF_TENTATIVE) { |
---|
2324 | /* |
---|
2325 | * The TENTATIVE flag was likely set by hand |
---|
2326 | * beforehand, implicitly indicating the need for DAD. |
---|
2327 | * We may be able to skip the random delay in this |
---|
2328 | * case, but we impose delays just in case. |
---|
2329 | */ |
---|
2330 | nd6_dad_start(ifa, |
---|
2331 | arc4random() % (MAX_RTR_SOLICITATION_DELAY * hz)); |
---|
2332 | } |
---|
2333 | } |
---|
2334 | IF_ADDR_RUNLOCK(ifp); |
---|
2335 | |
---|
2336 | /* |
---|
2337 | * special cases, like 6to4, are handled in in6_ifattach |
---|
2338 | */ |
---|
2339 | in6_ifattach(ifp, NULL); |
---|
2340 | } |
---|
2341 | |
---|
2342 | int |
---|
2343 | in6if_do_dad(struct ifnet *ifp) |
---|
2344 | { |
---|
2345 | if ((ifp->if_flags & IFF_LOOPBACK) != 0) |
---|
2346 | return (0); |
---|
2347 | |
---|
2348 | if (ND_IFINFO(ifp)->flags & ND6_IFF_IFDISABLED) |
---|
2349 | return (0); |
---|
2350 | |
---|
2351 | switch (ifp->if_type) { |
---|
2352 | #ifdef IFT_DUMMY |
---|
2353 | case IFT_DUMMY: |
---|
2354 | #endif |
---|
2355 | case IFT_FAITH: |
---|
2356 | /* |
---|
2357 | * These interfaces do not have the IFF_LOOPBACK flag, |
---|
2358 | * but loop packets back. We do not have to do DAD on such |
---|
2359 | * interfaces. We should even omit it, because loop-backed |
---|
2360 | * NS would confuse the DAD procedure. |
---|
2361 | */ |
---|
2362 | return (0); |
---|
2363 | default: |
---|
2364 | /* |
---|
2365 | * Our DAD routine requires the interface up and running. |
---|
2366 | * However, some interfaces can be up before the RUNNING |
---|
2367 | * status. Additionaly, users may try to assign addresses |
---|
2368 | * before the interface becomes up (or running). |
---|
2369 | * We simply skip DAD in such a case as a work around. |
---|
2370 | * XXX: we should rather mark "tentative" on such addresses, |
---|
2371 | * and do DAD after the interface becomes ready. |
---|
2372 | */ |
---|
2373 | if (!((ifp->if_flags & IFF_UP) && |
---|
2374 | (ifp->if_drv_flags & IFF_DRV_RUNNING))) |
---|
2375 | return (0); |
---|
2376 | |
---|
2377 | return (1); |
---|
2378 | } |
---|
2379 | } |
---|
2380 | |
---|
2381 | /* |
---|
2382 | * Calculate max IPv6 MTU through all the interfaces and store it |
---|
2383 | * to in6_maxmtu. |
---|
2384 | */ |
---|
2385 | void |
---|
2386 | in6_setmaxmtu(void) |
---|
2387 | { |
---|
2388 | unsigned long maxmtu = 0; |
---|
2389 | struct ifnet *ifp; |
---|
2390 | |
---|
2391 | IFNET_RLOCK_NOSLEEP(); |
---|
2392 | TAILQ_FOREACH(ifp, &V_ifnet, if_list) { |
---|
2393 | /* this function can be called during ifnet initialization */ |
---|
2394 | if (!ifp->if_afdata[AF_INET6]) |
---|
2395 | continue; |
---|
2396 | if ((ifp->if_flags & IFF_LOOPBACK) == 0 && |
---|
2397 | IN6_LINKMTU(ifp) > maxmtu) |
---|
2398 | maxmtu = IN6_LINKMTU(ifp); |
---|
2399 | } |
---|
2400 | IFNET_RUNLOCK_NOSLEEP(); |
---|
2401 | if (maxmtu) /* update only when maxmtu is positive */ |
---|
2402 | V_in6_maxmtu = maxmtu; |
---|
2403 | } |
---|
2404 | |
---|
2405 | /* |
---|
2406 | * Provide the length of interface identifiers to be used for the link attached |
---|
2407 | * to the given interface. The length should be defined in "IPv6 over |
---|
2408 | * xxx-link" document. Note that address architecture might also define |
---|
2409 | * the length for a particular set of address prefixes, regardless of the |
---|
2410 | * link type. As clarified in rfc2462bis, those two definitions should be |
---|
2411 | * consistent, and those really are as of August 2004. |
---|
2412 | */ |
---|
2413 | int |
---|
2414 | in6_if2idlen(struct ifnet *ifp) |
---|
2415 | { |
---|
2416 | switch (ifp->if_type) { |
---|
2417 | case IFT_ETHER: /* RFC2464 */ |
---|
2418 | #ifdef IFT_PROPVIRTUAL |
---|
2419 | case IFT_PROPVIRTUAL: /* XXX: no RFC. treat it as ether */ |
---|
2420 | #endif |
---|
2421 | #ifdef IFT_L2VLAN |
---|
2422 | case IFT_L2VLAN: /* ditto */ |
---|
2423 | #endif |
---|
2424 | #ifdef IFT_IEEE80211 |
---|
2425 | case IFT_IEEE80211: /* ditto */ |
---|
2426 | #endif |
---|
2427 | #ifdef IFT_MIP |
---|
2428 | case IFT_MIP: /* ditto */ |
---|
2429 | #endif |
---|
2430 | case IFT_INFINIBAND: |
---|
2431 | return (64); |
---|
2432 | case IFT_FDDI: /* RFC2467 */ |
---|
2433 | return (64); |
---|
2434 | case IFT_ISO88025: /* RFC2470 (IPv6 over Token Ring) */ |
---|
2435 | return (64); |
---|
2436 | case IFT_PPP: /* RFC2472 */ |
---|
2437 | return (64); |
---|
2438 | case IFT_ARCNET: /* RFC2497 */ |
---|
2439 | return (64); |
---|
2440 | case IFT_FRELAY: /* RFC2590 */ |
---|
2441 | return (64); |
---|
2442 | case IFT_IEEE1394: /* RFC3146 */ |
---|
2443 | return (64); |
---|
2444 | case IFT_GIF: |
---|
2445 | return (64); /* draft-ietf-v6ops-mech-v2-07 */ |
---|
2446 | case IFT_LOOP: |
---|
2447 | return (64); /* XXX: is this really correct? */ |
---|
2448 | default: |
---|
2449 | /* |
---|
2450 | * Unknown link type: |
---|
2451 | * It might be controversial to use the today's common constant |
---|
2452 | * of 64 for these cases unconditionally. For full compliance, |
---|
2453 | * we should return an error in this case. On the other hand, |
---|
2454 | * if we simply miss the standard for the link type or a new |
---|
2455 | * standard is defined for a new link type, the IFID length |
---|
2456 | * is very likely to be the common constant. As a compromise, |
---|
2457 | * we always use the constant, but make an explicit notice |
---|
2458 | * indicating the "unknown" case. |
---|
2459 | */ |
---|
2460 | printf("in6_if2idlen: unknown link type (%d)\n", ifp->if_type); |
---|
2461 | return (64); |
---|
2462 | } |
---|
2463 | } |
---|
2464 | |
---|
2465 | #include <sys/sysctl.h> |
---|
2466 | |
---|
2467 | struct in6_llentry { |
---|
2468 | struct llentry base; |
---|
2469 | struct sockaddr_in6 l3_addr6; |
---|
2470 | }; |
---|
2471 | |
---|
2472 | /* |
---|
2473 | * Deletes an address from the address table. |
---|
2474 | * This function is called by the timer functions |
---|
2475 | * such as arptimer() and nd6_llinfo_timer(), and |
---|
2476 | * the caller does the locking. |
---|
2477 | */ |
---|
2478 | static void |
---|
2479 | in6_lltable_free(struct lltable *llt, struct llentry *lle) |
---|
2480 | { |
---|
2481 | LLE_WUNLOCK(lle); |
---|
2482 | LLE_LOCK_DESTROY(lle); |
---|
2483 | free(lle, M_LLTABLE); |
---|
2484 | } |
---|
2485 | |
---|
2486 | static struct llentry * |
---|
2487 | in6_lltable_new(const struct sockaddr *l3addr, u_int flags) |
---|
2488 | { |
---|
2489 | struct in6_llentry *lle; |
---|
2490 | |
---|
2491 | lle = malloc(sizeof(struct in6_llentry), M_LLTABLE, M_NOWAIT | M_ZERO); |
---|
2492 | if (lle == NULL) /* NB: caller generates msg */ |
---|
2493 | return NULL; |
---|
2494 | |
---|
2495 | lle->l3_addr6 = *(const struct sockaddr_in6 *)l3addr; |
---|
2496 | lle->base.lle_refcnt = 1; |
---|
2497 | lle->base.lle_free = in6_lltable_free; |
---|
2498 | LLE_LOCK_INIT(&lle->base); |
---|
2499 | callout_init_rw(&lle->base.ln_timer_ch, &lle->base.lle_lock, |
---|
2500 | CALLOUT_RETURNUNLOCKED); |
---|
2501 | |
---|
2502 | return (&lle->base); |
---|
2503 | } |
---|
2504 | |
---|
2505 | static void |
---|
2506 | in6_lltable_prefix_free(struct lltable *llt, const struct sockaddr *prefix, |
---|
2507 | const struct sockaddr *mask, u_int flags) |
---|
2508 | { |
---|
2509 | const struct sockaddr_in6 *pfx = (const struct sockaddr_in6 *)prefix; |
---|
2510 | const struct sockaddr_in6 *msk = (const struct sockaddr_in6 *)mask; |
---|
2511 | struct llentry *lle, *next; |
---|
2512 | int i; |
---|
2513 | |
---|
2514 | /* |
---|
2515 | * (flags & LLE_STATIC) means deleting all entries |
---|
2516 | * including static ND6 entries. |
---|
2517 | */ |
---|
2518 | IF_AFDATA_WLOCK(llt->llt_ifp); |
---|
2519 | for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { |
---|
2520 | LIST_FOREACH_SAFE(lle, &llt->lle_head[i], lle_next, next) { |
---|
2521 | if (IN6_ARE_MASKED_ADDR_EQUAL( |
---|
2522 | &satosin6(L3_ADDR(lle))->sin6_addr, |
---|
2523 | &pfx->sin6_addr, &msk->sin6_addr) && |
---|
2524 | ((flags & LLE_STATIC) || |
---|
2525 | !(lle->la_flags & LLE_STATIC))) { |
---|
2526 | LLE_WLOCK(lle); |
---|
2527 | if (callout_stop(&lle->la_timer)) |
---|
2528 | LLE_REMREF(lle); |
---|
2529 | llentry_free(lle); |
---|
2530 | } |
---|
2531 | } |
---|
2532 | } |
---|
2533 | IF_AFDATA_WUNLOCK(llt->llt_ifp); |
---|
2534 | } |
---|
2535 | |
---|
2536 | static int |
---|
2537 | in6_lltable_rtcheck(struct ifnet *ifp, |
---|
2538 | u_int flags, |
---|
2539 | const struct sockaddr *l3addr) |
---|
2540 | { |
---|
2541 | struct rtentry *rt; |
---|
2542 | char ip6buf[INET6_ADDRSTRLEN]; |
---|
2543 | |
---|
2544 | KASSERT(l3addr->sa_family == AF_INET6, |
---|
2545 | ("sin_family %d", l3addr->sa_family)); |
---|
2546 | |
---|
2547 | /* Our local addresses are always only installed on the default FIB. */ |
---|
2548 | /* XXX rtalloc1 should take a const param */ |
---|
2549 | rt = in6_rtalloc1(__DECONST(struct sockaddr *, l3addr), 0, 0, |
---|
2550 | RT_DEFAULT_FIB); |
---|
2551 | if (rt == NULL || (rt->rt_flags & RTF_GATEWAY) || rt->rt_ifp != ifp) { |
---|
2552 | struct ifaddr *ifa; |
---|
2553 | /* |
---|
2554 | * Create an ND6 cache for an IPv6 neighbor |
---|
2555 | * that is not covered by our own prefix. |
---|
2556 | */ |
---|
2557 | /* XXX ifaof_ifpforaddr should take a const param */ |
---|
2558 | ifa = ifaof_ifpforaddr(__DECONST(struct sockaddr *, l3addr), ifp); |
---|
2559 | if (ifa != NULL) { |
---|
2560 | ifa_free(ifa); |
---|
2561 | if (rt != NULL) |
---|
2562 | RTFREE_LOCKED(rt); |
---|
2563 | return 0; |
---|
2564 | } |
---|
2565 | log(LOG_INFO, "IPv6 address: \"%s\" is not on the network\n", |
---|
2566 | ip6_sprintf(ip6buf, &((const struct sockaddr_in6 *)l3addr)->sin6_addr)); |
---|
2567 | if (rt != NULL) |
---|
2568 | RTFREE_LOCKED(rt); |
---|
2569 | return EINVAL; |
---|
2570 | } |
---|
2571 | RTFREE_LOCKED(rt); |
---|
2572 | return 0; |
---|
2573 | } |
---|
2574 | |
---|
2575 | static struct llentry * |
---|
2576 | in6_lltable_lookup(struct lltable *llt, u_int flags, |
---|
2577 | const struct sockaddr *l3addr) |
---|
2578 | { |
---|
2579 | const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)l3addr; |
---|
2580 | struct ifnet *ifp = llt->llt_ifp; |
---|
2581 | struct llentry *lle; |
---|
2582 | struct llentries *lleh; |
---|
2583 | u_int hashkey; |
---|
2584 | |
---|
2585 | IF_AFDATA_LOCK_ASSERT(ifp); |
---|
2586 | KASSERT(l3addr->sa_family == AF_INET6, |
---|
2587 | ("sin_family %d", l3addr->sa_family)); |
---|
2588 | |
---|
2589 | hashkey = sin6->sin6_addr.s6_addr32[3]; |
---|
2590 | lleh = &llt->lle_head[LLATBL_HASH(hashkey, LLTBL_HASHMASK)]; |
---|
2591 | LIST_FOREACH(lle, lleh, lle_next) { |
---|
2592 | struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)L3_ADDR(lle); |
---|
2593 | if (lle->la_flags & LLE_DELETED) |
---|
2594 | continue; |
---|
2595 | if (bcmp(&sa6->sin6_addr, &sin6->sin6_addr, |
---|
2596 | sizeof(struct in6_addr)) == 0) |
---|
2597 | break; |
---|
2598 | } |
---|
2599 | |
---|
2600 | if (lle == NULL) { |
---|
2601 | if (!(flags & LLE_CREATE)) |
---|
2602 | return (NULL); |
---|
2603 | IF_AFDATA_WLOCK_ASSERT(ifp); |
---|
2604 | /* |
---|
2605 | * A route that covers the given address must have |
---|
2606 | * been installed 1st because we are doing a resolution, |
---|
2607 | * verify this. |
---|
2608 | */ |
---|
2609 | if (!(flags & LLE_IFADDR) && |
---|
2610 | in6_lltable_rtcheck(ifp, flags, l3addr) != 0) |
---|
2611 | return NULL; |
---|
2612 | |
---|
2613 | lle = in6_lltable_new(l3addr, flags); |
---|
2614 | if (lle == NULL) { |
---|
2615 | log(LOG_INFO, "lla_lookup: new lle malloc failed\n"); |
---|
2616 | return NULL; |
---|
2617 | } |
---|
2618 | lle->la_flags = flags & ~LLE_CREATE; |
---|
2619 | if ((flags & (LLE_CREATE | LLE_IFADDR)) == (LLE_CREATE | LLE_IFADDR)) { |
---|
2620 | bcopy(IF_LLADDR(ifp), &lle->ll_addr, ifp->if_addrlen); |
---|
2621 | lle->la_flags |= (LLE_VALID | LLE_STATIC); |
---|
2622 | } |
---|
2623 | |
---|
2624 | lle->lle_tbl = llt; |
---|
2625 | lle->lle_head = lleh; |
---|
2626 | lle->la_flags |= LLE_LINKED; |
---|
2627 | LIST_INSERT_HEAD(lleh, lle, lle_next); |
---|
2628 | } else if (flags & LLE_DELETE) { |
---|
2629 | if (!(lle->la_flags & LLE_IFADDR) || (flags & LLE_IFADDR)) { |
---|
2630 | LLE_WLOCK(lle); |
---|
2631 | lle->la_flags |= LLE_DELETED; |
---|
2632 | #ifdef DIAGNOSTIC |
---|
2633 | log(LOG_INFO, "ifaddr cache = %p is deleted\n", lle); |
---|
2634 | #endif |
---|
2635 | if ((lle->la_flags & |
---|
2636 | (LLE_STATIC | LLE_IFADDR)) == LLE_STATIC) |
---|
2637 | llentry_free(lle); |
---|
2638 | else |
---|
2639 | LLE_WUNLOCK(lle); |
---|
2640 | } |
---|
2641 | lle = (void *)-1; |
---|
2642 | } |
---|
2643 | if (LLE_IS_VALID(lle)) { |
---|
2644 | if (flags & LLE_EXCLUSIVE) |
---|
2645 | LLE_WLOCK(lle); |
---|
2646 | else |
---|
2647 | LLE_RLOCK(lle); |
---|
2648 | } |
---|
2649 | return (lle); |
---|
2650 | } |
---|
2651 | |
---|
2652 | static int |
---|
2653 | in6_lltable_dump(struct lltable *llt, struct sysctl_req *wr) |
---|
2654 | { |
---|
2655 | struct ifnet *ifp = llt->llt_ifp; |
---|
2656 | struct llentry *lle; |
---|
2657 | /* XXX stack use */ |
---|
2658 | struct { |
---|
2659 | struct rt_msghdr rtm; |
---|
2660 | struct sockaddr_in6 sin6; |
---|
2661 | /* |
---|
2662 | * ndp.c assumes that sdl is word aligned |
---|
2663 | */ |
---|
2664 | #ifdef __LP64__ |
---|
2665 | uint32_t pad; |
---|
2666 | #endif |
---|
2667 | struct sockaddr_dl sdl; |
---|
2668 | } ndpc; |
---|
2669 | int i, error; |
---|
2670 | |
---|
2671 | if (ifp->if_flags & IFF_LOOPBACK) |
---|
2672 | return 0; |
---|
2673 | |
---|
2674 | LLTABLE_LOCK_ASSERT(); |
---|
2675 | |
---|
2676 | error = 0; |
---|
2677 | for (i = 0; i < LLTBL_HASHTBL_SIZE; i++) { |
---|
2678 | LIST_FOREACH(lle, &llt->lle_head[i], lle_next) { |
---|
2679 | struct sockaddr_dl *sdl; |
---|
2680 | |
---|
2681 | /* skip deleted or invalid entries */ |
---|
2682 | if ((lle->la_flags & (LLE_DELETED|LLE_VALID)) != LLE_VALID) |
---|
2683 | continue; |
---|
2684 | /* Skip if jailed and not a valid IP of the prison. */ |
---|
2685 | if (prison_if(wr->td->td_ucred, L3_ADDR(lle)) != 0) |
---|
2686 | continue; |
---|
2687 | /* |
---|
2688 | * produce a msg made of: |
---|
2689 | * struct rt_msghdr; |
---|
2690 | * struct sockaddr_in6 (IPv6) |
---|
2691 | * struct sockaddr_dl; |
---|
2692 | */ |
---|
2693 | bzero(&ndpc, sizeof(ndpc)); |
---|
2694 | ndpc.rtm.rtm_msglen = sizeof(ndpc); |
---|
2695 | ndpc.rtm.rtm_version = RTM_VERSION; |
---|
2696 | ndpc.rtm.rtm_type = RTM_GET; |
---|
2697 | ndpc.rtm.rtm_flags = RTF_UP; |
---|
2698 | ndpc.rtm.rtm_addrs = RTA_DST | RTA_GATEWAY; |
---|
2699 | ndpc.sin6.sin6_family = AF_INET6; |
---|
2700 | ndpc.sin6.sin6_len = sizeof(ndpc.sin6); |
---|
2701 | bcopy(L3_ADDR(lle), &ndpc.sin6, L3_ADDR_LEN(lle)); |
---|
2702 | |
---|
2703 | /* publish */ |
---|
2704 | if (lle->la_flags & LLE_PUB) |
---|
2705 | ndpc.rtm.rtm_flags |= RTF_ANNOUNCE; |
---|
2706 | |
---|
2707 | sdl = &ndpc.sdl; |
---|
2708 | sdl->sdl_family = AF_LINK; |
---|
2709 | sdl->sdl_len = sizeof(*sdl); |
---|
2710 | sdl->sdl_alen = ifp->if_addrlen; |
---|
2711 | sdl->sdl_index = ifp->if_index; |
---|
2712 | sdl->sdl_type = ifp->if_type; |
---|
2713 | bcopy(&lle->ll_addr, LLADDR(sdl), ifp->if_addrlen); |
---|
2714 | ndpc.rtm.rtm_rmx.rmx_expire = |
---|
2715 | lle->la_flags & LLE_STATIC ? 0 : lle->la_expire; |
---|
2716 | ndpc.rtm.rtm_flags |= (RTF_HOST | RTF_LLDATA); |
---|
2717 | if (lle->la_flags & LLE_STATIC) |
---|
2718 | ndpc.rtm.rtm_flags |= RTF_STATIC; |
---|
2719 | ndpc.rtm.rtm_index = ifp->if_index; |
---|
2720 | error = SYSCTL_OUT(wr, &ndpc, sizeof(ndpc)); |
---|
2721 | if (error) |
---|
2722 | break; |
---|
2723 | } |
---|
2724 | } |
---|
2725 | return error; |
---|
2726 | } |
---|
2727 | |
---|
2728 | void * |
---|
2729 | in6_domifattach(struct ifnet *ifp) |
---|
2730 | { |
---|
2731 | struct in6_ifextra *ext; |
---|
2732 | |
---|
2733 | ext = (struct in6_ifextra *)malloc(sizeof(*ext), M_IFADDR, M_WAITOK); |
---|
2734 | bzero(ext, sizeof(*ext)); |
---|
2735 | |
---|
2736 | ext->in6_ifstat = (struct in6_ifstat *)malloc(sizeof(struct in6_ifstat), |
---|
2737 | M_IFADDR, M_WAITOK); |
---|
2738 | bzero(ext->in6_ifstat, sizeof(*ext->in6_ifstat)); |
---|
2739 | |
---|
2740 | ext->icmp6_ifstat = |
---|
2741 | (struct icmp6_ifstat *)malloc(sizeof(struct icmp6_ifstat), |
---|
2742 | M_IFADDR, M_WAITOK); |
---|
2743 | bzero(ext->icmp6_ifstat, sizeof(*ext->icmp6_ifstat)); |
---|
2744 | |
---|
2745 | ext->nd_ifinfo = nd6_ifattach(ifp); |
---|
2746 | ext->scope6_id = scope6_ifattach(ifp); |
---|
2747 | ext->lltable = lltable_init(ifp, AF_INET6); |
---|
2748 | if (ext->lltable != NULL) { |
---|
2749 | ext->lltable->llt_prefix_free = in6_lltable_prefix_free; |
---|
2750 | ext->lltable->llt_lookup = in6_lltable_lookup; |
---|
2751 | ext->lltable->llt_dump = in6_lltable_dump; |
---|
2752 | } |
---|
2753 | |
---|
2754 | ext->mld_ifinfo = mld_domifattach(ifp); |
---|
2755 | |
---|
2756 | return ext; |
---|
2757 | } |
---|
2758 | |
---|
2759 | void |
---|
2760 | in6_domifdetach(struct ifnet *ifp, void *aux) |
---|
2761 | { |
---|
2762 | struct in6_ifextra *ext = (struct in6_ifextra *)aux; |
---|
2763 | |
---|
2764 | mld_domifdetach(ifp); |
---|
2765 | scope6_ifdetach(ext->scope6_id); |
---|
2766 | nd6_ifdetach(ext->nd_ifinfo); |
---|
2767 | lltable_free(ext->lltable); |
---|
2768 | free(ext->in6_ifstat, M_IFADDR); |
---|
2769 | free(ext->icmp6_ifstat, M_IFADDR); |
---|
2770 | free(ext, M_IFADDR); |
---|
2771 | } |
---|
2772 | |
---|
2773 | /* |
---|
2774 | * Convert sockaddr_in6 to sockaddr_in. Original sockaddr_in6 must be |
---|
2775 | * v4 mapped addr or v4 compat addr |
---|
2776 | */ |
---|
2777 | void |
---|
2778 | in6_sin6_2_sin(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) |
---|
2779 | { |
---|
2780 | |
---|
2781 | bzero(sin, sizeof(*sin)); |
---|
2782 | sin->sin_len = sizeof(struct sockaddr_in); |
---|
2783 | sin->sin_family = AF_INET; |
---|
2784 | sin->sin_port = sin6->sin6_port; |
---|
2785 | sin->sin_addr.s_addr = sin6->sin6_addr.s6_addr32[3]; |
---|
2786 | } |
---|
2787 | |
---|
2788 | /* Convert sockaddr_in to sockaddr_in6 in v4 mapped addr format. */ |
---|
2789 | void |
---|
2790 | in6_sin_2_v4mapsin6(struct sockaddr_in *sin, struct sockaddr_in6 *sin6) |
---|
2791 | { |
---|
2792 | bzero(sin6, sizeof(*sin6)); |
---|
2793 | sin6->sin6_len = sizeof(struct sockaddr_in6); |
---|
2794 | sin6->sin6_family = AF_INET6; |
---|
2795 | sin6->sin6_port = sin->sin_port; |
---|
2796 | sin6->sin6_addr.s6_addr32[0] = 0; |
---|
2797 | sin6->sin6_addr.s6_addr32[1] = 0; |
---|
2798 | sin6->sin6_addr.s6_addr32[2] = IPV6_ADDR_INT32_SMP; |
---|
2799 | sin6->sin6_addr.s6_addr32[3] = sin->sin_addr.s_addr; |
---|
2800 | } |
---|
2801 | |
---|
2802 | /* Convert sockaddr_in6 into sockaddr_in. */ |
---|
2803 | void |
---|
2804 | in6_sin6_2_sin_in_sock(struct sockaddr *nam) |
---|
2805 | { |
---|
2806 | struct sockaddr_in *sin_p; |
---|
2807 | struct sockaddr_in6 sin6; |
---|
2808 | |
---|
2809 | /* |
---|
2810 | * Save original sockaddr_in6 addr and convert it |
---|
2811 | * to sockaddr_in. |
---|
2812 | */ |
---|
2813 | sin6 = *(struct sockaddr_in6 *)nam; |
---|
2814 | sin_p = (struct sockaddr_in *)nam; |
---|
2815 | in6_sin6_2_sin(sin_p, &sin6); |
---|
2816 | } |
---|
2817 | |
---|
2818 | /* Convert sockaddr_in into sockaddr_in6 in v4 mapped addr format. */ |
---|
2819 | void |
---|
2820 | in6_sin_2_v4mapsin6_in_sock(struct sockaddr **nam) |
---|
2821 | { |
---|
2822 | struct sockaddr_in *sin_p; |
---|
2823 | struct sockaddr_in6 *sin6_p; |
---|
2824 | |
---|
2825 | sin6_p = malloc(sizeof *sin6_p, M_SONAME, M_WAITOK); |
---|
2826 | sin_p = (struct sockaddr_in *)*nam; |
---|
2827 | in6_sin_2_v4mapsin6(sin_p, sin6_p); |
---|
2828 | free(*nam, M_SONAME); |
---|
2829 | *nam = (struct sockaddr *)sin6_p; |
---|
2830 | } |
---|