in6_ifattach.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. /* $OpenBSD: in6_ifattach.c,v 1.90 2015/07/18 15:05:32 mpi Exp $ */
  2. /* $KAME: in6_ifattach.c,v 1.124 2001/07/18 08:32:51 jinmei Exp $ */
  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. #include <sys/param.h>
  32. #include <sys/systm.h>
  33. #include <sys/socket.h>
  34. #include <sys/sockio.h>
  35. #include <sys/kernel.h>
  36. #include <sys/syslog.h>
  37. #include <crypto/sha2.h>
  38. #include <net/if.h>
  39. #include <net/if_var.h>
  40. #include <net/if_dl.h>
  41. #include <net/if_types.h>
  42. #include <net/route.h>
  43. #include <netinet/in.h>
  44. #include <netinet6/in6_var.h>
  45. #include <netinet/ip6.h>
  46. #include <netinet6/ip6_var.h>
  47. #include <netinet6/in6_ifattach.h>
  48. #include <netinet6/nd6.h>
  49. #ifdef MROUTING
  50. #include <netinet6/ip6_mroute.h>
  51. #endif
  52. int get_last_resort_ifid(struct ifnet *, struct in6_addr *);
  53. int get_hw_ifid(struct ifnet *, struct in6_addr *);
  54. int get_ifid(struct ifnet *, struct in6_addr *);
  55. int in6_ifattach_loopback(struct ifnet *);
  56. #define EUI64_GBIT 0x01
  57. #define EUI64_UBIT 0x02
  58. #define EUI64_TO_IFID(in6) do {(in6)->s6_addr[8] ^= EUI64_UBIT; } while (0)
  59. #define EUI64_GROUP(in6) ((in6)->s6_addr[8] & EUI64_GBIT)
  60. #define EUI64_INDIVIDUAL(in6) (!EUI64_GROUP(in6))
  61. #define EUI64_LOCAL(in6) ((in6)->s6_addr[8] & EUI64_UBIT)
  62. #define EUI64_UNIVERSAL(in6) (!EUI64_LOCAL(in6))
  63. #define IFID_LOCAL(in6) (!EUI64_LOCAL(in6))
  64. #define IFID_UNIVERSAL(in6) (!EUI64_UNIVERSAL(in6))
  65. /*
  66. * Generate a last-resort interface identifier, when the machine has no
  67. * IEEE802/EUI64 address sources.
  68. * The goal here is to get an interface identifier that is
  69. * (1) random enough and (2) does not change across reboot.
  70. * We currently use SHA512(hostname) for it.
  71. *
  72. * in6 - upper 64bits are preserved
  73. */
  74. int
  75. get_last_resort_ifid(struct ifnet *ifp, struct in6_addr *in6)
  76. {
  77. SHA2_CTX ctx;
  78. u_int8_t digest[SHA512_DIGEST_LENGTH];
  79. #if 0
  80. /* we need at least several letters as seed for ifid */
  81. if (hostnamelen < 3)
  82. return -1;
  83. #endif
  84. /* generate 8 bytes of pseudo-random value. */
  85. SHA512Init(&ctx);
  86. SHA512Update(&ctx, hostname, hostnamelen);
  87. SHA512Final(digest, &ctx);
  88. /* assumes sizeof(digest) > sizeof(ifid) */
  89. bcopy(digest, &in6->s6_addr[8], 8);
  90. /* make sure to set "u" bit to local, and "g" bit to individual. */
  91. in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
  92. in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
  93. /* convert EUI64 into IPv6 interface identifier */
  94. EUI64_TO_IFID(in6);
  95. return 0;
  96. }
  97. /*
  98. * Generate a random interface identifier.
  99. *
  100. * in6 - upper 64bits are preserved
  101. */
  102. void
  103. in6_get_rand_ifid(struct ifnet *ifp, struct in6_addr *in6)
  104. {
  105. arc4random_buf(&in6->s6_addr32[2], 8);
  106. /* make sure to set "u" bit to local, and "g" bit to individual. */
  107. in6->s6_addr[8] &= ~EUI64_GBIT; /* g bit to "individual" */
  108. in6->s6_addr[8] |= EUI64_UBIT; /* u bit to "local" */
  109. /* convert EUI64 into IPv6 interface identifier */
  110. EUI64_TO_IFID(in6);
  111. }
  112. /*
  113. * Get interface identifier for the specified interface.
  114. *
  115. * in6 - upper 64bits are preserved
  116. */
  117. int
  118. get_hw_ifid(struct ifnet *ifp, struct in6_addr *in6)
  119. {
  120. struct sockaddr_dl *sdl;
  121. char *addr;
  122. size_t addrlen;
  123. static u_int8_t allzero[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
  124. static u_int8_t allone[8] =
  125. { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
  126. sdl = (struct sockaddr_dl *)ifp->if_sadl;
  127. if (sdl == NULL || sdl->sdl_alen == 0)
  128. return -1;
  129. addr = LLADDR(sdl);
  130. addrlen = sdl->sdl_alen;
  131. switch (ifp->if_type) {
  132. case IFT_IEEE1394:
  133. case IFT_IEEE80211:
  134. /* IEEE1394 uses 16byte length address starting with EUI64 */
  135. if (addrlen > 8)
  136. addrlen = 8;
  137. break;
  138. default:
  139. break;
  140. }
  141. /* get EUI64 */
  142. switch (ifp->if_type) {
  143. /* IEEE802/EUI64 cases - what others? */
  144. case IFT_ETHER:
  145. case IFT_CARP:
  146. case IFT_IEEE1394:
  147. case IFT_IEEE80211:
  148. /* look at IEEE802/EUI64 only */
  149. if (addrlen != 8 && addrlen != 6)
  150. return -1;
  151. /*
  152. * check for invalid MAC address - on bsdi, we see it a lot
  153. * since wildboar configures all-zero MAC on pccard before
  154. * card insertion.
  155. */
  156. if (bcmp(addr, allzero, addrlen) == 0)
  157. return -1;
  158. if (bcmp(addr, allone, addrlen) == 0)
  159. return -1;
  160. /* make EUI64 address */
  161. if (addrlen == 8)
  162. bcopy(addr, &in6->s6_addr[8], 8);
  163. else if (addrlen == 6) {
  164. in6->s6_addr[8] = addr[0];
  165. in6->s6_addr[9] = addr[1];
  166. in6->s6_addr[10] = addr[2];
  167. in6->s6_addr[11] = 0xff;
  168. in6->s6_addr[12] = 0xfe;
  169. in6->s6_addr[13] = addr[3];
  170. in6->s6_addr[14] = addr[4];
  171. in6->s6_addr[15] = addr[5];
  172. }
  173. break;
  174. case IFT_GIF:
  175. /*
  176. * RFC2893 says: "SHOULD use IPv4 address as ifid source".
  177. * however, IPv4 address is not very suitable as unique
  178. * identifier source (can be renumbered).
  179. * we don't do this.
  180. */
  181. return -1;
  182. default:
  183. return -1;
  184. }
  185. /* sanity check: g bit must not indicate "group" */
  186. if (EUI64_GROUP(in6))
  187. return -1;
  188. /* convert EUI64 into IPv6 interface identifier */
  189. EUI64_TO_IFID(in6);
  190. /*
  191. * sanity check: ifid must not be all zero, avoid conflict with
  192. * subnet router anycast
  193. */
  194. if ((in6->s6_addr[8] & ~(EUI64_GBIT | EUI64_UBIT)) == 0x00 &&
  195. bcmp(&in6->s6_addr[9], allzero, 7) == 0) {
  196. return -1;
  197. }
  198. return 0;
  199. }
  200. /*
  201. * Get interface identifier for the specified interface. If it is not
  202. * available on ifp0, borrow interface identifier from other information
  203. * sources.
  204. */
  205. int
  206. get_ifid(struct ifnet *ifp0, struct in6_addr *in6)
  207. {
  208. struct ifnet *ifp;
  209. /* first, try to get it from the interface itself */
  210. if (get_hw_ifid(ifp0, in6) == 0) {
  211. nd6log((LOG_DEBUG, "%s: got interface identifier from itself\n",
  212. ifp0->if_xname));
  213. goto success;
  214. }
  215. /* next, try to get it from some other hardware interface */
  216. TAILQ_FOREACH(ifp, &ifnet, if_list) {
  217. if (ifp == ifp0)
  218. continue;
  219. if (get_hw_ifid(ifp, in6) != 0)
  220. continue;
  221. /*
  222. * to borrow ifid from other interface, ifid needs to be
  223. * globally unique
  224. */
  225. if (IFID_UNIVERSAL(in6)) {
  226. nd6log((LOG_DEBUG,
  227. "%s: borrow interface identifier from %s\n",
  228. ifp0->if_xname, ifp->if_xname));
  229. goto success;
  230. }
  231. }
  232. /* last resort: get from random number source */
  233. if (get_last_resort_ifid(ifp, in6) == 0) {
  234. nd6log((LOG_DEBUG,
  235. "%s: interface identifier generated by random number\n",
  236. ifp0->if_xname));
  237. goto success;
  238. }
  239. printf("%s: failed to get interface identifier\n", ifp0->if_xname);
  240. return -1;
  241. success:
  242. nd6log((LOG_INFO, "%s: ifid: %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
  243. ifp0->if_xname, in6->s6_addr[8], in6->s6_addr[9], in6->s6_addr[10],
  244. in6->s6_addr[11], in6->s6_addr[12], in6->s6_addr[13],
  245. in6->s6_addr[14], in6->s6_addr[15]));
  246. return 0;
  247. }
  248. /*
  249. * ifid - used as EUI64 if not NULL, overrides other EUI64 sources
  250. */
  251. int
  252. in6_ifattach_linklocal(struct ifnet *ifp, struct in6_addr *ifid)
  253. {
  254. struct in6_ifaddr *ia6;
  255. struct in6_aliasreq ifra;
  256. int s, error;
  257. /*
  258. * configure link-local address.
  259. */
  260. bzero(&ifra, sizeof(ifra));
  261. /*
  262. * in6_update_ifa() does not use ifra_name, but we accurately set it
  263. * for safety.
  264. */
  265. strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
  266. ifra.ifra_addr.sin6_family = AF_INET6;
  267. ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
  268. ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
  269. ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  270. ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
  271. if ((ifp->if_flags & IFF_LOOPBACK) != 0) {
  272. ifra.ifra_addr.sin6_addr.s6_addr32[2] = 0;
  273. ifra.ifra_addr.sin6_addr.s6_addr32[3] = htonl(1);
  274. } else if (ifid) {
  275. ifra.ifra_addr.sin6_addr = *ifid;
  276. ifra.ifra_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
  277. ifra.ifra_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  278. ifra.ifra_addr.sin6_addr.s6_addr32[1] = 0;
  279. ifra.ifra_addr.sin6_addr.s6_addr[8] &= ~EUI64_GBIT;
  280. ifra.ifra_addr.sin6_addr.s6_addr[8] |= EUI64_UBIT;
  281. } else {
  282. if (get_ifid(ifp, &ifra.ifra_addr.sin6_addr) != 0) {
  283. nd6log((LOG_ERR,
  284. "%s: no ifid available\n", ifp->if_xname));
  285. return (-1);
  286. }
  287. }
  288. ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
  289. ifra.ifra_prefixmask.sin6_family = AF_INET6;
  290. ifra.ifra_prefixmask.sin6_addr = in6mask64;
  291. /* link-local addresses should NEVER expire. */
  292. ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
  293. ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
  294. /*
  295. * Do not let in6_update_ifa() do DAD, since we need a random delay
  296. * before sending an NS at the first time the interface becomes up.
  297. */
  298. ifra.ifra_flags |= IN6_IFF_NODAD;
  299. /*
  300. * Now call in6_update_ifa() to do a bunch of procedures to configure
  301. * a link-local address. In the case of CARP, we may be called after
  302. * one has already been configured, so check if it's already there
  303. * with in6ifa_ifpforlinklocal() and clobber it if it exists.
  304. */
  305. s = splsoftnet();
  306. error = in6_update_ifa(ifp, &ifra, in6ifa_ifpforlinklocal(ifp, 0));
  307. splx(s);
  308. if (error != 0) {
  309. /*
  310. * XXX: When the interface does not support IPv6, this call
  311. * would fail in the SIOCSIFADDR ioctl. I believe the
  312. * notification is rather confusing in this case, so just
  313. * suppress it. (jinmei@kame.net 20010130)
  314. */
  315. if (error != EAFNOSUPPORT)
  316. nd6log((LOG_NOTICE, "in6_ifattach_linklocal: failed to "
  317. "configure a link-local address on %s "
  318. "(errno=%d)\n",
  319. ifp->if_xname, error));
  320. return (-1);
  321. }
  322. /*
  323. * Adjust ia6_flags so that in6_ifattach() will perform DAD.
  324. * XXX: Some P2P interfaces seem not to send packets just after
  325. * becoming up, so we skip p2p interfaces for safety.
  326. */
  327. ia6 = in6ifa_ifpforlinklocal(ifp, 0); /* ia6 must not be NULL */
  328. #ifdef DIAGNOSTIC
  329. if (!ia6) {
  330. panic("ia6 == NULL in in6_ifattach_linklocal");
  331. /* NOTREACHED */
  332. }
  333. #endif
  334. if (in6if_do_dad(ifp) && ((ifp->if_flags & IFF_POINTOPOINT) ||
  335. (ifp->if_type == IFT_CARP)) == 0) {
  336. ia6->ia6_flags &= ~IN6_IFF_NODAD;
  337. ia6->ia6_flags |= IN6_IFF_TENTATIVE;
  338. }
  339. /*
  340. * Make the link-local prefix (fe80::/64%link) as on-link.
  341. * Since we'd like to manage prefixes separately from addresses,
  342. * we make an ND6 prefix structure for the link-local prefix,
  343. * and add it to the prefix list as a never-expire prefix.
  344. * XXX: this change might affect some existing code base...
  345. */
  346. if (nd6_prefix_add(ifp, &ifra.ifra_addr, &ifra.ifra_prefixmask,
  347. &ifra.ifra_lifetime, 1) == NULL)
  348. return (EINVAL);
  349. return (0);
  350. }
  351. int
  352. in6_ifattach_loopback(struct ifnet *ifp)
  353. {
  354. struct in6_aliasreq ifra;
  355. KASSERT(ifp->if_flags & IFF_LOOPBACK);
  356. bzero(&ifra, sizeof(ifra));
  357. /*
  358. * in6_update_ifa() does not use ifra_name, but we accurately set it
  359. * for safety.
  360. */
  361. strncpy(ifra.ifra_name, ifp->if_xname, sizeof(ifra.ifra_name));
  362. ifra.ifra_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
  363. ifra.ifra_prefixmask.sin6_family = AF_INET6;
  364. ifra.ifra_prefixmask.sin6_addr = in6mask128;
  365. /*
  366. * Always initialize ia_dstaddr (= broadcast address) to loopback
  367. * address. Follows IPv4 practice - see in_ifinit().
  368. */
  369. ifra.ifra_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
  370. ifra.ifra_dstaddr.sin6_family = AF_INET6;
  371. ifra.ifra_dstaddr.sin6_addr = in6addr_loopback;
  372. ifra.ifra_addr.sin6_len = sizeof(struct sockaddr_in6);
  373. ifra.ifra_addr.sin6_family = AF_INET6;
  374. ifra.ifra_addr.sin6_addr = in6addr_loopback;
  375. /* the loopback address should NEVER expire. */
  376. ifra.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
  377. ifra.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
  378. /* we don't need to perform DAD on loopback interfaces. */
  379. ifra.ifra_flags |= IN6_IFF_NODAD;
  380. /*
  381. * We are sure that this is a newly assigned address, so we can set
  382. * NULL to the 3rd arg.
  383. */
  384. return (in6_update_ifa(ifp, &ifra, NULL));
  385. }
  386. /*
  387. * compute NI group address, based on the current hostname setting.
  388. * see draft-ietf-ipngwg-icmp-name-lookup-* (04 and later).
  389. *
  390. * when ifp == NULL, the caller is responsible for filling scopeid.
  391. */
  392. int
  393. in6_nigroup(struct ifnet *ifp, const char *name, int namelen,
  394. struct sockaddr_in6 *sa6)
  395. {
  396. const char *p;
  397. u_int8_t *q;
  398. SHA2_CTX ctx;
  399. u_int8_t digest[SHA512_DIGEST_LENGTH];
  400. u_int8_t l;
  401. u_int8_t n[64]; /* a single label must not exceed 63 chars */
  402. if (!namelen || !name)
  403. return -1;
  404. p = name;
  405. while (p && *p && *p != '.' && p - name < namelen)
  406. p++;
  407. if (p - name > sizeof(n) - 1)
  408. return -1; /* label too long */
  409. l = p - name;
  410. strncpy((char *)n, name, l);
  411. n[(int)l] = '\0';
  412. for (q = n; *q; q++) {
  413. if ('A' <= *q && *q <= 'Z')
  414. *q = *q - 'A' + 'a';
  415. }
  416. /* generate 8 bytes of pseudo-random value. */
  417. SHA512Init(&ctx);
  418. SHA512Update(&ctx, &l, sizeof(l));
  419. SHA512Update(&ctx, n, l);
  420. SHA512Final(digest, &ctx);
  421. bzero(sa6, sizeof(*sa6));
  422. sa6->sin6_family = AF_INET6;
  423. sa6->sin6_len = sizeof(*sa6);
  424. sa6->sin6_addr.s6_addr16[0] = htons(0xff02);
  425. sa6->sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  426. sa6->sin6_addr.s6_addr8[11] = 2;
  427. bcopy(digest, &sa6->sin6_addr.s6_addr32[3],
  428. sizeof(sa6->sin6_addr.s6_addr32[3]));
  429. return 0;
  430. }
  431. /*
  432. * XXX multiple loopback interface needs more care. for instance,
  433. * nodelocal address needs to be configured onto only one of them.
  434. * XXX multiple link-local address case
  435. */
  436. int
  437. in6_ifattach(struct ifnet *ifp)
  438. {
  439. struct ifaddr *ifa;
  440. int dad_delay = 0; /* delay ticks before DAD output */
  441. /* some of the interfaces are inherently not IPv6 capable */
  442. switch (ifp->if_type) {
  443. case IFT_BRIDGE:
  444. case IFT_ENC:
  445. case IFT_PFLOG:
  446. case IFT_PFSYNC:
  447. return (0);
  448. }
  449. /*
  450. * if link mtu is too small, don't try to configure IPv6.
  451. * remember there could be some link-layer that has special
  452. * fragmentation logic.
  453. */
  454. if (ifp->if_mtu < IPV6_MMTU)
  455. return (EINVAL);
  456. if ((ifp->if_flags & IFF_MULTICAST) == 0)
  457. return (EINVAL);
  458. /* Assign a link-local address, if there's none. */
  459. if (in6ifa_ifpforlinklocal(ifp, 0) == NULL) {
  460. if (in6_ifattach_linklocal(ifp, NULL) != 0) {
  461. /* failed to assign linklocal address. bark? */
  462. }
  463. }
  464. /* Assign loopback address, if there's none. */
  465. if (ifp->if_flags & IFF_LOOPBACK) {
  466. struct in6_addr in6 = in6addr_loopback;
  467. if (in6ifa_ifpwithaddr(ifp, &in6) != NULL)
  468. return (0);
  469. return (in6_ifattach_loopback(ifp));
  470. }
  471. /* Perform DAD. */
  472. TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list) {
  473. if (ifa->ifa_addr->sa_family != AF_INET6)
  474. continue;
  475. if (ifatoia6(ifa)->ia6_flags & IN6_IFF_TENTATIVE)
  476. nd6_dad_start(ifa, &dad_delay);
  477. }
  478. if (ifp->if_xflags & IFXF_AUTOCONF6)
  479. nd6_rs_attach(ifp);
  480. return (0);
  481. }
  482. /*
  483. * NOTE: in6_ifdetach() does not support loopback if at this moment.
  484. */
  485. void
  486. in6_ifdetach(struct ifnet *ifp)
  487. {
  488. struct ifaddr *ifa, *next;
  489. struct rtentry *rt;
  490. struct sockaddr_in6 sin6;
  491. #ifdef MROUTING
  492. /* remove ip6_mrouter stuff */
  493. ip6_mrouter_detach(ifp);
  494. #endif
  495. /* nuke any of IPv6 addresses we have */
  496. TAILQ_FOREACH_SAFE(ifa, &ifp->if_addrlist, ifa_list, next) {
  497. if (ifa->ifa_addr->sa_family != AF_INET6)
  498. continue;
  499. in6_purgeaddr(ifa);
  500. dohooks(ifp->if_addrhooks, 0);
  501. }
  502. /*
  503. * Remove neighbor management table. Must be called after
  504. * purging addresses.
  505. */
  506. nd6_purge(ifp);
  507. /* remove route to interface local allnodes multicast (ff01::1) */
  508. bzero(&sin6, sizeof(sin6));
  509. sin6.sin6_len = sizeof(struct sockaddr_in6);
  510. sin6.sin6_family = AF_INET6;
  511. sin6.sin6_addr = in6addr_intfacelocal_allnodes;
  512. sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  513. rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
  514. if (rt && rt->rt_ifp == ifp) {
  515. rtdeletemsg(rt, ifp->if_rdomain);
  516. rtfree(rt);
  517. }
  518. /* remove route to link-local allnodes multicast (ff02::1) */
  519. bzero(&sin6, sizeof(sin6));
  520. sin6.sin6_len = sizeof(struct sockaddr_in6);
  521. sin6.sin6_family = AF_INET6;
  522. sin6.sin6_addr = in6addr_linklocal_allnodes;
  523. sin6.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
  524. rt = rtalloc(sin6tosa(&sin6), 0, ifp->if_rdomain);
  525. if (rt && rt->rt_ifp == ifp) {
  526. rtdeletemsg(rt, ifp->if_rdomain);
  527. rtfree(rt);
  528. }
  529. if (ifp->if_xflags & IFXF_AUTOCONF6) {
  530. nd6_rs_detach(ifp);
  531. ifp->if_xflags &= ~IFXF_AUTOCONF6;
  532. }
  533. }