Skip to content

Nanostack libservice update #8245

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Oct 10, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,10 @@ uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p
*
* \param ip6addr IPv6 address in string format.
* \param len Lenght of ipv6 string, maximum of 41.
* \param dest buffer for address. MUST be 16 bytes.
* \param dest buffer for address. MUST be 16 bytes. Filled with 0 on error.
* \return boolean set to true if conversion succeed, false if it didn't
*/
void stoip6(const char *ip6addr, size_t len, void *dest);
bool stoip6(const char *ip6addr, size_t len, void *dest);
/**
* Find out numeric IPv6 address prefix length.
*
Expand All @@ -69,6 +70,19 @@ void stoip6(const char *ip6addr, size_t len, void *dest);
*/
unsigned char sipv6_prefixlength(const char *ip6addr);

/**
* Convert numeric IPv6 address string with prefix to a binary.
*
* IPv4 tunneling addresses are not covered.
*
* \param ip6addr IPv6 address in string format.
* \param dest buffer for address. MUST be 16 bytes.
* \param prefix_len_out length of prefix, is set to -1 if no prefix given
*
* \return 0 on success, negative value otherwise. prefix_len_out contains prefix length.
*/
int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out);

#ifdef __cplusplus
}
#endif
Expand Down
113 changes: 97 additions & 16 deletions features/frameworks/nanostack-libservice/source/libip6string/stoip6.c
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,17 @@
#include "ip6string.h"

static uint16_t hex(const char *p);
static bool is_hex(char c);

/**
* Convert numeric IPv6 address string to a binary.
* IPv4 tunnelling addresses are not covered.
* \param ip6addr IPv6 address in string format.
* \param len Length of ipv6 string.
* \param dest buffer for address. MUST be 16 bytes.
* \return boolean set to true if conversion succeed, false if it didn't
*/
void stoip6(const char *ip6addr, size_t len, void *dest)
bool stoip6(const char *ip6addr, size_t len, void *dest)
{
uint8_t *addr;
const char *p, *q;
Expand All @@ -37,23 +39,45 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
addr = dest;

if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
return;
goto error;
}

// First go forward the string, until end, noting :: position if any
for (field_no = 0, p = ip6addr; (len > (size_t)(p - ip6addr)) && *p && field_no < 8; p = q + 1) {
q = p;
// Seek for ':' or end
while (*q && (*q != ':')) {
q++;
// We're decrementing `len` as we go forward, and stop when it reaches 0
for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {

for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
if (!is_hex(*q++)) { // There must only be hex characters besides ':'
goto error;
}
}

if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
goto error;
}

if (field_no == 8) { // If the address goes farther than 8 segments
goto error;
}
//Convert and write this part, (high-endian AKA network byte order)

// Convert and write this part, (high-endian AKA network byte order)
addr = common_write_16_bit(hex(p), addr);
field_no++;
//Check if we reached "::"
if ((len > (size_t)(q - ip6addr)) && *q && (q[0] == ':') && (q[1] == ':')) {
coloncolon = field_no;
q++;

// We handle the colons
if (len) {
// Check if we reached "::"
if (q[0] == ':' && q[1] == ':') {
if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
goto error;
}
coloncolon = field_no;
q++;
len -= 2;
}
else {
len -= 1;
}
}
}

Expand All @@ -65,19 +89,76 @@ void stoip6(const char *ip6addr, size_t len, void *dest)
addr = dest;
memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
memset(addr + head_size, 0, inserted_size);
} else if (field_no != 8) {
/* Should really report an error if we didn't get 8 fields */
memset(addr, 0, 16 - field_no * 2);
} else if (field_no != 8) { // Report an error if we didn't get 8 fields
goto error;
}
return true;

error:
// Fill the output buffer with 0 so we stick to the old failure behavior.
// We are however more agressive and wipe the entire address, and do so more often.
memset(dest, 0, 16);
return false;
}
unsigned char sipv6_prefixlength(const char *ip6addr)

unsigned char sipv6_prefixlength(const char *ip6addr)
{
char *ptr = strchr(ip6addr, '/');
if (ptr) {
return (unsigned char)strtoul(ptr + 1, 0, 10);
}
return 0;
}

int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
{
size_t addr_len, total_len;
int_fast16_t prefix_length;

if (prefix_len_out) {
*prefix_len_out = -1;
}

total_len = addr_len = strlen(ip6addr);
const char *ptr = strchr(ip6addr, '/');
if (ptr) {
addr_len = ptr - ip6addr;
if (prefix_len_out) {
if (total_len - addr_len > 3) {
/* too many digits in prefix */
return -1;
}

prefix_length = strtoul(ptr + 1, 0, 10);
if (prefix_length < 0 || prefix_length > 128) {
/* prefix value illegal */
return -1;
}

*prefix_len_out = prefix_length;
}
}

if (!stoip6(ip6addr, addr_len, dest)) {
/* parser failure */
return -1;
}

return 0;
}

static bool is_hex(char c)
{
// 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F')
return true;

if (c >= '0' && c <= '9')
return true;

return false;
}

static uint16_t hex(const char *p)
{
uint16_t val = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,4 @@ int main(int ac, char **av)

IMPORT_TEST_GROUP(stoip6);
IMPORT_TEST_GROUP(stoip6_2);
IMPORT_TEST_GROUP(stoip6_3);
Loading