in6_ifattach.c revision 1.1.2.1 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_DUMMY:
171 case IFT_GIF:
172 case IFT_FAITH:
173 /* pseudo interfaces - safe to initialize here */
174 in6_ifattach(ifp, IN6_IFT_P2P, 0, 0);
175 break;
176 case IFT_SLIP:
177 /* IPv6 is not supported */
178 break;
179 case IFT_PPP:
180 /* this is not a pseudo interface, skip it */
181 break;
182 default:
183 break;
184 }
185 }
186 }
187
188 void
189 in6_ifattach(ifp, type, laddr, noloop)
190 struct ifnet *ifp;
191 u_int type;
192 caddr_t laddr;
193 int noloop;
194 /* xxx sizeof(laddr) */
195 {
196 static size_t if_indexlim = 8;
197 struct sockaddr_in6 mltaddr;
198 struct sockaddr_in6 mltmask;
199 struct sockaddr_in6 gate;
200 struct sockaddr_in6 mask;
201
202 struct in6_ifaddr *ia, *ib, *oia;
203 struct ifaddr *ifa;
204 int rtflag = 0;
205
206 if (type == IN6_IFT_P2P && found_first_ifid == 0) {
207 printf("%s: no ifid available yet for IPv6 link-local address\n",
208 ifp->if_xname);
209 return;
210 }
211
212 if ((ifp->if_flags & IFF_MULTICAST) == 0) {
213 printf("%s: no multicast allowed, IPv6 is not enabled\n",
214 ifp->if_xname);
215 return;
216 }
217
218 /*
219 * We have some arrays that should be indexed by if_index.
220 * since if_index will grow dynamically, they should grow too.
221 * struct in6_addr **in6_iflladdr
222 */
223 if (in6_iflladdr == NULL || if_index >= if_indexlim) {
224 size_t n;
225 caddr_t q;
226
227 while(if_index >= if_indexlim)
228 if_indexlim <<= 1;
229
230 /* grow in6_iflladdr */
231 n = if_indexlim * sizeof(struct in6_addr *);
232 q = (caddr_t)malloc(n, M_IFADDR, M_WAITOK);
233 bzero(q, n);
234 if (in6_iflladdr) {
235 bcopy((caddr_t)in6_iflladdr, q, n/2);
236 free((caddr_t)in6_iflladdr, M_IFADDR);
237 }
238 in6_iflladdr = (struct in6_addr **)q;
239 }
240
241 /*
242 * To prevent to assign link-local address to PnP network
243 * cards multiple times.
244 * This is lengthy for P2P and LOOP but works.
245 */
246 ifa = TAILQ_FIRST(&ifp->if_addrlist);
247 if (ifa != NULL) {
248 for ( ; ifa; ifa = TAILQ_NEXT(ifa, ifa_list)) {
249 if (ifa->ifa_addr->sa_family != AF_INET6)
250 continue;
251 if (IN6_IS_ADDR_LINKLOCAL(&satosin6(ifa->ifa_addr)->sin6_addr))
252 return;
253 }
254 } else
255 TAILQ_INIT(&ifp->if_addrlist);
256
257 /*
258 * link-local address
259 */
260 ia = (struct in6_ifaddr *)malloc(sizeof(*ia), M_IFADDR, M_WAITOK);
261 bzero((caddr_t)ia, sizeof(*ia));
262 ia->ia_ifa.ifa_addr = (struct sockaddr *)&ia->ia_addr;
263 ia->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ia->ia_dstaddr;
264 ia->ia_ifa.ifa_netmask = (struct sockaddr *)&ia->ia_prefixmask;
265 ia->ia_ifp = ifp;
266 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
267 /*
268 * Also link into the IPv6 address chain beginning with in6_ifaddr.
269 * kazu opposed it, but itojun & jinmei wanted.
270 */
271 if ((oia = in6_ifaddr) != NULL) {
272 for (; oia->ia_next; oia = oia->ia_next)
273 continue;
274 oia->ia_next = ia;
275 } else
276 in6_ifaddr = ia;
277
278 ia->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
279 ia->ia_prefixmask.sin6_family = AF_INET6;
280 ia->ia_prefixmask.sin6_addr = in6mask64;
281
282 bzero(&ia->ia_addr, sizeof(struct sockaddr_in6));
283 ia->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
284 ia->ia_addr.sin6_family = AF_INET6;
285 ia->ia_addr.sin6_addr.s6_addr16[0] = htons(0xfe80);
286 ia->ia_addr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
287 ia->ia_addr.sin6_addr.s6_addr32[1] = 0;
288
289 switch (type) {
290 case IN6_IFT_LOOP:
291 ia->ia_addr.sin6_addr.s6_addr32[2] = 0;
292 ia->ia_addr.sin6_addr.s6_addr32[3] = htonl(1);
293 break;
294 case IN6_IFT_802:
295 ia->ia_ifa.ifa_rtrequest = nd6_rtrequest;
296 ia->ia_ifa.ifa_flags |= RTF_CLONING;
297 rtflag = RTF_CLONING;
298 /* fall through */
299 case IN6_IFT_P2P802:
300 if (laddr == NULL)
301 break;
302 ieee802_to_eui64(&ia->ia_addr.sin6_addr.s6_addr8[8], laddr);
303 /* set global bit */
304 ia->ia_addr.sin6_addr.s6_addr8[8] |= 0x02;
305 if (! found_first_ifid) {
306 if (in6_ifattach_getifid(ifp) == 0)
307 in6_ifattach_p2p();
308 }
309 break;
310 case IN6_IFT_P2P:
311 bcopy((caddr_t)first_ifid,
312 (caddr_t)&ia->ia_addr.sin6_addr.s6_addr8[8],
313 IFID_LEN);
314 break;
315 }
316
317 ia->ia_ifa.ifa_metric = ifp->if_metric;
318
319 if (ifp->if_ioctl != NULL) {
320 int s;
321 int error;
322
323 /*
324 * give the interface a chance to initialize, in case this
325 * is the first address to be added.
326 */
327 s = splimp();
328 error = (*ifp->if_ioctl)(ifp, SIOCSIFADDR, (caddr_t)ia);
329 splx(s);
330
331 if (error) {
332 switch (error) {
333 case EAFNOSUPPORT:
334 printf("%s: IPv6 is not supported\n",
335 ifp->if_xname);
336 break;
337 default:
338 printf("SIOCSIFADDR(%s) returned %d\n",
339 ifp->if_xname, error);
340 break;
341 }
342
343 /* undo changes */
344 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
345 if (oia)
346 oia->ia_next = ia->ia_next;
347 else
348 in6_ifaddr = ia->ia_next;
349 free(ia, M_IFADDR);
350 return;
351 }
352 }
353
354 /* add route to the interface. */
355 rtrequest(RTM_ADD,
356 (struct sockaddr *)&ia->ia_addr,
357 (struct sockaddr *)&ia->ia_addr,
358 (struct sockaddr *)&ia->ia_prefixmask,
359 RTF_UP|rtflag,
360 (struct rtentry **)0);
361 ia->ia_flags |= IFA_ROUTE;
362
363
364 if (type == IN6_IFT_P2P || type == IN6_IFT_P2P802) {
365 /*
366 * route local address to loopback
367 */
368 bzero(&gate, sizeof(gate));
369 gate.sin6_len = sizeof(struct sockaddr_in6);
370 gate.sin6_family = AF_INET6;
371 gate.sin6_addr = in6addr_loopback;
372 bzero(&mask, sizeof(mask));
373 mask.sin6_len = sizeof(struct sockaddr_in6);
374 mask.sin6_family = AF_INET6;
375 mask.sin6_addr = in6mask64;
376 rtrequest(RTM_ADD,
377 (struct sockaddr *)&ia->ia_addr,
378 (struct sockaddr *)&gate,
379 (struct sockaddr *)&mask,
380 RTF_UP|RTF_HOST,
381 (struct rtentry **)0);
382 }
383
384 /*
385 * loopback address
386 */
387 ib = (struct in6_ifaddr *)NULL;
388 if (type == IN6_IFT_LOOP) {
389 ib = (struct in6_ifaddr *)
390 malloc(sizeof(*ib), M_IFADDR, M_WAITOK);
391 bzero((caddr_t)ib, sizeof(*ib));
392 ib->ia_ifa.ifa_addr = (struct sockaddr *)&ib->ia_addr;
393 ib->ia_ifa.ifa_dstaddr = (struct sockaddr *)&ib->ia_dstaddr;
394 ib->ia_ifa.ifa_netmask = (struct sockaddr *)&ib->ia_prefixmask;
395 ib->ia_ifp = ifp;
396
397 ia->ia_next = ib;
398 TAILQ_INSERT_TAIL(&ifp->if_addrlist, (struct ifaddr *)ib,
399 ifa_list);
400
401 ib->ia_prefixmask.sin6_len = sizeof(struct sockaddr_in6);
402 ib->ia_prefixmask.sin6_family = AF_INET6;
403 ib->ia_prefixmask.sin6_addr = in6mask128;
404 ib->ia_addr.sin6_len = sizeof(struct sockaddr_in6);
405 ib->ia_addr.sin6_family = AF_INET6;
406 ib->ia_addr.sin6_addr = in6addr_loopback;
407 #ifdef __bsdi__
408 /*
409 * It is necessary to set the loopback address to the dstaddr
410 * field at least for BSDI. Without this setting, the BSDI
411 * version of ifa_ifwithroute() rejects to add a route
412 * to the loopback interface.
413 */
414 ib->ia_dstaddr.sin6_len = sizeof(struct sockaddr_in6);
415 ib->ia_dstaddr.sin6_family = AF_INET6;
416 ib->ia_dstaddr.sin6_addr = in6addr_loopback;
417 #endif /* __bsdi__ */
418
419 ib->ia_ifa.ifa_metric = ifp->if_metric;
420
421 rtrequest(RTM_ADD,
422 (struct sockaddr *)&ib->ia_addr,
423 (struct sockaddr *)&ib->ia_addr,
424 (struct sockaddr *)&ib->ia_prefixmask,
425 RTF_UP|RTF_HOST,
426 (struct rtentry **)0);
427
428 ib->ia_flags |= IFA_ROUTE;
429 }
430
431 /*
432 * join multicast
433 */
434 if (ifp->if_flags & IFF_MULTICAST) {
435 int error; /* not used */
436
437 #if !defined(__FreeBSD__) || __FreeBSD__ < 3
438 /* Restore saved multicast addresses(if any). */
439 in6_restoremkludge(ia, ifp);
440 #endif
441
442 bzero(&mltmask, sizeof(mltmask));
443 mltmask.sin6_len = sizeof(struct sockaddr_in6);
444 mltmask.sin6_family = AF_INET6;
445 mltmask.sin6_addr = in6mask32;
446
447 /*
448 * join link-local all-nodes address
449 */
450 bzero(&mltaddr, sizeof(mltaddr));
451 mltaddr.sin6_len = sizeof(struct sockaddr_in6);
452 mltaddr.sin6_family = AF_INET6;
453 mltaddr.sin6_addr = in6addr_linklocal_allnodes;
454 mltaddr.sin6_addr.s6_addr16[1] = htons(ifp->if_index);
455 rtrequest(RTM_ADD,
456 (struct sockaddr *)&mltaddr,
457 (struct sockaddr *)&ia->ia_addr,
458 (struct sockaddr *)&mltmask,
459 RTF_UP|RTF_CLONING, /* xxx */
460 (struct rtentry **)0);
461 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
462
463 if (type == IN6_IFT_LOOP) {
464 /*
465 * join node-local all-nodes address
466 */
467 mltaddr.sin6_addr = in6addr_nodelocal_allnodes;
468 rtrequest(RTM_ADD,
469 (struct sockaddr *)&mltaddr,
470 (struct sockaddr *)&ib->ia_addr,
471 (struct sockaddr *)&mltmask,
472 RTF_UP,
473 (struct rtentry **)0);
474 (void)in6_addmulti(&mltaddr.sin6_addr, ifp, &error);
475 } else {
476 /*
477 * join solicited multicast address
478 */
479 bzero(&llsol, sizeof(llsol));
480 llsol.s6_addr16[0] = htons(0xff02);
481 llsol.s6_addr16[1] = htons(ifp->if_index);
482 llsol.s6_addr32[1] = 0;
483 llsol.s6_addr32[2] = htonl(1);
484 llsol.s6_addr32[3] = ia->ia_addr.sin6_addr.s6_addr32[3];
485 llsol.s6_addr8[12] = 0xff;
486 (void)in6_addmulti(&llsol, ifp, &error);
487 }
488 }
489
490 /* update dynamically. */
491 in6_iflladdr[ifp->if_index] = &ia->ia_addr.sin6_addr;
492 if (in6_maxmtu < ifp->if_mtu)
493 in6_maxmtu = ifp->if_mtu;
494
495 /* initialize NDP variables */
496 nd6_ifattach(ifp);
497
498 /* mark the address TENTATIVE, if needed. */
499 switch (ifp->if_type) {
500 case IFT_ETHER:
501 case IFT_FDDI:
502 #if 0
503 case IFT_ATM:
504 case IFT_SLIP:
505 case IFT_PPP:
506 #endif
507 ia->ia6_flags |= IN6_IFF_TENTATIVE;
508 /* nd6_dad_start() will be called in in6_if_up */
509 break;
510 case IFT_DUMMY:
511 case IFT_GIF:
512 case IFT_LOOP:
513 case IFT_FAITH:
514 default:
515 break;
516 }
517
518 return;
519 }
520
521 void
522 in6_ifdetach(ifp)
523 struct ifnet *ifp;
524 {
525 struct in6_ifaddr *ia, *oia;
526 struct ifaddr *ifa;
527 struct rtentry *rt;
528 short rtflags;
529
530 for (ifa = ifp->if_addrlist.tqh_first; ifa; ifa = ifa->ifa_list.tqe_next) {
531 if (ifa->ifa_addr->sa_family != AF_INET6
532 || !IN6_IS_ADDR_LINKLOCAL(&satosin6(&ifa->ifa_addr)->sin6_addr)) {
533 continue;
534 }
535
536 ia = (struct in6_ifaddr *)ifa;
537
538 /* remove from the routing table */
539 if ((ia->ia_flags & IFA_ROUTE)
540 && (rt = rtalloc1((struct sockaddr *)&ia->ia_addr, 0))) {
541 rtflags = rt->rt_flags;
542 rtfree(rt);
543 rtrequest(RTM_DELETE,
544 (struct sockaddr *)&ia->ia_addr,
545 (struct sockaddr *)&ia->ia_addr,
546 (struct sockaddr *)&ia->ia_prefixmask,
547 rtflags, (struct rtentry **)0);
548 }
549
550 /* remove from the linked list */
551 TAILQ_REMOVE(&ifp->if_addrlist, (struct ifaddr *)ia, ifa_list);
552
553 /* also remove from the IPv6 address chain(itojun&jinmei) */
554 oia = ia;
555 if (oia == (ia = in6_ifaddr))
556 in6_ifaddr = ia->ia_next;
557 else {
558 while (ia->ia_next && (ia->ia_next != oia))
559 ia = ia->ia_next;
560 if (ia->ia_next)
561 ia->ia_next = oia->ia_next;
562 else
563 printf("Didn't unlink in6ifaddr from list\n");
564 }
565
566 free(ia, M_IFADDR);
567 }
568 }
569