1 | /* |
---|
2 | * Copyright (c) 1983, 1993 |
---|
3 | * The Regents of the University of California. 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 | * 4. Neither the name of the University 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 REGENTS 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 REGENTS 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 | #ifndef lint |
---|
31 | static const char rcsid[] = |
---|
32 | "$FreeBSD$"; |
---|
33 | #endif /* not lint */ |
---|
34 | |
---|
35 | #include <rtems/bsd/sys/param.h> |
---|
36 | #include <sys/ioctl.h> |
---|
37 | #include <sys/socket.h> |
---|
38 | #include <net/if.h> |
---|
39 | |
---|
40 | #include <err.h> |
---|
41 | #include <stdio.h> |
---|
42 | #include <stdlib.h> |
---|
43 | #include <string.h> |
---|
44 | #include <unistd.h> |
---|
45 | #include <ifaddrs.h> |
---|
46 | |
---|
47 | #include <arpa/inet.h> |
---|
48 | |
---|
49 | #include <netinet/in.h> |
---|
50 | #include <net/if_var.h> /* for struct ifaddr */ |
---|
51 | #include <netinet/in_var.h> |
---|
52 | #include <arpa/inet.h> |
---|
53 | #include <netdb.h> |
---|
54 | |
---|
55 | #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */ |
---|
56 | |
---|
57 | #include "ifconfig.h" |
---|
58 | |
---|
59 | static struct in6_ifreq in6_ridreq; |
---|
60 | static struct in6_aliasreq in6_addreq = |
---|
61 | { .ifra_flags = 0, |
---|
62 | .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } }; |
---|
63 | static int ip6lifetime; |
---|
64 | |
---|
65 | static void in6_fillscopeid(struct sockaddr_in6 *sin6); |
---|
66 | static int prefix(void *, int); |
---|
67 | static char *sec2str(time_t); |
---|
68 | static int explicit_prefix = 0; |
---|
69 | |
---|
70 | extern void setnd6flags(const char *, int, int, const struct afswtch *); |
---|
71 | extern void setnd6defif(const char *, int, int, const struct afswtch *); |
---|
72 | |
---|
73 | static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/ |
---|
74 | |
---|
75 | static void |
---|
76 | setifprefixlen(const char *addr, int dummy __unused, int s, |
---|
77 | const struct afswtch *afp) |
---|
78 | { |
---|
79 | if (afp->af_getprefix != NULL) |
---|
80 | afp->af_getprefix(addr, MASK); |
---|
81 | explicit_prefix = 1; |
---|
82 | } |
---|
83 | |
---|
84 | static void |
---|
85 | setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused, |
---|
86 | const struct afswtch *afp) |
---|
87 | { |
---|
88 | if (afp->af_af != AF_INET6) |
---|
89 | err(1, "address flags can be set only for inet6 addresses"); |
---|
90 | |
---|
91 | if (flag < 0) |
---|
92 | in6_addreq.ifra_flags &= ~(-flag); |
---|
93 | else |
---|
94 | in6_addreq.ifra_flags |= flag; |
---|
95 | } |
---|
96 | |
---|
97 | static void |
---|
98 | setip6lifetime(const char *cmd, const char *val, int s, |
---|
99 | const struct afswtch *afp) |
---|
100 | { |
---|
101 | time_t newval, t; |
---|
102 | char *ep; |
---|
103 | |
---|
104 | t = time(NULL); |
---|
105 | newval = (time_t)strtoul(val, &ep, 0); |
---|
106 | if (val == ep) |
---|
107 | errx(1, "invalid %s", cmd); |
---|
108 | if (afp->af_af != AF_INET6) |
---|
109 | errx(1, "%s not allowed for the AF", cmd); |
---|
110 | if (strcmp(cmd, "vltime") == 0) { |
---|
111 | in6_addreq.ifra_lifetime.ia6t_expire = t + newval; |
---|
112 | in6_addreq.ifra_lifetime.ia6t_vltime = newval; |
---|
113 | } else if (strcmp(cmd, "pltime") == 0) { |
---|
114 | in6_addreq.ifra_lifetime.ia6t_preferred = t + newval; |
---|
115 | in6_addreq.ifra_lifetime.ia6t_pltime = newval; |
---|
116 | } |
---|
117 | } |
---|
118 | |
---|
119 | static void |
---|
120 | setip6pltime(const char *seconds, int dummy __unused, int s, |
---|
121 | const struct afswtch *afp) |
---|
122 | { |
---|
123 | setip6lifetime("pltime", seconds, s, afp); |
---|
124 | } |
---|
125 | |
---|
126 | static void |
---|
127 | setip6vltime(const char *seconds, int dummy __unused, int s, |
---|
128 | const struct afswtch *afp) |
---|
129 | { |
---|
130 | setip6lifetime("vltime", seconds, s, afp); |
---|
131 | } |
---|
132 | |
---|
133 | static void |
---|
134 | setip6eui64(const char *cmd, int dummy __unused, int s, |
---|
135 | const struct afswtch *afp) |
---|
136 | { |
---|
137 | struct ifaddrs *ifap, *ifa; |
---|
138 | const struct sockaddr_in6 *sin6 = NULL; |
---|
139 | const struct in6_addr *lladdr = NULL; |
---|
140 | struct in6_addr *in6; |
---|
141 | |
---|
142 | if (afp->af_af != AF_INET6) |
---|
143 | errx(EXIT_FAILURE, "%s not allowed for the AF", cmd); |
---|
144 | in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr; |
---|
145 | if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0) |
---|
146 | errx(EXIT_FAILURE, "interface index is already filled"); |
---|
147 | if (getifaddrs(&ifap) != 0) |
---|
148 | err(EXIT_FAILURE, "getifaddrs"); |
---|
149 | for (ifa = ifap; ifa; ifa = ifa->ifa_next) { |
---|
150 | if (ifa->ifa_addr->sa_family == AF_INET6 && |
---|
151 | strcmp(ifa->ifa_name, name) == 0) { |
---|
152 | sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr; |
---|
153 | if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { |
---|
154 | lladdr = &sin6->sin6_addr; |
---|
155 | break; |
---|
156 | } |
---|
157 | } |
---|
158 | } |
---|
159 | if (!lladdr) |
---|
160 | errx(EXIT_FAILURE, "could not determine link local address"); |
---|
161 | |
---|
162 | memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8); |
---|
163 | |
---|
164 | freeifaddrs(ifap); |
---|
165 | } |
---|
166 | |
---|
167 | static void |
---|
168 | in6_fillscopeid(struct sockaddr_in6 *sin6) |
---|
169 | { |
---|
170 | #if defined(__KAME__) && defined(KAME_SCOPEID) |
---|
171 | if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { |
---|
172 | sin6->sin6_scope_id = |
---|
173 | ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]); |
---|
174 | sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0; |
---|
175 | } |
---|
176 | #endif |
---|
177 | } |
---|
178 | |
---|
179 | static void |
---|
180 | in6_status(int s __unused, const struct ifaddrs *ifa) |
---|
181 | { |
---|
182 | struct sockaddr_in6 *sin, null_sin; |
---|
183 | struct in6_ifreq ifr6; |
---|
184 | int s6; |
---|
185 | u_int32_t flags6; |
---|
186 | struct in6_addrlifetime lifetime; |
---|
187 | time_t t = time(NULL); |
---|
188 | int error; |
---|
189 | u_int32_t scopeid; |
---|
190 | |
---|
191 | memset(&null_sin, 0, sizeof(null_sin)); |
---|
192 | |
---|
193 | sin = (struct sockaddr_in6 *)ifa->ifa_addr; |
---|
194 | if (sin == NULL) |
---|
195 | return; |
---|
196 | |
---|
197 | strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name)); |
---|
198 | if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) { |
---|
199 | warn("socket(AF_INET6,SOCK_DGRAM)"); |
---|
200 | return; |
---|
201 | } |
---|
202 | ifr6.ifr_addr = *sin; |
---|
203 | if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) { |
---|
204 | warn("ioctl(SIOCGIFAFLAG_IN6)"); |
---|
205 | close(s6); |
---|
206 | return; |
---|
207 | } |
---|
208 | flags6 = ifr6.ifr_ifru.ifru_flags6; |
---|
209 | memset(&lifetime, 0, sizeof(lifetime)); |
---|
210 | ifr6.ifr_addr = *sin; |
---|
211 | if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) { |
---|
212 | warn("ioctl(SIOCGIFALIFETIME_IN6)"); |
---|
213 | close(s6); |
---|
214 | return; |
---|
215 | } |
---|
216 | lifetime = ifr6.ifr_ifru.ifru_lifetime; |
---|
217 | close(s6); |
---|
218 | |
---|
219 | /* XXX: embedded link local addr check */ |
---|
220 | if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && |
---|
221 | *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { |
---|
222 | u_short index; |
---|
223 | |
---|
224 | index = *(u_short *)&sin->sin6_addr.s6_addr[2]; |
---|
225 | *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; |
---|
226 | if (sin->sin6_scope_id == 0) |
---|
227 | sin->sin6_scope_id = ntohs(index); |
---|
228 | } |
---|
229 | scopeid = sin->sin6_scope_id; |
---|
230 | |
---|
231 | error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf, |
---|
232 | sizeof(addr_buf), NULL, 0, NI_NUMERICHOST); |
---|
233 | if (error != 0) |
---|
234 | inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, |
---|
235 | sizeof(addr_buf)); |
---|
236 | printf("\tinet6 %s ", addr_buf); |
---|
237 | |
---|
238 | if (ifa->ifa_flags & IFF_POINTOPOINT) { |
---|
239 | sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr; |
---|
240 | /* |
---|
241 | * some of the interfaces do not have valid destination |
---|
242 | * address. |
---|
243 | */ |
---|
244 | if (sin != NULL && sin->sin6_family == AF_INET6) { |
---|
245 | int error; |
---|
246 | |
---|
247 | /* XXX: embedded link local addr check */ |
---|
248 | if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) && |
---|
249 | *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) { |
---|
250 | u_short index; |
---|
251 | |
---|
252 | index = *(u_short *)&sin->sin6_addr.s6_addr[2]; |
---|
253 | *(u_short *)&sin->sin6_addr.s6_addr[2] = 0; |
---|
254 | if (sin->sin6_scope_id == 0) |
---|
255 | sin->sin6_scope_id = ntohs(index); |
---|
256 | } |
---|
257 | |
---|
258 | error = getnameinfo((struct sockaddr *)sin, |
---|
259 | sin->sin6_len, addr_buf, |
---|
260 | sizeof(addr_buf), NULL, 0, |
---|
261 | NI_NUMERICHOST); |
---|
262 | if (error != 0) |
---|
263 | inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, |
---|
264 | sizeof(addr_buf)); |
---|
265 | printf("--> %s ", addr_buf); |
---|
266 | } |
---|
267 | } |
---|
268 | |
---|
269 | sin = (struct sockaddr_in6 *)ifa->ifa_netmask; |
---|
270 | if (sin == NULL) |
---|
271 | sin = &null_sin; |
---|
272 | printf("prefixlen %d ", prefix(&sin->sin6_addr, |
---|
273 | sizeof(struct in6_addr))); |
---|
274 | |
---|
275 | if ((flags6 & IN6_IFF_ANYCAST) != 0) |
---|
276 | printf("anycast "); |
---|
277 | if ((flags6 & IN6_IFF_TENTATIVE) != 0) |
---|
278 | printf("tentative "); |
---|
279 | if ((flags6 & IN6_IFF_DUPLICATED) != 0) |
---|
280 | printf("duplicated "); |
---|
281 | if ((flags6 & IN6_IFF_DETACHED) != 0) |
---|
282 | printf("detached "); |
---|
283 | if ((flags6 & IN6_IFF_DEPRECATED) != 0) |
---|
284 | printf("deprecated "); |
---|
285 | if ((flags6 & IN6_IFF_AUTOCONF) != 0) |
---|
286 | printf("autoconf "); |
---|
287 | if ((flags6 & IN6_IFF_TEMPORARY) != 0) |
---|
288 | printf("temporary "); |
---|
289 | |
---|
290 | if (scopeid) |
---|
291 | printf("scopeid 0x%x ", scopeid); |
---|
292 | |
---|
293 | if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) { |
---|
294 | printf("pltime "); |
---|
295 | if (lifetime.ia6t_preferred) { |
---|
296 | printf("%s ", lifetime.ia6t_preferred < t |
---|
297 | ? "0" : sec2str(lifetime.ia6t_preferred - t)); |
---|
298 | } else |
---|
299 | printf("infty "); |
---|
300 | |
---|
301 | printf("vltime "); |
---|
302 | if (lifetime.ia6t_expire) { |
---|
303 | printf("%s ", lifetime.ia6t_expire < t |
---|
304 | ? "0" : sec2str(lifetime.ia6t_expire - t)); |
---|
305 | } else |
---|
306 | printf("infty "); |
---|
307 | } |
---|
308 | |
---|
309 | putchar('\n'); |
---|
310 | } |
---|
311 | |
---|
312 | #define SIN6(x) ((struct sockaddr_in6 *) &(x)) |
---|
313 | static struct sockaddr_in6 *sin6tab[] = { |
---|
314 | SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr), |
---|
315 | SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr) |
---|
316 | }; |
---|
317 | |
---|
318 | static void |
---|
319 | in6_getprefix(const char *plen, int which) |
---|
320 | { |
---|
321 | struct sockaddr_in6 *sin = sin6tab[which]; |
---|
322 | u_char *cp; |
---|
323 | int len = atoi(plen); |
---|
324 | |
---|
325 | if ((len < 0) || (len > 128)) |
---|
326 | errx(1, "%s: bad value", plen); |
---|
327 | sin->sin6_len = sizeof(*sin); |
---|
328 | if (which != MASK) |
---|
329 | sin->sin6_family = AF_INET6; |
---|
330 | if ((len == 0) || (len == 128)) { |
---|
331 | memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr)); |
---|
332 | return; |
---|
333 | } |
---|
334 | memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr)); |
---|
335 | for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8) |
---|
336 | *cp++ = 0xff; |
---|
337 | *cp = 0xff << (8 - len); |
---|
338 | } |
---|
339 | |
---|
340 | static void |
---|
341 | in6_getaddr(const char *s, int which) |
---|
342 | { |
---|
343 | struct sockaddr_in6 *sin = sin6tab[which]; |
---|
344 | struct addrinfo hints, *res; |
---|
345 | int error = -1; |
---|
346 | |
---|
347 | newaddr &= 1; |
---|
348 | |
---|
349 | sin->sin6_len = sizeof(*sin); |
---|
350 | if (which != MASK) |
---|
351 | sin->sin6_family = AF_INET6; |
---|
352 | |
---|
353 | if (which == ADDR) { |
---|
354 | char *p = NULL; |
---|
355 | if((p = strrchr(s, '/')) != NULL) { |
---|
356 | *p = '\0'; |
---|
357 | in6_getprefix(p + 1, MASK); |
---|
358 | explicit_prefix = 1; |
---|
359 | } |
---|
360 | } |
---|
361 | |
---|
362 | if (sin->sin6_family == AF_INET6) { |
---|
363 | bzero(&hints, sizeof(struct addrinfo)); |
---|
364 | hints.ai_family = AF_INET6; |
---|
365 | error = getaddrinfo(s, NULL, &hints, &res); |
---|
366 | } |
---|
367 | if (error != 0) { |
---|
368 | if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1) |
---|
369 | errx(1, "%s: bad value", s); |
---|
370 | } else |
---|
371 | bcopy(res->ai_addr, sin, res->ai_addrlen); |
---|
372 | } |
---|
373 | |
---|
374 | static int |
---|
375 | prefix(void *val, int size) |
---|
376 | { |
---|
377 | u_char *name = (u_char *)val; |
---|
378 | int byte, bit, plen = 0; |
---|
379 | |
---|
380 | for (byte = 0; byte < size; byte++, plen += 8) |
---|
381 | if (name[byte] != 0xff) |
---|
382 | break; |
---|
383 | if (byte == size) |
---|
384 | return (plen); |
---|
385 | for (bit = 7; bit != 0; bit--, plen++) |
---|
386 | if (!(name[byte] & (1 << bit))) |
---|
387 | break; |
---|
388 | for (; bit != 0; bit--) |
---|
389 | if (name[byte] & (1 << bit)) |
---|
390 | return(0); |
---|
391 | byte++; |
---|
392 | for (; byte < size; byte++) |
---|
393 | if (name[byte]) |
---|
394 | return(0); |
---|
395 | return (plen); |
---|
396 | } |
---|
397 | |
---|
398 | static char * |
---|
399 | sec2str(time_t total) |
---|
400 | { |
---|
401 | static char result[256]; |
---|
402 | int days, hours, mins, secs; |
---|
403 | int first = 1; |
---|
404 | char *p = result; |
---|
405 | |
---|
406 | if (0) { |
---|
407 | days = total / 3600 / 24; |
---|
408 | hours = (total / 3600) % 24; |
---|
409 | mins = (total / 60) % 60; |
---|
410 | secs = total % 60; |
---|
411 | |
---|
412 | if (days) { |
---|
413 | first = 0; |
---|
414 | p += sprintf(p, "%dd", days); |
---|
415 | } |
---|
416 | if (!first || hours) { |
---|
417 | first = 0; |
---|
418 | p += sprintf(p, "%dh", hours); |
---|
419 | } |
---|
420 | if (!first || mins) { |
---|
421 | first = 0; |
---|
422 | p += sprintf(p, "%dm", mins); |
---|
423 | } |
---|
424 | sprintf(p, "%ds", secs); |
---|
425 | } else |
---|
426 | sprintf(result, "%lu", (unsigned long)total); |
---|
427 | |
---|
428 | return(result); |
---|
429 | } |
---|
430 | |
---|
431 | static void |
---|
432 | in6_postproc(int s, const struct afswtch *afp) |
---|
433 | { |
---|
434 | if (explicit_prefix == 0) { |
---|
435 | /* Aggregatable address architecture defines all prefixes |
---|
436 | are 64. So, it is convenient to set prefixlen to 64 if |
---|
437 | it is not specified. */ |
---|
438 | setifprefixlen("64", 0, s, afp); |
---|
439 | /* in6_getprefix("64", MASK) if MASK is available here... */ |
---|
440 | } |
---|
441 | } |
---|
442 | |
---|
443 | static void |
---|
444 | in6_status_tunnel(int s) |
---|
445 | { |
---|
446 | char src[NI_MAXHOST]; |
---|
447 | char dst[NI_MAXHOST]; |
---|
448 | struct in6_ifreq in6_ifr; |
---|
449 | const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr; |
---|
450 | |
---|
451 | memset(&in6_ifr, 0, sizeof(in6_ifr)); |
---|
452 | strncpy(in6_ifr.ifr_name, name, IFNAMSIZ); |
---|
453 | |
---|
454 | if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0) |
---|
455 | return; |
---|
456 | if (sa->sa_family != AF_INET6) |
---|
457 | return; |
---|
458 | in6_fillscopeid(&in6_ifr.ifr_addr); |
---|
459 | if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0, |
---|
460 | NI_NUMERICHOST) != 0) |
---|
461 | src[0] = '\0'; |
---|
462 | |
---|
463 | if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0) |
---|
464 | return; |
---|
465 | if (sa->sa_family != AF_INET6) |
---|
466 | return; |
---|
467 | in6_fillscopeid(&in6_ifr.ifr_addr); |
---|
468 | if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0, |
---|
469 | NI_NUMERICHOST) != 0) |
---|
470 | dst[0] = '\0'; |
---|
471 | |
---|
472 | printf("\ttunnel inet6 %s --> %s\n", src, dst); |
---|
473 | } |
---|
474 | |
---|
475 | static void |
---|
476 | in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres) |
---|
477 | { |
---|
478 | struct in6_aliasreq in6_addreq; |
---|
479 | |
---|
480 | memset(&in6_addreq, 0, sizeof(in6_addreq)); |
---|
481 | strncpy(in6_addreq.ifra_name, name, IFNAMSIZ); |
---|
482 | memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len); |
---|
483 | memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr, |
---|
484 | dstres->ai_addr->sa_len); |
---|
485 | |
---|
486 | if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0) |
---|
487 | warn("SIOCSIFPHYADDR_IN6"); |
---|
488 | } |
---|
489 | |
---|
490 | static struct cmd inet6_cmds[] = { |
---|
491 | DEF_CMD_ARG("prefixlen", setifprefixlen), |
---|
492 | DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags), |
---|
493 | DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags), |
---|
494 | DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags), |
---|
495 | DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags), |
---|
496 | DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags), |
---|
497 | DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags), |
---|
498 | DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags), |
---|
499 | DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags), |
---|
500 | DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags), |
---|
501 | DEF_CMD("defaultif", 1, setnd6defif), |
---|
502 | DEF_CMD("-defaultif", -1, setnd6defif), |
---|
503 | DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags), |
---|
504 | DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags), |
---|
505 | DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags), |
---|
506 | DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags), |
---|
507 | DEF_CMD("prefer_source",ND6_IFF_PREFER_SOURCE, setnd6flags), |
---|
508 | DEF_CMD("-prefer_source",-ND6_IFF_PREFER_SOURCE,setnd6flags), |
---|
509 | DEF_CMD_ARG("pltime", setip6pltime), |
---|
510 | DEF_CMD_ARG("vltime", setip6vltime), |
---|
511 | DEF_CMD("eui64", 0, setip6eui64), |
---|
512 | }; |
---|
513 | |
---|
514 | static struct afswtch af_inet6 = { |
---|
515 | .af_name = "inet6", |
---|
516 | .af_af = AF_INET6, |
---|
517 | .af_status = in6_status, |
---|
518 | .af_getaddr = in6_getaddr, |
---|
519 | .af_getprefix = in6_getprefix, |
---|
520 | .af_postproc = in6_postproc, |
---|
521 | .af_status_tunnel = in6_status_tunnel, |
---|
522 | .af_settunnel = in6_set_tunnel, |
---|
523 | .af_difaddr = SIOCDIFADDR_IN6, |
---|
524 | .af_aifaddr = SIOCAIFADDR_IN6, |
---|
525 | .af_ridreq = &in6_addreq, |
---|
526 | .af_addreq = &in6_addreq, |
---|
527 | }; |
---|
528 | |
---|
529 | static void |
---|
530 | in6_Lopt_cb(const char *optarg __unused) |
---|
531 | { |
---|
532 | ip6lifetime++; /* print IPv6 address lifetime */ |
---|
533 | } |
---|
534 | #ifdef __rtems__ |
---|
535 | static struct ifconfig_option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb }; |
---|
536 | #else |
---|
537 | static struct option in6_Lopt = { .opt = "L", .opt_usage = "[-L]", .cb = in6_Lopt_cb }; |
---|
538 | #endif |
---|
539 | |
---|
540 | static __constructor void |
---|
541 | inet6_ctor(void) |
---|
542 | { |
---|
543 | #define N(a) (sizeof(a) / sizeof(a[0])) |
---|
544 | size_t i; |
---|
545 | |
---|
546 | for (i = 0; i < N(inet6_cmds); i++) |
---|
547 | cmd_register(&inet6_cmds[i]); |
---|
548 | af_register(&af_inet6); |
---|
549 | opt_register(&in6_Lopt); |
---|
550 | #undef N |
---|
551 | } |
---|