mirror of https://gerrit.osmocom.org/libosmocore
socket.h: Introduce API osmo_sockaddr_netmask_to_prefixlen()
Implementation is imported from osmo-ggsn.git 97f60e3dca581797007524e0006ca9fafad59713 in46a_netmasklen() and adapter to work with an osmo_sockaddr. This will be used by osmocom-bb's "modem" app. Change-Id: I75e75e251c6776801fffdde745aebedf21c68799
This commit is contained in:
parent
a13d5662b7
commit
cc296c9293
|
@ -7,5 +7,5 @@
|
||||||
# If any interfaces have been added since the last public release: c:r:a + 1.
|
# If any interfaces have been added since the last public release: c:r:a + 1.
|
||||||
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
# If any interfaces have been removed or changed since the last public release: c:r:0.
|
||||||
#library what description / commit summary line
|
#library what description / commit summary line
|
||||||
libosmocore new API osmo_sockaddr_is_any()
|
libosmocore new API osmo_sockaddr_is_any(), osmo_sockaddr_netmask_to_prefixlen()
|
||||||
libosmocore ABI breakage OSMO_NUM_DLIB change affecting internal_cat[]
|
libosmocore ABI breakage OSMO_NUM_DLIB change affecting internal_cat[]
|
||||||
|
|
|
@ -50,6 +50,8 @@ int osmo_sockaddr_cmp(const struct osmo_sockaddr *a,
|
||||||
int osmo_sockaddr_to_octets(uint8_t *dst, size_t dst_maxlen, const struct osmo_sockaddr *os);
|
int osmo_sockaddr_to_octets(uint8_t *dst, size_t dst_maxlen, const struct osmo_sockaddr *os);
|
||||||
int osmo_sockaddr_from_octets(struct osmo_sockaddr *os, const void *src, size_t src_len);
|
int osmo_sockaddr_from_octets(struct osmo_sockaddr *os, const void *src, size_t src_len);
|
||||||
|
|
||||||
|
int osmo_sockaddr_netmask_to_prefixlen(const struct osmo_sockaddr *addr);
|
||||||
|
|
||||||
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *sockaddr);
|
const char *osmo_sockaddr_to_str(const struct osmo_sockaddr *sockaddr);
|
||||||
char *osmo_sockaddr_to_str_buf(char *buf, size_t buf_len,
|
char *osmo_sockaddr_to_str_buf(char *buf, size_t buf_len,
|
||||||
const struct osmo_sockaddr *sockaddr);
|
const struct osmo_sockaddr *sockaddr);
|
||||||
|
|
57
src/socket.c
57
src/socket.c
|
@ -1291,6 +1291,63 @@ void osmo_sockaddr_set_port(struct sockaddr *sa, uint16_t port)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static unsigned int in6_addr_netmask_to_prefixlen(const struct in6_addr *netmask)
|
||||||
|
{
|
||||||
|
#if defined(__linux__)
|
||||||
|
#define ADDRFIELD(i) s6_addr32[i]
|
||||||
|
#else
|
||||||
|
#define ADDRFIELD(i) __u6_addr.__u6_addr32[i]
|
||||||
|
#endif
|
||||||
|
|
||||||
|
unsigned int i, j, prefix = 0;
|
||||||
|
|
||||||
|
for (j = 0; j < 4; j++) {
|
||||||
|
uint32_t bits = netmask->ADDRFIELD(j);
|
||||||
|
uint8_t *b = (uint8_t *)&bits;
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
while (b[i] & 0x80) {
|
||||||
|
prefix++;
|
||||||
|
b[i] = b[i] << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef ADDRFIELD
|
||||||
|
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
static unsigned int in_addr_netmask_to_prefixlen(const struct in_addr *netmask)
|
||||||
|
{
|
||||||
|
uint32_t bits = netmask->s_addr;
|
||||||
|
uint8_t *b = (uint8_t *)&bits;
|
||||||
|
unsigned int i, prefix = 0;
|
||||||
|
|
||||||
|
for (i = 0; i < 4; i++) {
|
||||||
|
while (b[i] & 0x80) {
|
||||||
|
prefix++;
|
||||||
|
b[i] = b[i] << 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*! Convert netmask to prefix length representation
|
||||||
|
* \param[in] netmask sockaddr containing a netmask (consecutive list of 1-bit followed by consecutive list of 0-bit)
|
||||||
|
* \returns prefix length representation of the netmask (count of 1-bit from the start of the netmask), negative on error.
|
||||||
|
*/
|
||||||
|
int osmo_sockaddr_netmask_to_prefixlen(const struct osmo_sockaddr *netmask)
|
||||||
|
{
|
||||||
|
switch (netmask->u.sa.sa_family) {
|
||||||
|
case AF_INET6:
|
||||||
|
return in6_addr_netmask_to_prefixlen(&netmask->u.sin6.sin6_addr);
|
||||||
|
case AF_INET:
|
||||||
|
return in_addr_netmask_to_prefixlen(&netmask->u.sin.sin_addr);
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*! Initialize a unix domain socket (including bind/connect)
|
/*! Initialize a unix domain socket (including bind/connect)
|
||||||
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
|
* \param[in] type Socket type like SOCK_DGRAM, SOCK_STREAM
|
||||||
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
|
* \param[in] proto Protocol like IPPROTO_TCP, IPPROTO_UDP
|
||||||
|
|
|
@ -385,6 +385,63 @@ static void test_osa_str(void)
|
||||||
OSMO_ASSERT(!strncmp("[2003:1234:5678:90ab:cdef:1234:4321:4321]:23420", result, sizeof(buf)));
|
OSMO_ASSERT(!strncmp("[2003:1234:5678:90ab:cdef:1234:4321:4321]:23420", result, sizeof(buf)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_osa_netmask_prefixlen(void)
|
||||||
|
{
|
||||||
|
struct osmo_sockaddr ipv4;
|
||||||
|
struct osmo_sockaddr ipv6;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ipv4.u.sin = (struct sockaddr_in){
|
||||||
|
.sin_family = AF_INET,
|
||||||
|
};
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("0.0.0.0");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
OSMO_ASSERT(rc == 0);
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("255.0.0.0");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
OSMO_ASSERT(rc == 8);
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("255.255.0.0");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
OSMO_ASSERT(rc == 16);
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("255.255.255.0");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
OSMO_ASSERT(rc == 24);
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("255.255.255.255");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
OSMO_ASSERT(rc == 32);
|
||||||
|
|
||||||
|
ipv4.u.sin.sin_addr.s_addr = inet_addr("0.255.0.0");
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv4);
|
||||||
|
/* FIXME: This shows the implementation is not that robust checking validity of input netmask: */
|
||||||
|
OSMO_ASSERT(rc == 8);
|
||||||
|
|
||||||
|
ipv6.u.sin6 = (struct sockaddr_in6){
|
||||||
|
.sin6_family = AF_INET6,
|
||||||
|
};
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, "fe::", &ipv6.u.sin6.sin6_addr);
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv6);
|
||||||
|
OSMO_ASSERT(rc == 7);
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, "ff::", &ipv6.u.sin6.sin6_addr);
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv6);
|
||||||
|
OSMO_ASSERT(rc == 8);
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, "ff:ff::", &ipv6.u.sin6.sin6_addr);
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv6);
|
||||||
|
OSMO_ASSERT(rc == 16);
|
||||||
|
|
||||||
|
inet_pton(AF_INET6, "ff:ff::ff", &ipv6.u.sin6.sin6_addr);
|
||||||
|
rc = osmo_sockaddr_netmask_to_prefixlen(&ipv6);
|
||||||
|
/* FIXME: This shows the implementation is not that robust checking validity of input netmask: */
|
||||||
|
OSMO_ASSERT(rc == 24);
|
||||||
|
}
|
||||||
|
|
||||||
const struct log_info_cat default_categories[] = {
|
const struct log_info_cat default_categories[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -407,6 +464,7 @@ int main(int argc, char *argv[])
|
||||||
test_get_ip_and_port();
|
test_get_ip_and_port();
|
||||||
test_sockinit_osa();
|
test_sockinit_osa();
|
||||||
test_osa_str();
|
test_osa_str();
|
||||||
|
test_osa_netmask_prefixlen();
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue