2 * SPDX-License-Identifier: BSD-3-Clause
4 * Copyright (c) 1983, 1993
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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 University 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.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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
33 static const char rcsid[] =
37 #include <sys/param.h>
38 #include <sys/ioctl.h>
39 #include <sys/socket.h>
50 #include <arpa/inet.h>
52 #include <netinet/in.h>
53 #include <netinet/in_var.h>
54 #include <arpa/inet.h>
57 #include <netinet6/nd6.h> /* Define ND6_INFINITE_LIFETIME */
60 #include "ifconfig_netlink.h"
62 #ifndef WITHOUT_NETLINK
70 struct in6_px dst_addr;
71 struct in6_addrlifetime lifetime;
76 static struct in6_pdata in6_del;
77 static struct in6_pdata in6_add = {
78 .lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME },
81 static struct in6_ifreq in6_ridreq;
82 static struct in6_aliasreq in6_addreq =
84 .ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
86 static int ip6lifetime;
88 #ifdef WITHOUT_NETLINK
89 static int prefix(void *, int);
91 static char *sec2str(time_t);
92 static int explicit_prefix = 0;
93 extern char *f_inet6, *f_addr;
95 extern void setnd6flags(if_ctx *, const char *, int);
96 extern void setnd6defif(if_ctx *,const char *, int);
97 extern void nd6_status(if_ctx *);
99 static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
102 setifprefixlen(if_ctx *ctx __netlink_unused, const char *addr, int dummy __unused)
104 #ifdef WITHOUT_NETLINK
105 const struct afswtch *afp = ctx->afp;
107 if (afp->af_getprefix != NULL)
108 afp->af_getprefix(addr, MASK);
110 int plen = strtol(addr, NULL, 10);
112 if ((plen < 0) || (plen > 128))
113 errx(1, "%s: bad value", addr);
114 in6_add.addr.plen = plen;
120 setip6flags(if_ctx *ctx, const char *dummyaddr __unused, int flag)
122 const struct afswtch *afp = ctx->afp;
124 if (afp->af_af != AF_INET6)
125 err(1, "address flags can be set only for inet6 addresses");
127 #ifdef WITHOUT_NETLINK
129 in6_addreq.ifra_flags &= ~(-flag);
131 in6_addreq.ifra_flags |= flag;
134 in6_add.flags &= ~(-flag);
136 in6_add.flags |= flag;
141 setip6lifetime(if_ctx *ctx, const char *cmd, const char *val)
143 const struct afswtch *afp = ctx->afp;
147 #ifdef WITHOUT_NETLINK
148 struct in6_addrlifetime *lifetime = &in6_addreq.ifra_lifetime;
150 struct in6_addrlifetime *lifetime = &in6_add.lifetime;
153 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
154 newval = (time_t)strtoul(val, &ep, 0);
156 errx(1, "invalid %s", cmd);
157 if (afp->af_af != AF_INET6)
158 errx(1, "%s not allowed for the AF", cmd);
159 if (strcmp(cmd, "vltime") == 0) {
160 lifetime->ia6t_expire = now.tv_sec + newval;
161 lifetime->ia6t_vltime = newval;
162 } else if (strcmp(cmd, "pltime") == 0) {
163 lifetime->ia6t_preferred = now.tv_sec + newval;
164 lifetime->ia6t_pltime = newval;
169 setip6pltime(if_ctx *ctx, const char *seconds, int dummy __unused)
171 setip6lifetime(ctx, "pltime", seconds);
175 setip6vltime(if_ctx *ctx, const char *seconds, int dummy __unused)
177 setip6lifetime(ctx, "vltime", seconds);
181 setip6eui64(if_ctx *ctx, const char *cmd, int dummy __unused)
183 const struct afswtch *afp = ctx->afp;
184 struct ifaddrs *ifap, *ifa;
185 const struct sockaddr_in6 *sin6 = NULL;
186 const struct in6_addr *lladdr = NULL;
187 struct in6_addr *in6;
189 if (afp->af_af != AF_INET6)
190 errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
191 #ifdef WITHOUT_NETLINK
192 in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
194 in6 = &in6_add.addr.addr;
196 if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
197 errx(EXIT_FAILURE, "interface index is already filled");
198 if (getifaddrs(&ifap) != 0)
199 err(EXIT_FAILURE, "getifaddrs");
200 for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
201 if (ifa->ifa_addr->sa_family == AF_INET6 &&
202 strcmp(ifa->ifa_name, name) == 0) {
203 sin6 = (const struct sockaddr_in6 *)satosin6(ifa->ifa_addr);
204 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
205 lladdr = &sin6->sin6_addr;
211 errx(EXIT_FAILURE, "could not determine link local address");
213 memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
219 print_addr(struct sockaddr_in6 *sin)
223 if (f_addr != NULL && strcmp(f_addr, "fqdn") == 0)
225 else if (f_addr != NULL && strcmp(f_addr, "host") == 0)
228 n_flags = NI_NUMERICHOST;
229 error = getnameinfo((struct sockaddr *)sin, sin->sin6_len,
230 addr_buf, sizeof(addr_buf), NULL, 0,
233 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf,
235 printf("\tinet6 %s", addr_buf);
239 print_p2p(struct sockaddr_in6 *sin)
243 error = getnameinfo((struct sockaddr *)sin, sin->sin6_len, addr_buf,
244 sizeof(addr_buf), NULL, 0, NI_NUMERICHOST);
247 inet_ntop(AF_INET6, &sin->sin6_addr, addr_buf, sizeof(addr_buf));
248 printf(" --> %s", addr_buf);
254 if (f_inet6 != NULL && strcmp(f_inet6, "cidr") == 0)
257 printf(" prefixlen %d", plen);
261 print_flags(int flags6)
263 if ((flags6 & IN6_IFF_ANYCAST) != 0)
265 if ((flags6 & IN6_IFF_TENTATIVE) != 0)
266 printf(" tentative");
267 if ((flags6 & IN6_IFF_DUPLICATED) != 0)
268 printf(" duplicated");
269 if ((flags6 & IN6_IFF_DETACHED) != 0)
271 if ((flags6 & IN6_IFF_DEPRECATED) != 0)
272 printf(" deprecated");
273 if ((flags6 & IN6_IFF_AUTOCONF) != 0)
275 if ((flags6 & IN6_IFF_TEMPORARY) != 0)
276 printf(" temporary");
277 if ((flags6 & IN6_IFF_PREFER_SOURCE) != 0)
278 printf(" prefer_source");
283 print_lifetime(const char *prepend, time_t px_time, struct timespec *now)
285 printf(" %s", prepend);
289 printf(" %s", px_time < now->tv_sec ? "0" : sec2str(px_time - now->tv_sec));
292 #ifdef WITHOUT_NETLINK
294 in6_status(if_ctx *ctx __unused, const struct ifaddrs *ifa)
296 struct sockaddr_in6 *sin, null_sin = {};
297 struct in6_ifreq ifr6;
300 struct in6_addrlifetime lifetime;
302 sin = (struct sockaddr_in6 *)ifa->ifa_addr;
306 strlcpy(ifr6.ifr_name, ifr.ifr_name, sizeof(ifr.ifr_name));
307 if ((s6 = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
308 warn("socket(AF_INET6,SOCK_DGRAM)");
311 ifr6.ifr_addr = *sin;
312 if (ioctl(s6, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
313 warn("ioctl(SIOCGIFAFLAG_IN6)");
317 flags6 = ifr6.ifr_ifru.ifru_flags6;
318 memset(&lifetime, 0, sizeof(lifetime));
319 ifr6.ifr_addr = *sin;
320 if (ioctl(s6, SIOCGIFALIFETIME_IN6, &ifr6) < 0) {
321 warn("ioctl(SIOCGIFALIFETIME_IN6)");
325 lifetime = ifr6.ifr_ifru.ifru_lifetime;
330 if (ifa->ifa_flags & IFF_POINTOPOINT) {
331 sin = (struct sockaddr_in6 *)ifa->ifa_dstaddr;
333 * some of the interfaces do not have valid destination
336 if (sin != NULL && sin->sin6_family == AF_INET6)
340 sin = (struct sockaddr_in6 *)ifa->ifa_netmask;
343 print_mask(prefix(&sin->sin6_addr, sizeof(struct in6_addr)));
347 if (((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id)
348 printf(" scopeid 0x%x",
349 ((struct sockaddr_in6 *)(ifa->ifa_addr))->sin6_scope_id);
351 if (ip6lifetime && (lifetime.ia6t_preferred || lifetime.ia6t_expire)) {
354 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
355 print_lifetime("pltime", lifetime.ia6t_preferred, &now);
356 print_lifetime("vltime", lifetime.ia6t_expire, &now);
359 print_vhid(ifa, " ");
366 show_lifetime(struct ifa_cacheinfo *ci)
374 int count = ci->ifa_prefered != ND6_INFINITE_LIFETIME;
375 count += ci->ifa_valid != ND6_INFINITE_LIFETIME;
379 pl = (ci->ifa_prefered == ND6_INFINITE_LIFETIME) ? 0 : ci->ifa_prefered;
380 vl = (ci->ifa_valid == ND6_INFINITE_LIFETIME) ? 0 : ci->ifa_valid;
382 clock_gettime(CLOCK_MONOTONIC_FAST, &now);
383 print_lifetime("pltime", pl + now.tv_sec, &now);
384 print_lifetime("vltime", vl + now.tv_sec, &now);
388 in6_status_nl(if_ctx *ctx __unused, if_link_t *link __unused, if_addr_t *ifa)
390 int plen = ifa->ifa_prefixlen;
393 if (ifa->ifa_local == NULL) {
394 /* Non-P2P address */
395 scopeid = satosin6(ifa->ifa_address)->sin6_scope_id;
396 print_addr(satosin6(ifa->ifa_address));
398 scopeid = satosin6(ifa->ifa_local)->sin6_scope_id;
399 print_addr(satosin6(ifa->ifa_local));
400 print_p2p(satosin6(ifa->ifa_address));
404 print_flags(ifa->ifaf_flags);
407 printf(" scopeid 0x%x", scopeid);
409 show_lifetime(ifa->ifa_cacheinfo);
411 if (ifa->ifaf_vhid != 0)
412 printf(" vhid %d", ifa->ifaf_vhid);
417 static struct in6_px *sin6tab_nl[] = {
418 &in6_del.addr, /* RIDADDR */
419 &in6_add.addr, /* ADDR */
421 &in6_add.dst_addr, /* DSTADDR*/
425 in6_copyaddr(if_ctx *ctx __unused, int to, int from)
427 sin6tab_nl[to]->addr = sin6tab_nl[from]->addr;
428 sin6tab_nl[to]->set = sin6tab_nl[from]->set;
432 in6_getaddr(const char *addr_str, int which)
434 struct in6_px *px = sin6tab_nl[which];
442 if((p = strrchr(addr_str, '/')) != NULL) {
444 int plen = strtol(p + 1, NULL, 10);
445 if (plen < 0 || plen > 128)
446 errx(1, "%s: bad value", p + 1);
452 struct addrinfo hints = { .ai_family = AF_INET6 };
453 struct addrinfo *res;
455 int error = getaddrinfo(addr_str, NULL, &hints, &res);
457 if (inet_pton(AF_INET6, addr_str, &px->addr) != 1)
458 errx(1, "%s: bad value", addr_str);
460 struct sockaddr_in6 *sin6;
462 sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
463 px->addr = sin6->sin6_addr;
469 in6_exec_nl(if_ctx *ctx, unsigned long action, void *data)
471 struct in6_pdata *pdata = (struct in6_pdata *)data;
472 struct snl_writer nw = {};
474 snl_init_writer(ctx->io_ss, &nw);
475 struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
476 struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
478 ifahdr->ifa_family = AF_INET6;
479 ifahdr->ifa_prefixlen = pdata->addr.plen;
480 ifahdr->ifa_index = if_nametoindex_nl(ctx->io_ss, name);
482 snl_add_msg_attr_ip6(&nw, IFA_LOCAL, &pdata->addr.addr);
483 if (action == NL_RTM_NEWADDR && pdata->dst_addr.set)
484 snl_add_msg_attr_ip6(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
486 struct ifa_cacheinfo ci = {
487 .ifa_prefered = pdata->lifetime.ia6t_pltime,
488 .ifa_valid = pdata->lifetime.ia6t_vltime,
490 snl_add_msg_attr(&nw, IFA_CACHEINFO, sizeof(ci), &ci);
492 int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
493 snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
494 if (pdata->vhid != 0)
495 snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
496 snl_end_attr_nested(&nw, off);
498 if (!snl_finalize_msg(&nw) || !snl_send_message(ctx->io_ss, hdr))
501 struct snl_errmsg_data e = {};
502 snl_read_reply_code(ctx->io_ss, hdr->nlmsg_seq, &e);
508 #ifdef WITHOUT_NETLINK
509 static struct sockaddr_in6 *sin6tab[] = {
510 &in6_ridreq.ifr_addr, &in6_addreq.ifra_addr,
511 &in6_addreq.ifra_prefixmask, &in6_addreq.ifra_dstaddr
515 in6_copyaddr(if_ctx *ctx, int to, int from)
517 memcpy(sin6tab[to], sin6tab[from], sizeof(struct sockaddr_in6));
521 in6_getprefix(const char *plen, int which)
523 struct sockaddr_in6 *sin = sin6tab[which];
525 int len = atoi(plen);
527 if ((len < 0) || (len > 128))
528 errx(1, "%s: bad value", plen);
529 sin->sin6_len = sizeof(*sin);
531 sin->sin6_family = AF_INET6;
532 if ((len == 0) || (len == 128)) {
533 memset(&sin->sin6_addr, 0xff, sizeof(struct in6_addr));
536 memset((void *)&sin->sin6_addr, 0x00, sizeof(sin->sin6_addr));
537 for (cp = (u_char *)&sin->sin6_addr; len > 7; len -= 8)
539 *cp = 0xff << (8 - len);
543 in6_getaddr(const char *s, int which)
545 struct sockaddr_in6 *sin = sin6tab[which];
546 struct addrinfo hints, *res;
551 sin->sin6_len = sizeof(*sin);
553 sin->sin6_family = AF_INET6;
557 if((p = strrchr(s, '/')) != NULL) {
559 in6_getprefix(p + 1, MASK);
564 if (sin->sin6_family == AF_INET6) {
565 bzero(&hints, sizeof(struct addrinfo));
566 hints.ai_family = AF_INET6;
567 error = getaddrinfo(s, NULL, &hints, &res);
569 if (inet_pton(AF_INET6, s, &sin->sin6_addr) != 1)
570 errx(1, "%s: bad value", s);
572 bcopy(res->ai_addr, sin, res->ai_addrlen);
579 prefix(void *val, int size)
581 u_char *name = (u_char *)val;
582 int byte, bit, plen = 0;
584 for (byte = 0; byte < size; byte++, plen += 8)
585 if (name[byte] != 0xff)
589 for (bit = 7; bit != 0; bit--, plen++)
590 if (!(name[byte] & (1 << bit)))
592 for (; bit != 0; bit--)
593 if (name[byte] & (1 << bit))
596 for (; byte < size; byte++)
604 sec2str(time_t total)
606 static char result[256];
607 int days, hours, mins, secs;
612 days = total / 3600 / 24;
613 hours = (total / 3600) % 24;
614 mins = (total / 60) % 60;
619 p += sprintf(p, "%dd", days);
621 if (!first || hours) {
623 p += sprintf(p, "%dh", hours);
625 if (!first || mins) {
627 p += sprintf(p, "%dm", mins);
629 sprintf(p, "%ds", secs);
631 sprintf(result, "%lu", (unsigned long)total);
637 in6_postproc(if_ctx *ctx, int newaddr __unused,
638 int ifflags __unused)
640 if (explicit_prefix == 0) {
641 /* Aggregatable address architecture defines all prefixes
642 are 64. So, it is convenient to set prefixlen to 64 if
643 it is not specified. */
644 setifprefixlen(ctx, "64", 0);
645 /* in6_getprefix("64", MASK) if MASK is available here... */
650 in6_status_tunnel(int s)
652 char src[NI_MAXHOST];
653 char dst[NI_MAXHOST];
654 struct in6_ifreq in6_ifr;
655 const struct sockaddr *sa = (const struct sockaddr *) &in6_ifr.ifr_addr;
657 memset(&in6_ifr, 0, sizeof(in6_ifr));
658 strlcpy(in6_ifr.ifr_name, name, sizeof(in6_ifr.ifr_name));
660 if (ioctl(s, SIOCGIFPSRCADDR_IN6, (caddr_t)&in6_ifr) < 0)
662 if (sa->sa_family != AF_INET6)
664 if (getnameinfo(sa, sa->sa_len, src, sizeof(src), 0, 0,
665 NI_NUMERICHOST) != 0)
668 if (ioctl(s, SIOCGIFPDSTADDR_IN6, (caddr_t)&in6_ifr) < 0)
670 if (sa->sa_family != AF_INET6)
672 if (getnameinfo(sa, sa->sa_len, dst, sizeof(dst), 0, 0,
673 NI_NUMERICHOST) != 0)
676 printf("\ttunnel inet6 %s --> %s\n", src, dst);
680 in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
682 struct in6_aliasreq in6_addreq;
684 memset(&in6_addreq, 0, sizeof(in6_addreq));
685 strlcpy(in6_addreq.ifra_name, name, sizeof(in6_addreq.ifra_name));
686 memcpy(&in6_addreq.ifra_addr, srcres->ai_addr, srcres->ai_addr->sa_len);
687 memcpy(&in6_addreq.ifra_dstaddr, dstres->ai_addr,
688 dstres->ai_addr->sa_len);
690 if (ioctl(s, SIOCSIFPHYADDR_IN6, &in6_addreq) < 0)
691 warn("SIOCSIFPHYADDR_IN6");
695 in6_set_vhid(int vhid)
697 #ifdef WITHOUT_NETLINK
698 in6_addreq.ifra_vhid = vhid;
700 in6_add.vhid = (uint32_t)vhid;
704 static struct cmd inet6_cmds[] = {
705 DEF_CMD_ARG("prefixlen", setifprefixlen),
706 DEF_CMD("anycast", IN6_IFF_ANYCAST, setip6flags),
707 DEF_CMD("tentative", IN6_IFF_TENTATIVE, setip6flags),
708 DEF_CMD("-tentative", -IN6_IFF_TENTATIVE, setip6flags),
709 DEF_CMD("deprecated", IN6_IFF_DEPRECATED, setip6flags),
710 DEF_CMD("-deprecated", -IN6_IFF_DEPRECATED, setip6flags),
711 DEF_CMD("autoconf", IN6_IFF_AUTOCONF, setip6flags),
712 DEF_CMD("-autoconf", -IN6_IFF_AUTOCONF, setip6flags),
713 DEF_CMD("prefer_source",IN6_IFF_PREFER_SOURCE, setip6flags),
714 DEF_CMD("-prefer_source",-IN6_IFF_PREFER_SOURCE,setip6flags),
715 DEF_CMD("accept_rtadv", ND6_IFF_ACCEPT_RTADV, setnd6flags),
716 DEF_CMD("-accept_rtadv",-ND6_IFF_ACCEPT_RTADV, setnd6flags),
717 DEF_CMD("no_radr", ND6_IFF_NO_RADR, setnd6flags),
718 DEF_CMD("-no_radr", -ND6_IFF_NO_RADR, setnd6flags),
719 DEF_CMD("defaultif", 1, setnd6defif),
720 DEF_CMD("-defaultif", -1, setnd6defif),
721 DEF_CMD("ifdisabled", ND6_IFF_IFDISABLED, setnd6flags),
722 DEF_CMD("-ifdisabled", -ND6_IFF_IFDISABLED, setnd6flags),
723 DEF_CMD("nud", ND6_IFF_PERFORMNUD, setnd6flags),
724 DEF_CMD("-nud", -ND6_IFF_PERFORMNUD, setnd6flags),
725 DEF_CMD("auto_linklocal",ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
726 DEF_CMD("-auto_linklocal",-ND6_IFF_AUTO_LINKLOCAL,setnd6flags),
727 DEF_CMD("no_prefer_iface",ND6_IFF_NO_PREFER_IFACE,setnd6flags),
728 DEF_CMD("-no_prefer_iface",-ND6_IFF_NO_PREFER_IFACE,setnd6flags),
729 DEF_CMD("no_dad", ND6_IFF_NO_DAD, setnd6flags),
730 DEF_CMD("-no_dad", -ND6_IFF_NO_DAD, setnd6flags),
731 DEF_CMD_ARG("pltime", setip6pltime),
732 DEF_CMD_ARG("vltime", setip6vltime),
733 DEF_CMD("eui64", 0, setip6eui64),
735 DEF_CMD("ipv6_only", ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
736 DEF_CMD("-ipv6_only", -ND6_IFF_IPV6_ONLY_MANUAL,setnd6flags),
740 static struct afswtch af_inet6 = {
743 #ifdef WITHOUT_NETLINK
744 .af_status = in6_status,
746 .af_status = in6_status_nl,
748 .af_getaddr = in6_getaddr,
749 .af_copyaddr = in6_copyaddr,
750 #ifdef WITHOUT_NETLINK
751 .af_getprefix = in6_getprefix,
753 .af_other_status = nd6_status,
754 .af_postproc = in6_postproc,
755 .af_status_tunnel = in6_status_tunnel,
756 .af_settunnel = in6_set_tunnel,
757 .af_setvhid = in6_set_vhid,
758 #ifdef WITHOUT_NETLINK
759 .af_difaddr = SIOCDIFADDR_IN6,
760 .af_aifaddr = SIOCAIFADDR_IN6,
761 .af_ridreq = &in6_addreq,
762 .af_addreq = &in6_addreq,
763 .af_exec = af_exec_ioctl,
765 .af_difaddr = NL_RTM_DELADDR,
766 .af_aifaddr = NL_RTM_NEWADDR,
767 .af_ridreq = &in6_add,
768 .af_addreq = &in6_add,
769 .af_exec = in6_exec_nl,
774 in6_Lopt_cb(const char *arg __unused)
776 ip6lifetime++; /* print IPv6 address lifetime */
778 static struct option in6_Lopt = {
784 static __constructor void
790 if (!feature_present("inet6"))
794 for (i = 0; i < nitems(inet6_cmds); i++)
795 cmd_register(&inet6_cmds[i]);
796 af_register(&af_inet6);
797 opt_register(&in6_Lopt);