Exemplo n.º 1
0
static void
link_status(int s __unused, const struct ifaddrs *ifa)
{
	/* XXX no const 'cuz LLADDR is defined wrong */
	struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;

	if (sdl != NULL && sdl->sdl_alen > 0) {
#ifdef notyet
		if (sdl->sdl_type == IFT_ETHER &&
		    sdl->sdl_alen == ETHER_ADDR_LEN)
			printf("\tether %s\n",
			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
		else {
			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;

			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
		}
#else
		char *cp = (char *)LLADDR(sdl);
		int n = sdl->sdl_alen;
		
		if (sdl->sdl_type == IFT_ETHER)
			printf ("\tether ");
		else
			printf ("\tlladdr ");
		while (--n >= 0)
			printf("%02x%c",*cp++ & 0xff, n>0? ':' : ' ');
		putchar('\n');
#endif
	}
}
Exemplo n.º 2
0
/*-
 * Convert a network address from binary to printable numeric format.
 * This API is copied from INRIA's IPv6 implementation, but it is a
 * bit bogus in two ways:
 *
 *      1) There is no value in passing both an address family and
 *         an address length; either one should imply the other,
 *         or we should be passing sockaddrs instead.
 *      2) There should by contrast be /added/ a length for the buffer
 *         that we pass in, so that programmers are spared the need to
 *         manually calculate (read: ``guess'') the maximum length.
 *
 * Flash: the API is also the same in the NRL implementation, and seems to
 * be some sort of standard, so we appear to be stuck with both the bad
 * naming and the poor choice of arguments.
 */
char *addr2ascii (int af, const void *addrp, int len, char *buf)
{
    static char staticbuf[64];    /* 64 for AF_LINK > 16 for AF_INET */

    if (!buf)
        buf = staticbuf;

    switch (af)
    {
    case AF_INET:
        if (len != sizeof (struct in_addr))
        {
            SOCK_ERR (ENAMETOOLONG);
            return (NULL);
        }
        strcpy (buf, inet_ntoa (*(const struct in_addr *) addrp));
        break;

    case AF_LINK:
        if (len != sizeof (struct sockaddr_dl))
        {
            SOCK_ERR (ENAMETOOLONG);
            return (NULL);
        }
        strcpy (buf, link_ntoa ((const struct sockaddr_dl *) addrp));
        break;

    default:
        SOCK_ERR (EPROTONOSUPPORT);
        return (NULL);
    }
    return (buf);
}
Exemplo n.º 3
0
int
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
{
	char buffer[64];
	unsigned short port = 0;
	int n = -1;

	switch(addr->sa_family)
	{
#ifdef AF_INET6
	case AF_INET6:
		if(inet_ntop(addr->sa_family,
		             &((struct sockaddr_in6 *)addr)->sin6_addr,
		             buffer, sizeof(buffer)) == NULL) {
			snprintf(buffer, sizeof(buffer), "inet_ntop: %s", strerror(errno));
		}
		port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
		n = snprintf(str, size, "[%s]:%hu", buffer, port);
		break;
#endif /* AF_INET6 */
	case AF_INET:
		if(inet_ntop(addr->sa_family,
		             &((struct sockaddr_in *)addr)->sin_addr,
		             buffer, sizeof(buffer)) == NULL) {
			snprintf(buffer, sizeof(buffer), "inet_ntop: %s", strerror(errno));
		}
		port = ntohs(((struct sockaddr_in *)addr)->sin_port);
		n = snprintf(str, size, "%s:%hu", buffer, port);
		break;
#ifdef AF_LINK
#if defined(__sun)
		/* solaris does not seem to have link_ntoa */
		/* #define link_ntoa _link_ntoa	*/
#define link_ntoa(x) "dummy-link_ntoa"
#endif
	case AF_LINK:
		{
			struct sockaddr_dl * sdl = (struct sockaddr_dl *)addr;
			n = snprintf(str, size, "index=%hu type=%d %s",
			             sdl->sdl_index, sdl->sdl_type,
			             link_ntoa(sdl));
		}
		break;
#endif	/* AF_LINK */
	default:
		n = snprintf(str, size, "unknown address family %d", addr->sa_family);
#if 0
		n = snprintf(str, size, "unknown address family %d "
		             "%02x %02x %02x %02x %02x %02x %02x %02x",
		             addr->sa_family,
		             addr->sa_data[0], addr->sa_data[1], (unsigned)addr->sa_data[2], addr->sa_data[3],
		             addr->sa_data[4], addr->sa_data[5], (unsigned)addr->sa_data[6], addr->sa_data[7]);
#endif
	}
	return n;
}
Exemplo n.º 4
0
int
sockaddr_to_string(const struct sockaddr * addr, char * str, size_t size)
{
	char buffer[64];
	unsigned short port = 0;
	int n = -1;

	switch(addr->sa_family)
	{
	case AF_INET6:
		inet_ntop(addr->sa_family,
		          &((struct sockaddr_in6 *)addr)->sin6_addr,
		          buffer, sizeof(buffer));
		port = ntohs(((struct sockaddr_in6 *)addr)->sin6_port);
		n = snprintf(str, size, "[%s]:%hu", buffer, port);
		break;
	case AF_INET:
		inet_ntop(addr->sa_family,
		          &((struct sockaddr_in *)addr)->sin_addr,
		          buffer, sizeof(buffer));
		port = ntohs(((struct sockaddr_in *)addr)->sin_port);
		n = snprintf(str, size, "%s:%hu", buffer, port);
		break;
#ifdef AF_LINK
	case AF_LINK:
		{
			struct sockaddr_dl * sdl = (struct sockaddr_dl *)addr;
			n = snprintf(str, size, "index=%hu type=%d %s",
			             sdl->sdl_index, sdl->sdl_type,
			             link_ntoa(sdl));
		}
		break;
#endif
	default:
		n = snprintf(str, size, "unknown address family %d", addr->sa_family);
#if 0
		n = snprintf(str, size, "unknown address family %d "
		             "%02x %02x %02x %02x %02x %02x %02x %02x",
		             addr->sa_family,
		             addr->sa_data[0], addr->sa_data[1], (unsigned)addr->sa_data[2], addr->sa_data[3],
		             addr->sa_data[4], addr->sa_data[5], (unsigned)addr->sa_data[6], addr->sa_data[7]);
#endif
	}
	return n;
}
Exemplo n.º 5
0
static void
mpe_status(int s)
{
	struct if_laddrreq iflr;
	struct sockaddr_mpls *smpls;
	struct sockaddr_dl *sdl;
	
	(void)memset(&iflr, 0, sizeof(iflr));
	(void)memcpy(iflr.iflr_name, name, IFNAMSIZ);	
	
	smpls = (struct sockaddr_mpls *)&iflr.addr;
	smpls->smpls_len = sizeof(*smpls);
	smpls->smpls_family = AF_MPLS;
	
	sdl = (struct sockaddr_dl *)&iflr.dstaddr;
	sdl->sdl_len = sizeof(*sdl);
	sdl->sdl_family = AF_LINK;	
	
	if (ioctl(s, SIOCGLIFPHYADDR, (caddr_t)&iflr) < 0)  
		return;
/*
 * Following code-section is reused from implementation 
 * of in af_link.c defined link_status procedure, part of
 * ifconfig(8) implementation. 
 */		
	(void)printf("\tlink ");
		
	if (sdl != NULL && sdl->sdl_alen > 0) {
		if ((sdl->sdl_type == IFT_ETHER 
			|| sdl->sdl_type == IFT_L2VLAN 
			|| sdl->sdl_type == IFT_BRIDGE) 
			&& sdl->sdl_alen == ETHER_ADDR_LEN) {
			
			(void)printf("%s ",
				ether_ntoa((struct ether_addr *)LLADDR(sdl)));
		} else {
			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;
			
			(void)printf("%s ", link_ntoa(sdl) + n);
		}
	}	
}
Exemplo n.º 6
0
static void
link_status(int s __unused, const struct ifaddrs *ifa)
{
	/* XXX no const 'cuz LLADDR is defined wrong */
	struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;

	if (sdl != NULL && sdl->sdl_alen > 0) {
		if ((sdl->sdl_type == IFT_ETHER ||
		    sdl->sdl_type == IFT_L2VLAN ||
		    sdl->sdl_type == IFT_BRIDGE) &&
		    sdl->sdl_alen == ETHER_ADDR_LEN)
			printf("\tether %s\n",
			    ether_ntoa((struct ether_addr *)LLADDR(sdl)));
		else {
			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;

			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
		}
	}
}
Exemplo n.º 7
0
const char *
satos(const struct sockaddr *sa)
{
	switch (sa->sa_family) {
		case AF_INET:
		{
			const struct sockaddr_in *sin =
			    (const struct sockaddr_in *)sa;
			if (inet_ntop(AF_INET, &(sin->sin_addr), satos_str,
			    sizeof(satos_str)) == NULL)
				return "INET ERROR";
			break;
		}
		case AF_INET6:
		{
			const struct sockaddr_in6 *sin6 =
			    (const struct sockaddr_in6 *)sa;
			if (inet_ntop(AF_INET6, &(sin6->sin6_addr), satos_str,
			    sizeof(satos_str)) == NULL)
				return "INET6 ERROR";
			break;
		}
		case AF_LINK:
		{
			strlcpy(satos_str,
			    link_ntoa((const struct sockaddr_dl *)sa),
			    sizeof(satos_str));
			break;
		}
		case AF_MPLS:
		{
			strlcpy(satos_str,
			    mpls_ntoa((const struct sockaddr_mpls *)sa),
			    sizeof(satos_str));
			break;
		}
		default:
			return "UNKNOWN AF";
	}
	return satos_str;
}
Exemplo n.º 8
0
static const char *
fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags)
{
	static char workbuf[128];
	const char *cp;

	if (sa == NULL)
		return ("null");

	switch(sa->sa_family) {
	case AF_INET:
	    {
		struct sockaddr_in *sockin = (struct sockaddr_in *)sa;

		if ((sockin->sin_addr.s_addr == INADDR_ANY) &&
			mask &&
			ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr)
				==0L)
				cp = "default" ;
		else if (flags & RTF_HOST)
			cp = routename(sockin->sin_addr.s_addr);
		else if (mask)
			cp = netname(sockin->sin_addr.s_addr,
				     ntohl(((struct sockaddr_in *)mask)
					   ->sin_addr.s_addr));
		else
			cp = netname(sockin->sin_addr.s_addr, 0L);
		break;
	    }

#ifdef INET6
	case AF_INET6:
	    {
		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;

		in6_fillscopeid(sa6);

		if (flags & RTF_HOST)
		    cp = routename6(sa6);
		else if (mask)
		    cp = netname6(sa6,
				  &((struct sockaddr_in6 *)mask)->sin6_addr);
		else {
		    cp = netname6(sa6, NULL);
		}
		break;
	    }
#endif /*INET6*/

	case AF_IPX:
	    {
		struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
		if (ipx_nullnet(satoipx_addr(work)))
			cp = "default";
		else
			cp = ipx_print(sa);
		break;
	    }
	case AF_APPLETALK:
	    {
		if (!(flags & RTF_HOST) && mask)
			cp = atalk_print2(sa,mask,9);
		else
			cp = atalk_print(sa,11);
		break;
	    }
	case AF_NETGRAPH:
	    {
		strlcpy(workbuf, ((struct sockaddr_ng *)sa)->sg_data,
		        sizeof(workbuf));
		cp = workbuf;
		break;
	    }

	case AF_LINK:
	    {
		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;

		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
		    sdl->sdl_slen == 0) {
			(void) sprintf(workbuf, "link#%d", sdl->sdl_index);
			cp = workbuf;
		} else
			switch (sdl->sdl_type) {

			case IFT_ETHER:
			case IFT_L2VLAN:
			case IFT_BRIDGE:
				if (sdl->sdl_alen == ETHER_ADDR_LEN) {
					cp = ether_ntoa((struct ether_addr *)
					    (sdl->sdl_data + sdl->sdl_nlen));
					break;
				}
				/* FALLTHROUGH */
			default:
				cp = link_ntoa(sdl);
				break;
			}
		break;
	    }

	default:
	    {
		u_char *s = (u_char *)sa->sa_data, *slim;
		char *cq, *cqlim;

		cq = workbuf;
		slim =  sa->sa_len + (u_char *) sa;
		cqlim = cq + sizeof(workbuf) - 6;
		cq += sprintf(cq, "(%d)", sa->sa_family);
		while (s < slim && cq < cqlim) {
			cq += sprintf(cq, " %02x", *s++);
			if (s < slim)
			    cq += sprintf(cq, "%02x", *s++);
		}
		cp = workbuf;
	    }
	}

	return (cp);
}
Exemplo n.º 9
0
static void
link_status(int s __unused, const struct ifaddrs *ifa)
{
	/* XXX no const 'cuz LLADDR is defined wrong */
	struct sockaddr_dl *sdl = (struct sockaddr_dl *) ifa->ifa_addr;
	char *ether_format, *format_char;

	if (sdl != NULL && sdl->sdl_alen > 0) {
		if ((sdl->sdl_type == IFT_ETHER ||
		    sdl->sdl_type == IFT_L2VLAN ||
		    sdl->sdl_type == IFT_BRIDGE) &&
		    sdl->sdl_alen == ETHER_ADDR_LEN) {
			ether_format = ether_ntoa((struct ether_addr *)LLADDR(sdl));
			if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
				for (format_char = strchr(ether_format, ':');
				    format_char != NULL; 
				    format_char = strchr(ether_format, ':'))
					*format_char = '-';
			}
			printf("\tether %s\n", ether_format);
		} else {
			int n = sdl->sdl_nlen > 0 ? sdl->sdl_nlen + 1 : 0;

			printf("\tlladdr %s\n", link_ntoa(sdl) + n);
		}
		/* Best-effort (i.e. failures are silent) to get original
		 * hardware address, as read by NIC driver at attach time. Only
		 * applies to Ethernet NICs (IFT_ETHER). However, laggX
		 * interfaces claim to be IFT_ETHER, and re-type their component
		 * Ethernet NICs as IFT_IEEE8023ADLAG. So, check for both. If
		 * the MAC is zeroed, then it's actually a lagg.
		 */
		if ((sdl->sdl_type == IFT_ETHER ||
		    sdl->sdl_type == IFT_IEEE8023ADLAG) &&
		    sdl->sdl_alen == ETHER_ADDR_LEN) {
			struct ifreq ifr;
			int sock_hw;
			int rc;
			static const u_char laggaddr[6] = {0};

			strncpy(ifr.ifr_name, ifa->ifa_name,
			    sizeof(ifr.ifr_name));
			memcpy(&ifr.ifr_addr, ifa->ifa_addr,
			    sizeof(ifa->ifa_addr->sa_len));
			ifr.ifr_addr.sa_family = AF_LOCAL;
			if ((sock_hw = socket(AF_LOCAL, SOCK_DGRAM, 0)) < 0) {
				warn("socket(AF_LOCAL,SOCK_DGRAM)");
				return;
			}
			rc = ioctl(sock_hw, SIOCGHWADDR, &ifr);
			close(sock_hw);
			if (rc != 0) {
				return;
			}

			/*
			 * If this is definitely a lagg device or the hwaddr
			 * matches the link addr, don't bother.
			 */
			if (memcmp(ifr.ifr_addr.sa_data, laggaddr,
			    sdl->sdl_alen) == 0 ||
			    memcmp(ifr.ifr_addr.sa_data, LLADDR(sdl),
			    sdl->sdl_alen) == 0) {
				return;
			}
			ether_format = ether_ntoa((const struct ether_addr *)
			    &ifr.ifr_addr.sa_data);
			if (f_ether != NULL && strcmp(f_ether, "dash") == 0) {
				for (format_char = strchr(ether_format, ':');
				    format_char != NULL; 
				    format_char = strchr(ether_format, ':'))
					*format_char = '-';
			}
			printf("\thwaddr %s\n", ether_format);
		}
	}
}
Exemplo n.º 10
0
Arquivo: route.c Projeto: MarginC/kame
static const char *
fmt_sockaddr(struct sockaddr *sa, struct sockaddr *mask, int flags)
{
	static char workbuf[128];
	const char *cp;

	switch(sa->sa_family) {
	case AF_INET:
	    {
		struct sockaddr_in *sockin = (struct sockaddr_in *)sa;

		if ((sockin->sin_addr.s_addr == INADDR_ANY) &&
			mask &&
			ntohl(((struct sockaddr_in *)mask)->sin_addr.s_addr)
				==0L)
				cp = "default" ;
		else if (flags & RTF_HOST)
			cp = routename(sockin->sin_addr.s_addr);
		else if (mask)
			cp = netname(sockin->sin_addr.s_addr,
				     ntohl(((struct sockaddr_in *)mask)
					   ->sin_addr.s_addr));
		else
			cp = netname(sockin->sin_addr.s_addr, 0L);
		break;
	    }

#ifdef INET6
	case AF_INET6:
	    {
		struct sockaddr_in6 *sa6 = (struct sockaddr_in6 *)sa;
		struct in6_addr *in6 = &sa6->sin6_addr;

		/*
		 * XXX: This is a special workaround for KAME kernels.
		 * sin6_scope_id field of SA should be set in the future.
		 */
		if (IN6_IS_ADDR_LINKLOCAL(in6) ||
		    IN6_IS_ADDR_MC_LINKLOCAL(in6) ||
		    IN6_IS_ADDR_MC_NODELOCAL(in6)) {
		    /* XXX: override is ok? */
		    sa6->sin6_scope_id = (u_int32_t)ntohs(*(u_short *)&in6->s6_addr[2]);
		    *(u_short *)&in6->s6_addr[2] = 0;
		}

		if (flags & RTF_HOST)
		    cp = routename6(sa6);
		else if (mask)
		    cp = netname6(sa6,
				  &((struct sockaddr_in6 *)mask)->sin6_addr);
		else {
		    cp = netname6(sa6, NULL);
		}
		break;
	    }
#endif /*INET6*/

	case AF_IPX:
	    {
		struct ipx_addr work = ((struct sockaddr_ipx *)sa)->sipx_addr;
		if (ipx_nullnet(satoipx_addr(work)))
			cp = "default";
		else
			cp = ipx_print(sa);
		break;
	    }
	case AF_APPLETALK:
	    {
		if (!(flags & RTF_HOST) && mask)
			cp = atalk_print2(sa,mask,9);
		else
			cp = atalk_print(sa,11);
		break;
	    }
	case AF_NETGRAPH:
	    {
		printf("%s", ((struct sockaddr_ng *)sa)->sg_data);
		break;
	    }

	case AF_LINK:
	    {
		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;

		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
		    sdl->sdl_slen == 0) {
			(void) sprintf(workbuf, "link#%d", sdl->sdl_index);
			cp = workbuf;
		} else
			switch (sdl->sdl_type) {

			case IFT_ETHER:
			case IFT_L2VLAN:
				if (sdl->sdl_alen == ETHER_ADDR_LEN) {
					cp = ether_ntoa((struct ether_addr *)
					    (sdl->sdl_data + sdl->sdl_nlen));
					break;
				}
				/* FALLTHROUGH */
			default:
				cp = link_ntoa(sdl);
				break;
			}
		break;
	    }

	default:
	    {
		u_char *s = (u_char *)sa->sa_data, *slim;
		char *cq, *cqlim;

		cq = workbuf;
		slim =  sa->sa_len + (u_char *) sa;
		cqlim = cq + sizeof(workbuf) - 6;
		cq += sprintf(cq, "(%d)", sa->sa_family);
		while (s < slim && cq < cqlim) {
			cq += sprintf(cq, " %02x", *s++);
			if (s < slim)
			    cq += sprintf(cq, "%02x", *s++);
		}
		cp = workbuf;
	    }
	}

	return (cp);
}
Exemplo n.º 11
0
static int
p_sockaddr(struct sockaddr *sa, int flags, int width)
{
	char workbuf[128];
	char *cp = workbuf;
	const char *cplim;
	int len = sizeof(workbuf);
	int count;

	switch(sa->sa_family) {

	case AF_LINK:
	    {
		struct sockaddr_dl *sdl = (struct sockaddr_dl *)sa;

		if (sdl->sdl_nlen == 0 && sdl->sdl_alen == 0 &&
		    sdl->sdl_slen == 0) {
			snprintf(workbuf, sizeof(workbuf),
			    "link#%d", sdl->sdl_index);
		} else {
			switch (sdl->sdl_type) {
			case IFT_ETHER:
			    {
				int i;
				u_char *lla = (u_char *)sdl->sdl_data +
				    sdl->sdl_nlen;

				cplim = "";
				for (i = 0; i < sdl->sdl_alen; i++, lla++) {
					snprintf(cp, len, "%s%x", cplim, *lla);
					len -= strlen(cp);
					cp += strlen(cp);
					if (len <= 0)
						break;	/* overflow */
					cplim = ":";
				}
				cp = workbuf;
				break;
			    }
			default:
				cp = link_ntoa(sdl);
				break;
			}
		}
		break;
	    }

	case AF_INET:
	    {
		struct sockaddr_in *in = (struct sockaddr_in *)sa;

		if (in->sin_addr.s_addr == 0) {
			/* cp points to workbuf */
			strncpy(cp, "default", len);
		} else
			cp = (flags & RTF_HOST) ? routename(sa) : netname(sa);
		break;
	    }

#ifdef INET6
	case AF_INET6:
	    {
		struct sockaddr_in6 *in6 = (struct sockaddr_in6 *)sa;

		if (IN6_IS_ADDR_UNSPECIFIED(&in6->sin6_addr)) {
			/* cp points to workbuf */
			strncpy(cp, "default", len);
		} else {
			cp = ((flags & RTF_HOST) ? routename(sa)
						 : netname(sa));
		}
		/* make sure numeric address is not truncated */
		if (strchr(cp, ':') != NULL &&
		    (width < 0 || strlen(cp) > (size_t)width))
			width = strlen(cp);
		break;
	    }
#endif /* INET6 */

	default:
	    {
		u_char *s = (u_char *)sa->sa_data, *slim;

		slim =  sa->sa_len + (u_char *) sa;
		cplim = cp + sizeof(workbuf) - 6;
		snprintf(cp, len, "(%d)", sa->sa_family);
		len -= strlen(cp);
		cp += strlen(cp);
		if (len <= 0) {
			cp = workbuf;
			break;		/* overflow */
		}
		while (s < slim && cp < cplim) {
			snprintf(cp, len, " %02x", *s++);
			len -= strlen(cp);
			cp += strlen(cp);
			if (len <= 0)
				break;		/* overflow */
			if (s < slim) {
				snprintf(cp, len, "%02x", *s++);
				len -= strlen(cp);
				cp += strlen(cp);
				if (len <= 0)
					break;		/* overflow */
			}
		}
		cp = workbuf;
	    }
	}
	if (width < 0) {
		count = printf("%s ", cp);
	} else {
		if (nflag || wflag)
			count = printf("%-*s ", width, cp);
		else
			count = printf("%-*.*s ", width, width, cp);
	}
	return(count);
}
Exemplo n.º 12
0
int
sockaddr_snprintf(char * const sbuf, const size_t len, const char * const fmt,
    const struct sockaddr * const sa)
{
	const void *a = NULL;
	char abuf[1024], nbuf[1024], *addr = NULL;

	char Abuf[1024], pbuf[32], *name = NULL, *port = NULL;
	char *ebuf = &sbuf[len - 1], *buf = sbuf;
	const char *ptr, *s;
	int p = -1;
#ifdef HAVE_NETATALK_AT_H
	const struct sockaddr_at *sat = NULL;
#endif
	const struct sockaddr_in *sin4 = NULL;
	const struct sockaddr_in6 *sin6 = NULL;
	const struct sockaddr_un *sun = NULL;
#ifdef HAVE_NET_IF_DL_H
	const struct sockaddr_dl *sdl = NULL;
	char *w = NULL;
#endif
	int na = 1;

#define ADDC(c) do { if (buf < ebuf) *buf++ = c; else buf++; } \
	while (/*CONSTCOND*/0)
#define ADDS(p) do { for (s = p; *s; s++) ADDC(*s); } \
	while (/*CONSTCOND*/0)
#define ADDNA() do { if (na) ADDS("N/A"); } \
	while (/*CONSTCOND*/0)

	switch (sa->sa_family) {
	case AF_UNSPEC:
		goto done;
#ifdef HAVE_NETATALK_AT_H
	case AF_APPLETALK:
		sat = ((const struct sockaddr_at *)(const void *)sa);
		p = ntohs(sat->sat_port);
		(void)snprintf(addr = abuf, sizeof(abuf), "%u.%u",
			ntohs(sat->sat_addr.s_net), sat->sat_addr.s_node);
		(void)snprintf(port = pbuf, sizeof(pbuf), "%d", p);
		break;
#endif
	case AF_LOCAL:
		sun = ((const struct sockaddr_un *)(const void *)sa);
		(void)strlcpy(addr = abuf, sun->sun_path, sizeof(abuf));
		break;
	case AF_INET:
		sin4 = ((const struct sockaddr_in *)(const void *)sa);
		p = ntohs(sin4->sin_port);
		a = &sin4->sin_addr;
		break;
	case AF_INET6:
		sin6 = ((const struct sockaddr_in6 *)(const void *)sa);
		p = ntohs(sin6->sin6_port);
		a = &sin6->sin6_addr;
		break;
#ifdef HAVE_NET_IF_DL_H
	case AF_LINK:
		sdl = ((const struct sockaddr_dl *)(const void *)sa);
		(void)strlcpy(addr = abuf, link_ntoa(sdl), sizeof(abuf));
		if ((w = strchr(addr, ':')) != NULL) {
			*w++ = '\0';
			addr = w;
		}
		break;
#endif
	default:
		errno = EAFNOSUPPORT;
		return -1;
	}

	if (addr == abuf)
		name = addr;

	if (a && getnameinfo(sa, (socklen_t)SLEN(sa), addr = abuf,
	    (unsigned int)sizeof(abuf), NULL, 0,
	    NI_NUMERICHOST|NI_NUMERICSERV) != 0)
		return -1;

	for (ptr = fmt; *ptr; ptr++) {
		if (*ptr != '%') {
			ADDC(*ptr);
			continue;
		}
	  next_char:
		switch (*++ptr) {
		case '?':
			na = 0;
			goto next_char;
		case 'a':
			ADDS(addr);
			break;
		case 'p':
			if (p != -1) {
				(void)snprintf(nbuf, sizeof(nbuf), "%d", p);
				ADDS(nbuf);
			} else
				ADDNA();
			break;
		case 'f':
			(void)snprintf(nbuf, sizeof(nbuf), "%d", sa->sa_family);
			ADDS(nbuf);
			break;
		case 'l':
			(void)snprintf(nbuf, sizeof(nbuf), "%d", SLEN(sa));
			ADDS(nbuf);
			break;
		case 'A':
			if (name)
				ADDS(name);
			else if (!a)
				ADDNA();
			else {
				getnameinfo(sa, (socklen_t)SLEN(sa),
					name = Abuf,
					(unsigned int)sizeof(nbuf), NULL, 0, 0);
				ADDS(name);
			}
			break;
		case 'P':
			if (port)
				ADDS(port);
			else if (p == -1)
				ADDNA();
			else {
				getnameinfo(sa, (socklen_t)SLEN(sa), NULL, 0,
					port = pbuf,
					(unsigned int)sizeof(pbuf), 0);
				ADDS(port);
			}
			break;
		case 'I':
#ifdef HAVE_NET_IF_DL_H
			if (sdl && addr != abuf) {
				ADDS(abuf);
			} else
#endif
			{
				ADDNA();
			}
			break;
		case 'F':
			if (sin6) {
				(void)snprintf(nbuf, sizeof(nbuf), "%d",
				    sin6->sin6_flowinfo);
				ADDS(nbuf);
				break;
			} else {
				ADDNA();
			}
			break;
		case 'S':
			if (sin6) {
				(void)snprintf(nbuf, sizeof(nbuf), "%d",
				    sin6->sin6_scope_id);
				ADDS(nbuf);
				break;
			} else {
				ADDNA();
			}
			break;
		case 'R':
#ifdef HAVE_NETATALK_AT_H
			if (sat) {
				const struct netrange *n =
				    &sat->sat_range.r_netrange;
				(void)snprintf(nbuf, sizeof(nbuf),
				    "%d:[%d,%d]", n->nr_phase , n->nr_firstnet,
				    n->nr_lastnet);
				ADDS(nbuf);
			} else
#endif
			{
				ADDNA();
			}
			break;
		case 'D':
			switch (sa->sa_family) {
#ifdef HAVE_NETATALK_AT_H
			case AF_APPLETALK:
				debug_at(nbuf, sizeof(nbuf), sat);
				break;
#endif
			case AF_LOCAL:
				debug_un(nbuf, sizeof(nbuf), sun);
				break;
			case AF_INET:
				debug_in(nbuf, sizeof(nbuf), sin4);
				break;
			case AF_INET6:
				debug_in6(nbuf, sizeof(nbuf), sin6);
				break;
#ifdef HAVE_NET_IF_DL_H
			case AF_LINK:
				debug_dl(nbuf, sizeof(nbuf), sdl);
				break;
#endif
			default:
				abort();
			}
			ADDS(nbuf);
			break;
		default:
			ADDC('%');
			if (na == 0)
				ADDC('?');
			if (*ptr == '\0')
				goto done;
			/*FALLTHROUGH*/
		case '%':
			ADDC(*ptr);
			break;
		}
		na = 1;
	}
done:
	if (buf < ebuf)
		*buf = '\0';
	else if (len != 0)
		sbuf[len - 1] = '\0';
	return (int)(buf - sbuf);
}