]> git.saurik.com Git - apple/network_cmds.git/blob - ifconfig.tproj/af_inet6.c
network_cmds-543.tar.gz
[apple/network_cmds.git] / ifconfig.tproj / af_inet6.c
1 /*
2 * Copyright (c) 2009-2014 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * Copyright (c) 1983, 1993
31 * The Regents of the University of California. All rights reserved.
32 *
33 * Redistribution and use in source and binary forms, with or without
34 * modification, are permitted provided that the following conditions
35 * are met:
36 * 1. Redistributions of source code must retain the above copyright
37 * notice, this list of conditions and the following disclaimer.
38 * 2. Redistributions in binary form must reproduce the above copyright
39 * notice, this list of conditions and the following disclaimer in the
40 * documentation and/or other materials provided with the distribution.
41 * 4. Neither the name of the University nor the names of its contributors
42 * may be used to endorse or promote products derived from this software
43 * without specific prior written permission.
44 *
45 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
46 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
47 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
48 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
49 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
50 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
51 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
52 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
53 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
54 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
55 * SUCH DAMAGE.
56 */
57
58
59 #include <sys/param.h>
60 #include <sys/ioctl.h>
61 #include <sys/socket.h>
62 #include <net/if.h>
63
64 #include <err.h>
65 #include <errno.h>
66 #include <stdio.h>
67 #include <stdlib.h>
68 #include <string.h>
69 #include <unistd.h>
70 #include <ifaddrs.h>
71
72 #include <arpa/inet.h>
73
74 #include <netinet/in.h>
75 #include <net/if_var.h> /* for struct ifaddr */
76 #include <netinet/in_var.h>
77 #include <arpa/inet.h>
78 #include <netdb.h>
79
80 #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
81
82 #include "ifconfig.h"
83
84 #define ND6BITS "\020\001PERFORMNUD\002ACCEPT_RTADV\003PREFER_SOURCE" \
85 "\004IFDISABLED\005DONT_SET_IFROUTE\006PROXY_PREFIXES" \
86 "\007IGNORE_NA\010INSECURE\011REPLICATED\012DAD"
87
88 static struct in6_ifreq in6_ridreq;
89 static struct in6_aliasreq in6_addreq =
90 { { 0 },
91 { 0 },
92 { 0 },
93 { 0 },
94 0,
95 { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
96 static int ip6lifetime;
97
98 static void in6_fillscopeid(struct sockaddr_in6 *sin6);
99 static int prefix(void *, int);
100 static char *sec2str(time_t);
101 static int explicit_prefix = 0;
102
103 static char addr_buf[MAXHOSTNAMELEN *2 + 1]; /*for getnameinfo()*/
104
105 static void
106 setifprefixlen(const char *addr, int dummy __unused, int s,
107 const struct afswtch *afp)
108 {
109 if (afp->af_getprefix != NULL)
110 afp->af_getprefix(addr, MASK);
111 explicit_prefix = 1;
112 }
113
114 static void
115 setnd6flags(const char *dummyaddr __unused, int d, int s,
116 const struct afswtch *afp)
117 {
118 struct in6_ndireq nd;
119 int error;
120
121 memset(&nd, 0, sizeof(nd));
122 strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
123 error = ioctl(s, SIOCGIFINFO_IN6, &nd);
124 if (error) {
125 warn("ioctl(SIOCGIFINFO_IN6)");
126 return;
127 }
128 if (d < 0)
129 nd.ndi.flags &= ~(-d);
130 else
131 nd.ndi.flags |= d;
132 error = ioctl(s, SIOCSIFINFO_FLAGS, (caddr_t)&nd);
133 if (error)
134 warn("ioctl(SIOCSIFINFO_FLAGS)");
135 }
136
137 static void
138 setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
139 const struct afswtch *afp)
140 {
141 if (afp->af_af != AF_INET6)
142 err(1, "address flags can be set only for inet6 addresses");
143
144 if (flag < 0)
145 in6_addreq.ifra_flags &= ~(-flag);
146 else
147 in6_addreq.ifra_flags |= flag;
148 }
149
150 static void
151 setip6lifetime(const char *cmd, const char *val, int s,
152 const struct afswtch *afp)
153 {
154 time_t newval, t;
155 char *ep;
156
157 t = time(NULL);
158 newval = (time_t)strtoul(val, &ep, 0);
159 if (val == ep)
160 errx(1, "invalid %s", cmd);
161 if (afp->af_af != AF_INET6)
162 errx(1, "%s not allowed for the AF", cmd);
163 if (strcmp(cmd, "vltime") == 0) {
164 in6_addreq.ifra_lifetime.ia6t_expire = t + newval;
165 in6_addreq.ifra_lifetime.ia6t_vltime = newval;
166 } else if (strcmp(cmd, "pltime") == 0) {
167 in6_addreq.ifra_lifetime.ia6t_preferred = t + newval;
168 in6_addreq.ifra_lifetime.ia6t_pltime = newval;
169 }
170 }
171
172 static void
173 setip6pltime(const char *seconds, int dummy __unused, int s,
174 const struct afswtch *afp)
175 {
176 setip6lifetime("pltime", seconds, s, afp);
177 }
178
179 static void
180 setip6vltime(const char *seconds, int dummy __unused, int s,
181 const struct afswtch *afp)
182 {
183 setip6lifetime("vltime", seconds, s, afp);
184 }
185
186 static void
187 setip6eui64(const char *cmd, int dummy __unused, int s,
188 const struct afswtch *afp)
189 {
190 struct ifaddrs *ifap, *ifa;
191 const struct sockaddr_in6 *sin6 = NULL;
192 const struct in6_addr *lladdr = NULL;
193 struct in6_addr *in6;
194
195 if (afp->af_af != AF_INET6)
196 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
197 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
198 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
199 errx(EXIT_FAILURE, "interface index is already filled");
200 if (getifaddrs(&ifap) != 0)
201 err(EXIT_FAILURE, "getifaddrs");
202 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
203 if (ifa->ifa_addr->sa_family == AF_INET6 &&
204 strcmp(ifa->ifa_name, name) == 0) {
205 sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
206 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
207 lladdr = &sin6->sin6_addr;
208 break;
209 }
210 }
211 }
212 if (!lladdr)
213 errx(EXIT_FAILURE, "could not determine link local address");
214
215 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
216
217 freeifaddrs(ifap);
218 }
219
220 static void
221 in6_fillscopeid(struct sockaddr_in6 *sin6)
222 {
223 #if defined(__KAME__) && defined(KAME_SCOPEID)
224 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
225 sin6->sin6_scope_id =
226 ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
227 sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
228 }
229 #endif
230 }
231
232 static void
233 in6_status(int s __unused, const struct ifaddrs *ifa)
234 {
235 struct sockaddr_in6 *sin, null_sin;
236 struct in6_ifreq ifr6;
237 int s6;
238 u_int32_t flags6;
239 struct in6_addrlifetime lifetime;
240 time_t t = time(NULL);
241 int error;
242 u_int32_t scopeid;
243
244 memset(&null_sin, 0, sizeof(null_sin));
245
246 sin = (struct sockaddr_in6 *)ifa->ifa_addr;
247 if (sin == NULL)
248 return;
249
250 strncpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
251 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
252 warn("socket(AF_INET6,SOCK_DGRAM)");
253 return;
254 }
255 ifr6.ifr_addr = *sin;
256 if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
257 warn("ioctl(SIOCGIFAFLAG_IN6)");
258 close(s6);
259 return;
260 }
261 flags6 = ifr6.ifr_ifru.ifru_flags6;
262 memset(&lifetime, 0, sizeof(lifetime));
263 ifr6.ifr_addr = *sin;
264 if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
265 warn("ioctl(SIOCGIFALIFETIME_IN6)");
266 close(s6);
267 return;
268 }
269 lifetime = ifr6.ifr_ifru.ifru_lifetime;
270 close(s6);
271
272 /* XXX: embedded link local addr check */
273 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
274 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
275 u_short index;
276
277 index = *(u_short *)&sin->sin6_addr.s6_addr[2];
278 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
279 if (sin->sin6_scope_id == 0)
280 sin->sin6_scope_id = ntohs(index);
281 }
282 scopeid = sin->sin6_scope_id;
283
284 error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
285 sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
286 if (error != 0)
287 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
288 sizeof(addr_buf));
289 printf("\tinet6 %s ", addr_buf);
290
291 if (ifa->ifa_flags & IFF_POINTOPOINT) {
292 sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
293 /*
294 * some of the interfaces do not have valid destination
295 * address.
296 */
297 if (sin != NULL && sin->sin6_family == AF_INET6) {
298 int error;
299
300 /* XXX: embedded link local addr check */
301 if (IN6_IS_ADDR_LINKLOCAL(&sin->sin6_addr) &&
302 *(u_short *)&sin->sin6_addr.s6_addr[2] != 0) {
303 u_short index;
304
305 index = *(u_short *)&sin->sin6_addr.s6_addr[2];
306 *(u_short *)&sin->sin6_addr.s6_addr[2] = 0;
307 if (sin->sin6_scope_id == 0)
308 sin->sin6_scope_id = ntohs(index);
309 }
310
311 error = getnameinfo((struct sockaddr *)sin,
312 sin->sin6_len, addr_buf,
313 sizeof(addr_buf), NULL, 0,
314 NI_NUMERICHOST);
315 if (error != 0)
316 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
317 sizeof(addr_buf));
318 printf("--> %s ", addr_buf);
319 }
320 }
321
322 sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
323 if (sin == NULL)
324 sin = &null_sin;
325 printf("prefixlen %d ", prefix(&sin->sin6_addr,
326 sizeof(struct in6_addr)));
327
328 if ((flags6 & IN6_IFF_ANYCAST) != 0)
329 printf("anycast ");
330 if ((flags6 & IN6_IFF_TENTATIVE) != 0)
331 printf("tentative ");
332 if ((flags6 & IN6_IFF_OPTIMISTIC) != 0)
333 printf("optimistic ");
334 if ((flags6 & IN6_IFF_DUPLICATED) != 0)
335 printf("duplicated ");
336 if ((flags6 & IN6_IFF_DETACHED) != 0)
337 printf("detached ");
338 if ((flags6 & IN6_IFF_DEPRECATED) != 0)
339 printf("deprecated ");
340 if ((flags6 & IN6_IFF_AUTOCONF) != 0)
341 printf("autoconf ");
342 if ((flags6 & IN6_IFF_TEMPORARY) != 0)
343 printf("temporary ");
344 if ((flags6 & IN6_IFF_DYNAMIC) != 0)
345 printf("dynamic ");
346 if ((flags6 & IN6_IFF_SECURED) != 0)
347 printf("secured ");
348
349 if (scopeid)
350 printf("scopeid 0x%x ", scopeid);
351
352 if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
353 printf("pltime ");
354 if (lifetime.ia6t_preferred) {
355 printf("%s ", lifetime.ia6t_preferred < t
356 ? "0" : sec2str(lifetime.ia6t_preferred - t));
357 } else
358 printf("infty ");
359
360 printf("vltime ");
361 if (lifetime.ia6t_expire) {
362 printf("%s ", lifetime.ia6t_expire < t
363 ? "0" : sec2str(lifetime.ia6t_expire - t));
364 } else
365 printf("infty ");
366 }
367
368 putchar('\n');
369 }
370
371 #define SIN6(x) ((struct sockaddr_in6 *) &(x))
372 static struct sockaddr_in6 *sin6tab[] = {
373 SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
374 SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)
375 };
376
377 static void
378 in6_getprefix(const char *plen, int which)
379 {
380 struct sockaddr_in6 *sin = sin6tab[which];
381 u_char *cp;
382 int len = atoi(plen);
383
384 if ((len < 0) || (len > 128))
385 errx(1, "%s: bad value", plen);
386 sin->sin6_len = sizeof(*sin);
387 if (which != MASK)
388 sin->sin6_family = AF_INET6;
389 if ((len == 0) || (len == 128)) {
390 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
391 return;
392 }
393 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
394 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
395 *cp++ = 0xff;
396 *cp = 0xff << (8 - len);
397 }
398
399 static void
400 in6_getaddr(const char *s, int which)
401 {
402 struct sockaddr_in6 *sin = sin6tab[which];
403 struct addrinfo hints, *res;
404 int error = -1;
405
406 newaddr &= 1;
407
408 sin->sin6_len = sizeof(*sin);
409 if (which != MASK)
410 sin->sin6_family = AF_INET6;
411
412 if (which == ADDR) {
413 char *p = NULL;
414 if((p = strrchr(s, '/')) != NULL) {
415 *p = '\0';
416 in6_getprefix(p + 1, MASK);
417 explicit_prefix = 1;
418 }
419 }
420
421 if (sin->sin6_family == AF_INET6) {
422 bzero(&hints, sizeof(struct addrinfo));
423 hints.ai_family = AF_INET6;
424 error = getaddrinfo(s, NULL, &hints, &res);
425 }
426 if (error != 0) {
427 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
428 errx(1, "%s: bad value", s);
429 } else
430 bcopy(res->ai_addr, sin, res->ai_addrlen);
431 }
432
433 static int
434 prefix(void *val, int size)
435 {
436 u_char *name = (u_char *)val;
437 int byte, bit, plen = 0;
438
439 for (byte = 0; byte < size; byte++, plen += 8)
440 if (name[byte] != 0xff)
441 break;
442 if (byte == size)
443 return (plen);
444 for (bit = 7; bit != 0; bit--, plen++)
445 if (!(name[byte] & (1 << bit)))
446 break;
447 for (; bit != 0; bit--)
448 if (name[byte] & (1 << bit))
449 return(0);
450 byte++;
451 for (; byte < size; byte++)
452 if (name[byte])
453 return(0);
454 return (plen);
455 }
456
457 static char *
458 sec2str(time_t total)
459 {
460 static char result[256];
461 int days, hours, mins, secs;
462 int first = 1;
463 char *p = result;
464
465 if (0) {
466 days = total / 3600 / 24;
467 hours = (total / 3600) % 24;
468 mins = (total / 60) % 60;
469 secs = total % 60;
470
471 if (days) {
472 first = 0;
473 p += snprintf(p, sizeof(result) - (p - result), "%dd", days);
474 }
475 if (!first || hours) {
476 first = 0;
477 p += snprintf(p, sizeof(result) - (p - result), "%dh", hours);
478 }
479 if (!first || mins) {
480 first = 0;
481 p += snprintf(p, sizeof(result) - (p - result), "%dm", mins);
482 }
483 snprintf(p, sizeof(result) - (p - result), "%ds", secs);
484 } else
485 snprintf(result, sizeof(result), "%lu", (unsigned long)total);
486
487 return(result);
488 }
489
490 static void
491 in6_postproc(int s, const struct afswtch *afp)
492 {
493 if (explicit_prefix == 0) {
494 /* Aggregatable address architecture defines all prefixes
495 are 64. So, it is convenient to set prefixlen to 64 if
496 it is not specified. */
497 setifprefixlen("64", 0, s, afp);
498 /* in6_getprefix("64", MASK) if MASK is available here... */
499 }
500 }
501
502 static void
503 in6_status_tunnel(int s)
504 {
505 char src[NI_MAXHOST];
506 char dst[NI_MAXHOST];
507 struct in6_ifreq in6_ifr;
508 const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
509
510 memset(&in6_ifr, 0, sizeof(in6_ifr));
511 strncpy(in6_ifr.ifr_name, name, IFNAMSIZ);
512
513 if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
514 return;
515 if (sa->sa_family != AF_INET6)
516 return;
517 in6_fillscopeid(&in6_ifr.ifr_addr);
518 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
519 NI_NUMERICHOST) != 0)
520 src[0] = '\0';
521
522 if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
523 return;
524 if (sa->sa_family != AF_INET6)
525 return;
526 in6_fillscopeid(&in6_ifr.ifr_addr);
527 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
528 NI_NUMERICHOST) != 0)
529 dst[0] = '\0';
530
531 printf("\ttunnel inet6 %s --> %s\n", src, dst);
532 }
533
534 static void
535 nd6_status(int s)
536 {
537 struct in6_ndireq nd;
538 int s6;
539 int error;
540
541 memset(&nd, 0, sizeof(nd));
542 strncpy(nd.ifname, ifr.ifr_name, sizeof(nd.ifname));
543 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
544 if (errno != EPROTONOSUPPORT)
545 warn("socket(AF_INET6, SOCK_DGRAM)");
546 return;
547 }
548 error = ioctl(s6, SIOCGIFINFO_IN6, &nd);
549 if (error) {
550 if (errno != EPFNOSUPPORT && errno != EINVAL)
551 warn("ioctl(SIOCGIFINFO_IN6)");
552 close(s6);
553 return;
554 }
555 close(s6);
556 if (nd.ndi.flags == 0)
557 return;
558 printb("\tnd6 options", (unsigned int)nd.ndi.flags, ND6BITS);
559 putchar('\n');
560 }
561
562 static void
563 in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
564 {
565 struct in6_aliasreq in6_addreq;
566
567 memset(&in6_addreq, 0, sizeof(in6_addreq));
568 strncpy(in6_addreq.ifra_name, name, IFNAMSIZ);
569 memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
570 memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
571 dstres->ai_addr->sa_len);
572
573 if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
574 warn("SIOCSIFPHYADDR_IN6");
575 }
576
577 static void
578 in6_set_router(int s, int enable)
579 {
580 struct ifreq ifr;
581
582 bzero(&ifr, sizeof (ifr));
583 strncpy(ifr.ifr_name, name, IFNAMSIZ);
584 ifr.ifr_intval = enable;
585
586 if (ioctl(s, SIOCSETROUTERMODE_IN6, &ifr) < 0)
587 warn("SIOCSETROUTERMODE_IN6");
588 }
589
590 static struct cmd inet6_cmds[] = {
591 DEF_CMD_ARG("prefixlen", setifprefixlen),
592 DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
593 DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
594 DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
595 /* RFC 4429, section 3.1, says:
596 * "Optimistic DAD SHOULD NOT be used for manually entered
597 * addresses."
598 * it's not a MUST...
599 */
600 DEF_CMD("optimistic", IN6_IFF_OPTIMISTIC, setip6flags),
601 DEF_CMD("-optimistic", -IN6_IFF_OPTIMISTIC, setip6flags),
602 DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
603 DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
604 DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
605 DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
606 DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
607 DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
608 DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
609 DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
610 DEF_CMD("replicated", ND6_IFF_REPLICATED, setnd6flags),
611 DEF_CMD("-replicated", -ND6_IFF_REPLICATED, setnd6flags),
612 DEF_CMD("proxy_prefixes", ND6_IFF_PROXY_PREFIXES, setnd6flags),
613 DEF_CMD("-proxy_prefixes", -ND6_IFF_PROXY_PREFIXES, setnd6flags),
614 DEF_CMD("insecure", ND6_IFF_INSECURE, setnd6flags),
615 DEF_CMD("-insecure", -ND6_IFF_INSECURE, setnd6flags),
616 DEF_CMD_ARG("pltime", setip6pltime),
617 DEF_CMD_ARG("vltime", setip6vltime),
618 DEF_CMD("eui64", 0, setip6eui64),
619 DEF_CMD("secured", IN6_IFF_SECURED, setip6flags),
620 DEF_CMD("-secured", -IN6_IFF_SECURED, setip6flags),
621 DEF_CMD("dad", ND6_IFF_DAD, setnd6flags),
622 DEF_CMD("-dad", -ND6_IFF_DAD, setnd6flags),
623 };
624
625 static struct afswtch af_inet6 = {
626 .af_name = "inet6",
627 .af_af = AF_INET6,
628 .af_status = in6_status,
629 .af_getaddr = in6_getaddr,
630 .af_getprefix = in6_getprefix,
631 .af_other_status = nd6_status,
632 .af_postproc = in6_postproc,
633 .af_status_tunnel = in6_status_tunnel,
634 .af_settunnel = in6_set_tunnel,
635 .af_setrouter = in6_set_router,
636 .af_difaddr = SIOCDIFADDR_IN6,
637 .af_aifaddr = SIOCAIFADDR_IN6,
638 .af_ridreq = &in6_ridreq,
639 .af_addreq = &in6_addreq,
640 };
641
642 static void
643 in6_Lopt_cb(const char *optarg __unused)
644 {
645 ip6lifetime++; /* print IPv6 address lifetime */
646 }
647 static struct option in6_Lopt = { "L", "[-L]", in6_Lopt_cb };
648
649 static __constructor void
650 inet6_ctor(void)
651 {
652 #define N(a) (sizeof(a) / sizeof(a[0]))
653 int i;
654
655 for (i = 0; i < N(inet6_cmds); i++)
656 cmd_register(&inet6_cmds[i]);
657 af_register(&af_inet6);
658 opt_register(&in6_Lopt);
659 #undef N
660 }