1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33#include <sys/param.h>
34#include <sys/systm.h>
35#include <sys/malloc.h>
36#include <sys/socket.h>
37#include <sys/socketvar.h>
38#include <sys/sockio.h>
39#include <sys/kernel.h>
40#include <sys/syslog.h>
41#include <sys/md5.h>
42#include <kern/lock.h>
43
44#include <net/if.h>
45#include <net/if_dl.h>
46#include <net/if_types.h>
47#include <net/route.h>
48
49#include <netinet/in.h>
50#include <netinet/in_var.h>
51#include <netinet/if_ether.h>
52#include <netinet/in_pcb.h>
53
54#include <netinet/ip6.h>
55#include <netinet6/ip6_var.h>
56#include <netinet6/in6_var.h>
57#include <netinet6/in6_pcb.h>
58#include <netinet6/in6_ifattach.h>
59#include <netinet6/ip6_var.h>
60#include <netinet6/nd6.h>
61#include <netinet6/scope6_var.h>
62
63#include <net/net_osdep.h>
64
65struct in6_ifstat **in6_ifstat = NULL;
66struct icmp6_ifstat **icmp6_ifstat = NULL;
67size_t in6_ifstatmax = 0;
68size_t icmp6_ifstatmax = 0;
69unsigned long in6_maxmtu = 0;
70extern lck_mtx_t *nd6_mutex;
71
72#if IP6_AUTO_LINKLOCAL
73int ip6_auto_linklocal = IP6_AUTO_LINKLOCAL;
74#else
75int ip6_auto_linklocal = 1;
76#endif
77
78
79extern struct inpcbinfo udbinfo;
80extern struct inpcbinfo ripcbinfo;
81extern lck_mtx_t *rt_mtx;
82
83static int get_rand_ifid(struct ifnet *, struct in6_addr *);
84static int generate_tmp_ifid(u_int8_t *, const u_int8_t *, u_int8_t *);
85static int get_hw_ifid(struct ifnet *, struct in6_addr *);
86static int get_ifid(struct ifnet *, struct ifnet *, struct in6_addr *);
87static int in6_ifattach_linklocal(struct ifnet *, struct ifnet *, struct in6_aliasreq *);
88static int in6_ifattach_loopback(struct ifnet *);
89
90#define EUI64_GBIT 0x01
91#define EUI64_UBIT 0x02
92#define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
93#define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
94#define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
95#define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
96#define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
97
98#define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
99#define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
100
101
102
103
104
105
106
107
108static int
109get_rand_ifid(
110 struct ifnet *ifp,
111 struct in6_addr *in6)
112{
113 MD5_CTX ctxt;
114 u_int8_t digest[16];
115 int hostnamelen = strlen(hostname);
116
117#if 0
118
119 if (hostnamelen < 3)
120 return -1;
121#endif
122
123
124 bzero(&ctxt, sizeof(ctxt));
125 MD5Init(&ctxt);
126 MD5Update(&ctxt, hostname, hostnamelen);
127 MD5Final(digest, &ctxt);
128
129
130 bcopy(digest, &in6->s6_addr[8], 8);
131
132
133 in6->s6_addr[8] &= ~EUI64_GBIT;
134 in6->s6_addr[8] |= EUI64_UBIT;
135
136
137 EUI64_TO_IFID(in6);
138
139 return 0;
140}
141
142static int
143generate_tmp_ifid(
144 u_int8_t *seed0,
145 const u_int8_t *seed1,
146 u_int8_t *ret)
147{
148 MD5_CTX ctxt;
149 u_int8_t seed[16], digest[16], nullbuf[8];
150 u_int32_t val32;
151 struct timeval tv;
152
153
154 bzero(nullbuf, sizeof(nullbuf));
155 if (bcmp(nullbuf, seed0, sizeof(nullbuf)) == 0) {
156 int i;
157
158 for (i = 0; i < 2; i++) {
159 microtime(&tv);
160 val32 = random() ^ tv.tv_usec;
161 bcopy(&val32, seed + sizeof(val32) * i, sizeof(val32));
162 }
163 } else {
164 bcopy(seed0, seed, 8);
165 }
166
167
168
169 bcopy(seed1, &seed[8], 8);
170
171 if (0) {
172 int i;
173
174 printf("generate_tmp_ifid: new randomized ID from: ");
175 for (i = 0; i < 16; i++)
176 printf("%02x", seed[i]);
177 printf(" ");
178 }
179
180
181 bzero(&ctxt, sizeof(ctxt));
182 MD5Init(&ctxt);
183 MD5Update(&ctxt, seed, sizeof(seed));
184 MD5Final(digest, &ctxt);
185
186
187
188
189
190
191 bcopy(digest, ret, 8);
192 ret[0] &= ~EUI64_UBIT;
193
194
195
196
197
198
199 if (bcmp(nullbuf, ret, sizeof(nullbuf)) == 0) {
200 log(LOG_INFO,
201 "generate_tmp_ifid: computed MD5 value is zero.\n");
202
203 microtime(&tv);
204 val32 = random() ^ tv.tv_usec;
205 val32 = 1 + (val32 % (0xffffffff - 1));
206 }
207
208
209
210
211
212
213
214 bcopy(&digest[8], seed0, 8);
215
216 if (0) {
217 int i;
218
219 printf("to: ");
220 for (i = 0; i < 16; i++)
221 printf("%02x", digest[i]);
222 printf("\n");
223 }
224
225 return 0;
226}
227
228
229
230
231
232static int
233get_hw_ifid(
234 struct ifnet *ifp,
235 struct in6_addr *in6)
236{
237 struct ifaddr *ifa;
238 struct sockaddr_dl *sdl;
239 u_int8_t *addr;
240 size_t addrlen;
241 static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
242 static u_int8_t allone[8] =
243 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
244
245
246 ifnet_lock_shared(ifp);
247 for (ifa = ifp->if_addrlist.tqh_first;
248 ifa;
249 ifa = ifa->ifa_list.tqe_next)
250 {
251 if (ifa->ifa_addr->sa_family != AF_LINK)
252 continue;
253 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
254 if (sdl == NULL)
255 continue;
256 if (sdl->sdl_alen == 0)
257 continue;
258
259 goto found;
260 }
261 ifnet_lock_done(ifp);
262
263 return -1;
264
265found:
266 ifnet_lock_done(ifp);
267 addr = LLADDR(sdl);
268 addrlen = sdl->sdl_alen;
269
270
271 switch (ifp->if_type) {
272 case IFT_ETHER:
273 case IFT_FDDI:
274 case IFT_ATM:
275 case IFT_IEEE1394:
276 case IFT_L2VLAN:
277 case IFT_IEEE8023ADLAG:
278#if IFT_IEEE80211
279 case IFT_IEEE80211:
280#endif
281
282
283 if (addrlen > 8)
284 addrlen = 8;
285
286
287 if (addrlen != 8 && addrlen != 6)
288 return -1;
289
290
291
292
293
294
295 if (bcmp(addr, allzero, addrlen) == 0)
296 return -1;
297 if (bcmp(addr, allone, addrlen) == 0)
298 return -1;
299
300
301 if (addrlen == 8)
302 bcopy(addr, &in6->s6_addr[8], 8);
303 else if (addrlen == 6) {
304 in6->s6_addr[8] = addr[0];
305 in6->s6_addr[9] = addr[1];
306 in6->s6_addr[10] = addr[2];
307 in6->s6_addr[11] = 0xff;
308 in6->s6_addr[12] = 0xfe;
309 in6->s6_addr[13] = addr[3];
310 in6->s6_addr[14] = addr[4];
311 in6->s6_addr[15] = addr[5];
312 }
313 break;
314
315 case IFT_ARCNET:
316 if (addrlen != 1)
317 return -1;
318 if (!addr[0])
319 return -1;
320
321 bzero(&in6->s6_addr[8], 8);
322 in6->s6_addr[15] = addr[0];
323
324
325
326
327 in6->s6_addr[8] &= ~EUI64_GBIT;
328 in6->s6_addr[8] |= EUI64_UBIT;
329 break;
330
331 case IFT_GIF:
332#if IFT_STF
333 case IFT_STF:
334#endif
335
336
337
338
339
340
341 return -1;
342
343 default:
344 return -1;
345 }
346
347
348 if (EUI64_GROUP(in6))
349 return -1;
350
351
352 EUI64_TO_IFID(in6);
353
354
355
356
357
358 if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
359 bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
360 return -1;
361 }
362
363 return 0;
364}
365
366
367
368
369
370
371static int
372get_ifid(
373 struct ifnet *ifp0,
374 struct ifnet *altifp,
375 struct in6_addr *in6)
376{
377 struct ifnet *ifp;
378
379
380 if (get_hw_ifid(ifp0, in6) == 0) {
381 nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
382 if_name(ifp0)));
383 goto success;
384 }
385
386
387 if (altifp && get_hw_ifid(altifp, in6) == 0) {
388 nd6log((LOG_DEBUG, "%s: got interface identifier from %s\n",
389 if_name(ifp0), if_name(altifp)));
390 goto success;
391 }
392
393
394 ifnet_head_lock_shared();
395 TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
396 if (ifp == ifp0)
397 continue;
398 if (get_hw_ifid(ifp, in6) != 0)
399 continue;
400
401
402
403
404
405 if (IFID_UNIVERSAL(in6)) {
406 nd6log((LOG_DEBUG,
407 "%s: borrow interface identifier from %s\n",
408 if_name(ifp0), if_name(ifp)));
409 ifnet_head_done();
410 goto success;
411 }
412 }
413 ifnet_head_done();
414
415
416 if (get_rand_ifid(ifp, in6) == 0) {
417 nd6log((LOG_DEBUG,
418 "%s: interface identifier generated by random number\n",
419 if_name(ifp0)));
420 goto success;
421 }
422
423 printf("%s: failed to get interface identifier\n", if_name(ifp0));
424 return -1;
425
426success:
427 nd6log((LOG_INFO, "%s: ifid: "
428 "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
429 if_name(ifp0),
430 in6->s6_addr[8], in6->s6_addr[9],
431 in6->s6_addr[10], in6->s6_addr[11],
432 in6->s6_addr[12], in6->s6_addr[13],
433 in6->s6_addr[14], in6->s6_addr[15]));
434 return 0;
435}
436
437static int
438in6_ifattach_linklocal(
439 struct ifnet *ifp,
440 struct ifnet *altifp,
441 struct in6_aliasreq *ifra_passed)
442{
443 struct in6_ifaddr *ia;
444 struct in6_aliasreq ifra;
445 struct nd_prefix pr0;
446 int i, error;
447
448
449
450
451 bzero(&ifra, sizeof(ifra));
452
453 dlil_plumb_protocol(PF_INET6, ifp);
454
455
456
457
458
459 strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
460
461 if (ifp->if_type == IFT_PPP && ifra_passed != NULL)
462 bcopy(&ifra_passed->ifra_addr, &(ifra.ifra_addr), sizeof(struct sockaddr_in6));
463 else {
464 ifra.ifra_addr.sin6_family = AF_INET6;
465 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
466 ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
467#if SCOPEDROUTING
468 ifra.ifra_addr.sin6_addr.s6_addr16[1] = 0
469#else
470 ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
471#endif
472 ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
473 if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
474 ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
475 ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
476 } else {
477 if (get_ifid(ifp, altifp, &ifra.ifra_addr.sin6_addr) != 0) {
478 nd6log((LOG_ERR,
479 " %s: no ifid available\n", if_name(ifp)));
480 return -1;
481 }
482 }
483#if SCOPEDROUTING
484 ifra.ifra_addr.sin6_scope_id =
485 in6_addr2scopeid(ifp, &ifra.ifra_addr.sin6_addr);
486#endif
487 }
488 ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
489 ifra.ifra_prefixmask.sin6_family = AF_INET6;
490 ifra.ifra_prefixmask.sin6_addr = in6mask64;
491#if SCOPEDROUTING
492
493 ifra.ifra_prefixmask.sin6_scope_id = 0xffffffff;
494#endif
495
496 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
497 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
498
499
500
501
502
503
504 ifra.ifra_flags |= IN6_IFF_NODAD;
505
506
507
508
509
510
511
512 if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
513
514
515
516
517
518
519 if (error != EAFNOSUPPORT)
520 log(LOG_NOTICE, "in6_ifattach_linklocal: failed to "
521 "configure a link-local address on %s "
522 "(errno=%d)\n",
523 if_name(ifp), error);
524 return(-1);
525 }
526
527
528
529
530
531
532 ia = in6ifa_ifpforlinklocal(ifp, 0);
533#if DIAGNOSTIC
534 if (!ia) {
535 panic("ia == NULL in in6_ifattach_linklocal");
536
537 }
538#endif
539 if (in6if_do_dad(ifp) && (ifp->if_flags & IFF_POINTOPOINT) == 0) {
540 ia->ia6_flags &= ~IN6_IFF_NODAD;
541 ia->ia6_flags |= IN6_IFF_TENTATIVE;
542 }
543
544
545
546
547
548
549
550
551 bzero(&pr0, sizeof(pr0));
552 pr0.ndpr_ifp = ifp;
553
554 pr0.ndpr_plen = in6_mask2len(&ifra.ifra_prefixmask.sin6_addr, NULL);
555 pr0.ndpr_mask = ifra.ifra_prefixmask.sin6_addr;
556 pr0.ndpr_prefix = ifra.ifra_addr;
557
558 for (i = 0; i < 4; i++) {
559 pr0.ndpr_prefix.sin6_addr.s6_addr32[i] &=
560 in6mask64.s6_addr32[i];
561 }
562
563
564
565
566 pr0.ndpr_raf_onlink = 1;
567 pr0.ndpr_raf_auto = 1;
568 pr0.ndpr_vltime = ND6_INFINITE_LIFETIME;
569 pr0.ndpr_pltime = ND6_INFINITE_LIFETIME;
570
571
572
573
574
575
576
577 if (nd6_prefix_lookup(&pr0) == NULL) {
578 if ((error = nd6_prelist_add(&pr0, NULL, NULL)) != 0)
579 return(error);
580 }
581
582 in6_post_msg(ifp, KEV_INET6_NEW_LL_ADDR, ia);
583 return 0;
584}
585
586static int
587in6_ifattach_loopback(
588 struct ifnet *ifp)
589{
590 struct in6_aliasreq ifra;
591 int error;
592
593 bzero(&ifra, sizeof(ifra));
594
595
596
597
598
599 strncpy(ifra.ifra_name, if_name(ifp), sizeof(ifra.ifra_name));
600
601 ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
602 ifra.ifra_prefixmask.sin6_family = AF_INET6;
603 ifra.ifra_prefixmask.sin6_addr = in6mask128;
604
605
606
607
608
609 ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
610 ifra.ifra_dstaddr.sin6_family = AF_INET6;
611 ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
612
613 ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
614 ifra.ifra_addr.sin6_family = AF_INET6;
615 ifra.ifra_addr.sin6_addr = in6addr_loopback;
616
617
618 ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
619 ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
620
621
622 ifra.ifra_flags |= IN6_IFF_NODAD;
623
624
625 ifra.ifra_flags |= IN6_IFF_NOPFX;
626
627
628
629
630
631 if ((error = in6_update_ifa(ifp, &ifra, NULL)) != 0) {
632 log(LOG_ERR, "in6_ifattach_loopback: failed to configure "
633 "the loopback address on %s (errno=%d)\n",
634 if_name(ifp), error);
635 return(-1);
636 }
637
638 return 0;
639}
640
641
642
643
644
645
646
647int
648in6_nigroup(
649 struct ifnet *ifp,
650 const char *name,
651 int namelen,
652 struct in6_addr *in6)
653{
654 const char *p;
655 u_char *q;
656 MD5_CTX ctxt;
657 u_int8_t digest[16];
658 char l;
659 char n[64];
660
661 if (!namelen || !name)
662 return -1;
663
664 p = name;
665 while (p && *p && *p != '.' && p - name < namelen)
666 p++;
667 if (p - name > sizeof(n) - 1)
668 return -1;
669 l = p - name;
670 strncpy(n, name, l);
671 n[(int)l] = '\0';
672 for (q = n; *q; q++) {
673 if ('A' <= *q && *q <= 'Z')
674 *q = *q - 'A' + 'a';
675 }
676
677
678 bzero(&ctxt, sizeof(ctxt));
679 MD5Init(&ctxt);
680 MD5Update(&ctxt, &l, sizeof(l));
681 MD5Update(&ctxt, n, l);
682 MD5Final(digest, &ctxt);
683
684 bzero(in6, sizeof(*in6));
685 in6->s6_addr16[0] = htons(0xff02);
686 if (ifp)
687 in6->s6_addr16[1] = htons(ifp->if_index);
688 in6->s6_addr8[11] = 2;
689 bcopy(digest, &in6->s6_addr32[3], sizeof(in6->s6_addr32[3]));
690
691 return 0;
692}
693
694void
695in6_nigroup_attach(
696 const char *name,
697 int namelen)
698{
699 struct ifnet *ifp;
700 struct sockaddr_in6 mltaddr;
701 struct in6_multi *in6m;
702 int error;
703
704 bzero(&mltaddr, sizeof(mltaddr));
705 mltaddr.sin6_family = AF_INET6;
706 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
707 if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
708 return;
709
710 ifnet_head_lock_shared();
711 TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
712 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
713 ifnet_lock_shared(ifp);
714 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
715 ifnet_lock_done(ifp);
716 if (!in6m) {
717 if (!in6_addmulti(&mltaddr.sin6_addr, ifp, &error, 0)) {
718 nd6log((LOG_ERR, "%s: failed to join %s "
719 "(errno=%d)\n", if_name(ifp),
720 ip6_sprintf(&mltaddr.sin6_addr),
721 error));
722 }
723 }
724 }
725 ifnet_head_done();
726}
727
728void
729in6_nigroup_detach(
730 const char *name,
731 int namelen)
732{
733 struct ifnet *ifp;
734 struct sockaddr_in6 mltaddr;
735 struct in6_multi *in6m;
736
737 bzero(&mltaddr, sizeof(mltaddr));
738 mltaddr.sin6_family = AF_INET6;
739 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
740 if (in6_nigroup(NULL, name, namelen, &mltaddr.sin6_addr) != 0)
741 return;
742
743 ifnet_head_lock_shared();
744 TAILQ_FOREACH(ifp, &ifnet_head, if_list) {
745 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
746 ifnet_lock_shared(ifp);
747 IN6_LOOKUP_MULTI(mltaddr.sin6_addr, ifp, in6m);
748 ifnet_lock_done(ifp);
749 if (in6m)
750 in6_delmulti(in6m, 0);
751 }
752 ifnet_head_done();
753}
754
755
756
757
758
759
760void
761in6_ifattach(
762 struct ifnet *ifp,
763 struct ifnet *altifp,
764 struct in6_aliasreq *ifra)
765{
766 static size_t if_indexlim = 8;
767 struct in6_ifaddr *ia;
768 struct in6_addr in6;
769
770
771
772
773
774
775
776 if (in6_ifstat == NULL || icmp6_ifstat == NULL ||
777 if_index >= if_indexlim) {
778 size_t n;
779 caddr_t q;
780 size_t olim;
781
782 olim = if_indexlim;
783 while (if_index >= if_indexlim)
784 if_indexlim <<= 1;
785
786
787 n = if_indexlim * sizeof(struct in6_ifstat *);
788 q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK);
789 bzero(q, n);
790 if (in6_ifstat) {
791 bcopy((caddr_t)in6_ifstat, q,
792 olim * sizeof(struct in6_ifstat *));
793 FREE((caddr_t)in6_ifstat, M_IFADDR);
794 }
795 in6_ifstat = (struct in6_ifstat **)q;
796 in6_ifstatmax = if_indexlim;
797
798
799 n = if_indexlim * sizeof(struct icmp6_ifstat *);
800 q = (caddr_t)_MALLOC(n, M_IFADDR, M_WAITOK);
801 bzero(q, n);
802 if (icmp6_ifstat) {
803 bcopy((caddr_t)icmp6_ifstat, q,
804 olim * sizeof(struct icmp6_ifstat *));
805 FREE((caddr_t)icmp6_ifstat, M_IFADDR);
806 }
807 icmp6_ifstat = (struct icmp6_ifstat **)q;
808 icmp6_ifstatmax = if_indexlim;
809 }
810
811
812 nd6_ifattach(ifp);
813
814
815 scope6_ifattach(ifp);
816
817
818
819
820 switch (ifp->if_type) {
821#if IFT_STF
822 case IFT_STF:
823
824
825
826
827
828
829 goto statinit;
830#endif
831 default:
832 break;
833 }
834
835
836
837
838 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
839 log(LOG_INFO, "in6_ifattach: "
840 "%s is not multicast capable, IPv6 not enabled\n",
841 if_name(ifp));
842 return;
843 }
844
845
846
847
848
849 if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
850 struct in6_ifaddr *ia6 = NULL;
851 in6 = in6addr_loopback;
852 if ((ia6 = in6ifa_ifpwithaddr(ifp, &in6)) == NULL) {
853 if (in6_ifattach_loopback(ifp) != 0)
854 return;
855 }
856 else {
857 ifafree(&ia6->ia_ifa);
858 }
859 }
860
861
862
863
864 if (ip6_auto_linklocal) {
865 ia = in6ifa_ifpforlinklocal(ifp, 0);
866 if (ia == NULL) {
867 if (in6_ifattach_linklocal(ifp, altifp, ifra) == 0) {
868
869 } else {
870 log(LOG_INFO, "in6_ifattach: "
871 "%s failed to attach a linklocal address.\n",
872 if_name(ifp));
873
874 }
875 }
876 }
877
878#if IFT_STF
879statinit:
880#endif
881
882
883 if (in6_maxmtu < ifp->if_mtu)
884 in6_maxmtu = ifp->if_mtu;
885
886 if (in6_ifstat[ifp->if_index] == NULL) {
887 in6_ifstat[ifp->if_index] = (struct in6_ifstat *)
888 _MALLOC(sizeof(struct in6_ifstat), M_IFADDR, M_WAITOK);
889 bzero(in6_ifstat[ifp->if_index], sizeof(struct in6_ifstat));
890 }
891 if (icmp6_ifstat[ifp->if_index] == NULL) {
892 icmp6_ifstat[ifp->if_index] = (struct icmp6_ifstat *)
893 _MALLOC(sizeof(struct icmp6_ifstat), M_IFADDR, M_WAITOK);
894 bzero(icmp6_ifstat[ifp->if_index], sizeof(struct icmp6_ifstat));
895 }
896}
897
898
899
900
901
902
903void
904in6_ifdetach(
905 struct ifnet *ifp)
906{
907 struct in6_ifaddr *ia, *oia, *nia;
908 struct ifaddr *ifa, *next;
909 struct rtentry *rt;
910 short rtflags;
911 struct sockaddr_in6 sin6;
912 struct in6_multi *in6m;
913 struct in6_multi *in6m_next;
914
915
916 in6_purgeprefix(ifp);
917
918
919 nd6_purge(ifp);
920
921
922
923 lck_mtx_lock(nd6_mutex);
924 for (ia = in6_ifaddrs; ia != NULL; ia = nia) {
925 nia = ia->ia_next;
926 if (ia->ia_ifa.ifa_ifp != ifp)
927 continue;
928 in6_purgeaddr(&ia->ia_ifa, 1);
929 }
930 lck_mtx_unlock(nd6_mutex);
931
932 ifnet_lock_exclusive(ifp);
933
934
935 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = next)
936 {
937 next = ifa->ifa_list.tqe_next;
938
939
940 if (ifa->ifa_addr->sa_family != AF_INET6
941 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
942 continue;
943 }
944
945 ia = (struct in6_ifaddr *)ifa;
946
947
948 lck_mtx_lock(rt_mtx);
949 if ((ia->ia_flags & IFA_ROUTE)
950 && (rt = rtalloc1_locked((struct sockaddr *)&ia->ia_addr, 0, 0UL))) {
951 rtflags = rt->rt_flags;
952 rtfree_locked(rt);
953 rtrequest_locked(RTM_DELETE,
954 (struct sockaddr *)&ia->ia_addr,
955 (struct sockaddr *)&ia->ia_addr,
956 (struct sockaddr *)&ia->ia_prefixmask,
957 rtflags, (struct rtentry **)0);
958 }
959 lck_mtx_unlock(rt_mtx);
960
961
962 if_detach_ifa(ifp, &ia->ia_ifa);
963 ifafree(&ia->ia_ifa);
964
965
966 oia = ia;
967 lck_mtx_lock(nd6_mutex);
968 if (oia == (ia = in6_ifaddrs))
969 in6_ifaddrs = ia->ia_next;
970 else {
971 while (ia->ia_next && (ia->ia_next != oia))
972 ia = ia->ia_next;
973 if (ia->ia_next)
974 ia->ia_next = oia->ia_next;
975 else {
976 nd6log((LOG_ERR,
977 "%s: didn't unlink in6ifaddr from "
978 "list\n", if_name(ifp)));
979 }
980 }
981 lck_mtx_unlock(nd6_mutex);
982
983 ifafree(&oia->ia_ifa);
984 }
985 ifnet_lock_done(ifp);
986
987
988
989
990
991
992
993
994
995 nd6_purge(ifp);
996
997
998 bzero(&sin6, sizeof(sin6));
999 sin6.sin6_len = sizeof(struct sockaddr_in6);
1000 sin6.sin6_family = AF_INET6;
1001 sin6.sin6_addr = in6addr_linklocal_allnodes;
1002 sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
1003 lck_mtx_lock(rt_mtx);
1004 rt = rtalloc1_locked((struct sockaddr *)&sin6, 0, 0UL);
1005 if (rt && rt->rt_ifp == ifp) {
1006 rtrequest_locked(RTM_DELETE, (struct sockaddr *)rt_key(rt),
1007 rt->rt_gateway, rt_mask(rt), rt->rt_flags, 0);
1008 rtfree_locked(rt);
1009 }
1010 lck_mtx_unlock(rt_mtx);
1011}
1012
1013void
1014in6_get_tmpifid(
1015 struct ifnet *ifp,
1016 u_int8_t *retbuf,
1017 const u_int8_t *baseid,
1018 int generate)
1019{
1020 u_int8_t nullbuf[8];
1021 struct nd_ifinfo *ndi = &nd_ifinfo[ifp->if_index];
1022
1023 bzero(nullbuf, sizeof(nullbuf));
1024 if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) == 0) {
1025
1026 generate = 1;
1027 }
1028
1029 if (generate) {
1030 bcopy(baseid, ndi->randomseed1, sizeof(ndi->randomseed1));
1031
1032
1033 (void)generate_tmp_ifid(ndi->randomseed0, ndi->randomseed1,
1034 ndi->randomid);
1035 }
1036 bcopy(ndi->randomid, retbuf, 8);
1037}
1038
1039extern size_t nd_ifinfo_indexlim;
1040extern int ip6_use_tempaddr;
1041void
1042in6_tmpaddrtimer(
1043 void *ignored_arg)
1044{
1045 int i;
1046 struct nd_ifinfo *ndi;
1047 u_int8_t nullbuf[8];
1048 int s = splnet();
1049
1050 timeout(in6_tmpaddrtimer, (caddr_t)0,
1051 (ip6_temp_preferred_lifetime - ip6_desync_factor -
1052 ip6_temp_regen_advance) * hz);
1053
1054 if (ip6_use_tempaddr) {
1055
1056 bzero(nullbuf, sizeof(nullbuf));
1057 for (i = 1; i < nd_ifinfo_indexlim + 1; i++) {
1058 ndi = &nd_ifinfo[i];
1059 if (ndi->flags != ND6_IFF_PERFORMNUD)
1060 continue;
1061 if (bcmp(ndi->randomid, nullbuf, sizeof(nullbuf)) != 0) {
1062
1063
1064
1065
1066 (void)generate_tmp_ifid(ndi->randomseed0,
1067 ndi->randomseed1,
1068 ndi->randomid);
1069 }
1070 }
1071 }
1072
1073 splx(s);
1074}
1075