in6_ifattach.c revision 1.2 1 /*
2 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 */
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/malloc.h>
33 #include <sys/socket.h>
34 #include <sys/sockio.h>
35
36 #include <net/if.h>
37 #include <net/if_dl.h>
38 #include <net/if_types.h>
39 #include <net/route.h>
40
41 #include <netinet/in.h>
42 #include <netinet/in_var.h>
43 #ifndef __NetBSD__
44 #include <netinet/if_ether.h>
45 #endif
46
47 #include <netinet6/in6.h>
48 #include <netinet6/ip6.h>
49 #include <netinet6/ip6_var.h>
50 #include <netinet6/in6_ifattach.h>
51 #include <netinet6/ip6.h>
52 #include <netinet6/ip6_var.h>
53 #include <netinet6/nd6.h>
54
55 static struct in6_addr llsol;
56
57 struct in6_addr **in6_iflladdr = NULL;
58 unsigned long in6_maxmtu = 0;
59
60 int found_first_ifid = 0;
61 #define IFID_LEN 8
62 static char first_ifid[IFID_LEN];
63
64 static void ieee802_to_eui64 __P((u_int8_t *, u_int8_t *));
65
66 static void
67 ieee802_to_eui64(dst, src)
68 u_int8_t *dst;
69 u_int8_t *src;
70 {
71 dst[0] = src[0];
72 dst[1] = src[1];
73 dst[2] = src[2];
74 dst[3] = 0xff;
75 dst[4] = 0xfe;
76 dst[5] = src[3];
77 dst[6] = src[4];
78 dst[7] = src[5];
79 }
80
81 /*
82 * find first ifid on list of interfaces.
83 */
84 int
85 in6_ifattach_getifid(ifp0)
86 struct ifnet *ifp0;
87 {
88 struct ifnet *ifp;
89 struct ifaddr *ifa;
90 u_int8_t *addr = NULL;
91 int addrlen = 0;
92 struct sockaddr_dl *sdl;
93
94 if (found_first_ifid)
95 return 0;
96
97 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
98 if (ifp0 != NULL && ifp0 != ifp)
99 continue;
100 for (ifa = ifp->if_addrlist.tqh_first;
101 ifa;
102 ifa = ifa->ifa_list.tqe_next) {
103 if (ifa->ifa_addr->sa_family != AF_LINK)
104 continue;
105 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
106 if (sdl == NULL)
107 continue;
108 if (sdl->sdl_alen == 0)
109 continue;
110 switch (ifp->if_type) {
111 case IFT_ETHER:
112 case IFT_FDDI:
113 case IFT_ATM:
114 /* what others? */
115 addr = LLADDR(sdl);
116 addrlen = sdl->sdl_alen;
117 goto found;
118 default:
119 break;
120 }
121 }
122 }
123 printf("failed to get EUI64");
124 return EADDRNOTAVAIL;
125
126 found:
127 switch (addrlen) {
128 case 6:
129 ieee802_to_eui64(first_ifid, addr);
130 found_first_ifid = 1;
131 break;
132 case 8:
133 bcopy(addr, first_ifid, 8);
134 found_first_ifid = 1;
135 break;
136 default:
137 break;
138 }
139
140 if (found_first_ifid) {
141 printf("got EUI64 from %s, "
142 "value %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n",
143 ifp->if_xname,
144 first_ifid[0] & 0xff, first_ifid[1] & 0xff,
145 first_ifid[2] & 0xff, first_ifid[3] & 0xff,
146 first_ifid[4] & 0xff, first_ifid[5] & 0xff,
147 first_ifid[6] & 0xff, first_ifid[7] & 0xff);
148 return 0;
149 } else {
150 printf("failed to get EUI64");
151 return EADDRNOTAVAIL;
152 }
153 }
154
155 /*
156 * add link-local address to *pseudo* p2p interfaces.
157 * get called when the first MAC address is made available in in6_ifattach().
158 */
159 void
160 in6_ifattach_p2p()
161 {
162 struct ifnet *ifp;
163
164 /* prevent infinite loop. just in case. */
165 if (! found_first_ifid)
166 return;
167
168 for (ifp = ifnet.tqh_first; ifp; ifp = ifp->if_list.tqe_next) {
169 switch (ifp->if_type) {
170 case IFT_GIF:
171 case IFT_FAITH:
172 /* pseudo interfaces - safe to initialize here */
173 in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
174 break;
175 case IFT_SLIP:
176 /* IPv6 is not supported */
177 break;
178 case IFT_PPP:
179 /* this is not a pseudo interface, skip it */
180 break;
181 default:
182 break;
183 }
184 }
185 }
186
187 void
188 in6_ifattach(ifp, type, laddr, noloop)
189 struct ifnet *ifp;
190 u_int type;
191 caddr_t laddr;
192 int noloop;
193 /* xxx sizeof(laddr) */
194 {
195 static size_t if_indexlim = 8;
196 struct sockaddr_in6 mltaddr;
197 struct sockaddr_in6 mltmask;
198 struct sockaddr_in6 gate;
199 struct sockaddr_in6 mask;
200
201 struct in6_ifaddr *ia, *ib, *oia;
202 struct ifaddr *ifa;
203 int rtflag = 0;
204
205 if (type == IN6_IFT_P2P && found_first_ifid == 0) {
206 printf("%s: no ifid available yet for IPv6 link-local address\n",
207 ifp->if_xname);
208 return;
209 }
210
211 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
212 printf("%s: no multicast allowed, IPv6 is not enabled\n",
213 ifp->if_xname);
214 return;
215 }
216
217 /*
218 * We have some arrays that should be indexed by if_index.
219 * since if_index will grow dynamically, they should grow too.
220 * struct in6_addr **in6_iflladdr
221 */
222 if (in6_iflladdr == NULL || if_index >= if_indexlim) {
223 size_t n;
224 caddr_t q;
225
226 while(if_index >= if_indexlim)
227 if_indexlim <<= 1;
228
229 /* grow in6_iflladdr */
230 n = if_indexlim * sizeof(struct in6_addr *);
231 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
232 bzero(q, n);
233 if (in6_iflladdr) {
234 bcopy((caddr_t)in6_iflladdr, q, n/2);
235 free((caddr_t)in6_iflladdr, M_IFADDR);
236 }
237 in6_iflladdr = (struct in6_addr **)q;
238 }
239
240 /*
241 * To prevent to assign link-local address to PnP network
242 * cards multiple times.
243 * This is lengthy for P2P and LOOP but works.
244 */
245 ifa = TAILQ_FIRST(&ifp->if_addrlist);
246 if (ifa != NULL) {
247 for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
248 if (ifa->ifa_addr->sa_family != AF_INET6)
249 continue;
250 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
251 return;
252 }
253 } else
254 TAILQ_INIT(&ifp->if_addrlist);
255
256 /*
257 * link-local address
258 */
259 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
260 bzero((caddr_t)ia, sizeof(*ia));
261 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
262 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
263 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
264 ia->ia_ifp = ifp;
265 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
266 /*
267 * Also link into the IPv6 address chain beginning with in6_ifaddr.
268 * kazu opposed it, but itojun & jinmei wanted.
269 */
270 if ((oia = in6_ifaddr) != NULL) {
271 for (; oia->ia_next; oia = oia->ia_next)
272 continue;
273 oia->ia_next = ia;
274 } else
275 in6_ifaddr = ia;
276
277 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
278 ia->ia_prefixmask.sin6_family = AF_INET6;
279 ia->ia_prefixmask.sin6_addr = in6mask64;
280
281 bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
282 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
283 ia->ia_addr.sin6_family = AF_INET6;
284 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
285 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
286 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
287
288 switch (type) {
289 case IN6_IFT_LOOP:
290 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
291 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
292 break;
293 case IN6_IFT_802:
294 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
295 ia->ia_ifa.ifa_flags |= RTF_CLONING;
296 rtflag = RTF_CLONING;
297 /* fall through */
298 case IN6_IFT_P2P802:
299 if (laddr == NULL)
300 break;
301 ieee802_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], laddr);
302 /* set global bit */
303 ia->ia_addr.sin6_addr.s6_addr8[8] |= 0x02;
304 if (! found_first_ifid) {
305 if (in6_ifattach_getifid(ifp) == 0)
306 in6_ifattach_p2p();
307 }
308 break;
309 case IN6_IFT_P2P:
310 bcopy((caddr_t)first_ifid,
311 (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
312 IFID_LEN);
313 break;
314 }
315
316 ia->ia_ifa.ifa_metric = ifp->if_metric;
317
318 if (ifp->if_ioctl != NULL) {
319 int s;
320 int error;
321
322 /*
323 * give the interface a chance to initialize, in case this
324 * is the first address to be added.
325 */
326 s = splimp();
327 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
328 splx(s);
329
330 if (error) {
331 switch (error) {
332 case EAFNOSUPPORT:
333 printf("%s: IPv6 is not supported\n",
334 ifp->if_xname);
335 break;
336 default:
337 printf("SIOCSIFADDR(%s) returned %d\n",
338 ifp->if_xname, error);
339 break;
340 }
341
342 /* undo changes */
343 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
344 if (oia)
345 oia->ia_next = ia->ia_next;
346 else
347 in6_ifaddr = ia->ia_next;
348 free(ia, M_IFADDR);
349 return;
350 }
351 }
352
353 /* add route to the interface. */
354 rtrequest(RTM_ADD,
355 (struct sockaddr *)&ia->ia_addr,
356 (struct sockaddr *)&ia->ia_addr,
357 (struct sockaddr *)&ia->ia_prefixmask,
358 RTF_UP|rtflag,
359 (struct rtentry **)0);
360 ia->ia_flags |= IFA_ROUTE;
361
362
363 if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
364 /*
365 * route local address to loopback
366 */
367 bzero(&gate, sizeof(gate));
368 gate.sin6_len = sizeof(struct sockaddr_in6);
369 gate.sin6_family = AF_INET6;
370 gate.sin6_addr = in6addr_loopback;
371 bzero(&mask, sizeof(mask));
372 mask.sin6_len = sizeof(struct sockaddr_in6);
373 mask.sin6_family = AF_INET6;
374 mask.sin6_addr = in6mask64;
375 rtrequest(RTM_ADD,
376 (struct sockaddr *)&ia->ia_addr,
377 (struct sockaddr *)&gate,
378 (struct sockaddr *)&mask,
379 RTF_UP|RTF_HOST,
380 (struct rtentry **)0);
381 }
382
383 /*
384 * loopback address
385 */
386 ib = (struct in6_ifaddr *)NULL;
387 if (type == IN6_IFT_LOOP) {
388 ib = (struct in6_ifaddr *)
389 malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
390 bzero((caddr_t)ib, sizeof(*ib));
391 ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
392 ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
393 ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
394 ib->ia_ifp = ifp;
395
396 ia->ia_next = ib;
397 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
398 ifa_list);
399
400 ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
401 ib->ia_prefixmask.sin6_family = AF_INET6;
402 ib->ia_prefixmask.sin6_addr = in6mask128;
403 ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
404 ib->ia_addr.sin6_family = AF_INET6;
405 ib->ia_addr.sin6_addr = in6addr_loopback;
406 #ifdef __bsdi__
407 /*
408 * It is necessary to set the loopback address to the dstaddr
409 * field at least for BSDI. Without this setting, the BSDI
410 * version of ifa_ifwithroute() rejects to add a route
411 * to the loopback interface.
412 */
413 ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
414 ib->ia_dstaddr.sin6_family = AF_INET6;
415 ib->ia_dstaddr.sin6_addr = in6addr_loopback;
416 #endif /* __bsdi__ */
417
418 ib->ia_ifa.ifa_metric = ifp->if_metric;
419
420 rtrequest(RTM_ADD,
421 (struct sockaddr *)&ib->ia_addr,
422 (struct sockaddr *)&ib->ia_addr,
423 (struct sockaddr *)&ib->ia_prefixmask,
424 RTF_UP|RTF_HOST,
425 (struct rtentry **)0);
426
427 ib->ia_flags |= IFA_ROUTE;
428 }
429
430 /*
431 * join multicast
432 */
433 if (ifp->if_flags & IFF_MULTICAST) {
434 int error; /* not used */
435
436 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
437 /* Restore saved multicast addresses(if any). */
438 in6_restoremkludge(ia, ifp);
439 #endif
440
441 bzero(&mltmask, sizeof(mltmask));
442 mltmask.sin6_len = sizeof(struct sockaddr_in6);
443 mltmask.sin6_family = AF_INET6;
444 mltmask.sin6_addr = in6mask32;
445
446 /*
447 * join link-local all-nodes address
448 */
449 bzero(&mltaddr, sizeof(mltaddr));
450 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
451 mltaddr.sin6_family = AF_INET6;
452 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
453 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
454 rtrequest(RTM_ADD,
455 (struct sockaddr *)&mltaddr,
456 (struct sockaddr *)&ia->ia_addr,
457 (struct sockaddr *)&mltmask,
458 RTF_UP|RTF_CLONING, /* xxx */
459 (struct rtentry **)0);
460 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
461
462 if (type == IN6_IFT_LOOP) {
463 /*
464 * join node-local all-nodes address
465 */
466 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
467 rtrequest(RTM_ADD,
468 (struct sockaddr *)&mltaddr,
469 (struct sockaddr *)&ib->ia_addr,
470 (struct sockaddr *)&mltmask,
471 RTF_UP,
472 (struct rtentry **)0);
473 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
474 } else {
475 /*
476 * join solicited multicast address
477 */
478 bzero(&llsol, sizeof(llsol));
479 llsol.s6_addr16[0] = htons(0xff02);
480 llsol.s6_addr16[1] = htons(ifp->if_index);
481 llsol.s6_addr32[1] = 0;
482 llsol.s6_addr32[2] = htonl(1);
483 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
484 llsol.s6_addr8[12] = 0xff;
485 (void)in6_addmulti(&llsol, ifp, &error);
486 }
487 }
488
489 /* update dynamically. */
490 in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr;
491 if (in6_maxmtu < ifp->if_mtu)
492 in6_maxmtu = ifp->if_mtu;
493
494 /* initialize NDP variables */
495 nd6_ifattach(ifp);
496
497 /* mark the address TENTATIVE, if needed. */
498 switch (ifp->if_type) {
499 case IFT_ETHER:
500 case IFT_FDDI:
501 #if 0
502 case IFT_ATM:
503 case IFT_SLIP:
504 case IFT_PPP:
505 #endif
506 ia->ia6_flags |= IN6_IFF_TENTATIVE;
507 /* nd6_dad_start() will be called in in6_if_up */
508 break;
509 case IFT_GIF:
510 case IFT_LOOP:
511 case IFT_FAITH:
512 default:
513 break;
514 }
515
516 return;
517 }
518
519 void
520 in6_ifdetach(ifp)
521 struct ifnet *ifp;
522 {
523 struct in6_ifaddr *ia, *oia;
524 struct ifaddr *ifa;
525 struct rtentry *rt;
526 short rtflags;
527
528 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
529 if (ifa->ifa_addr->sa_family != AF_INET6
530 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
531 continue;
532 }
533
534 ia = (struct in6_ifaddr *)ifa;
535
536 /* remove from the routing table */
537 if ((ia->ia_flags & IFA_ROUTE)
538 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
539 rtflags = rt->rt_flags;
540 rtfree(rt);
541 rtrequest(RTM_DELETE,
542 (struct sockaddr *)&ia->ia_addr,
543 (struct sockaddr *)&ia->ia_addr,
544 (struct sockaddr *)&ia->ia_prefixmask,
545 rtflags, (struct rtentry **)0);
546 }
547
548 /* remove from the linked list */
549 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
550
551 /* also remove from the IPv6 address chain(itojun&jinmei) */
552 oia = ia;
553 if (oia == (ia = in6_ifaddr))
554 in6_ifaddr = ia->ia_next;
555 else {
556 while (ia->ia_next && (ia->ia_next != oia))
557 ia = ia->ia_next;
558 if (ia->ia_next)
559 ia->ia_next = oia->ia_next;
560 else
561 printf("Didn't unlink in6ifaddr from list\n");
562 }
563
564 free(ia, M_IFADDR);
565 }
566 }
567