HelenOS sources
This source file includes following definitions.
- addr128
- addr128_compare
- eth_addr_solicited_node
- host2addr128_t_be
- addr128_t_be2host
- inet_addr
- inet_naddr
- inet_addr6
- inet_naddr6
- inet_naddr_addr
- inet_addr_naddr
- inet_addr_any
- inet_naddr_any
- inet_addr_compare
- inet_addr_is_any
- inet_naddr_compare
- inet_naddr_compare_mask
- inet_addr_parse_v4
- inet_addr_parse_v6
- inet_addr_parse
- inet_naddr_parse
- inet_addr_format_v4
- inet_addr_format_v6
- inet_addr_format
- inet_naddr_format
- inet_addr_get
- inet_naddr_get
- inet_addr_set
- inet_naddr_set
- inet_addr_set6
- inet_naddr_set6
#include <assert.h>
#include <errno.h>
#include <inet/addr.h>
#include <inet/eth_addr.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <bitops.h>
#include <inttypes.h>
#include <str.h>
#define INET_PREFIXSTRSIZE 5
#define INET6_ADDRSTRLEN (8 * 4 + 7 + 1)
#if !(defined(__BE__) ^ defined(__LE__))
#error The architecture must be either big-endian or little-endian.
#endif
const addr32_t addr32_broadcast_all_hosts = 0xffffffff;
static eth_addr_t inet_eth_addr_solicited_node =
ETH_ADDR_INITIALIZER(0x33, 0x33, 0xff, 0, 0, 0);
static const inet_addr_t inet_addr_any_addr = {
.version = ip_v4,
.addr = 0
};
static const inet_addr_t inet_addr_any_addr6 = {
.version = ip_v6,
.addr6 = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
};
void addr128(const addr128_t src, addr128_t dst)
{
memcpy(dst, src, 16);
}
int addr128_compare(const addr128_t a, const addr128_t b)
{
return memcmp(a, b, 16) == 0;
}
void eth_addr_solicited_node(const addr128_t ip, eth_addr_t *mac)
{
uint8_t b[6];
mac->a = inet_eth_addr_solicited_node.a;
eth_addr_encode(&inet_eth_addr_solicited_node, b);
memcpy(&b[3], ip + 13, 3);
eth_addr_decode(b, mac);
}
void host2addr128_t_be(const addr128_t host, addr128_t be)
{
memcpy(be, host, 16);
}
void addr128_t_be2host(const addr128_t be, addr128_t host)
{
memcpy(host, be, 16);
}
void inet_addr(inet_addr_t *addr, uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
addr->version = ip_v4;
addr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
((addr32_t) c << 8) | ((addr32_t) d);
}
void inet_naddr(inet_naddr_t *naddr, uint8_t a, uint8_t b, uint8_t c, uint8_t d,
uint8_t prefix)
{
naddr->version = ip_v4;
naddr->addr = ((addr32_t) a << 24) | ((addr32_t) b << 16) |
((addr32_t) c << 8) | ((addr32_t) d);
naddr->prefix = prefix;
}
void inet_addr6(inet_addr_t *addr, uint16_t a, uint16_t b, uint16_t c,
uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h)
{
addr->version = ip_v6;
addr->addr6[0] = (a >> 8) & 0xff;
addr->addr6[1] = a & 0xff;
addr->addr6[2] = (b >> 8) & 0xff;
addr->addr6[3] = b & 0xff;
addr->addr6[4] = (c >> 8) & 0xff;
addr->addr6[5] = c & 0xff;
addr->addr6[6] = (d >> 8) & 0xff;
addr->addr6[7] = d & 0xff;
addr->addr6[8] = (e >> 8) & 0xff;
addr->addr6[9] = e & 0xff;
addr->addr6[10] = (f >> 8) & 0xff;
addr->addr6[11] = f & 0xff;
addr->addr6[12] = (g >> 8) & 0xff;
addr->addr6[13] = g & 0xff;
addr->addr6[14] = (h >> 8) & 0xff;
addr->addr6[15] = h & 0xff;
}
void inet_naddr6(inet_naddr_t *naddr, uint16_t a, uint16_t b, uint16_t c,
uint16_t d, uint16_t e, uint16_t f, uint16_t g, uint16_t h, uint8_t prefix)
{
naddr->version = ip_v6;
naddr->addr6[0] = (a >> 8) & 0xff;
naddr->addr6[1] = a & 0xff;
naddr->addr6[2] = (b >> 8) & 0xff;
naddr->addr6[3] = b & 0xff;
naddr->addr6[4] = (c >> 8) & 0xff;
naddr->addr6[5] = c & 0xff;
naddr->addr6[6] = (d >> 8) & 0xff;
naddr->addr6[7] = d & 0xff;
naddr->addr6[8] = (e >> 8) & 0xff;
naddr->addr6[9] = e & 0xff;
naddr->addr6[10] = (f >> 8) & 0xff;
naddr->addr6[11] = f & 0xff;
naddr->addr6[12] = (g >> 8) & 0xff;
naddr->addr6[13] = g & 0xff;
naddr->addr6[14] = (h >> 8) & 0xff;
naddr->addr6[15] = h & 0xff;
naddr->prefix = prefix;
}
void inet_naddr_addr(const inet_naddr_t *naddr, inet_addr_t *addr)
{
addr->version = naddr->version;
memcpy(addr->addr6, naddr->addr6, 16);
}
void inet_addr_naddr(const inet_addr_t *addr, uint8_t prefix,
inet_naddr_t *naddr)
{
naddr->version = addr->version;
memcpy(naddr->addr6, addr->addr6, 16);
naddr->prefix = prefix;
}
void inet_addr_any(inet_addr_t *addr)
{
addr->version = ip_any;
memset(addr->addr6, 0, 16);
}
void inet_naddr_any(inet_naddr_t *naddr)
{
naddr->version = ip_any;
memset(naddr->addr6, 0, 16);
naddr->prefix = 0;
}
int inet_addr_compare(const inet_addr_t *a, const inet_addr_t *b)
{
if (a->version != b->version)
return 0;
switch (a->version) {
case ip_v4:
return (a->addr == b->addr);
case ip_v6:
return addr128_compare(a->addr6, b->addr6);
default:
return 0;
}
}
int inet_addr_is_any(const inet_addr_t *addr)
{
return ((addr->version == ip_any) ||
(inet_addr_compare(addr, &inet_addr_any_addr)) ||
(inet_addr_compare(addr, &inet_addr_any_addr6)));
}
int inet_naddr_compare(const inet_naddr_t *naddr, const inet_addr_t *addr)
{
if (naddr->version != addr->version)
return 0;
switch (naddr->version) {
case ip_v4:
return (naddr->addr == addr->addr);
case ip_v6:
return addr128_compare(naddr->addr6, addr->addr6);
default:
return 0;
}
}
int inet_naddr_compare_mask(const inet_naddr_t *naddr, const inet_addr_t *addr)
{
if (naddr->version != addr->version)
return 0;
switch (naddr->version) {
case ip_v4:
if (naddr->prefix > 32)
return 0;
addr32_t mask =
BIT_RANGE(addr32_t, 31, 31 - (naddr->prefix - 1));
return ((naddr->addr & mask) == (addr->addr & mask));
case ip_v6:
if (naddr->prefix > 128)
return 0;
size_t pos = 0;
for (size_t i = 0; i < 16; i++) {
if (naddr->prefix < pos)
break;
if (naddr->prefix - pos > 8) {
if (naddr->addr6[i] != addr->addr6[i])
return 0;
} else {
uint8_t mask =
BIT_RANGE(uint8_t, 8, 8 - (naddr->prefix - pos - 1));
if ((naddr->addr6[i] & mask) != (addr->addr6[i] & mask))
return 0;
}
pos += 8;
}
return 1;
default:
return 0;
}
}
static errno_t inet_addr_parse_v4(const char *str, inet_addr_t *raddr,
int *prefix, char **endptr)
{
uint32_t a = 0;
uint8_t b;
char *cur = (char *)str;
size_t i = 0;
while (i < 4) {
errno_t rc = str_uint8_t(cur, (const char **)&cur, 10, false, &b);
if (rc != EOK)
return rc;
a = (a << 8) + b;
i++;
if (*cur != '.')
break;
if (i < 4)
cur++;
}
if (prefix != NULL) {
if (*cur != '/')
return EINVAL;
cur++;
*prefix = strtoul(cur, &cur, 10);
if (*prefix > 32)
return EINVAL;
}
if (i != 4)
return EINVAL;
if (endptr == NULL && *cur != '\0')
return EINVAL;
raddr->version = ip_v4;
raddr->addr = a;
if (endptr != NULL)
*endptr = cur;
return EOK;
}
static errno_t inet_addr_parse_v6(const char *str, inet_addr_t *raddr, int *prefix,
char **endptr)
{
uint8_t data[16];
int explicit_groups;
memset(data, 0, 16);
const char *cur = str;
size_t i = 0;
size_t wildcard_pos = (size_t) -1;
size_t wildcard_size = 0;
if ((str[0] == ':') && (str[1] == ':')) {
cur = str + 2;
wildcard_pos = 0;
wildcard_size = 16;
}
while (i < 16) {
uint16_t bioctet;
const char *gend;
errno_t rc = str_uint16_t(cur, &gend, 16, false, &bioctet);
if (rc != EOK)
break;
data[i] = (bioctet >> 8) & 0xff;
data[i + 1] = bioctet & 0xff;
if (wildcard_pos != (size_t) -1) {
if (wildcard_size < 2)
return EINVAL;
wildcard_size -= 2;
}
i += 2;
if (*gend != ':') {
cur = gend;
break;
}
if (i < 16) {
if (gend[1] == ':') {
if (wildcard_pos != (size_t) -1)
return EINVAL;
wildcard_pos = i;
wildcard_size = 16 - i;
cur = gend + 2;
continue;
}
}
cur = gend + 1;
}
explicit_groups = i;
if (prefix != NULL) {
if (*cur != '/')
return EINVAL;
cur++;
*prefix = strtoul(cur, (char **)&cur, 10);
if (*prefix > 128)
return EINVAL;
}
if (endptr == NULL && *cur != '\0')
return EINVAL;
if ((wildcard_pos != (size_t) -1) && (wildcard_size > 0)) {
size_t wildcard_shift = 16 - wildcard_size;
for (i = wildcard_pos + wildcard_shift; i > wildcard_pos; i--) {
size_t j = i - 1;
data[j + wildcard_size] = data[j];
data[j] = 0;
}
} else {
if (explicit_groups != 16)
return EINVAL;
}
raddr->version = ip_v6;
memcpy(raddr->addr6, data, 16);
if (endptr != NULL)
*endptr = (char *)cur;
return EOK;
}
errno_t inet_addr_parse(const char *text, inet_addr_t *addr, char **endptr)
{
errno_t rc;
rc = inet_addr_parse_v4(text, addr, NULL, endptr);
if (rc == EOK)
return EOK;
rc = inet_addr_parse_v6(text, addr, NULL, endptr);
if (rc == EOK)
return EOK;
return EINVAL;
}
errno_t inet_naddr_parse(const char *text, inet_naddr_t *naddr, char **endptr)
{
errno_t rc;
inet_addr_t addr;
int prefix;
rc = inet_addr_parse_v4(text, &addr, &prefix, endptr);
if (rc == EOK) {
inet_addr_naddr(&addr, prefix, naddr);
return EOK;
}
rc = inet_addr_parse_v6(text, &addr, &prefix, endptr);
if (rc == EOK) {
inet_addr_naddr(&addr, prefix, naddr);
return EOK;
}
return EINVAL;
}
static errno_t inet_addr_format_v4(addr32_t addr, char **bufp)
{
int rc;
rc = asprintf(bufp, "%u.%u.%u.%u", (addr >> 24) & 0xff,
(addr >> 16) & 0xff, (addr >> 8) & 0xff, addr & 0xff);
if (rc < 0)
return ENOMEM;
return EOK;
}
static errno_t inet_addr_format_v6(const addr128_t addr, char **bufp)
{
*bufp = (char *) malloc(INET6_ADDRSTRLEN);
if (*bufp == NULL)
return ENOMEM;
uint16_t zeroes[8];
uint16_t bioctets[8];
for (size_t i = 8; i > 0; i--) {
size_t j = i - 1;
bioctets[j] = (addr[j << 1] << 8) | addr[(j << 1) + 1];
if (bioctets[j] == 0) {
zeroes[j] = 1;
if (j < 7)
zeroes[j] += zeroes[j + 1];
} else
zeroes[j] = 0;
}
size_t wildcard_pos = (size_t) -1;
size_t wildcard_size = 0;
for (size_t i = 0; i < 8; i++) {
if (zeroes[i] > wildcard_size) {
wildcard_pos = i;
wildcard_size = zeroes[i];
}
}
char *cur = *bufp;
size_t rest = INET6_ADDRSTRLEN;
bool tail_zero = false;
int ret;
for (size_t i = 0; i < 8; i++) {
if ((i == wildcard_pos) && (wildcard_size > 1)) {
ret = snprintf(cur, rest, ":");
i += wildcard_size - 1;
tail_zero = true;
} else if (i == 0) {
ret = snprintf(cur, rest, "%" PRIx16, bioctets[i]);
tail_zero = false;
} else {
ret = snprintf(cur, rest, ":%" PRIx16, bioctets[i]);
tail_zero = false;
}
if (ret < 0)
return EINVAL;
cur += ret;
rest -= ret;
}
if (tail_zero)
(void) snprintf(cur, rest, ":");
return EOK;
}
errno_t inet_addr_format(const inet_addr_t *addr, char **bufp)
{
errno_t rc;
int ret;
rc = ENOTSUP;
switch (addr->version) {
case ip_any:
ret = asprintf(bufp, "none");
if (ret < 0)
return ENOMEM;
rc = EOK;
break;
case ip_v4:
rc = inet_addr_format_v4(addr->addr, bufp);
break;
case ip_v6:
rc = inet_addr_format_v6(addr->addr6, bufp);
break;
}
return rc;
}
errno_t inet_naddr_format(const inet_naddr_t *naddr, char **bufp)
{
errno_t rc;
int ret;
char *astr;
rc = ENOTSUP;
switch (naddr->version) {
case ip_any:
ret = asprintf(bufp, "none");
if (ret < 0)
return ENOMEM;
rc = EOK;
break;
case ip_v4:
rc = inet_addr_format_v4(naddr->addr, &astr);
if (rc != EOK)
return ENOMEM;
ret = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
if (ret < 0) {
free(astr);
return ENOMEM;
}
rc = EOK;
break;
case ip_v6:
rc = inet_addr_format_v6(naddr->addr6, &astr);
if (rc != EOK)
return ENOMEM;
ret = asprintf(bufp, "%s/%" PRIu8, astr, naddr->prefix);
if (ret < 0) {
free(astr);
return ENOMEM;
}
rc = EOK;
break;
}
return rc;
}
ip_ver_t inet_addr_get(const inet_addr_t *addr, addr32_t *v4, addr128_t *v6)
{
switch (addr->version) {
case ip_v4:
if (v4 != NULL)
*v4 = addr->addr;
break;
case ip_v6:
if (v6 != NULL)
memcpy(*v6, addr->addr6, 16);
break;
default:
assert(false);
break;
}
return addr->version;
}
ip_ver_t inet_naddr_get(const inet_naddr_t *naddr, addr32_t *v4, addr128_t *v6,
uint8_t *prefix)
{
switch (naddr->version) {
case ip_v4:
if (v4 != NULL)
*v4 = naddr->addr;
if (prefix != NULL)
*prefix = naddr->prefix;
break;
case ip_v6:
if (v6 != NULL)
memcpy(*v6, naddr->addr6, 16);
if (prefix != NULL)
*prefix = naddr->prefix;
break;
default:
assert(false);
break;
}
return naddr->version;
}
void inet_addr_set(addr32_t v4, inet_addr_t *addr)
{
addr->version = ip_v4;
addr->addr = v4;
}
void inet_naddr_set(addr32_t v4, uint8_t prefix, inet_naddr_t *naddr)
{
naddr->version = ip_v4;
naddr->addr = v4;
naddr->prefix = prefix;
}
void inet_addr_set6(addr128_t v6, inet_addr_t *addr)
{
addr->version = ip_v6;
memcpy(addr->addr6, v6, 16);
}
void inet_naddr_set6(addr128_t v6, uint8_t prefix, inet_naddr_t *naddr)
{
naddr->version = ip_v6;
memcpy(naddr->addr6, v6, 16);
naddr->prefix = prefix;
}
HelenOS homepage, sources at GitHub