mirror of https://github.com/ARMmbed/mbed-os.git
Merge pull request #8245 from artokin/nanostack_libservice_update
Nanostack libservice updatepull/8364/merge
commit
d58f241b75
|
@ -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.
|
||||
*
|
||||
|
@ -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
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include "ip6string.h"
|
||||
|
||||
static uint16_t hex(const char *p);
|
||||
static bool is_hex(char c);
|
||||
|
||||
/**
|
||||
* Convert numeric IPv6 address string to a binary.
|
||||
|
@ -27,8 +28,9 @@ static uint16_t hex(const char *p);
|
|||
* \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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
//Convert and write this part, (high-endian AKA network byte order)
|
||||
|
||||
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)
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,12 +89,19 @@ 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) {
|
||||
|
@ -78,6 +109,56 @@ unsigned char sipv6_prefixlength(const char *ip6addr)
|
|||
}
|
||||
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;
|
||||
|
|
|
@ -25,3 +25,4 @@ int main(int ac, char **av)
|
|||
|
||||
IMPORT_TEST_GROUP(stoip6);
|
||||
IMPORT_TEST_GROUP(stoip6_2);
|
||||
IMPORT_TEST_GROUP(stoip6_3);
|
||||
|
|
|
@ -42,11 +42,10 @@ TEST(stoip6, TooShort)
|
|||
{
|
||||
char *addr = "FFFF:FFFF:";
|
||||
uint8_t ip[16];
|
||||
uint8_t correct[16] = {0xff, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
||||
// This should sto parsing when too short address given, the buffer hoewever is filled to that long
|
||||
// So basically there is no error handling. We just check that first FFFF:FFFF gets filled and not trash after that.
|
||||
// Rest should be filled with zeroes
|
||||
stoip6(addr, strlen(addr), ip);
|
||||
uint8_t correct[16] = {0};
|
||||
// This should stop parsing when too short address given.
|
||||
// Despite partial parsing, the entire buffer should be filled with zeroes
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
|
@ -58,7 +57,7 @@ TEST(stoip6, TooLongString)
|
|||
uint8_t correct[16] = {0};
|
||||
// This should not fill anything, too long string.
|
||||
// This is basically only validation we do
|
||||
stoip6(addr, strlen(addr), ip);
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
|
@ -66,12 +65,11 @@ TEST(stoip6, TooManyFields)
|
|||
{
|
||||
// String len must be less than 40
|
||||
char *addr = "FF:FF:FF:FF:FF:FF:FFFF:FFFF:FFFF:FFFF:";
|
||||
uint8_t ip[17] = {0};
|
||||
uint8_t correct[17] = { 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
|
||||
// Again.. there is not really any error handling (no return value)
|
||||
// Just make sure that it does not overflow
|
||||
stoip6(addr, strlen(addr), ip);
|
||||
CHECK(0 == memcmp(ip, correct, 17)); // Note, we are checking 17, to make sure one byte after address in not touched.
|
||||
uint8_t ip[16] = {0};
|
||||
uint8_t correct[16] = {0};
|
||||
|
||||
CHECK(false == stoip6(addr, strlen(addr), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
|
||||
TEST(stoip6, Prefixlen)
|
||||
|
@ -96,13 +94,31 @@ TEST(stoip6, RegressionTestForOffByOne)
|
|||
0x64, 0x3f, 0xf5, 0x4a, 0xec, 0x29, 0xcd, 0xbb
|
||||
};
|
||||
|
||||
stoip6(sourceTemp, sourceTempLen, ip);
|
||||
|
||||
CHECK(true == stoip6(sourceTemp, sourceTempLen, ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
|
||||
free(sourceTemp);
|
||||
}
|
||||
|
||||
// Test various illegal formats to ensure proper rejection
|
||||
TEST(stoip6, InvalidAddresses)
|
||||
{
|
||||
uint8_t ip[16];
|
||||
uint8_t correct[16] = {0};
|
||||
|
||||
const char *invalidArray[] =
|
||||
{
|
||||
"FFFF:FFFF::FFFF::FFFF", // Two ::
|
||||
"F:F:F:FqF:F:F:F:F", // Non-hex character
|
||||
"F:F:F:FFFFF:F:F:F:F" // >4 hex characters in a segment
|
||||
};
|
||||
|
||||
for (uint8_t i = 0; i < 3; ++i) {
|
||||
CHECK(false == stoip6(invalidArray[i], strlen(invalidArray[i]), ip));
|
||||
CHECK(0 == memcmp(ip, correct, 16));
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Second test group for the old tests that were once lost */
|
||||
|
||||
|
@ -161,63 +177,122 @@ TEST_GROUP(stoip6_2)
|
|||
TEST(stoip6_2, test_2_1)
|
||||
{
|
||||
i = 0;
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
|
||||
TEST(stoip6_2, test_2_2)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_3)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_4)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_5)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_6)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_7)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_8)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_9)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, strlen(buf)));
|
||||
}
|
||||
TEST(stoip6_2, test_2_10)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
TEST(stoip6_2, test_2_11)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
TEST(stoip6_2, test_2_12)
|
||||
{
|
||||
stoip6(string_addr[i], strlen(string_addr[i]), buf);
|
||||
CHECK(true == stoip6(string_addr[i], strlen(string_addr[i]), buf));
|
||||
CHECK(0 == memcmp(hex_addr[i], buf, 16));
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* Third test group for stoip6_prefix */
|
||||
|
||||
const char string_prefix_addr[][40] =
|
||||
{
|
||||
"2001:db8::1:0:0:1/64", // 1
|
||||
"2001::/60", // 2
|
||||
"::1/48", // 3
|
||||
"::/00", // 4
|
||||
"2002::02/99", // 5
|
||||
"2003::03/", // 6
|
||||
"2004::04", // 7
|
||||
"2005::05/2000", // 8
|
||||
"2005::05/-1", // 9
|
||||
};
|
||||
|
||||
|
||||
const uint8_t hex_prefix_addr[][16] =
|
||||
{
|
||||
{ 0x20, 0x01, 0xd, 0xb8, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1 }, // 1
|
||||
{ 0x20, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, // 2
|
||||
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1 }, // 3
|
||||
{ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, // 4
|
||||
{ 0x20, 0x02, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2 }, // 5
|
||||
{ 0x20, 0x03, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3 }, // 6
|
||||
{ 0x20, 0x04, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4 }, // 7
|
||||
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 8
|
||||
{ 0x20, 0x05, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5 }, // 9
|
||||
};
|
||||
|
||||
const int_fast16_t prefix_len_tbl[] = {64, 60, 48, 0, 99, 0, -1, -1, -1};
|
||||
const int prefix_status_tbl[] = {0, 0, 0, 0, 0, 0, 0, -1, -1};
|
||||
|
||||
TEST_GROUP(stoip6_3)
|
||||
{
|
||||
void setup() {
|
||||
}
|
||||
|
||||
void teardown() {
|
||||
}
|
||||
};
|
||||
|
||||
TEST(stoip6_3, stoip6_prefix_test)
|
||||
{
|
||||
for (int i = 0; i < 9; i++) {
|
||||
uint8_t ip[16];
|
||||
int_fast16_t prefix_len;
|
||||
int result;
|
||||
const char *addr = &string_prefix_addr[i][0];
|
||||
|
||||
result = stoip6_prefix(addr, ip, &prefix_len);
|
||||
CHECK(result == prefix_status_tbl[i]);
|
||||
if (result == 0) {
|
||||
CHECK(0 == memcmp(ip, &hex_prefix_addr[i][0], 16));
|
||||
CHECK(prefix_len == prefix_len_tbl[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -33,6 +33,7 @@ struct ip6_addresses_and_its_binary_form_t {
|
|||
{ "2001:db8::", { 0x20, 0x01, 0xd, 0xb8 }},
|
||||
{ "::aaaa:0:0:1", { 0, 0, 0, 0, 0, 0, 0, 0, 0xaa, 0xaa, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "::1", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 }},
|
||||
{ "fe80::1", { 0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}},
|
||||
{ "::", { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }},
|
||||
{ "FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF:FFFF", { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}},
|
||||
{NULL, {0}}
|
||||
|
|
Loading…
Reference in New Issue