]>
Commit | Line | Data |
---|---|---|
2d21ac55 | 1 | /* |
eb6b6ca3 | 2 | * Copyright (c) 2003-2020 Apple Inc. All rights reserved. |
2d21ac55 A |
3 | * |
4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ | |
39236c6e | 5 | * |
2d21ac55 A |
6 | * This file contains Original Code and/or Modifications of Original Code |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. The rights granted to you under the License | |
10 | * may not be used to create, or enable the creation or redistribution of, | |
11 | * unlawful or unlicensed copies of an Apple operating system, or to | |
12 | * circumvent, violate, or enable the circumvention or violation of, any | |
13 | * terms of an Apple operating system software license agreement. | |
39236c6e | 14 | * |
2d21ac55 A |
15 | * Please obtain a copy of the License at |
16 | * http://www.opensource.apple.com/apsl/ and read it before using this file. | |
39236c6e | 17 | * |
2d21ac55 A |
18 | * The Original Code and all software distributed under the License are |
19 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
20 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
21 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
22 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
23 | * Please see the License for the specific language governing rights and | |
24 | * limitations under the License. | |
39236c6e | 25 | * |
2d21ac55 A |
26 | * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ |
27 | */ | |
1c79356b A |
28 | |
29 | /* | |
30 | * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. | |
31 | * All rights reserved. | |
32 | * | |
33 | * Redistribution and use in source and binary forms, with or without | |
34 | * modification, are permitted provided that the following conditions | |
35 | * are met: | |
36 | * 1. Redistributions of source code must retain the above copyright | |
37 | * notice, this list of conditions and the following disclaimer. | |
38 | * 2. Redistributions in binary form must reproduce the above copyright | |
39 | * notice, this list of conditions and the following disclaimer in the | |
40 | * documentation and/or other materials provided with the distribution. | |
41 | * 3. Neither the name of the project nor the names of its contributors | |
42 | * may be used to endorse or promote products derived from this software | |
43 | * without specific prior written permission. | |
44 | * | |
45 | * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND | |
46 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
47 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
48 | * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE | |
49 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL | |
50 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS | |
51 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) | |
52 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
53 | * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | |
54 | * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | |
55 | * SUCH DAMAGE. | |
56 | */ | |
57 | ||
58 | #include <sys/param.h> | |
59 | #include <sys/systm.h> | |
60 | #include <sys/malloc.h> | |
61 | #include <sys/socket.h> | |
9bccf70c | 62 | #include <sys/socketvar.h> |
1c79356b A |
63 | #include <sys/sockio.h> |
64 | #include <sys/kernel.h> | |
9bccf70c | 65 | #include <sys/syslog.h> |
316670eb | 66 | #include <libkern/crypto/sha1.h> |
2d21ac55 | 67 | #include <libkern/OSAtomic.h> |
fe8ab488 | 68 | #include <kern/locks.h> |
1c79356b A |
69 | |
70 | #include <net/if.h> | |
71 | #include <net/if_dl.h> | |
72 | #include <net/if_types.h> | |
73 | #include <net/route.h> | |
2d21ac55 | 74 | #include <net/kpi_protocol.h> |
5ba3f43e | 75 | #include <net/if_llatbl.h> |
1c79356b A |
76 | |
77 | #include <netinet/in.h> | |
78 | #include <netinet/in_var.h> | |
1c79356b | 79 | #include <netinet/if_ether.h> |
9bccf70c | 80 | #include <netinet/in_pcb.h> |
6d2010ae | 81 | #include <netinet/icmp6.h> |
1c79356b A |
82 | |
83 | #include <netinet/ip6.h> | |
84 | #include <netinet6/ip6_var.h> | |
9bccf70c A |
85 | #include <netinet6/in6_var.h> |
86 | #include <netinet6/in6_pcb.h> | |
1c79356b A |
87 | #include <netinet6/in6_ifattach.h> |
88 | #include <netinet6/ip6_var.h> | |
89 | #include <netinet6/nd6.h> | |
9bccf70c | 90 | #include <netinet6/scope6_var.h> |
1c79356b A |
91 | |
92 | #include <net/net_osdep.h> | |
39236c6e | 93 | #include <dev/random/randomdev.h> |
1c79356b | 94 | |
b0d623f7 | 95 | u_int32_t in6_maxmtu = 0; |
91447636 | 96 | extern lck_mtx_t *nd6_mutex; |
1c79356b | 97 | |
9bccf70c A |
98 | #if IP6_AUTO_LINKLOCAL |
99 | int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL; | |
100 | #else | |
0a7de745 | 101 | int ip6_auto_linklocal = 1; /* enable by default */ |
9bccf70c | 102 | #endif |
1c79356b | 103 | |
9bccf70c A |
104 | extern struct inpcbinfo udbinfo; |
105 | extern struct inpcbinfo ripcbinfo; | |
1c79356b | 106 | |
39236c6e | 107 | static const unsigned int in6_extra_size = sizeof(struct in6_ifextra); |
0a7de745 | 108 | static const unsigned int in6_extra_bufsize = in6_extra_size + |
39236c6e A |
109 | sizeof(void *) + sizeof(uint64_t); |
110 | ||
111 | static int get_rand_iid(struct ifnet *, struct in6_addr *); | |
112 | static int in6_generate_tmp_iid(u_int8_t *, const u_int8_t *, u_int8_t *); | |
113 | static int in6_select_iid_from_all_hw(struct ifnet *, struct ifnet *, | |
114 | struct in6_addr *); | |
115 | static int in6_ifattach_linklocal(struct ifnet *, struct in6_aliasreq *); | |
91447636 | 116 | static int in6_ifattach_loopback(struct ifnet *); |
1c79356b | 117 | |
1c79356b A |
118 | /* |
119 | * Generate a last-resort interface identifier, when the machine has no | |
120 | * IEEE802/EUI64 address sources. | |
9bccf70c A |
121 | * The goal here is to get an interface identifier that is |
122 | * (1) random enough and (2) does not change across reboot. | |
316670eb | 123 | * We currently use SHA1(hostname) for it. |
6d2010ae A |
124 | * |
125 | * in6 - upper 64bits are preserved | |
1c79356b A |
126 | */ |
127 | static int | |
39236c6e | 128 | get_rand_iid( |
2d21ac55 | 129 | __unused struct ifnet *ifp, |
0a7de745 | 130 | struct in6_addr *in6) /* upper 64bits are preserved */ |
1c79356b | 131 | { |
316670eb A |
132 | SHA1_CTX ctxt; |
133 | u_int8_t digest[SHA1_RESULTLEN]; | |
f427ee49 | 134 | size_t hostnlen; |
9bccf70c | 135 | |
9bccf70c | 136 | /* generate 8 bytes of pseudo-random value. */ |
0a7de745 | 137 | bzero(&ctxt, sizeof(ctxt)); |
316670eb | 138 | SHA1Init(&ctxt); |
cb323159 A |
139 | lck_mtx_lock(&hostname_lock); |
140 | hostnlen = strlen(hostname); | |
316670eb | 141 | SHA1Update(&ctxt, hostname, hostnlen); |
cb323159 | 142 | lck_mtx_unlock(&hostname_lock); |
316670eb | 143 | SHA1Final(digest, &ctxt); |
1c79356b | 144 | |
39236c6e | 145 | /* assumes sizeof (digest) > sizeof (iid) */ |
9bccf70c | 146 | bcopy(digest, &in6->s6_addr[8], 8); |
1c79356b A |
147 | |
148 | /* make sure to set "u" bit to local, and "g" bit to individual. */ | |
0a7de745 A |
149 | in6->s6_addr[8] &= ~ND6_EUI64_GBIT; /* g bit to "individual" */ |
150 | in6->s6_addr[8] |= ND6_EUI64_UBIT; /* u bit to "local" */ | |
9bccf70c A |
151 | |
152 | /* convert EUI64 into IPv6 interface identifier */ | |
316670eb | 153 | ND6_EUI64_TO_IFID(in6); |
9bccf70c | 154 | |
0a7de745 | 155 | return 0; |
9bccf70c A |
156 | } |
157 | ||
158 | static int | |
39236c6e | 159 | in6_generate_tmp_iid( |
91447636 A |
160 | u_int8_t *seed0, |
161 | const u_int8_t *seed1, | |
162 | u_int8_t *ret) | |
9bccf70c | 163 | { |
316670eb A |
164 | SHA1_CTX ctxt; |
165 | u_int8_t seed[16], nullbuf[8], digest[SHA1_RESULTLEN]; | |
9bccf70c A |
166 | u_int32_t val32; |
167 | struct timeval tv; | |
168 | ||
6d2010ae | 169 | /* If there's no history, start with a random seed. */ |
0a7de745 A |
170 | bzero(nullbuf, sizeof(nullbuf)); |
171 | if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) { | |
9bccf70c A |
172 | int i; |
173 | ||
174 | for (i = 0; i < 2; i++) { | |
39236c6e A |
175 | getmicrotime(&tv); |
176 | val32 = RandomULong() ^ tv.tv_usec; | |
0a7de745 A |
177 | bcopy(&val32, seed + sizeof(val32) * i, |
178 | sizeof(val32)); | |
9bccf70c | 179 | } |
55e303ae | 180 | } else { |
9bccf70c | 181 | bcopy(seed0, seed, 8); |
55e303ae | 182 | } |
9bccf70c A |
183 | |
184 | /* copy the right-most 64-bits of the given address */ | |
185 | /* XXX assumption on the size of IFID */ | |
186 | bcopy(seed1, &seed[8], 8); | |
187 | ||
0a7de745 | 188 | if ((0)) { /* for debugging purposes only */ |
9bccf70c A |
189 | int i; |
190 | ||
39236c6e | 191 | printf("%s: new randomized ID from: ", __func__); |
0a7de745 | 192 | for (i = 0; i < 16; i++) { |
9bccf70c | 193 | printf("%02x", seed[i]); |
0a7de745 | 194 | } |
9bccf70c A |
195 | printf(" "); |
196 | } | |
197 | ||
198 | /* generate 16 bytes of pseudo-random value. */ | |
0a7de745 | 199 | bzero(&ctxt, sizeof(ctxt)); |
316670eb | 200 | SHA1Init(&ctxt); |
0a7de745 | 201 | SHA1Update(&ctxt, seed, sizeof(seed)); |
316670eb | 202 | SHA1Final(digest, &ctxt); |
9bccf70c A |
203 | |
204 | /* | |
6d2010ae | 205 | * RFC 4941 3.2.1. (3) |
316670eb | 206 | * Take the left-most 64-bits of the SHA1 digest and set bit 6 (the |
9bccf70c A |
207 | * left-most bit is numbered 0) to zero. |
208 | */ | |
209 | bcopy(digest, ret, 8); | |
316670eb | 210 | ret[0] &= ~ND6_EUI64_UBIT; |
9bccf70c A |
211 | |
212 | /* | |
213 | * XXX: we'd like to ensure that the generated value is not zero | |
214 | * for simplicity. If the caclculated digest happens to be zero, | |
215 | * use a random non-zero value as the last resort. | |
216 | */ | |
0a7de745 | 217 | if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) { |
cb323159 A |
218 | nd6log(info, |
219 | "%s: computed SHA1 value is zero.\n", __func__); | |
9bccf70c | 220 | |
39236c6e | 221 | getmicrotime(&tv); |
9bccf70c A |
222 | val32 = random() ^ tv.tv_usec; |
223 | val32 = 1 + (val32 % (0xffffffff - 1)); | |
224 | } | |
225 | ||
226 | /* | |
6d2010ae | 227 | * RFC 4941 3.2.1. (4) |
316670eb | 228 | * Take the next 64-bits of the SHA1 digest and save them in |
9bccf70c | 229 | * stable storage as the history value to be used in the next |
6d2010ae | 230 | * iteration of the algorithm. |
9bccf70c A |
231 | */ |
232 | bcopy(&digest[8], seed0, 8); | |
233 | ||
0a7de745 | 234 | if ((0)) { /* for debugging purposes only */ |
9bccf70c A |
235 | int i; |
236 | ||
237 | printf("to: "); | |
0a7de745 | 238 | for (i = 0; i < 16; i++) { |
9bccf70c | 239 | printf("%02x", digest[i]); |
0a7de745 | 240 | } |
9bccf70c A |
241 | printf("\n"); |
242 | } | |
1c79356b | 243 | |
0a7de745 | 244 | return 0; |
1c79356b A |
245 | } |
246 | ||
247 | /* | |
39236c6e A |
248 | * Get interface identifier for the specified interface using the method in |
249 | * Appendix A of RFC 4291. | |
250 | * | |
9bccf70c | 251 | * XXX assumes single sockaddr_dl (AF_LINK address) per an interface |
6d2010ae A |
252 | * |
253 | * in6 - upper 64bits are preserved | |
1c79356b | 254 | */ |
6d2010ae | 255 | int |
39236c6e | 256 | in6_iid_from_hw(struct ifnet *ifp, struct in6_addr *in6) |
9bccf70c | 257 | { |
6d2010ae | 258 | struct ifaddr *ifa = NULL; |
1c79356b | 259 | struct sockaddr_dl *sdl; |
9bccf70c A |
260 | u_int8_t *addr; |
261 | size_t addrlen; | |
262 | static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; | |
263 | static u_int8_t allone[8] = | |
0a7de745 | 264 | { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; |
6d2010ae | 265 | int err = -1; |
9bccf70c | 266 | |
91447636 A |
267 | /* Why doesn't this code use ifnet_addrs? */ |
268 | ifnet_lock_shared(ifp); | |
6d2010ae | 269 | ifa = ifp->if_lladdr; |
316670eb | 270 | sdl = (struct sockaddr_dl *)(void *)ifa->ifa_addr; |
6d2010ae A |
271 | if (sdl->sdl_alen == 0) { |
272 | ifnet_lock_done(ifp); | |
0a7de745 | 273 | return -1; |
9bccf70c | 274 | } |
0a7de745 | 275 | IFA_ADDREF(ifa); /* for this routine */ |
91447636 | 276 | ifnet_lock_done(ifp); |
1c79356b | 277 | |
6d2010ae | 278 | IFA_LOCK(ifa); |
2d21ac55 | 279 | addr = (u_int8_t *) LLADDR(sdl); |
9bccf70c A |
280 | addrlen = sdl->sdl_alen; |
281 | ||
282 | /* get EUI64 */ | |
283 | switch (ifp->if_type) { | |
284 | case IFT_ETHER: | |
285 | case IFT_FDDI: | |
6d2010ae | 286 | case IFT_ISO88025: |
9bccf70c A |
287 | case IFT_ATM: |
288 | case IFT_IEEE1394: | |
91447636 A |
289 | case IFT_L2VLAN: |
290 | case IFT_IEEE8023ADLAG: | |
9bccf70c A |
291 | #if IFT_IEEE80211 |
292 | case IFT_IEEE80211: | |
1c79356b | 293 | #endif |
b7266188 | 294 | case IFT_BRIDGE: |
cb323159 | 295 | case IFT_6LOWPAN: |
9bccf70c A |
296 | /* IEEE802/EUI64 cases - what others? */ |
297 | /* IEEE1394 uses 16byte length address starting with EUI64 */ | |
0a7de745 | 298 | if (addrlen > 8) { |
9bccf70c | 299 | addrlen = 8; |
0a7de745 | 300 | } |
9bccf70c A |
301 | |
302 | /* look at IEEE802/EUI64 only */ | |
0a7de745 | 303 | if (addrlen != 8 && addrlen != 6) { |
6d2010ae | 304 | goto done; |
0a7de745 | 305 | } |
9bccf70c A |
306 | |
307 | /* | |
308 | * check for invalid MAC address - on bsdi, we see it a lot | |
309 | * since wildboar configures all-zero MAC on pccard before | |
310 | * card insertion. | |
311 | */ | |
0a7de745 | 312 | if (bcmp(addr, allzero, addrlen) == 0) { |
6d2010ae | 313 | goto done; |
0a7de745 A |
314 | } |
315 | if (bcmp(addr, allone, addrlen) == 0) { | |
6d2010ae | 316 | goto done; |
0a7de745 | 317 | } |
9bccf70c A |
318 | |
319 | /* make EUI64 address */ | |
0a7de745 | 320 | if (addrlen == 8) { |
9bccf70c | 321 | bcopy(addr, &in6->s6_addr[8], 8); |
0a7de745 | 322 | } else if (addrlen == 6) { |
9bccf70c A |
323 | in6->s6_addr[8] = addr[0]; |
324 | in6->s6_addr[9] = addr[1]; | |
325 | in6->s6_addr[10] = addr[2]; | |
326 | in6->s6_addr[11] = 0xff; | |
327 | in6->s6_addr[12] = 0xfe; | |
328 | in6->s6_addr[13] = addr[3]; | |
329 | in6->s6_addr[14] = addr[4]; | |
330 | in6->s6_addr[15] = addr[5]; | |
331 | } | |
332 | break; | |
333 | ||
334 | case IFT_ARCNET: | |
0a7de745 | 335 | if (addrlen != 1) { |
6d2010ae | 336 | goto done; |
0a7de745 A |
337 | } |
338 | if (!addr[0]) { | |
6d2010ae | 339 | goto done; |
0a7de745 | 340 | } |
9bccf70c A |
341 | |
342 | bzero(&in6->s6_addr[8], 8); | |
343 | in6->s6_addr[15] = addr[0]; | |
344 | ||
345 | /* | |
346 | * due to insufficient bitwidth, we mark it local. | |
347 | */ | |
0a7de745 A |
348 | in6->s6_addr[8] &= ~ND6_EUI64_GBIT; /* g to "individual" */ |
349 | in6->s6_addr[8] |= ND6_EUI64_UBIT; /* u to "local" */ | |
9bccf70c A |
350 | break; |
351 | ||
352 | case IFT_GIF: | |
353 | #if IFT_STF | |
354 | case IFT_STF: | |
355 | #endif | |
356 | /* | |
39236c6e | 357 | * RFC2893 says: "SHOULD use IPv4 address as IID source". |
9bccf70c A |
358 | * however, IPv4 address is not very suitable as unique |
359 | * identifier source (can be renumbered). | |
360 | * we don't do this. | |
361 | */ | |
6d2010ae A |
362 | goto done; |
363 | ||
364 | case IFT_CELLULAR: | |
365 | goto done; | |
9bccf70c A |
366 | |
367 | default: | |
6d2010ae | 368 | goto done; |
9bccf70c A |
369 | } |
370 | ||
371 | /* sanity check: g bit must not indicate "group" */ | |
0a7de745 | 372 | if (ND6_EUI64_GROUP(in6)) { |
6d2010ae | 373 | goto done; |
0a7de745 | 374 | } |
9bccf70c A |
375 | |
376 | /* convert EUI64 into IPv6 interface identifier */ | |
316670eb | 377 | ND6_EUI64_TO_IFID(in6); |
9bccf70c A |
378 | |
379 | /* | |
39236c6e | 380 | * sanity check: iid must not be all zero, avoid conflict with |
9bccf70c A |
381 | * subnet router anycast |
382 | */ | |
316670eb | 383 | if ((in6->s6_addr[8] & ~(ND6_EUI64_GBIT | ND6_EUI64_UBIT)) == 0x00 && |
9bccf70c | 384 | bcmp(&in6->s6_addr[9], allzero, 7) == 0) { |
6d2010ae | 385 | goto done; |
9bccf70c A |
386 | } |
387 | ||
0a7de745 | 388 | err = 0; /* found */ |
6d2010ae A |
389 | |
390 | done: | |
391 | /* This must not be the last reference to the lladdr */ | |
392 | if (IFA_REMREF_LOCKED(ifa) == NULL) { | |
393 | panic("%s: unexpected (missing) refcnt ifa=%p", __func__, ifa); | |
394 | /* NOTREACHED */ | |
395 | } | |
396 | IFA_UNLOCK(ifa); | |
0a7de745 | 397 | return err; |
9bccf70c A |
398 | } |
399 | ||
400 | /* | |
39236c6e A |
401 | * Get interface identifier for the specified interface using the method in |
402 | * Appendix A of RFC 4291. If it is not available on ifp0, borrow interface | |
403 | * identifier from other information sources. | |
6d2010ae | 404 | * |
39236c6e A |
405 | * ifp - primary EUI64 source |
406 | * altifp - secondary EUI64 source | |
407 | * in6 - IPv6 address to output IID | |
9bccf70c A |
408 | */ |
409 | static int | |
39236c6e | 410 | in6_select_iid_from_all_hw( |
91447636 | 411 | struct ifnet *ifp0, |
0a7de745 | 412 | struct ifnet *altifp, /* secondary EUI64 source */ |
91447636 | 413 | struct in6_addr *in6) |
9bccf70c A |
414 | { |
415 | struct ifnet *ifp; | |
416 | ||
417 | /* first, try to get it from the interface itself */ | |
39236c6e | 418 | if (in6_iid_from_hw(ifp0, in6) == 0) { |
cb323159 A |
419 | nd6log(debug, "%s: IID derived from HW interface.\n", |
420 | if_name(ifp0)); | |
9bccf70c A |
421 | goto success; |
422 | } | |
423 | ||
424 | /* try secondary EUI64 source. this basically is for ATM PVC */ | |
39236c6e | 425 | if (altifp && in6_iid_from_hw(altifp, in6) == 0) { |
cb323159 A |
426 | nd6log(debug, "%s: IID from alterate HW interface %s.\n", |
427 | if_name(ifp0), if_name(altifp)); | |
9bccf70c A |
428 | goto success; |
429 | } | |
430 | ||
431 | /* next, try to get it from some other hardware interface */ | |
91447636 A |
432 | ifnet_head_lock_shared(); |
433 | TAILQ_FOREACH(ifp, &ifnet_head, if_list) { | |
0a7de745 | 434 | if (ifp == ifp0) { |
1c79356b | 435 | continue; |
0a7de745 A |
436 | } |
437 | if (in6_iid_from_hw(ifp, in6) != 0) { | |
9bccf70c | 438 | continue; |
0a7de745 | 439 | } |
9bccf70c A |
440 | |
441 | /* | |
39236c6e | 442 | * to borrow IID from other interface, IID needs to be |
9bccf70c A |
443 | * globally unique |
444 | */ | |
316670eb | 445 | if (ND6_IFID_UNIVERSAL(in6)) { |
cb323159 A |
446 | nd6log(debug, "%s: borrowed IID from %s\n", |
447 | if_name(ifp0), if_name(ifp)); | |
91447636 | 448 | ifnet_head_done(); |
9bccf70c A |
449 | goto success; |
450 | } | |
451 | } | |
91447636 | 452 | ifnet_head_done(); |
9bccf70c A |
453 | |
454 | /* last resort: get from random number source */ | |
39236c6e | 455 | if (get_rand_iid(ifp, in6) == 0) { |
cb323159 | 456 | nd6log(debug, "%s: IID from PRNG.\n", if_name(ifp0)); |
9bccf70c A |
457 | goto success; |
458 | } | |
459 | ||
460 | printf("%s: failed to get interface identifier\n", if_name(ifp0)); | |
0a7de745 | 461 | return -1; |
9bccf70c A |
462 | |
463 | success: | |
cb323159 | 464 | nd6log(info, "%s: IID: " |
0a7de745 A |
465 | "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", |
466 | if_name(ifp0), | |
467 | in6->s6_addr[8], in6->s6_addr[9], | |
468 | in6->s6_addr[10], in6->s6_addr[11], | |
469 | in6->s6_addr[12], in6->s6_addr[13], | |
cb323159 | 470 | in6->s6_addr[14], in6->s6_addr[15]); |
0a7de745 | 471 | return 0; |
9bccf70c A |
472 | } |
473 | ||
474 | static int | |
39236c6e | 475 | in6_ifattach_linklocal(struct ifnet *ifp, struct in6_aliasreq *ifra) |
9bccf70c A |
476 | { |
477 | struct in6_ifaddr *ia; | |
2d21ac55 | 478 | struct nd_prefix pr0, *pr; |
91447636 | 479 | int i, error; |
9bccf70c | 480 | |
39236c6e | 481 | VERIFY(ifra != NULL); |
9bccf70c | 482 | |
2d21ac55 | 483 | proto_plumb(PF_INET6, ifp); |
55e303ae | 484 | |
39236c6e A |
485 | error = in6_update_ifa(ifp, ifra, IN6_IFAUPDATE_DADDELAY, &ia); |
486 | if (error != 0) { | |
9bccf70c A |
487 | /* |
488 | * XXX: When the interface does not support IPv6, this call | |
489 | * would fail in the SIOCSIFADDR ioctl. I believe the | |
490 | * notification is rather confusing in this case, so just | |
6d2010ae | 491 | * suppress it. (jinmei@kame.net 20010130) |
9bccf70c | 492 | */ |
0a7de745 | 493 | if (error != EAFNOSUPPORT) { |
cb323159 | 494 | nd6log(info, "%s: failed to " |
9bccf70c A |
495 | "configure a link-local address on %s " |
496 | "(errno=%d)\n", | |
cb323159 | 497 | __func__, if_name(ifp), error); |
0a7de745 A |
498 | } |
499 | return EADDRNOTAVAIL; | |
9bccf70c | 500 | } |
39236c6e | 501 | VERIFY(ia != NULL); |
9bccf70c | 502 | |
9bccf70c | 503 | /* |
6d2010ae | 504 | * Make the link-local prefix (fe80::%link/64) as on-link. |
9bccf70c A |
505 | * Since we'd like to manage prefixes separately from addresses, |
506 | * we make an ND6 prefix structure for the link-local prefix, | |
507 | * and add it to the prefix list as a never-expire prefix. | |
508 | * XXX: this change might affect some existing code base... | |
509 | */ | |
0a7de745 | 510 | bzero(&pr0, sizeof(pr0)); |
6d2010ae | 511 | lck_mtx_init(&pr0.ndpr_lock, ifa_mtx_grp, ifa_mtx_attr); |
9bccf70c A |
512 | pr0.ndpr_ifp = ifp; |
513 | /* this should be 64 at this moment. */ | |
f427ee49 | 514 | pr0.ndpr_plen = (u_char)in6_mask2len(&ifra->ifra_prefixmask.sin6_addr, NULL); |
39236c6e A |
515 | pr0.ndpr_mask = ifra->ifra_prefixmask.sin6_addr; |
516 | pr0.ndpr_prefix = ifra->ifra_addr; | |
9bccf70c A |
517 | /* apply the mask for safety. (nd6_prelist_add will apply it again) */ |
518 | for (i = 0; i < 4; i++) { | |
519 | pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &= | |
0a7de745 | 520 | in6mask64.s6_addr32[i]; |
9bccf70c A |
521 | } |
522 | /* | |
523 | * Initialize parameters. The link-local prefix must always be | |
524 | * on-link, and its lifetimes never expire. | |
525 | */ | |
526 | pr0.ndpr_raf_onlink = 1; | |
0a7de745 | 527 | pr0.ndpr_raf_auto = 1; /* probably meaningless */ |
9bccf70c A |
528 | pr0.ndpr_vltime = ND6_INFINITE_LIFETIME; |
529 | pr0.ndpr_pltime = ND6_INFINITE_LIFETIME; | |
6d2010ae | 530 | pr0.ndpr_stateflags |= NDPRF_STATIC; |
9bccf70c A |
531 | /* |
532 | * Since there is no other link-local addresses, nd6_prefix_lookup() | |
533 | * probably returns NULL. However, we cannot always expect the result. | |
534 | * For example, if we first remove the (only) existing link-local | |
535 | * address, and then reconfigure another one, the prefix is still | |
536 | * valid with referring to the old link-local address. | |
537 | */ | |
3e170ce0 | 538 | if ((pr = nd6_prefix_lookup(&pr0, ND6_PREFIX_EXPIRY_UNSPEC)) == NULL) { |
6d2010ae A |
539 | if ((error = nd6_prelist_add(&pr0, NULL, &pr, TRUE)) != 0) { |
540 | IFA_REMREF(&ia->ia_ifa); | |
541 | lck_mtx_destroy(&pr0.ndpr_lock, ifa_mtx_grp); | |
0a7de745 | 542 | return error; |
b0d623f7 | 543 | } |
9bccf70c A |
544 | } |
545 | ||
fe8ab488 | 546 | in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia, NULL); |
39236c6e | 547 | IFA_REMREF(&ia->ia_ifa); |
2d21ac55 A |
548 | |
549 | /* Drop use count held above during lookup/add */ | |
0a7de745 | 550 | if (pr != NULL) { |
6d2010ae | 551 | NDPR_REMREF(pr); |
0a7de745 | 552 | } |
6d2010ae A |
553 | |
554 | lck_mtx_destroy(&pr0.ndpr_lock, ifa_mtx_grp); | |
0a7de745 | 555 | return 0; |
9bccf70c A |
556 | } |
557 | ||
558 | static int | |
91447636 | 559 | in6_ifattach_loopback( |
0a7de745 | 560 | struct ifnet *ifp) /* must be IFT_LOOP */ |
9bccf70c A |
561 | { |
562 | struct in6_aliasreq ifra; | |
39236c6e | 563 | struct in6_ifaddr *ia; |
9bccf70c A |
564 | int error; |
565 | ||
0a7de745 | 566 | bzero(&ifra, sizeof(ifra)); |
9bccf70c A |
567 | |
568 | /* | |
569 | * in6_update_ifa() does not use ifra_name, but we accurately set it | |
570 | * for safety. | |
571 | */ | |
0a7de745 | 572 | strlcpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); |
9bccf70c | 573 | |
0a7de745 | 574 | ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); |
9bccf70c A |
575 | ifra.ifra_prefixmask.sin6_family = AF_INET6; |
576 | ifra.ifra_prefixmask.sin6_addr = in6mask128; | |
577 | ||
578 | /* | |
579 | * Always initialize ia_dstaddr (= broadcast address) to loopback | |
580 | * address. Follows IPv4 practice - see in_ifinit(). | |
581 | */ | |
0a7de745 | 582 | ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6); |
9bccf70c A |
583 | ifra.ifra_dstaddr.sin6_family = AF_INET6; |
584 | ifra.ifra_dstaddr.sin6_addr = in6addr_loopback; | |
585 | ||
0a7de745 | 586 | ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); |
9bccf70c A |
587 | ifra.ifra_addr.sin6_family = AF_INET6; |
588 | ifra.ifra_addr.sin6_addr = in6addr_loopback; | |
589 | ||
590 | /* the loopback address should NEVER expire. */ | |
591 | ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
592 | ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; | |
593 | ||
55e303ae | 594 | /* we don't need to perform DAD on loopback interfaces. */ |
9bccf70c A |
595 | ifra.ifra_flags |= IN6_IFF_NODAD; |
596 | ||
39236c6e A |
597 | /* add the new interface address */ |
598 | error = in6_update_ifa(ifp, &ifra, 0, &ia); | |
599 | if (error != 0) { | |
cb323159 | 600 | nd6log(error, |
39236c6e | 601 | "%s: failed to configure loopback address %s (error=%d)\n", |
cb323159 | 602 | __func__, if_name(ifp), error); |
39236c6e | 603 | VERIFY(ia == NULL); |
0a7de745 | 604 | return EADDRNOTAVAIL; |
9bccf70c A |
605 | } |
606 | ||
39236c6e A |
607 | VERIFY(ia != NULL); |
608 | IFA_REMREF(&ia->ia_ifa); | |
0a7de745 | 609 | return 0; |
1c79356b A |
610 | } |
611 | ||
612 | /* | |
9bccf70c | 613 | * compute NI group address, based on the current hostname setting. |
39236c6e | 614 | * see RFC 4620. |
9bccf70c A |
615 | * |
616 | * when ifp == NULL, the caller is responsible for filling scopeid. | |
1c79356b | 617 | */ |
9bccf70c | 618 | int |
91447636 A |
619 | in6_nigroup( |
620 | struct ifnet *ifp, | |
621 | const char *name, | |
f427ee49 | 622 | size_t namelen, |
91447636 | 623 | struct in6_addr *in6) |
1c79356b | 624 | { |
9bccf70c A |
625 | const char *p; |
626 | u_char *q; | |
316670eb A |
627 | SHA1_CTX ctxt; |
628 | u_int8_t digest[SHA1_RESULTLEN]; | |
f427ee49 | 629 | size_t l; |
0a7de745 | 630 | char n[64]; /* a single label must not exceed 63 chars */ |
9bccf70c | 631 | |
0a7de745 A |
632 | if (!namelen || !name) { |
633 | return -1; | |
634 | } | |
9bccf70c A |
635 | |
636 | p = name; | |
0a7de745 | 637 | while (p && *p && *p != '.' && p - name < namelen) { |
9bccf70c | 638 | p++; |
0a7de745 A |
639 | } |
640 | if (p - name > sizeof(n) - 1) { | |
641 | return -1; /* label too long */ | |
642 | } | |
9bccf70c | 643 | l = p - name; |
fe8ab488 | 644 | strlcpy(n, name, l); |
9bccf70c | 645 | n[(int)l] = '\0'; |
2d21ac55 | 646 | for (q = (u_char *) n; *q; q++) { |
0a7de745 | 647 | if ('A' <= *q && *q <= 'Z') { |
9bccf70c | 648 | *q = *q - 'A' + 'a'; |
0a7de745 | 649 | } |
9bccf70c | 650 | } |
1c79356b | 651 | |
39236c6e | 652 | /* generate 16 bytes of pseudo-random value. */ |
0a7de745 | 653 | bzero(&ctxt, sizeof(ctxt)); |
316670eb | 654 | SHA1Init(&ctxt); |
0a7de745 | 655 | SHA1Update(&ctxt, &l, sizeof(l)); |
316670eb A |
656 | SHA1Update(&ctxt, n, l); |
657 | SHA1Final(digest, &ctxt); | |
9bccf70c | 658 | |
0a7de745 | 659 | bzero(in6, sizeof(*in6)); |
6d2010ae | 660 | in6->s6_addr16[0] = IPV6_ADDR_INT16_MLL; |
9bccf70c | 661 | in6->s6_addr8[11] = 2; |
39236c6e A |
662 | in6->s6_addr8[12] = 0xff; |
663 | /* copy first 3 bytes of prefix into address */ | |
664 | bcopy(digest, &in6->s6_addr8[13], 3); | |
0a7de745 A |
665 | if (in6_setscope(in6, ifp, NULL)) { |
666 | return -1; /* XXX: should not fail */ | |
667 | } | |
668 | return 0; | |
9bccf70c A |
669 | } |
670 | ||
6d2010ae A |
671 | int |
672 | in6_domifattach(struct ifnet *ifp) | |
9bccf70c | 673 | { |
39236c6e A |
674 | int error; |
675 | ||
676 | VERIFY(ifp != NULL); | |
1c79356b | 677 | |
39236c6e A |
678 | error = proto_plumb(PF_INET6, ifp); |
679 | if (error != 0) { | |
0a7de745 | 680 | if (error != EEXIST) { |
39236c6e A |
681 | log(LOG_ERR, "%s: proto_plumb returned %d if=%s\n", |
682 | __func__, error, if_name(ifp)); | |
0a7de745 | 683 | } |
6d2010ae | 684 | } else { |
39236c6e A |
685 | error = in6_ifattach_prelim(ifp); |
686 | if (error != 0) { | |
687 | int errorx; | |
688 | ||
689 | log(LOG_ERR, | |
690 | "%s: in6_ifattach_prelim returned %d if=%s%d\n", | |
691 | __func__, error, ifp->if_name, ifp->if_unit); | |
692 | ||
693 | errorx = proto_unplumb(PF_INET6, ifp); | |
0a7de745 | 694 | if (errorx != 0) { /* XXX should not fail */ |
39236c6e A |
695 | log(LOG_ERR, |
696 | "%s: proto_unplumb returned %d if=%s%d\n", | |
697 | __func__, errorx, ifp->if_name, | |
698 | ifp->if_unit); | |
0a7de745 | 699 | } |
39236c6e | 700 | } |
1c79356b | 701 | } |
9bccf70c | 702 | |
0a7de745 | 703 | return error; |
9bccf70c A |
704 | } |
705 | ||
b0d623f7 | 706 | int |
39236c6e | 707 | in6_ifattach_prelim(struct ifnet *ifp) |
9bccf70c | 708 | { |
39236c6e A |
709 | struct in6_ifextra *ext; |
710 | void **pbuf, *base; | |
711 | int error = 0; | |
3e170ce0 | 712 | struct in6_ifaddr *ia6 = NULL; |
55e303ae | 713 | |
39236c6e | 714 | VERIFY(ifp != NULL); |
1c79356b | 715 | |
39236c6e | 716 | /* quirks based on interface type */ |
9bccf70c A |
717 | switch (ifp->if_type) { |
718 | #if IFT_STF | |
719 | case IFT_STF: | |
720 | /* | |
55e303ae A |
721 | * 6to4 interface is a very special kind of beast. |
722 | * no multicast, no linklocal. RFC2529 specifies how to make | |
723 | * linklocals for 6to4 interface, but there's no use and | |
724 | * it is rather harmful to have one. | |
9bccf70c | 725 | */ |
39236c6e | 726 | goto skipmcast; |
0b4e3aa0 | 727 | #endif |
9bccf70c | 728 | default: |
1c79356b | 729 | break; |
1c79356b A |
730 | } |
731 | ||
1c79356b | 732 | /* |
39236c6e A |
733 | * IPv6 requires multicast capability at the interface. |
734 | * (previously, this was a silent error.) | |
1c79356b | 735 | */ |
9bccf70c | 736 | if ((ifp->if_flags & IFF_MULTICAST) == 0) { |
cb323159 A |
737 | nd6log0(info, "in6_ifattach: %s is not multicast capable, IPv6 not enabled\n", |
738 | if_name(ifp)); | |
0a7de745 | 739 | return EINVAL; |
1c79356b A |
740 | } |
741 | ||
39236c6e A |
742 | #if IFT_STF |
743 | skipmcast: | |
744 | #endif | |
745 | ||
746 | if (ifp->if_inet6data == NULL) { | |
3e170ce0 | 747 | ext = (struct in6_ifextra *)_MALLOC(in6_extra_bufsize, M_IFADDR, |
0a7de745 A |
748 | M_WAITOK | M_ZERO); |
749 | if (!ext) { | |
750 | return ENOMEM; | |
751 | } | |
39236c6e A |
752 | base = (void *)P2ROUNDUP((intptr_t)ext + sizeof(uint64_t), |
753 | sizeof(uint64_t)); | |
3e170ce0 | 754 | VERIFY(((intptr_t)base + in6_extra_size) <= |
39236c6e A |
755 | ((intptr_t)ext + in6_extra_bufsize)); |
756 | pbuf = (void **)((intptr_t)base - sizeof(void *)); | |
757 | *pbuf = ext; | |
758 | ifp->if_inet6data = base; | |
5ba3f43e | 759 | IN6_IFEXTRA(ifp)->ii_llt = in6_lltattach(ifp); |
39236c6e A |
760 | VERIFY(IS_P2ALIGNED(ifp->if_inet6data, sizeof(uint64_t))); |
761 | } else { | |
762 | /* | |
3e170ce0 | 763 | * Since the structure is never freed, we need to zero out |
39236c6e A |
764 | * some of its members. We avoid zeroing out the scope6 |
765 | * structure on purpose because other threads might be | |
766 | * using its contents. | |
767 | */ | |
768 | bzero(&IN6_IFEXTRA(ifp)->icmp6_ifstat, | |
769 | sizeof(IN6_IFEXTRA(ifp)->icmp6_ifstat)); | |
770 | bzero(&IN6_IFEXTRA(ifp)->in6_ifstat, | |
771 | sizeof(IN6_IFEXTRA(ifp)->in6_ifstat)); | |
5ba3f43e | 772 | /* XXX TBD Purge the layer two table */ |
3e170ce0 A |
773 | /* |
774 | * XXX When recycling, nd_ifinfo gets initialized, other | |
775 | * than the lock, inside nd6_ifattach | |
776 | */ | |
39236c6e A |
777 | } |
778 | ||
3e170ce0 | 779 | /* |
d9a64523 | 780 | * XXX Only initialize IPv6 configuration for the interface |
3e170ce0 A |
781 | * if interface has not yet been configured with |
782 | * link local IPv6 address. | |
783 | * Could possibly be optimized with an interface flag if need | |
784 | * be. For now using in6ifa_ifpforlinklocal. | |
785 | */ | |
786 | ia6 = in6ifa_ifpforlinklocal(ifp, 0); | |
787 | if (ia6 == NULL) { | |
d9a64523 A |
788 | IN6_IFEXTRA(ifp)->netsig_len = 0; |
789 | bzero(&IN6_IFEXTRA(ifp)->netsig, | |
790 | sizeof(IN6_IFEXTRA(ifp)->netsig)); | |
791 | bzero(IN6_IFEXTRA(ifp)->nat64_prefixes, | |
792 | sizeof(IN6_IFEXTRA(ifp)->nat64_prefixes)); | |
3e170ce0 A |
793 | /* initialize NDP variables */ |
794 | nd6_ifattach(ifp); | |
795 | } else { | |
796 | VERIFY(ND_IFINFO(ifp)->initialized); | |
797 | IFA_REMREF(&ia6->ia_ifa); | |
798 | ia6 = NULL; | |
799 | } | |
39236c6e A |
800 | scope6_ifattach(ifp); |
801 | ||
802 | /* initialize loopback interface address */ | |
9bccf70c | 803 | if ((ifp->if_flags & IFF_LOOPBACK) != 0) { |
39236c6e A |
804 | error = in6_ifattach_loopback(ifp); |
805 | if (error != 0) { | |
806 | log(LOG_ERR, "%s: in6_ifattach_loopback returned %d\n", | |
f427ee49 | 807 | __func__, error); |
0a7de745 | 808 | return error; |
6d2010ae | 809 | } |
1c79356b A |
810 | } |
811 | ||
39236c6e | 812 | /* update dynamically. */ |
0a7de745 | 813 | if (in6_maxmtu < ifp->if_mtu) { |
39236c6e | 814 | in6_maxmtu = ifp->if_mtu; |
0a7de745 | 815 | } |
39236c6e A |
816 | |
817 | VERIFY(error == 0); | |
0a7de745 | 818 | return 0; |
39236c6e A |
819 | } |
820 | ||
39037602 A |
821 | /* |
822 | * This routine is only meant to configure IPv6 Link Local | |
823 | * addresses. | |
824 | */ | |
39236c6e A |
825 | int |
826 | in6_ifattach_aliasreq(struct ifnet *ifp, struct ifnet *altifp, | |
827 | struct in6_aliasreq *ifra0) | |
828 | { | |
829 | int error; | |
830 | struct in6_ifaddr *ia6; | |
831 | struct in6_aliasreq ifra; | |
832 | ||
833 | error = in6_ifattach_prelim(ifp); | |
0a7de745 A |
834 | if (error != 0) { |
835 | return error; | |
836 | } | |
39236c6e | 837 | |
0a7de745 A |
838 | if (!ip6_auto_linklocal) { |
839 | return 0; | |
840 | } | |
39236c6e | 841 | |
39037602 A |
842 | /* |
843 | * Assign a link-local address, only if there isn't one here already. | |
844 | * XXX If we ever allow more than one LLA on the interface | |
845 | * make sure that the corresponding prefix on the prefixlist | |
846 | * is reference counted and the address's prefix pointer | |
847 | * points to the prefix. | |
848 | */ | |
39236c6e A |
849 | ia6 = in6ifa_ifpforlinklocal(ifp, 0); |
850 | if (ia6 != NULL) { | |
851 | IFA_REMREF(&ia6->ia_ifa); | |
0a7de745 | 852 | return 0; |
39236c6e A |
853 | } |
854 | ||
0a7de745 | 855 | bzero(&ifra, sizeof(ifra)); |
39236c6e | 856 | |
1c79356b | 857 | /* |
39236c6e A |
858 | * in6_update_ifa() does not use ifra_name, but we accurately set it |
859 | * for safety. | |
1c79356b | 860 | */ |
0a7de745 | 861 | strlcpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); |
39236c6e A |
862 | |
863 | /* Initialize the IPv6 interface address in our in6_aliasreq block */ | |
39037602 | 864 | if (ifra0 != NULL) { |
39236c6e A |
865 | /* interface provided both addresses for us */ |
866 | struct sockaddr_in6 *sin6 = &ifra.ifra_addr; | |
867 | struct in6_addr *in6 = &sin6->sin6_addr; | |
868 | boolean_t ok = TRUE; | |
869 | ||
0a7de745 | 870 | bcopy(&ifra0->ifra_addr, sin6, sizeof(struct sockaddr_in6)); |
39236c6e | 871 | |
0a7de745 | 872 | if (sin6->sin6_family != AF_INET6 || sin6->sin6_port != 0) { |
39236c6e | 873 | ok = FALSE; |
0a7de745 A |
874 | } |
875 | if (ok && (in6->s6_addr16[0] != htons(0xfe80))) { | |
39236c6e | 876 | ok = FALSE; |
0a7de745 | 877 | } |
39236c6e | 878 | if (ok) { |
0a7de745 | 879 | if (sin6->sin6_scope_id == 0 && in6->s6_addr16[1] == 0) { |
39236c6e | 880 | in6->s6_addr16[1] = htons(ifp->if_index); |
0a7de745 A |
881 | } else if (sin6->sin6_scope_id != 0 && |
882 | sin6->sin6_scope_id != ifp->if_index) { | |
39236c6e | 883 | ok = FALSE; |
0a7de745 A |
884 | } else if (in6->s6_addr16[1] != 0 && |
885 | ntohs(in6->s6_addr16[1]) != ifp->if_index) { | |
39236c6e | 886 | ok = FALSE; |
0a7de745 | 887 | } |
39236c6e | 888 | } |
0a7de745 | 889 | if (ok && (in6->s6_addr32[1] != 0)) { |
39236c6e | 890 | ok = FALSE; |
0a7de745 A |
891 | } |
892 | if (!ok) { | |
893 | return EINVAL; | |
894 | } | |
39236c6e A |
895 | } else { |
896 | ifra.ifra_addr.sin6_family = AF_INET6; | |
0a7de745 | 897 | ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); |
39236c6e A |
898 | ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); |
899 | ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); | |
900 | ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; | |
901 | if ((ifp->if_flags & IFF_LOOPBACK) != 0) { | |
902 | ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0; | |
903 | ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1); | |
904 | } else { | |
905 | if (in6_select_iid_from_all_hw(ifp, altifp, | |
906 | &ifra.ifra_addr.sin6_addr) != 0) { | |
cb323159 A |
907 | nd6log(error, "%s: no IID available\n", |
908 | if_name(ifp)); | |
0a7de745 | 909 | return EADDRNOTAVAIL; |
9bccf70c | 910 | } |
1c79356b A |
911 | } |
912 | } | |
913 | ||
0a7de745 A |
914 | if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) { |
915 | return EADDRNOTAVAIL; | |
916 | } | |
9bccf70c | 917 | |
39236c6e | 918 | /* Set the prefix mask */ |
0a7de745 | 919 | ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); |
39236c6e A |
920 | ifra.ifra_prefixmask.sin6_family = AF_INET6; |
921 | ifra.ifra_prefixmask.sin6_addr = in6mask64; | |
1c79356b | 922 | |
39236c6e A |
923 | /* link-local addresses should NEVER expire. */ |
924 | ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
925 | ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME; | |
926 | ||
927 | /* Attach the link-local address */ | |
928 | if (in6_ifattach_linklocal(ifp, &ifra) != 0) { | |
cb323159 | 929 | nd6log(info, |
39236c6e | 930 | "%s: %s could not attach link-local address.\n", |
cb323159 | 931 | __func__, if_name(ifp)); |
39236c6e A |
932 | /* NB: not an error */ |
933 | } | |
934 | ||
0a7de745 | 935 | return 0; |
39236c6e A |
936 | } |
937 | ||
938 | int | |
39037602 | 939 | in6_ifattach_llcgareq(struct ifnet *ifp, struct in6_cgareq *llcgasr) |
39236c6e A |
940 | { |
941 | struct in6_aliasreq ifra; | |
3e170ce0 A |
942 | struct in6_ifaddr *ia6 = NULL; |
943 | struct nd_ifinfo *ndi = NULL; | |
39236c6e A |
944 | int error; |
945 | ||
39037602 | 946 | VERIFY(llcgasr != NULL); |
39236c6e A |
947 | |
948 | error = in6_ifattach_prelim(ifp); | |
0a7de745 A |
949 | if (error != 0) { |
950 | return error; | |
951 | } | |
39236c6e | 952 | |
0a7de745 A |
953 | if (!ip6_auto_linklocal) { |
954 | return 0; | |
955 | } | |
39236c6e | 956 | |
0a7de745 A |
957 | if (nd6_send_opstate == ND6_SEND_OPMODE_DISABLED) { |
958 | return ENXIO; | |
959 | } | |
39236c6e | 960 | |
39236c6e A |
961 | ndi = ND_IFINFO(ifp); |
962 | VERIFY(ndi != NULL && ndi->initialized); | |
963 | if ((ndi->flags & ND6_IFF_INSECURE) != 0) { | |
0a7de745 | 964 | return ENXIO; |
39236c6e | 965 | } |
39236c6e | 966 | |
39037602 A |
967 | /* |
968 | * Assign a link-local address, only if there isn't one here already. | |
969 | * XXX If we ever allow more than one LLA on the interface | |
970 | * make sure that the corresponding prefix on the prefixlist | |
971 | * is reference counted and the address's prefix pointer | |
972 | * points to the prefix. | |
973 | */ | |
39236c6e A |
974 | ia6 = in6ifa_ifpforlinklocal(ifp, 0); |
975 | if (ia6 != NULL) { | |
976 | IFA_REMREF(&ia6->ia_ifa); | |
0a7de745 | 977 | return 0; |
39236c6e A |
978 | } |
979 | ||
0a7de745 A |
980 | bzero(&ifra, sizeof(ifra)); |
981 | strlcpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name)); | |
39236c6e A |
982 | |
983 | ifra.ifra_addr.sin6_family = AF_INET6; | |
0a7de745 | 984 | ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6); |
39236c6e A |
985 | ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80); |
986 | ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index); | |
987 | ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0; | |
988 | ifra.ifra_flags = IN6_IFF_SECURED; | |
989 | ||
990 | in6_cga_node_lock(); | |
f427ee49 A |
991 | if (in6_cga_generate(&llcgasr->cgar_cgaprep, llcgasr->cgar_collision_count, |
992 | &ifra.ifra_addr.sin6_addr, ifp)) { | |
39236c6e | 993 | in6_cga_node_unlock(); |
0a7de745 | 994 | return EADDRNOTAVAIL; |
39236c6e A |
995 | } |
996 | in6_cga_node_unlock(); | |
997 | ||
0a7de745 A |
998 | if (in6_setscope(&ifra.ifra_addr.sin6_addr, ifp, NULL)) { |
999 | return EADDRNOTAVAIL; | |
1000 | } | |
39236c6e A |
1001 | |
1002 | /* Set the prefix mask */ | |
0a7de745 | 1003 | ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6); |
39236c6e A |
1004 | ifra.ifra_prefixmask.sin6_family = AF_INET6; |
1005 | ifra.ifra_prefixmask.sin6_addr = in6mask64; | |
1006 | ||
1007 | /* | |
1008 | * link-local addresses should NEVER expire, but cryptographic | |
1009 | * ones may have finite preferred lifetime [if it's important to | |
1010 | * keep them from being used by applications as persistent device | |
1011 | * identifiers]. | |
1012 | */ | |
1013 | ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME; | |
39037602 | 1014 | ifra.ifra_lifetime.ia6t_pltime = llcgasr->cgar_lifetime.ia6t_pltime; |
39236c6e A |
1015 | |
1016 | /* Attach the link-local address */ | |
1017 | if (in6_ifattach_linklocal(ifp, &ifra) != 0) { | |
1018 | /* NB: not an error */ | |
cb323159 | 1019 | nd6log(info, |
39236c6e | 1020 | "%s: %s could not attach link-local address.\n", |
cb323159 | 1021 | __func__, if_name(ifp)); |
39236c6e A |
1022 | } |
1023 | ||
1024 | VERIFY(error == 0); | |
0a7de745 | 1025 | return error; |
1c79356b A |
1026 | } |
1027 | ||
1028 | /* | |
1029 | * NOTE: in6_ifdetach() does not support loopback if at this moment. | |
1030 | */ | |
1031 | void | |
6d2010ae | 1032 | in6_ifdetach(struct ifnet *ifp) |
1c79356b | 1033 | { |
eb6b6ca3 | 1034 | struct in6_ifaddr *ia, *nia; |
6d2010ae | 1035 | struct ifaddr *ifa; |
1c79356b | 1036 | struct rtentry *rt; |
1c79356b | 1037 | struct sockaddr_in6 sin6; |
6d2010ae A |
1038 | struct in6_multi_mship *imm; |
1039 | int unlinked; | |
1c79356b | 1040 | |
5ba3f43e | 1041 | LCK_MTX_ASSERT(nd6_mutex, LCK_MTX_ASSERT_NOTOWNED); |
1c79356b A |
1042 | |
1043 | /* remove neighbor management table */ | |
1044 | nd6_purge(ifp); | |
1045 | ||
0a7de745 | 1046 | if (LLTABLE6(ifp)) { |
5ba3f43e | 1047 | lltable_free(LLTABLE6(ifp)); |
0a7de745 | 1048 | } |
5ba3f43e | 1049 | |
9bccf70c | 1050 | /* nuke any of IPv6 addresses we have */ |
6d2010ae | 1051 | lck_rw_lock_exclusive(&in6_ifaddr_rwlock); |
eb6b6ca3 A |
1052 | boolean_t from_begining = TRUE; |
1053 | while (from_begining) { | |
1054 | from_begining = FALSE; | |
1055 | TAILQ_FOREACH(ia, &in6_ifaddrhead, ia6_link) { | |
1056 | if (ia->ia_ifa.ifa_ifp != ifp) { | |
1057 | continue; | |
1058 | } | |
1059 | IFA_ADDREF(&ia->ia_ifa); /* for us */ | |
1060 | lck_rw_done(&in6_ifaddr_rwlock); | |
1061 | in6_purgeaddr(&ia->ia_ifa); | |
1062 | IFA_REMREF(&ia->ia_ifa); /* for us */ | |
1063 | lck_rw_lock_exclusive(&in6_ifaddr_rwlock); | |
1064 | /* | |
1065 | * Purging the address caused in6_ifaddr_rwlock | |
1066 | * to be dropped and reacquired; | |
1067 | * therefore search again from the beginning | |
1068 | * of in6_ifaddrs list. | |
1069 | */ | |
1070 | from_begining = TRUE; | |
1071 | break; | |
6d2010ae | 1072 | } |
9bccf70c | 1073 | } |
6d2010ae | 1074 | lck_rw_done(&in6_ifaddr_rwlock); |
91447636 A |
1075 | |
1076 | ifnet_lock_exclusive(ifp); | |
9bccf70c A |
1077 | |
1078 | /* undo everything done by in6_ifattach(), just in case */ | |
6d2010ae A |
1079 | ifa = TAILQ_FIRST(&ifp->if_addrlist); |
1080 | while (ifa != NULL) { | |
1081 | IFA_LOCK(ifa); | |
1082 | if (ifa->ifa_addr->sa_family != AF_INET6 || | |
1083 | !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)-> | |
1084 | sin6_addr)) { | |
1085 | IFA_UNLOCK(ifa); | |
1086 | ifa = TAILQ_NEXT(ifa, ifa_list); | |
1c79356b A |
1087 | continue; |
1088 | } | |
1089 | ||
1090 | ia = (struct in6_ifaddr *)ifa; | |
1091 | ||
6d2010ae A |
1092 | /* hold a reference for this routine */ |
1093 | IFA_ADDREF_LOCKED(ifa); | |
1094 | /* remove from the linked list */ | |
1095 | if_detach_ifa(ifp, ifa); | |
1096 | IFA_UNLOCK(ifa); | |
1097 | ||
1098 | /* | |
1099 | * Leaving the multicast group(s) may involve freeing the | |
1100 | * link address multicast structure(s) for the interface, | |
1101 | * which is protected by ifnet lock. To avoid violating | |
1102 | * lock ordering, we must drop ifnet lock before doing so. | |
1103 | * The ifa won't go away since we held a refcnt above. | |
1104 | */ | |
1105 | ifnet_lock_done(ifp); | |
1106 | ||
1107 | /* | |
1108 | * We have to do this work manually here instead of calling | |
1109 | * in6_purgeaddr() since in6_purgeaddr() uses the RTM_HOST flag. | |
1110 | */ | |
1111 | ||
1112 | /* | |
1113 | * leave from multicast groups we have joined for the interface | |
1114 | */ | |
1115 | IFA_LOCK(ifa); | |
1116 | while ((imm = ia->ia6_memberships.lh_first) != NULL) { | |
1117 | LIST_REMOVE(imm, i6mm_chain); | |
1118 | IFA_UNLOCK(ifa); | |
1119 | in6_leavegroup(imm); | |
1120 | IFA_LOCK(ifa); | |
1c79356b A |
1121 | } |
1122 | ||
6d2010ae A |
1123 | /* remove from the routing table */ |
1124 | if (ia->ia_flags & IFA_ROUTE) { | |
1125 | IFA_UNLOCK(ifa); | |
1126 | rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0, 0); | |
1127 | if (rt != NULL) { | |
1128 | (void) rtrequest(RTM_DELETE, | |
0a7de745 A |
1129 | (struct sockaddr *)&ia->ia_addr, |
1130 | (struct sockaddr *)&ia->ia_addr, | |
1131 | (struct sockaddr *)&ia->ia_prefixmask, | |
1132 | rt->rt_flags, (struct rtentry **)0); | |
6d2010ae A |
1133 | rtfree(rt); |
1134 | } | |
1135 | } else { | |
1136 | IFA_UNLOCK(ifa); | |
1137 | } | |
1c79356b A |
1138 | |
1139 | /* also remove from the IPv6 address chain(itojun&jinmei) */ | |
eb6b6ca3 | 1140 | unlinked = 0; |
6d2010ae | 1141 | lck_rw_lock_exclusive(&in6_ifaddr_rwlock); |
eb6b6ca3 A |
1142 | TAILQ_FOREACH(nia, &in6_ifaddrhead, ia6_link) { |
1143 | if (ia == nia) { | |
1144 | TAILQ_REMOVE(&in6_ifaddrhead, ia, ia6_link); | |
1145 | unlinked = 1; | |
1146 | break; | |
9bccf70c | 1147 | } |
1c79356b | 1148 | } |
6d2010ae A |
1149 | lck_rw_done(&in6_ifaddr_rwlock); |
1150 | ||
6d2010ae A |
1151 | /* |
1152 | * release another refcnt for the link from in6_ifaddrs. | |
1153 | * Do this only if it's not already unlinked in the event | |
39236c6e A |
1154 | * that we lost the race, since in6_ifaddr_rwlock was |
1155 | * momentarily dropped above. | |
6d2010ae | 1156 | */ |
0a7de745 | 1157 | if (unlinked) { |
6d2010ae | 1158 | IFA_REMREF(ifa); |
0a7de745 | 1159 | } |
6d2010ae A |
1160 | /* release reference held for this routine */ |
1161 | IFA_REMREF(ifa); | |
1c79356b | 1162 | |
6d2010ae A |
1163 | /* |
1164 | * This is suboptimal, but since we dropped ifnet lock above | |
1165 | * the list might have changed. Repeat the search from the | |
1166 | * beginning until we find the first eligible IPv6 address. | |
1167 | */ | |
1168 | ifnet_lock_exclusive(ifp); | |
1169 | ifa = TAILQ_FIRST(&ifp->if_addrlist); | |
1c79356b | 1170 | } |
91447636 | 1171 | ifnet_lock_done(ifp); |
1c79356b | 1172 | |
39236c6e A |
1173 | /* invalidate route caches */ |
1174 | routegenid_inet6_update(); | |
1175 | ||
9bccf70c A |
1176 | /* |
1177 | * remove neighbor management table. we call it twice just to make | |
1178 | * sure we nuke everything. maybe we need just one call. | |
1179 | * XXX: since the first call did not release addresses, some prefixes | |
1180 | * might remain. We should call nd6_purge() again to release the | |
1181 | * prefixes after removing all addresses above. | |
1182 | * (Or can we just delay calling nd6_purge until at this point?) | |
1183 | */ | |
1c79356b A |
1184 | nd6_purge(ifp); |
1185 | ||
1186 | /* remove route to link-local allnodes multicast (ff02::1) */ | |
0a7de745 A |
1187 | bzero(&sin6, sizeof(sin6)); |
1188 | sin6.sin6_len = sizeof(struct sockaddr_in6); | |
1c79356b A |
1189 | sin6.sin6_family = AF_INET6; |
1190 | sin6.sin6_addr = in6addr_linklocal_allnodes; | |
1191 | sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index); | |
b0d623f7 | 1192 | rt = rtalloc1((struct sockaddr *)&sin6, 0, 0); |
2d21ac55 | 1193 | if (rt != NULL) { |
b0d623f7 | 1194 | RT_LOCK(rt); |
39236c6e | 1195 | if (rt->rt_ifp == ifp) { |
b0d623f7 A |
1196 | /* |
1197 | * Prevent another thread from modifying rt_key, | |
1198 | * rt_gateway via rt_setgate() after the rt_lock | |
1199 | * is dropped by marking the route as defunct. | |
1200 | */ | |
1201 | rt->rt_flags |= RTF_CONDEMNED; | |
1202 | RT_UNLOCK(rt); | |
1203 | (void) rtrequest(RTM_DELETE, rt_key(rt), rt->rt_gateway, | |
1204 | rt_mask(rt), rt->rt_flags, 0); | |
1205 | } else { | |
1206 | RT_UNLOCK(rt); | |
2d21ac55 | 1207 | } |
b0d623f7 | 1208 | rtfree(rt); |
1c79356b A |
1209 | } |
1210 | } | |
9bccf70c A |
1211 | |
1212 | void | |
39236c6e A |
1213 | in6_iid_mktmp(struct ifnet *ifp, u_int8_t *retbuf, const u_int8_t *baseid, |
1214 | int generate) | |
9bccf70c A |
1215 | { |
1216 | u_int8_t nullbuf[8]; | |
3e170ce0 | 1217 | struct nd_ifinfo *ndi = ND_IFINFO(ifp); |
9bccf70c | 1218 | |
316670eb A |
1219 | VERIFY(ndi != NULL && ndi->initialized); |
1220 | lck_mtx_lock(&ndi->lock); | |
0a7de745 A |
1221 | bzero(nullbuf, sizeof(nullbuf)); |
1222 | if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) { | |
9bccf70c A |
1223 | /* we've never created a random ID. Create a new one. */ |
1224 | generate = 1; | |
1225 | } | |
1226 | ||
1227 | if (generate) { | |
0a7de745 | 1228 | bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1)); |
9bccf70c | 1229 | |
39236c6e A |
1230 | /* in6_generate_tmp_iid will update seedn and buf */ |
1231 | (void) in6_generate_tmp_iid(ndi->randomseed0, ndi->randomseed1, | |
1232 | ndi->randomid); | |
9bccf70c | 1233 | } |
39236c6e | 1234 | |
9bccf70c | 1235 | bcopy(ndi->randomid, retbuf, 8); |
316670eb | 1236 | lck_mtx_unlock(&ndi->lock); |
9bccf70c A |
1237 | } |
1238 | ||
9bccf70c | 1239 | void |
316670eb | 1240 | in6_tmpaddrtimer(void *arg) |
9bccf70c | 1241 | { |
316670eb | 1242 | #pragma unused(arg) |
3e170ce0 A |
1243 | struct ifnet *ifp = NULL; |
1244 | struct nd_ifinfo *ndi = NULL; | |
9bccf70c | 1245 | u_int8_t nullbuf[8]; |
9bccf70c | 1246 | |
39236c6e A |
1247 | timeout(in6_tmpaddrtimer, (caddr_t)0, (ip6_temp_preferred_lifetime - |
1248 | ip6_desync_factor - ip6_temp_regen_advance) * hz); | |
9bccf70c | 1249 | |
0a7de745 | 1250 | bzero(nullbuf, sizeof(nullbuf)); |
3e170ce0 A |
1251 | ifnet_head_lock_shared(); |
1252 | for (ifp = ifnet_head.tqh_first; ifp; | |
1253 | ifp = ifp->if_link.tqe_next) { | |
1254 | ndi = ND_IFINFO(ifp); | |
1255 | if ((NULL == ndi) || (FALSE == ndi->initialized)) { | |
316670eb | 1256 | continue; |
3e170ce0 | 1257 | } |
316670eb | 1258 | lck_mtx_lock(&ndi->lock); |
0a7de745 | 1259 | if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) { |
316670eb A |
1260 | /* |
1261 | * We've been generating a random ID on this interface. | |
1262 | * Create a new one. | |
1263 | */ | |
39236c6e A |
1264 | (void) in6_generate_tmp_iid(ndi->randomseed0, |
1265 | ndi->randomseed1, ndi->randomid); | |
9bccf70c | 1266 | } |
316670eb | 1267 | lck_mtx_unlock(&ndi->lock); |
9bccf70c | 1268 | } |
3e170ce0 | 1269 | ifnet_head_done(); |
9bccf70c | 1270 | } |