blob: 39ff5e5baeb8fa68395a914dfe65ede534e42939 [file] [log] [blame]
#ifndef ZIRCON_THIRD_PARTY_ULIB_MUSL_SRC_NETWORK_GETIFADDRS_H_
#define ZIRCON_THIRD_PARTY_ULIB_MUSL_SRC_NETWORK_GETIFADDRS_H_
#include <errno.h>
#include <ifaddrs.h>
#include <net/if.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include "netlink.h"
#define IFADDRS_HASH_SIZE 64
/* getifaddrs() reports hardware addresses with PF_PACKET that implies
* struct sockaddr_ll. But e.g. Infiniband socket address length is
* longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
* to extend ssl_addr - callers should be able to still use it. */
struct sockaddr_ll_hack {
unsigned short sll_family, sll_protocol;
int sll_ifindex;
unsigned short sll_hatype;
unsigned char sll_pkttype;
socklen_t sll_halen;
unsigned char sll_addr[24];
};
union sockany {
struct sockaddr sa;
struct sockaddr_ll_hack ll;
struct sockaddr_in v4;
struct sockaddr_in6 v6;
};
struct ifaddrs_storage {
struct ifaddrs ifa;
struct ifaddrs_storage* hash_next;
union sockany addr, netmask, ifu;
unsigned int index;
char name[IFNAMSIZ + 1];
};
struct ifaddrs_ctx {
struct ifaddrs_storage* first;
struct ifaddrs_storage* last;
struct ifaddrs_storage* hash[IFADDRS_HASH_SIZE];
};
static inline void copy_addr(struct sockaddr** r, sa_family_t af, union sockany* sa, void* addr,
socklen_t addrlen, uint32_t ifindex) {
uint8_t* dst;
size_t len;
switch (af) {
case AF_INET:
dst = (uint8_t*)&sa->v4.sin_addr;
len = 4;
break;
case AF_INET6:
dst = (uint8_t*)&sa->v6.sin6_addr;
len = 16;
if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
sa->v6.sin6_scope_id = ifindex;
break;
default:
return;
}
if (addrlen < len)
return;
sa->sa.sa_family = af;
memcpy(dst, addr, len);
*r = &sa->sa;
}
static inline void gen_netmask(struct sockaddr** r, sa_family_t af, union sockany* sa,
uint8_t prefixlen) {
uint8_t addr[16] = {};
size_t i;
if (prefixlen > 8 * sizeof(addr))
prefixlen = 8 * sizeof(addr);
i = prefixlen / 8;
memset(addr, 0xff, i);
if (i < sizeof(addr))
addr[i++] = (uint8_t)(0xff << (8 - (prefixlen % 8)));
copy_addr(r, af, sa, addr, sizeof(addr), 0);
}
static inline void copy_lladdr(struct sockaddr** r, union sockany* sa, void* addr,
socklen_t addrlen, uint32_t ifindex, unsigned short hatype) {
if (addrlen > sizeof(sa->ll.sll_addr))
return;
sa->ll.sll_family = AF_PACKET;
sa->ll.sll_ifindex = ifindex;
sa->ll.sll_hatype = hatype;
sa->ll.sll_halen = addrlen;
memcpy(sa->ll.sll_addr, addr, addrlen);
*r = &sa->sa;
}
#endif // ZIRCON_THIRD_PARTY_ULIB_MUSL_SRC_NETWORK_GETIFADDRS_H_