xref: /dflybsd-src/contrib/dhcpcd/src/sa.c (revision 6a6d63c5317abf314a78f8c8300ef73c2bc0c39e)
18d36e1dfSRoy Marples /* SPDX-License-Identifier: BSD-2-Clause */
27827cba2SAaron LI /*
37827cba2SAaron LI  * Socket Address handling for dhcpcd
480aa9461SRoy Marples  * Copyright (c) 2015-2023 Roy Marples <roy@marples.name>
57827cba2SAaron LI  * All rights reserved
67827cba2SAaron LI 
77827cba2SAaron LI  * Redistribution and use in source and binary forms, with or without
87827cba2SAaron LI  * modification, are permitted provided that the following conditions
97827cba2SAaron LI  * are met:
107827cba2SAaron LI  * 1. Redistributions of source code must retain the above copyright
117827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer.
127827cba2SAaron LI  * 2. Redistributions in binary form must reproduce the above copyright
137827cba2SAaron LI  *    notice, this list of conditions and the following disclaimer in the
147827cba2SAaron LI  *    documentation and/or other materials provided with the distribution.
157827cba2SAaron LI  *
167827cba2SAaron LI  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
177827cba2SAaron LI  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
187827cba2SAaron LI  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
197827cba2SAaron LI  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
207827cba2SAaron LI  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
217827cba2SAaron LI  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
227827cba2SAaron LI  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
237827cba2SAaron LI  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
247827cba2SAaron LI  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
257827cba2SAaron LI  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
267827cba2SAaron LI  * SUCH DAMAGE.
277827cba2SAaron LI  */
287827cba2SAaron LI 
297827cba2SAaron LI #include <sys/socket.h>
307827cba2SAaron LI #include <sys/types.h>
317827cba2SAaron LI 
327827cba2SAaron LI #include <arpa/inet.h>
337827cba2SAaron LI #ifdef AF_LINK
347827cba2SAaron LI #include <net/if_dl.h>
35d4fb1e02SRoy Marples #elif defined(AF_PACKET)
367827cba2SAaron LI #include <linux/if_packet.h>
377827cba2SAaron LI #endif
387827cba2SAaron LI 
397827cba2SAaron LI #include <assert.h>
407827cba2SAaron LI #include <errno.h>
418d36e1dfSRoy Marples #include <stdbool.h>
427827cba2SAaron LI #include <stddef.h>
437827cba2SAaron LI #include <stdio.h>
447827cba2SAaron LI #include <stdint.h>
457827cba2SAaron LI #include <string.h>
467827cba2SAaron LI 
477827cba2SAaron LI #include "config.h"
487827cba2SAaron LI #include "common.h"
497827cba2SAaron LI #include "sa.h"
507827cba2SAaron LI 
517827cba2SAaron LI #ifndef NDEBUG
527827cba2SAaron LI static bool sa_inprefix;
537827cba2SAaron LI #endif
547827cba2SAaron LI 
557827cba2SAaron LI socklen_t
sa_addroffset(const struct sockaddr * sa)567827cba2SAaron LI sa_addroffset(const struct sockaddr *sa)
577827cba2SAaron LI {
587827cba2SAaron LI 
597827cba2SAaron LI 	assert(sa != NULL);
607827cba2SAaron LI 	switch(sa->sa_family) {
617827cba2SAaron LI #ifdef INET
627827cba2SAaron LI 	case AF_INET:
637827cba2SAaron LI 		return offsetof(struct sockaddr_in, sin_addr) +
647827cba2SAaron LI 		       offsetof(struct in_addr, s_addr);
657827cba2SAaron LI #endif /* INET */
667827cba2SAaron LI #ifdef INET6
677827cba2SAaron LI 	case AF_INET6:
687827cba2SAaron LI 		return offsetof(struct sockaddr_in6, sin6_addr) +
697827cba2SAaron LI 		       offsetof(struct in6_addr, s6_addr);
707827cba2SAaron LI #endif /* INET6 */
717827cba2SAaron LI 	default:
727827cba2SAaron LI 		errno = EAFNOSUPPORT;
737827cba2SAaron LI 		return 0;
747827cba2SAaron LI 	}
757827cba2SAaron LI }
767827cba2SAaron LI 
777827cba2SAaron LI socklen_t
sa_addrlen(const struct sockaddr * sa)787827cba2SAaron LI sa_addrlen(const struct sockaddr *sa)
797827cba2SAaron LI {
807827cba2SAaron LI #define membersize(type, member) sizeof(((type *)0)->member)
817827cba2SAaron LI 	assert(sa != NULL);
827827cba2SAaron LI 	switch(sa->sa_family) {
837827cba2SAaron LI #ifdef INET
847827cba2SAaron LI 	case AF_INET:
857827cba2SAaron LI 		return membersize(struct in_addr, s_addr);
867827cba2SAaron LI #endif /* INET */
877827cba2SAaron LI #ifdef INET6
887827cba2SAaron LI 	case AF_INET6:
897827cba2SAaron LI 		return membersize(struct in6_addr, s6_addr);
907827cba2SAaron LI #endif /* INET6 */
917827cba2SAaron LI 	default:
927827cba2SAaron LI 		errno = EAFNOSUPPORT;
937827cba2SAaron LI 		return 0;
947827cba2SAaron LI 	}
957827cba2SAaron LI }
967827cba2SAaron LI 
978d36e1dfSRoy Marples #ifndef HAVE_SA_LEN
988d36e1dfSRoy Marples socklen_t
sa_len(const struct sockaddr * sa)998d36e1dfSRoy Marples sa_len(const struct sockaddr *sa)
1008d36e1dfSRoy Marples {
1018d36e1dfSRoy Marples 
1028d36e1dfSRoy Marples 	switch (sa->sa_family) {
1038d36e1dfSRoy Marples #ifdef AF_LINK
1048d36e1dfSRoy Marples 	case AF_LINK:
1058d36e1dfSRoy Marples 		return sizeof(struct sockaddr_dl);
1068d36e1dfSRoy Marples #endif
1078d36e1dfSRoy Marples #ifdef AF_PACKET
1088d36e1dfSRoy Marples 	case AF_PACKET:
1098d36e1dfSRoy Marples 		return sizeof(struct sockaddr_ll);
1108d36e1dfSRoy Marples #endif
1118d36e1dfSRoy Marples 	case AF_INET:
1128d36e1dfSRoy Marples 		return sizeof(struct sockaddr_in);
1138d36e1dfSRoy Marples 	case AF_INET6:
1148d36e1dfSRoy Marples 		return sizeof(struct sockaddr_in6);
1158d36e1dfSRoy Marples 	default:
1168d36e1dfSRoy Marples 		return sizeof(struct sockaddr);
1178d36e1dfSRoy Marples 	}
1188d36e1dfSRoy Marples }
1198d36e1dfSRoy Marples #endif
1208d36e1dfSRoy Marples 
1217827cba2SAaron LI bool
sa_is_unspecified(const struct sockaddr * sa)1227827cba2SAaron LI sa_is_unspecified(const struct sockaddr *sa)
1237827cba2SAaron LI {
1247827cba2SAaron LI 
1257827cba2SAaron LI 	assert(sa != NULL);
1267827cba2SAaron LI 	switch(sa->sa_family) {
1277827cba2SAaron LI 	case AF_UNSPEC:
1287827cba2SAaron LI 		return true;
1297827cba2SAaron LI #ifdef INET
1307827cba2SAaron LI 	case AF_INET:
1317827cba2SAaron LI 		return satocsin(sa)->sin_addr.s_addr == INADDR_ANY;
1327827cba2SAaron LI #endif /* INET */
1337827cba2SAaron LI #ifdef INET6
1347827cba2SAaron LI 	case AF_INET6:
1357827cba2SAaron LI 		return IN6_IS_ADDR_UNSPECIFIED(&satocsin6(sa)->sin6_addr);
1367827cba2SAaron LI #endif /* INET6 */
1377827cba2SAaron LI 	default:
1387827cba2SAaron LI 		errno = EAFNOSUPPORT;
1397827cba2SAaron LI 		return false;
1407827cba2SAaron LI 	}
1417827cba2SAaron LI }
1427827cba2SAaron LI 
1437827cba2SAaron LI #ifdef INET6
1447827cba2SAaron LI #ifndef IN6MASK128
1457827cba2SAaron LI #define IN6MASK128 {{{ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, \
1467827cba2SAaron LI 		       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }}}
1477827cba2SAaron LI #endif
1487827cba2SAaron LI static const struct in6_addr in6allones = IN6MASK128;
1497827cba2SAaron LI #endif
1507827cba2SAaron LI 
1517827cba2SAaron LI bool
sa_is_allones(const struct sockaddr * sa)1527827cba2SAaron LI sa_is_allones(const struct sockaddr *sa)
1537827cba2SAaron LI {
1547827cba2SAaron LI 
1557827cba2SAaron LI 	assert(sa != NULL);
1567827cba2SAaron LI 	switch(sa->sa_family) {
1577827cba2SAaron LI 	case AF_UNSPEC:
1587827cba2SAaron LI 		return false;
1597827cba2SAaron LI #ifdef INET
1607827cba2SAaron LI 	case AF_INET:
1617827cba2SAaron LI 	{
1627827cba2SAaron LI 		const struct sockaddr_in *sin;
1637827cba2SAaron LI 
1647827cba2SAaron LI 		sin = satocsin(sa);
1657827cba2SAaron LI 		return sin->sin_addr.s_addr == INADDR_BROADCAST;
1667827cba2SAaron LI 	}
1677827cba2SAaron LI #endif /* INET */
1687827cba2SAaron LI #ifdef INET6
1697827cba2SAaron LI 	case AF_INET6:
1707827cba2SAaron LI 	{
1717827cba2SAaron LI 		const struct sockaddr_in6 *sin6;
1727827cba2SAaron LI 
1737827cba2SAaron LI 		sin6 = satocsin6(sa);
1747827cba2SAaron LI 		return IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr, &in6allones);
1757827cba2SAaron LI 	}
1767827cba2SAaron LI #endif /* INET6 */
1777827cba2SAaron LI 	default:
1787827cba2SAaron LI 		errno = EAFNOSUPPORT;
1797827cba2SAaron LI 		return false;
1807827cba2SAaron LI 	}
1817827cba2SAaron LI }
1827827cba2SAaron LI 
1837827cba2SAaron LI bool
sa_is_loopback(const struct sockaddr * sa)1847827cba2SAaron LI sa_is_loopback(const struct sockaddr *sa)
1857827cba2SAaron LI {
1867827cba2SAaron LI 
1877827cba2SAaron LI 	assert(sa != NULL);
1887827cba2SAaron LI 	switch(sa->sa_family) {
1897827cba2SAaron LI 	case AF_UNSPEC:
1907827cba2SAaron LI 		return false;
1917827cba2SAaron LI #ifdef INET
1927827cba2SAaron LI 	case AF_INET:
1937827cba2SAaron LI 	{
1947827cba2SAaron LI 		const struct sockaddr_in *sin;
1957827cba2SAaron LI 
1967827cba2SAaron LI 		sin = satocsin(sa);
1977827cba2SAaron LI 		return sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK);
1987827cba2SAaron LI 	}
1997827cba2SAaron LI #endif /* INET */
2007827cba2SAaron LI #ifdef INET6
2017827cba2SAaron LI 	case AF_INET6:
2027827cba2SAaron LI 	{
2037827cba2SAaron LI 		const struct sockaddr_in6 *sin6;
2047827cba2SAaron LI 
2057827cba2SAaron LI 		sin6 = satocsin6(sa);
2067827cba2SAaron LI 		return IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr);
2077827cba2SAaron LI 	}
2087827cba2SAaron LI #endif /* INET6 */
2097827cba2SAaron LI 	default:
2107827cba2SAaron LI 		errno = EAFNOSUPPORT;
2117827cba2SAaron LI 		return false;
2127827cba2SAaron LI 	}
2137827cba2SAaron LI }
2147827cba2SAaron LI 
2157827cba2SAaron LI int
sa_toprefix(const struct sockaddr * sa)2167827cba2SAaron LI sa_toprefix(const struct sockaddr *sa)
2177827cba2SAaron LI {
2187827cba2SAaron LI 	int prefix;
2197827cba2SAaron LI 
2207827cba2SAaron LI 	assert(sa != NULL);
2217827cba2SAaron LI 	switch(sa->sa_family) {
2227827cba2SAaron LI #ifdef INET
2237827cba2SAaron LI 	case AF_INET:
2247827cba2SAaron LI 	{
2257827cba2SAaron LI 		const struct sockaddr_in *sin;
2267827cba2SAaron LI 		uint32_t mask;
2277827cba2SAaron LI 
2287827cba2SAaron LI 		sin = satocsin(sa);
2297827cba2SAaron LI 		if (sin->sin_addr.s_addr == INADDR_ANY) {
2307827cba2SAaron LI 			prefix = 0;
2317827cba2SAaron LI 			break;
2327827cba2SAaron LI 		}
2337827cba2SAaron LI 		mask = ntohl(sin->sin_addr.s_addr);
2347827cba2SAaron LI 		prefix = 33 - ffs((int)mask);	/* 33 - (1 .. 32) -> 32 .. 1 */
2357827cba2SAaron LI 		if (prefix < 32) {		/* more than 1 bit in mask */
2367827cba2SAaron LI 			/* check for non-contig netmask */
2377827cba2SAaron LI 			if ((mask^(((1U << prefix)-1) << (32 - prefix))) != 0) {
2387827cba2SAaron LI 				errno = EINVAL;
2397827cba2SAaron LI 				return -1;	/* noncontig, no pfxlen */
2407827cba2SAaron LI 			}
2417827cba2SAaron LI 		}
2427827cba2SAaron LI 		break;
2437827cba2SAaron LI 	}
2447827cba2SAaron LI #endif
2457827cba2SAaron LI #ifdef INET6
2467827cba2SAaron LI 	case AF_INET6:
2477827cba2SAaron LI 	{
2487827cba2SAaron LI 		const struct sockaddr_in6 *sin6;
2497827cba2SAaron LI 		int x, y;
2507827cba2SAaron LI 		const uint8_t *lim, *p;
2517827cba2SAaron LI 
2527827cba2SAaron LI 		sin6 = satocsin6(sa);
2537827cba2SAaron LI 		p = (const uint8_t *)sin6->sin6_addr.s6_addr;
2547827cba2SAaron LI 		lim = p + sizeof(sin6->sin6_addr.s6_addr);
2557827cba2SAaron LI 		for (x = 0; p < lim; x++, p++) {
2567827cba2SAaron LI 			if (*p != 0xff)
2577827cba2SAaron LI 				break;
2587827cba2SAaron LI 		}
2597827cba2SAaron LI 		y = 0;
2607827cba2SAaron LI 		if (p < lim) {
2617827cba2SAaron LI 			for (y = 0; y < NBBY; y++) {
2627827cba2SAaron LI 				if ((*p & (0x80 >> y)) == 0)
2637827cba2SAaron LI 					break;
2647827cba2SAaron LI 			}
2657827cba2SAaron LI 		}
2667827cba2SAaron LI 
2677827cba2SAaron LI 		/*
2687827cba2SAaron LI 		 * when the limit pointer is given, do a stricter check on the
2697827cba2SAaron LI 		 * remaining bits.
2707827cba2SAaron LI 		 */
2717827cba2SAaron LI 		if (p < lim) {
2727827cba2SAaron LI 			if (y != 0 && (*p & (0x00ff >> y)) != 0)
2737827cba2SAaron LI 				return 0;
2747827cba2SAaron LI 			for (p = p + 1; p < lim; p++)
2757827cba2SAaron LI 				if (*p != 0)
2767827cba2SAaron LI 					return 0;
2777827cba2SAaron LI 		}
2787827cba2SAaron LI 
2797827cba2SAaron LI 		prefix = x * NBBY + y;
2807827cba2SAaron LI 		break;
2817827cba2SAaron LI 	}
2827827cba2SAaron LI #endif
2837827cba2SAaron LI 	default:
2847827cba2SAaron LI 		errno = EAFNOSUPPORT;
2857827cba2SAaron LI 		return -1;
2867827cba2SAaron LI 	}
2877827cba2SAaron LI 
2887827cba2SAaron LI #ifndef NDEBUG
2897827cba2SAaron LI 	/* Ensure the calculation is correct */
2907827cba2SAaron LI 	if (!sa_inprefix) {
291d4fb1e02SRoy Marples 		union sa_ss ss = { .sa = { .sa_family = sa->sa_family } };
2927827cba2SAaron LI 
2937827cba2SAaron LI 		sa_inprefix = true;
2947827cba2SAaron LI 		sa_fromprefix(&ss.sa, prefix);
2957827cba2SAaron LI 		assert(sa_cmp(sa, &ss.sa) == 0);
2967827cba2SAaron LI 		sa_inprefix = false;
2977827cba2SAaron LI 	}
2987827cba2SAaron LI #endif
2997827cba2SAaron LI 
3007827cba2SAaron LI 	return prefix;
3017827cba2SAaron LI }
3027827cba2SAaron LI 
303*54175cefSRoy Marples static void
ipbytes_fromprefix(uint8_t * ap,int prefix,int max_prefix)304*54175cefSRoy Marples ipbytes_fromprefix(uint8_t *ap, int prefix, int max_prefix)
305*54175cefSRoy Marples {
306*54175cefSRoy Marples 	int bytes, bits, i;
307*54175cefSRoy Marples 
308*54175cefSRoy Marples 	bytes = prefix / NBBY;
309*54175cefSRoy Marples 	bits = prefix % NBBY;
310*54175cefSRoy Marples 
311*54175cefSRoy Marples 	for (i = 0; i < bytes; i++)
312*54175cefSRoy Marples 		*ap++ = 0xff;
313*54175cefSRoy Marples 	if (bits) {
314*54175cefSRoy Marples 		uint8_t a;
315*54175cefSRoy Marples 
316*54175cefSRoy Marples 		a = 0xff;
317*54175cefSRoy Marples 		a  = (uint8_t)(a << (8 - bits));
318*54175cefSRoy Marples 		*ap++ = a;
319*54175cefSRoy Marples 	}
320*54175cefSRoy Marples 	bytes = (max_prefix - prefix) / NBBY;
321*54175cefSRoy Marples 	for (i = 0; i < bytes; i++)
322*54175cefSRoy Marples 		*ap++ = 0x00;
323*54175cefSRoy Marples }
324*54175cefSRoy Marples 
325*54175cefSRoy Marples void
in6_addr_fromprefix(struct in6_addr * addr,int prefix)326*54175cefSRoy Marples in6_addr_fromprefix(struct in6_addr *addr, int prefix)
327*54175cefSRoy Marples {
328*54175cefSRoy Marples 	ipbytes_fromprefix((uint8_t *)addr, prefix, 128);
329*54175cefSRoy Marples }
330*54175cefSRoy Marples 
3317827cba2SAaron LI int
sa_fromprefix(struct sockaddr * sa,int prefix)3327827cba2SAaron LI sa_fromprefix(struct sockaddr *sa, int prefix)
3337827cba2SAaron LI {
3347827cba2SAaron LI 	uint8_t *ap;
335*54175cefSRoy Marples 	int max_prefix;
3367827cba2SAaron LI 
3377827cba2SAaron LI 	switch (sa->sa_family) {
3387827cba2SAaron LI #ifdef INET
3397827cba2SAaron LI 	case AF_INET:
3407827cba2SAaron LI 		max_prefix = 32;
3417827cba2SAaron LI #ifdef HAVE_SA_LEN
3427827cba2SAaron LI 		sa->sa_len = sizeof(struct sockaddr_in);
3437827cba2SAaron LI #endif
3447827cba2SAaron LI 		break;
3457827cba2SAaron LI #endif
3467827cba2SAaron LI #ifdef INET6
3477827cba2SAaron LI 	case AF_INET6:
3487827cba2SAaron LI 		max_prefix = 128;
3497827cba2SAaron LI #ifdef HAVE_SA_LEN
3507827cba2SAaron LI 		sa->sa_len = sizeof(struct sockaddr_in6);
3517827cba2SAaron LI #endif
3527827cba2SAaron LI 		break;
3537827cba2SAaron LI #endif
3547827cba2SAaron LI 	default:
3557827cba2SAaron LI 		errno = EAFNOSUPPORT;
3567827cba2SAaron LI 		return -1;
3577827cba2SAaron LI 	}
3587827cba2SAaron LI 
3597827cba2SAaron LI 	ap = (uint8_t *)sa + sa_addroffset(sa);
360*54175cefSRoy Marples 	ipbytes_fromprefix(ap, prefix, max_prefix);
3617827cba2SAaron LI 
3627827cba2SAaron LI #ifndef NDEBUG
3637827cba2SAaron LI 	/* Ensure the calculation is correct */
3647827cba2SAaron LI 	if (!sa_inprefix) {
3657827cba2SAaron LI 		sa_inprefix = true;
3667827cba2SAaron LI 		assert(sa_toprefix(sa) == prefix);
3677827cba2SAaron LI 		sa_inprefix = false;
3687827cba2SAaron LI 	}
3697827cba2SAaron LI #endif
3707827cba2SAaron LI 	return 0;
3717827cba2SAaron LI }
3727827cba2SAaron LI 
3737827cba2SAaron LI /* inet_ntop, but for sockaddr. */
3747827cba2SAaron LI const char *
sa_addrtop(const struct sockaddr * sa,char * buf,socklen_t len)3757827cba2SAaron LI sa_addrtop(const struct sockaddr *sa, char *buf, socklen_t len)
3767827cba2SAaron LI {
3777827cba2SAaron LI 	const void *addr;
3787827cba2SAaron LI 
3797827cba2SAaron LI 	assert(buf != NULL);
3808d36e1dfSRoy Marples 	assert(len > 0);
3818d36e1dfSRoy Marples 
3828d36e1dfSRoy Marples 	if (sa->sa_family == 0) {
3838d36e1dfSRoy Marples 		*buf = '\0';
3848d36e1dfSRoy Marples 		return NULL;
3858d36e1dfSRoy Marples 	}
3868d36e1dfSRoy Marples 
3877827cba2SAaron LI #ifdef AF_LINK
3887827cba2SAaron LI #ifndef CLLADDR
3897827cba2SAaron LI #define CLLADDR(sdl) (const void *)((sdl)->sdl_data + (sdl)->sdl_nlen)
3907827cba2SAaron LI #endif
3917827cba2SAaron LI 	if (sa->sa_family == AF_LINK) {
3927827cba2SAaron LI 		const struct sockaddr_dl *sdl;
3937827cba2SAaron LI 
3947827cba2SAaron LI 		sdl = (const void *)sa;
3957827cba2SAaron LI 		if (sdl->sdl_alen == 0) {
3967827cba2SAaron LI 			if (snprintf(buf, len, "link#%d", sdl->sdl_index) == -1)
3977827cba2SAaron LI 				return NULL;
3987827cba2SAaron LI 			return buf;
3997827cba2SAaron LI 		}
4007827cba2SAaron LI 		return hwaddr_ntoa(CLLADDR(sdl), sdl->sdl_alen, buf, len);
4017827cba2SAaron LI 	}
402d4fb1e02SRoy Marples #elif defined(AF_PACKET)
4037827cba2SAaron LI 	if (sa->sa_family == AF_PACKET) {
4047827cba2SAaron LI 		const struct sockaddr_ll *sll;
4057827cba2SAaron LI 
4067827cba2SAaron LI 		sll = (const void *)sa;
4077827cba2SAaron LI 		return hwaddr_ntoa(sll->sll_addr, sll->sll_halen, buf, len);
4087827cba2SAaron LI 	}
4097827cba2SAaron LI #endif
4107827cba2SAaron LI 	addr = (const char *)sa + sa_addroffset(sa);
4117827cba2SAaron LI 	return inet_ntop(sa->sa_family, addr, buf, len);
4127827cba2SAaron LI }
4137827cba2SAaron LI 
4147827cba2SAaron LI int
sa_cmp(const struct sockaddr * sa1,const struct sockaddr * sa2)4157827cba2SAaron LI sa_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2)
4167827cba2SAaron LI {
4177827cba2SAaron LI 	socklen_t offset, len;
4187827cba2SAaron LI 
4197827cba2SAaron LI 	assert(sa1 != NULL);
4207827cba2SAaron LI 	assert(sa2 != NULL);
4217827cba2SAaron LI 
4227827cba2SAaron LI 	/* Treat AF_UNSPEC as the unspecified address. */
4237827cba2SAaron LI 	if ((sa1->sa_family == AF_UNSPEC || sa2->sa_family == AF_UNSPEC) &&
4247827cba2SAaron LI 	    sa_is_unspecified(sa1) && sa_is_unspecified(sa2))
4257827cba2SAaron LI 		return 0;
4267827cba2SAaron LI 
4277827cba2SAaron LI 	if (sa1->sa_family != sa2->sa_family)
4287827cba2SAaron LI 		return sa1->sa_family - sa2->sa_family;
4297827cba2SAaron LI 
4307827cba2SAaron LI #ifdef HAVE_SA_LEN
4317827cba2SAaron LI 	len = MIN(sa1->sa_len, sa2->sa_len);
4327827cba2SAaron LI #endif
4337827cba2SAaron LI 
4347827cba2SAaron LI 	switch (sa1->sa_family) {
4357827cba2SAaron LI #ifdef INET
4367827cba2SAaron LI 	case AF_INET:
4377827cba2SAaron LI 		offset = offsetof(struct sockaddr_in, sin_addr);
4387827cba2SAaron LI #ifdef HAVE_SA_LEN
4397827cba2SAaron LI 		len -= offset;
4407827cba2SAaron LI 		len = MIN(len, sizeof(struct in_addr));
4417827cba2SAaron LI #else
4427827cba2SAaron LI 		len = sizeof(struct in_addr);
4437827cba2SAaron LI #endif
4447827cba2SAaron LI 		break;
4457827cba2SAaron LI #endif
4467827cba2SAaron LI #ifdef INET6
4477827cba2SAaron LI 	case AF_INET6:
4487827cba2SAaron LI 		offset = offsetof(struct sockaddr_in6, sin6_addr);
4497827cba2SAaron LI #ifdef HAVE_SA_LEN
4507827cba2SAaron LI 		len -= offset;
4517827cba2SAaron LI 		len = MIN(len, sizeof(struct in6_addr));
4527827cba2SAaron LI #else
4537827cba2SAaron LI 		len = sizeof(struct in6_addr);
4547827cba2SAaron LI #endif
4557827cba2SAaron LI 		break;
4567827cba2SAaron LI #endif
4577827cba2SAaron LI 	default:
4587827cba2SAaron LI 		offset = 0;
4597827cba2SAaron LI #ifndef HAVE_SA_LEN
4607827cba2SAaron LI 		len = sizeof(struct sockaddr);
4617827cba2SAaron LI #endif
4627827cba2SAaron LI 		break;
4637827cba2SAaron LI 	}
4647827cba2SAaron LI 
4657827cba2SAaron LI 	return memcmp((const char *)sa1 + offset,
4667827cba2SAaron LI 	    (const char *)sa2 + offset,
4677827cba2SAaron LI 	    len);
4687827cba2SAaron LI }
4697827cba2SAaron LI 
4707827cba2SAaron LI #ifdef INET
4717827cba2SAaron LI void
sa_in_init(struct sockaddr * sa,const struct in_addr * addr)4727827cba2SAaron LI sa_in_init(struct sockaddr *sa, const struct in_addr *addr)
4737827cba2SAaron LI {
4747827cba2SAaron LI 	struct sockaddr_in *sin;
4757827cba2SAaron LI 
4767827cba2SAaron LI 	assert(sa != NULL);
4777827cba2SAaron LI 	assert(addr != NULL);
4787827cba2SAaron LI 	sin = satosin(sa);
4797827cba2SAaron LI 	sin->sin_family = AF_INET;
4807827cba2SAaron LI #ifdef HAVE_SA_LEN
4817827cba2SAaron LI 	sin->sin_len = sizeof(*sin);
4827827cba2SAaron LI #endif
4837827cba2SAaron LI 	sin->sin_addr.s_addr = addr->s_addr;
4847827cba2SAaron LI }
4857827cba2SAaron LI #endif
4867827cba2SAaron LI 
4877827cba2SAaron LI #ifdef INET6
4887827cba2SAaron LI void
sa_in6_init(struct sockaddr * sa,const struct in6_addr * addr)4897827cba2SAaron LI sa_in6_init(struct sockaddr *sa, const struct in6_addr *addr)
4907827cba2SAaron LI {
4917827cba2SAaron LI 	struct sockaddr_in6 *sin6;
4927827cba2SAaron LI 
4937827cba2SAaron LI 	assert(sa != NULL);
4947827cba2SAaron LI 	assert(addr != NULL);
4957827cba2SAaron LI 	sin6 = satosin6(sa);
4967827cba2SAaron LI 	sin6->sin6_family = AF_INET6;
4977827cba2SAaron LI #ifdef HAVE_SA_LEN
4987827cba2SAaron LI 	sin6->sin6_len = sizeof(*sin6);
4997827cba2SAaron LI #endif
5007827cba2SAaron LI 	memcpy(&sin6->sin6_addr.s6_addr, &addr->s6_addr,
5017827cba2SAaron LI 	    sizeof(sin6->sin6_addr.s6_addr));
5027827cba2SAaron LI }
5037827cba2SAaron LI #endif
504