Home | History | Annotate | Line # | Download | only in ifconfig
af_inet6.c revision 1.11
      1  1.11    dyoung /*	$NetBSD: af_inet6.c,v 1.11 2008/05/07 18:08:30 dyoung Exp $	*/
      2   1.1   thorpej 
      3   1.1   thorpej /*
      4   1.1   thorpej  * Copyright (c) 1983, 1993
      5   1.1   thorpej  *      The Regents of the University of California.  All rights reserved.
      6   1.1   thorpej  *
      7   1.1   thorpej  * Redistribution and use in source and binary forms, with or without
      8   1.1   thorpej  * modification, are permitted provided that the following conditions
      9   1.1   thorpej  * are met:
     10   1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     11   1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     12   1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     13   1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     14   1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     15   1.1   thorpej  * 3. Neither the name of the University nor the names of its contributors
     16   1.1   thorpej  *    may be used to endorse or promote products derived from this software
     17   1.1   thorpej  *    without specific prior written permission.
     18   1.1   thorpej  *
     19   1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     20   1.1   thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     21   1.1   thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     22   1.1   thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     23   1.1   thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     24   1.1   thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     25   1.1   thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     26   1.1   thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     27   1.1   thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     28   1.1   thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     29   1.1   thorpej  * SUCH DAMAGE.
     30   1.1   thorpej  */
     31   1.1   thorpej 
     32   1.1   thorpej #include <sys/cdefs.h>
     33   1.1   thorpej #ifndef lint
     34  1.11    dyoung __RCSID("$NetBSD: af_inet6.c,v 1.11 2008/05/07 18:08:30 dyoung Exp $");
     35   1.1   thorpej #endif /* not lint */
     36   1.1   thorpej 
     37   1.1   thorpej #include <sys/param.h>
     38   1.1   thorpej #include <sys/ioctl.h>
     39   1.1   thorpej #include <sys/socket.h>
     40   1.1   thorpej 
     41   1.1   thorpej #include <net/if.h>
     42   1.1   thorpej #include <netinet/in.h>
     43   1.1   thorpej #include <netinet/in_var.h>
     44   1.1   thorpej #include <netinet6/nd6.h>
     45   1.1   thorpej 
     46   1.1   thorpej #include <err.h>
     47   1.1   thorpej #include <errno.h>
     48   1.1   thorpej #include <ifaddrs.h>
     49   1.1   thorpej #include <netdb.h>
     50   1.1   thorpej #include <string.h>
     51   1.1   thorpej #include <stdlib.h>
     52   1.1   thorpej #include <stdio.h>
     53   1.5  christos #include <util.h>
     54   1.1   thorpej 
     55   1.8    dyoung #include "env.h"
     56   1.8    dyoung #include "parse.h"
     57   1.1   thorpej #include "extern.h"
     58   1.1   thorpej #include "af_inet6.h"
     59   1.1   thorpej 
     60   1.8    dyoung struct in6_ifreq    in6_ridreq = {
     61   1.8    dyoung 	.ifr_addr = {
     62   1.8    dyoung 		.sin6_family = AF_INET6,
     63   1.8    dyoung 		.sin6_addr = {
     64   1.8    dyoung 			.s6_addr =
     65   1.8    dyoung 			    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}
     66   1.8    dyoung 		}
     67   1.8    dyoung 	}
     68   1.8    dyoung };
     69   1.1   thorpej 
     70   1.6    dyoung struct in6_aliasreq in6_addreq = {
     71   1.6    dyoung 	.ifra_prefixmask = {
     72  1.11    dyoung 		.sin6_len = sizeof(in6_addreq.ifra_prefixmask),
     73   1.6    dyoung 		.sin6_addr = {
     74   1.6    dyoung 			.s6_addr =
     75   1.6    dyoung 			    {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}},
     76   1.6    dyoung 	.ifra_lifetime = {
     77   1.6    dyoung 		  .ia6t_pltime = ND6_INFINITE_LIFETIME
     78   1.6    dyoung 		, .ia6t_vltime = ND6_INFINITE_LIFETIME
     79   1.6    dyoung 	}
     80   1.6    dyoung };
     81   1.1   thorpej 
     82   1.8    dyoung static int setia6lifetime(prop_dictionary_t, int64_t, time_t *, uint32_t *);
     83   1.8    dyoung static void in6_alias(const char *, prop_dictionary_t, prop_dictionary_t,
     84   1.8    dyoung     struct in6_ifreq *);
     85   1.8    dyoung 
     86   1.1   thorpej static char *
     87   1.1   thorpej sec2str(time_t total)
     88   1.1   thorpej {
     89   1.1   thorpej 	static char result[256];
     90   1.1   thorpej 	int days, hours, mins, secs;
     91   1.1   thorpej 	int first = 1;
     92   1.1   thorpej 	char *p = result;
     93   1.1   thorpej 	char *end = &result[sizeof(result)];
     94   1.1   thorpej 	int n;
     95   1.1   thorpej 
     96   1.1   thorpej 	if (0) {	/*XXX*/
     97   1.1   thorpej 		days = total / 3600 / 24;
     98   1.1   thorpej 		hours = (total / 3600) % 24;
     99   1.1   thorpej 		mins = (total / 60) % 60;
    100   1.1   thorpej 		secs = total % 60;
    101   1.1   thorpej 
    102   1.1   thorpej 		if (days) {
    103   1.1   thorpej 			first = 0;
    104   1.1   thorpej 			n = snprintf(p, end - p, "%dd", days);
    105   1.1   thorpej 			if (n < 0 || n >= end - p)
    106   1.1   thorpej 				return(result);
    107   1.1   thorpej 			p += n;
    108   1.1   thorpej 		}
    109   1.1   thorpej 		if (!first || hours) {
    110   1.1   thorpej 			first = 0;
    111   1.1   thorpej 			n = snprintf(p, end - p, "%dh", hours);
    112   1.1   thorpej 			if (n < 0 || n >= end - p)
    113   1.1   thorpej 				return(result);
    114   1.1   thorpej 			p += n;
    115   1.1   thorpej 		}
    116   1.1   thorpej 		if (!first || mins) {
    117   1.1   thorpej 			first = 0;
    118   1.1   thorpej 			n = snprintf(p, end - p, "%dm", mins);
    119   1.1   thorpej 			if (n < 0 || n >= end - p)
    120   1.1   thorpej 				return(result);
    121   1.1   thorpej 			p += n;
    122   1.1   thorpej 		}
    123   1.1   thorpej 		snprintf(p, end - p, "%ds", secs);
    124   1.1   thorpej 	} else
    125   1.1   thorpej 		snprintf(p, end - p, "%lu", (u_long)total);
    126   1.1   thorpej 
    127   1.1   thorpej 	return(result);
    128   1.1   thorpej }
    129   1.1   thorpej 
    130   1.1   thorpej static int
    131   1.1   thorpej prefix(void *val, int size)
    132   1.1   thorpej {
    133   1.1   thorpej 	u_char *pname = (u_char *)val;
    134   1.1   thorpej 	int byte, bit, plen = 0;
    135   1.1   thorpej 
    136   1.1   thorpej 	for (byte = 0; byte < size; byte++, plen += 8)
    137   1.1   thorpej 		if (pname[byte] != 0xff)
    138   1.1   thorpej 			break;
    139   1.1   thorpej 	if (byte == size)
    140   1.1   thorpej 		return (plen);
    141   1.1   thorpej 	for (bit = 7; bit != 0; bit--, plen++)
    142   1.1   thorpej 		if (!(pname[byte] & (1 << bit)))
    143   1.1   thorpej 			break;
    144   1.1   thorpej 	for (; bit != 0; bit--)
    145   1.1   thorpej 		if (pname[byte] & (1 << bit))
    146   1.1   thorpej 			return(0);
    147   1.1   thorpej 	byte++;
    148   1.1   thorpej 	for (; byte < size; byte++)
    149   1.1   thorpej 		if (pname[byte])
    150   1.1   thorpej 			return(0);
    151   1.1   thorpej 	return (plen);
    152   1.1   thorpej }
    153   1.1   thorpej 
    154   1.8    dyoung int
    155   1.8    dyoung setia6flags_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
    156   1.1   thorpej {
    157  1.10    dyoung 	int64_t ia6flag;
    158   1.1   thorpej 
    159  1.10    dyoung 	if (!prop_dictionary_get_int64(env, "ia6flag", &ia6flag)) {
    160   1.8    dyoung 		errno = ENOENT;
    161   1.8    dyoung 		return -1;
    162   1.8    dyoung 	}
    163   1.8    dyoung 
    164   1.8    dyoung 	if (ia6flag < 0) {
    165   1.8    dyoung 		ia6flag = -ia6flag;
    166   1.8    dyoung 		ifra->ifra_flags &= ~ia6flag;
    167   1.1   thorpej 	} else
    168   1.8    dyoung 		ifra->ifra_flags |= ia6flag;
    169   1.8    dyoung 	return 0;
    170   1.8    dyoung }
    171   1.8    dyoung 
    172   1.8    dyoung int
    173   1.8    dyoung setia6flags(prop_dictionary_t env, prop_dictionary_t xenv)
    174   1.8    dyoung {
    175   1.8    dyoung 	return setia6flags_impl(env, &in6_addreq);
    176   1.1   thorpej }
    177   1.1   thorpej 
    178   1.8    dyoung int
    179   1.8    dyoung setia6pltime_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
    180   1.1   thorpej {
    181  1.10    dyoung 	int64_t pltime;
    182   1.8    dyoung 
    183  1.10    dyoung 	if (!prop_dictionary_get_int64(env, "pltime", &pltime)) {
    184   1.8    dyoung 		errno = ENOENT;
    185   1.8    dyoung 		return -1;
    186   1.8    dyoung 	}
    187   1.1   thorpej 
    188  1.10    dyoung 	return setia6lifetime(env, pltime,
    189   1.8    dyoung 	    &ifra->ifra_lifetime.ia6t_preferred,
    190   1.8    dyoung 	    &ifra->ifra_lifetime.ia6t_pltime);
    191   1.8    dyoung }
    192   1.8    dyoung 
    193   1.8    dyoung int
    194   1.8    dyoung setia6pltime(prop_dictionary_t env, prop_dictionary_t xenv)
    195   1.8    dyoung {
    196   1.8    dyoung 	return setia6pltime_impl(env, &in6_addreq);
    197   1.1   thorpej }
    198   1.1   thorpej 
    199   1.8    dyoung int
    200   1.8    dyoung setia6vltime_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
    201   1.1   thorpej {
    202  1.10    dyoung 	int64_t vltime;
    203   1.8    dyoung 
    204  1.10    dyoung 	if (!prop_dictionary_get_int64(env, "vltime", &vltime)) {
    205   1.8    dyoung 		errno = ENOENT;
    206   1.8    dyoung 		return -1;
    207   1.8    dyoung 	}
    208   1.1   thorpej 
    209  1.10    dyoung 	return setia6lifetime(env, vltime,
    210   1.8    dyoung 		&ifra->ifra_lifetime.ia6t_expire,
    211   1.8    dyoung 		&ifra->ifra_lifetime.ia6t_vltime);
    212   1.8    dyoung }
    213   1.8    dyoung 
    214   1.8    dyoung int
    215   1.8    dyoung setia6vltime(prop_dictionary_t env, prop_dictionary_t xenv)
    216   1.8    dyoung {
    217   1.8    dyoung 	return setia6vltime_impl(env, &in6_addreq);
    218   1.1   thorpej }
    219   1.1   thorpej 
    220   1.8    dyoung static int
    221   1.8    dyoung setia6lifetime(prop_dictionary_t env, int64_t val, time_t *timep,
    222   1.8    dyoung     uint32_t *ivalp)
    223   1.1   thorpej {
    224   1.8    dyoung 	time_t t;
    225   1.8    dyoung 	int af;
    226   1.8    dyoung 
    227   1.8    dyoung 	if ((af = getaf(env)) == -1 || af != AF_INET6) {
    228   1.8    dyoung 		errx(EXIT_FAILURE,
    229   1.8    dyoung 		    "inet6 address lifetime not allowed for the AF");
    230   1.8    dyoung 	}
    231   1.1   thorpej 
    232   1.1   thorpej 	t = time(NULL);
    233   1.8    dyoung 	*timep = t + val;
    234   1.8    dyoung 	*ivalp = val;
    235   1.8    dyoung 	return 0;
    236   1.1   thorpej }
    237   1.1   thorpej 
    238   1.8    dyoung int
    239   1.8    dyoung setia6eui64_impl(prop_dictionary_t env, struct in6_aliasreq *ifra)
    240   1.1   thorpej {
    241   1.1   thorpej 	struct ifaddrs *ifap, *ifa;
    242   1.1   thorpej 	const struct sockaddr_in6 *sin6 = NULL;
    243   1.1   thorpej 	const struct in6_addr *lladdr = NULL;
    244   1.1   thorpej 	struct in6_addr *in6;
    245   1.8    dyoung 	const char *ifname;
    246   1.8    dyoung 	int af;
    247   1.1   thorpej 
    248   1.8    dyoung 	if ((ifname = getifname(env)) == NULL)
    249   1.8    dyoung 		return -1;
    250   1.8    dyoung 
    251   1.8    dyoung 	af = getaf(env);
    252   1.8    dyoung 	if (af != AF_INET6) {
    253   1.8    dyoung 		errx(EXIT_FAILURE,
    254   1.8    dyoung 		    "eui64 address modifier not allowed for the AF");
    255   1.8    dyoung 	}
    256   1.8    dyoung  	in6 = &ifra->ifra_addr.sin6_addr;
    257   1.1   thorpej 	if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
    258   1.1   thorpej 		errx(EXIT_FAILURE, "interface index is already filled");
    259   1.1   thorpej 	if (getifaddrs(&ifap) != 0)
    260   1.1   thorpej 		err(EXIT_FAILURE, "getifaddrs");
    261   1.1   thorpej 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    262   1.1   thorpej 		if (ifa->ifa_addr->sa_family == AF_INET6 &&
    263   1.8    dyoung 		    strcmp(ifa->ifa_name, ifname) == 0) {
    264   1.1   thorpej 			sin6 = (const struct sockaddr_in6 *)ifa->ifa_addr;
    265   1.1   thorpej 			if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
    266   1.1   thorpej 				lladdr = &sin6->sin6_addr;
    267   1.1   thorpej 				break;
    268   1.1   thorpej 			}
    269   1.1   thorpej 		}
    270   1.1   thorpej 	}
    271   1.1   thorpej 	if (!lladdr)
    272   1.1   thorpej 		errx(EXIT_FAILURE, "could not determine link local address");
    273   1.1   thorpej 
    274   1.1   thorpej  	memcpy(&in6->s6_addr[8], &lladdr->s6_addr[8], 8);
    275   1.1   thorpej 
    276   1.1   thorpej 	freeifaddrs(ifap);
    277   1.8    dyoung 	return 0;
    278   1.8    dyoung }
    279   1.8    dyoung 
    280   1.8    dyoung int
    281   1.8    dyoung setia6eui64(prop_dictionary_t env, prop_dictionary_t xenv)
    282   1.8    dyoung {
    283   1.8    dyoung 	return setia6eui64_impl(env, &in6_addreq);
    284   1.1   thorpej }
    285   1.1   thorpej 
    286   1.1   thorpej void
    287   1.1   thorpej in6_fillscopeid(struct sockaddr_in6 *sin6)
    288   1.1   thorpej {
    289   1.8    dyoung 	/* KAME idiosyncrasy */
    290   1.1   thorpej 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) {
    291   1.1   thorpej 		sin6->sin6_scope_id =
    292   1.1   thorpej 			ntohs(*(u_int16_t *)&sin6->sin6_addr.s6_addr[2]);
    293   1.1   thorpej 		sin6->sin6_addr.s6_addr[2] = sin6->sin6_addr.s6_addr[3] = 0;
    294   1.1   thorpej 	}
    295   1.1   thorpej }
    296   1.1   thorpej 
    297   1.1   thorpej /* XXX not really an alias */
    298   1.1   thorpej void
    299   1.8    dyoung in6_alias(const char *ifname, prop_dictionary_t env, prop_dictionary_t oenv,
    300   1.8    dyoung     struct in6_ifreq *creq)
    301   1.1   thorpej {
    302   1.8    dyoung 	struct in6_ifreq ifr6;
    303   1.1   thorpej 	struct sockaddr_in6 *sin6;
    304   1.1   thorpej 	char hbuf[NI_MAXHOST];
    305   1.1   thorpej 	u_int32_t scopeid;
    306   1.8    dyoung 	int s;
    307   1.1   thorpej 	const int niflag = NI_NUMERICHOST;
    308   1.8    dyoung 	unsigned short flags;
    309   1.1   thorpej 
    310   1.1   thorpej 	/* Get the non-alias address for this interface. */
    311   1.8    dyoung 	if ((s = getsock(AF_INET6)) == -1) {
    312   1.3      tron 		if (errno == EAFNOSUPPORT)
    313   1.1   thorpej 			return;
    314   1.1   thorpej 		err(EXIT_FAILURE, "socket");
    315   1.1   thorpej 	}
    316   1.1   thorpej 
    317   1.1   thorpej 	sin6 = (struct sockaddr_in6 *)&creq->ifr_addr;
    318   1.1   thorpej 
    319   1.1   thorpej 	in6_fillscopeid(sin6);
    320   1.1   thorpej 	scopeid = sin6->sin6_scope_id;
    321   1.1   thorpej 	if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
    322   1.1   thorpej 			hbuf, sizeof(hbuf), NULL, 0, niflag))
    323   1.1   thorpej 		strlcpy(hbuf, "", sizeof(hbuf));	/* some message? */
    324   1.1   thorpej 	printf("\tinet6 %s", hbuf);
    325   1.1   thorpej 
    326   1.8    dyoung 	if (getifflags(env, oenv, &flags) == -1)
    327   1.8    dyoung 		err(EXIT_FAILURE, "%s: getifflags", __func__);
    328   1.8    dyoung 
    329   1.1   thorpej 	if (flags & IFF_POINTOPOINT) {
    330   1.7    dyoung 		memset(&ifr6, 0, sizeof(ifr6));
    331   1.8    dyoung 		estrlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
    332   1.1   thorpej 		ifr6.ifr_addr = creq->ifr_addr;
    333   1.1   thorpej 		if (ioctl(s, SIOCGIFDSTADDR_IN6, &ifr6) == -1) {
    334   1.1   thorpej 			if (errno != EADDRNOTAVAIL)
    335   1.1   thorpej 				warn("SIOCGIFDSTADDR_IN6");
    336   1.7    dyoung 			memset(&ifr6.ifr_addr, 0, sizeof(ifr6.ifr_addr));
    337   1.1   thorpej 			ifr6.ifr_addr.sin6_family = AF_INET6;
    338   1.1   thorpej 			ifr6.ifr_addr.sin6_len = sizeof(struct sockaddr_in6);
    339   1.1   thorpej 		}
    340   1.1   thorpej 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
    341   1.1   thorpej 		in6_fillscopeid(sin6);
    342   1.1   thorpej 		hbuf[0] = '\0';
    343   1.1   thorpej 		if (getnameinfo((struct sockaddr *)sin6, sin6->sin6_len,
    344   1.1   thorpej 				hbuf, sizeof(hbuf), NULL, 0, niflag))
    345   1.1   thorpej 			strlcpy(hbuf, "", sizeof(hbuf)); /* some message? */
    346   1.1   thorpej 		printf(" -> %s", hbuf);
    347   1.1   thorpej 	}
    348   1.1   thorpej 
    349   1.7    dyoung 	memset(&ifr6, 0, sizeof(ifr6));
    350   1.8    dyoung 	estrlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
    351   1.1   thorpej 	ifr6.ifr_addr = creq->ifr_addr;
    352   1.1   thorpej 	if (ioctl(s, SIOCGIFNETMASK_IN6, &ifr6) == -1) {
    353   1.1   thorpej 		if (errno != EADDRNOTAVAIL)
    354   1.1   thorpej 			warn("SIOCGIFNETMASK_IN6");
    355   1.1   thorpej 	} else {
    356   1.1   thorpej 		sin6 = (struct sockaddr_in6 *)&ifr6.ifr_addr;
    357   1.1   thorpej 		printf(" prefixlen %d", prefix(&sin6->sin6_addr,
    358   1.1   thorpej 					       sizeof(struct in6_addr)));
    359   1.1   thorpej 	}
    360   1.1   thorpej 
    361   1.7    dyoung 	memset(&ifr6, 0, sizeof(ifr6));
    362   1.8    dyoung 	estrlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
    363   1.1   thorpej 	ifr6.ifr_addr = creq->ifr_addr;
    364   1.1   thorpej 	if (ioctl(s, SIOCGIFAFLAG_IN6, &ifr6) == -1) {
    365   1.1   thorpej 		if (errno != EADDRNOTAVAIL)
    366   1.1   thorpej 			warn("SIOCGIFAFLAG_IN6");
    367   1.1   thorpej 	} else {
    368   1.1   thorpej 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST)
    369   1.1   thorpej 			printf(" anycast");
    370   1.1   thorpej 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_TENTATIVE)
    371   1.1   thorpej 			printf(" tentative");
    372   1.1   thorpej 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DUPLICATED)
    373   1.1   thorpej 			printf(" duplicated");
    374   1.1   thorpej 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DETACHED)
    375   1.1   thorpej 			printf(" detached");
    376   1.1   thorpej 		if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_DEPRECATED)
    377   1.1   thorpej 			printf(" deprecated");
    378   1.1   thorpej 	}
    379   1.1   thorpej 
    380   1.1   thorpej 	if (scopeid)
    381   1.1   thorpej 		printf(" scopeid 0x%x", scopeid);
    382   1.1   thorpej 
    383   1.1   thorpej 	if (Lflag) {
    384   1.1   thorpej 		struct in6_addrlifetime *lifetime;
    385   1.7    dyoung 		memset(&ifr6, 0, sizeof(ifr6));
    386   1.8    dyoung 		estrlcpy(ifr6.ifr_name, ifname, sizeof(ifr6.ifr_name));
    387   1.1   thorpej 		ifr6.ifr_addr = creq->ifr_addr;
    388   1.1   thorpej 		lifetime = &ifr6.ifr_ifru.ifru_lifetime;
    389   1.1   thorpej 		if (ioctl(s, SIOCGIFALIFETIME_IN6, &ifr6) == -1) {
    390   1.1   thorpej 			if (errno != EADDRNOTAVAIL)
    391   1.1   thorpej 				warn("SIOCGIFALIFETIME_IN6");
    392   1.1   thorpej 		} else if (lifetime->ia6t_preferred || lifetime->ia6t_expire) {
    393   1.1   thorpej 			time_t t = time(NULL);
    394   1.1   thorpej 			printf(" pltime ");
    395   1.1   thorpej 			if (lifetime->ia6t_preferred) {
    396   1.1   thorpej 				printf("%s", lifetime->ia6t_preferred < t
    397   1.1   thorpej 					? "0"
    398   1.1   thorpej 					: sec2str(lifetime->ia6t_preferred - t));
    399   1.1   thorpej 			} else
    400   1.1   thorpej 				printf("infty");
    401   1.1   thorpej 
    402   1.1   thorpej 			printf(" vltime ");
    403   1.1   thorpej 			if (lifetime->ia6t_expire) {
    404   1.1   thorpej 				printf("%s", lifetime->ia6t_expire < t
    405   1.1   thorpej 					? "0"
    406   1.1   thorpej 					: sec2str(lifetime->ia6t_expire - t));
    407   1.1   thorpej 			} else
    408   1.1   thorpej 				printf("infty");
    409   1.1   thorpej 		}
    410   1.1   thorpej 	}
    411   1.1   thorpej 
    412   1.1   thorpej 	printf("\n");
    413   1.1   thorpej }
    414   1.1   thorpej 
    415   1.1   thorpej void
    416   1.9    dyoung in6_status(prop_dictionary_t env, prop_dictionary_t oenv, bool force)
    417   1.1   thorpej {
    418   1.1   thorpej 	struct ifaddrs *ifap, *ifa;
    419   1.8    dyoung 	struct in6_ifreq ifr;
    420   1.8    dyoung 	const char *ifname;
    421   1.8    dyoung 
    422   1.8    dyoung 	if ((ifname = getifname(env)) == NULL)
    423   1.8    dyoung 		err(EXIT_FAILURE, "%s: getifname", __func__);
    424   1.1   thorpej 
    425   1.1   thorpej 	if (getifaddrs(&ifap) != 0)
    426   1.1   thorpej 		err(EXIT_FAILURE, "getifaddrs");
    427   1.1   thorpej 	for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
    428   1.8    dyoung 		if (strcmp(ifname, ifa->ifa_name) != 0)
    429   1.1   thorpej 			continue;
    430   1.1   thorpej 		if (ifa->ifa_addr->sa_family != AF_INET6)
    431   1.1   thorpej 			continue;
    432   1.8    dyoung 		if (sizeof(ifr.ifr_addr) < ifa->ifa_addr->sa_len)
    433   1.1   thorpej 			continue;
    434   1.1   thorpej 
    435   1.8    dyoung 		memset(&ifr, 0, sizeof(ifr));
    436   1.8    dyoung 		estrlcpy(ifr.ifr_name, ifa->ifa_name, sizeof(ifr.ifr_name));
    437   1.8    dyoung 		memcpy(&ifr.ifr_addr, ifa->ifa_addr, ifa->ifa_addr->sa_len);
    438   1.8    dyoung 		in6_alias(ifname, env, oenv, &ifr);
    439   1.1   thorpej 	}
    440   1.1   thorpej 	freeifaddrs(ifap);
    441   1.1   thorpej }
    442   1.1   thorpej 
    443   1.1   thorpej #define SIN6(x) ((struct sockaddr_in6 *) &(x))
    444   1.1   thorpej struct sockaddr_in6 *sin6tab[] = {
    445   1.1   thorpej     SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
    446   1.1   thorpej     SIN6(in6_addreq.ifra_prefixmask), SIN6(in6_addreq.ifra_dstaddr)};
    447   1.1   thorpej 
    448   1.1   thorpej void
    449   1.8    dyoung in6_getaddr(const struct paddr_prefix *pfx, int which)
    450   1.1   thorpej {
    451   1.1   thorpej 	struct sockaddr_in6 *sin6 = sin6tab[which];
    452   1.8    dyoung 
    453   1.8    dyoung 	if (pfx->pfx_addr.sa_family != AF_INET6)
    454   1.8    dyoung 		errx(EXIT_FAILURE, "%s: address family mismatch", __func__);
    455   1.8    dyoung 
    456  1.11    dyoung 	if (which == ADDR && pfx->pfx_len >= 0)
    457   1.8    dyoung 		in6_getprefix(pfx->pfx_len, MASK);
    458   1.8    dyoung 
    459   1.8    dyoung 	memcpy(sin6, &pfx->pfx_addr, MIN(sizeof(*sin6), pfx->pfx_addr.sa_len));
    460   1.8    dyoung 
    461   1.8    dyoung 	/* KAME idiosyncrasy */
    462   1.1   thorpej 	if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr) && sin6->sin6_scope_id) {
    463   1.1   thorpej 		*(u_int16_t *)&sin6->sin6_addr.s6_addr[2] =
    464   1.1   thorpej 			htons(sin6->sin6_scope_id);
    465   1.1   thorpej 		sin6->sin6_scope_id = 0;
    466   1.1   thorpej 	}
    467   1.1   thorpej }
    468   1.1   thorpej 
    469   1.1   thorpej void
    470   1.8    dyoung in6_getprefix(int len, int which)
    471   1.1   thorpej {
    472   1.1   thorpej 	struct sockaddr_in6 *gpsin = sin6tab[which];
    473   1.1   thorpej 	u_char *cp;
    474   1.1   thorpej 
    475   1.8    dyoung 	if (len < 0 || len > 128)
    476   1.8    dyoung 		errx(EXIT_FAILURE, "%d: bad value", len);
    477   1.1   thorpej 	gpsin->sin6_len = sizeof(*gpsin);
    478   1.1   thorpej 	if (which != MASK)
    479   1.1   thorpej 		gpsin->sin6_family = AF_INET6;
    480   1.8    dyoung 	if (len == 0 || len == 128) {
    481   1.1   thorpej 		memset(&gpsin->sin6_addr, 0xff, sizeof(struct in6_addr));
    482   1.1   thorpej 		return;
    483   1.1   thorpej 	}
    484   1.1   thorpej 	memset((void *)&gpsin->sin6_addr, 0x00, sizeof(gpsin->sin6_addr));
    485   1.1   thorpej 	for (cp = (u_char *)&gpsin->sin6_addr; len > 7; len -= 8)
    486   1.1   thorpej 		*cp++ = 0xff;
    487   1.1   thorpej 	if (len)
    488   1.1   thorpej 		*cp = 0xff << (8 - len);
    489   1.1   thorpej }
    490