123

Committer:
hudakz
Date:
Fri Jun 05 15:12:21 2020 +0000
Revision:
16:269f652b4d0b
Parent:
utility/stoip6.c@14:7648334eb41b
Library for ENC28J60 Ethernet modules.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
hudakz 14:7648334eb41b 1 /*
hudakz 14:7648334eb41b 2 * Copyright (c) 2014-2015 ARM Limited. All rights reserved.
hudakz 14:7648334eb41b 3 * SPDX-License-Identifier: Apache-2.0
hudakz 14:7648334eb41b 4 * Licensed under the Apache License, Version 2.0 (the License); you may
hudakz 14:7648334eb41b 5 * not use this file except in compliance with the License.
hudakz 14:7648334eb41b 6 * You may obtain a copy of the License at
hudakz 14:7648334eb41b 7 *
hudakz 14:7648334eb41b 8 * http://www.apache.org/licenses/LICENSE-2.0
hudakz 14:7648334eb41b 9 *
hudakz 14:7648334eb41b 10 * Unless required by applicable law or agreed to in writing, software
hudakz 14:7648334eb41b 11 * distributed under the License is distributed on an AS IS BASIS, WITHOUT
hudakz 14:7648334eb41b 12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
hudakz 14:7648334eb41b 13 * See the License for the specific language governing permissions and
hudakz 14:7648334eb41b 14 * limitations under the License.
hudakz 14:7648334eb41b 15 */
hudakz 14:7648334eb41b 16 #include "mbed_version.h"
hudakz 14:7648334eb41b 17
hudakz 14:7648334eb41b 18 #if MBED_MAJOR_VERSION == 2
hudakz 14:7648334eb41b 19
hudakz 14:7648334eb41b 20 #include <string.h>
hudakz 14:7648334eb41b 21 #include <stdlib.h>
hudakz 14:7648334eb41b 22 #include <stdint.h>
hudakz 14:7648334eb41b 23 #include "common_functions.h"
hudakz 14:7648334eb41b 24 #include "ip6string.h"
hudakz 14:7648334eb41b 25
hudakz 14:7648334eb41b 26 static uint16_t hex(const char *p);
hudakz 14:7648334eb41b 27 static bool is_hex(char c);
hudakz 14:7648334eb41b 28
hudakz 14:7648334eb41b 29 /**
hudakz 14:7648334eb41b 30 * Convert numeric IPv6 address string to a binary.
hudakz 14:7648334eb41b 31 * IPv4 tunnelling addresses are not covered.
hudakz 14:7648334eb41b 32 * \param ip6addr IPv6 address in string format.
hudakz 14:7648334eb41b 33 * \param len Length of ipv6 string.
hudakz 14:7648334eb41b 34 * \param dest buffer for address. MUST be 16 bytes.
hudakz 14:7648334eb41b 35 * \return boolean set to true if conversion succeed, false if it didn't
hudakz 14:7648334eb41b 36 */
hudakz 14:7648334eb41b 37 bool stoip6(const char *ip6addr, size_t len, void *dest)
hudakz 14:7648334eb41b 38 {
hudakz 14:7648334eb41b 39 uint8_t *addr;
hudakz 14:7648334eb41b 40 const char *p, *q;
hudakz 14:7648334eb41b 41 int_fast8_t field_no, coloncolon = -1;
hudakz 14:7648334eb41b 42
hudakz 14:7648334eb41b 43 addr = dest;
hudakz 14:7648334eb41b 44
hudakz 14:7648334eb41b 45 if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses
hudakz 14:7648334eb41b 46 goto error;
hudakz 14:7648334eb41b 47 }
hudakz 14:7648334eb41b 48
hudakz 14:7648334eb41b 49 // First go forward the string, until end, noting :: position if any
hudakz 14:7648334eb41b 50 // We're decrementing `len` as we go forward, and stop when it reaches 0
hudakz 14:7648334eb41b 51 for (field_no = 0, p = ip6addr; len && *p; p = q + 1) {
hudakz 14:7648334eb41b 52
hudakz 14:7648334eb41b 53 for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end
hudakz 14:7648334eb41b 54 if (!is_hex(*q++)) { // There must only be hex characters besides ':'
hudakz 14:7648334eb41b 55 goto error;
hudakz 14:7648334eb41b 56 }
hudakz 14:7648334eb41b 57 }
hudakz 14:7648334eb41b 58
hudakz 14:7648334eb41b 59 if ((q - p) > 4) { // We can't have more than 4 hex digits per segment
hudakz 14:7648334eb41b 60 goto error;
hudakz 14:7648334eb41b 61 }
hudakz 14:7648334eb41b 62
hudakz 14:7648334eb41b 63 if (field_no == 8) { // If the address goes farther than 8 segments
hudakz 14:7648334eb41b 64 goto error;
hudakz 14:7648334eb41b 65 }
hudakz 14:7648334eb41b 66
hudakz 14:7648334eb41b 67 // Convert and write this part, (high-endian AKA network byte order)
hudakz 14:7648334eb41b 68 addr = common_write_16_bit(hex(p), addr);
hudakz 14:7648334eb41b 69 field_no++;
hudakz 14:7648334eb41b 70
hudakz 14:7648334eb41b 71 // We handle the colons
hudakz 14:7648334eb41b 72 if (len) {
hudakz 14:7648334eb41b 73 // Check if we reached "::"
hudakz 14:7648334eb41b 74 if (q[0] == ':' && q[1] == ':') {
hudakz 14:7648334eb41b 75 if (coloncolon != -1) { // We are not supposed to see "::" more than once per address
hudakz 14:7648334eb41b 76 goto error;
hudakz 14:7648334eb41b 77 }
hudakz 14:7648334eb41b 78 coloncolon = field_no;
hudakz 14:7648334eb41b 79 q++;
hudakz 14:7648334eb41b 80 len -= 2;
hudakz 14:7648334eb41b 81 } else {
hudakz 14:7648334eb41b 82 len -= 1;
hudakz 14:7648334eb41b 83 }
hudakz 14:7648334eb41b 84 }
hudakz 14:7648334eb41b 85 }
hudakz 14:7648334eb41b 86
hudakz 14:7648334eb41b 87 if (coloncolon != -1) {
hudakz 14:7648334eb41b 88 /* Insert zeros in the appropriate place */
hudakz 14:7648334eb41b 89 uint_fast8_t head_size = 2 * coloncolon;
hudakz 14:7648334eb41b 90 uint_fast8_t inserted_size = 2 * (8 - field_no);
hudakz 14:7648334eb41b 91 uint_fast8_t tail_size = 16 - head_size - inserted_size;
hudakz 14:7648334eb41b 92 addr = dest;
hudakz 14:7648334eb41b 93 memmove(addr + head_size + inserted_size, addr + head_size, tail_size);
hudakz 14:7648334eb41b 94 memset(addr + head_size, 0, inserted_size);
hudakz 14:7648334eb41b 95 } else if (field_no != 8) { // Report an error if we didn't get 8 fields
hudakz 14:7648334eb41b 96 goto error;
hudakz 14:7648334eb41b 97 }
hudakz 14:7648334eb41b 98 return true;
hudakz 14:7648334eb41b 99
hudakz 14:7648334eb41b 100 error:
hudakz 14:7648334eb41b 101 // Fill the output buffer with 0 so we stick to the old failure behavior.
hudakz 14:7648334eb41b 102 // We are however more agressive and wipe the entire address, and do so more often.
hudakz 14:7648334eb41b 103 memset(dest, 0, 16);
hudakz 14:7648334eb41b 104 return false;
hudakz 14:7648334eb41b 105 }
hudakz 14:7648334eb41b 106
hudakz 14:7648334eb41b 107 unsigned char sipv6_prefixlength(const char *ip6addr)
hudakz 14:7648334eb41b 108 {
hudakz 14:7648334eb41b 109 char *ptr = strchr(ip6addr, '/');
hudakz 14:7648334eb41b 110 if (ptr) {
hudakz 14:7648334eb41b 111 return (unsigned char)strtoul(ptr + 1, 0, 10);
hudakz 14:7648334eb41b 112 }
hudakz 14:7648334eb41b 113 return 0;
hudakz 14:7648334eb41b 114 }
hudakz 14:7648334eb41b 115
hudakz 14:7648334eb41b 116 int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out)
hudakz 14:7648334eb41b 117 {
hudakz 14:7648334eb41b 118 size_t addr_len, total_len;
hudakz 14:7648334eb41b 119 int_fast16_t prefix_length;
hudakz 14:7648334eb41b 120
hudakz 14:7648334eb41b 121 if (prefix_len_out) {
hudakz 14:7648334eb41b 122 *prefix_len_out = -1;
hudakz 14:7648334eb41b 123 }
hudakz 14:7648334eb41b 124
hudakz 14:7648334eb41b 125 total_len = addr_len = strlen(ip6addr);
hudakz 14:7648334eb41b 126 const char *ptr = strchr(ip6addr, '/');
hudakz 14:7648334eb41b 127 if (ptr) {
hudakz 14:7648334eb41b 128 addr_len = ptr - ip6addr;
hudakz 14:7648334eb41b 129 if (prefix_len_out) {
hudakz 14:7648334eb41b 130 if (total_len - addr_len > 3) {
hudakz 14:7648334eb41b 131 /* too many digits in prefix */
hudakz 14:7648334eb41b 132 return -1;
hudakz 14:7648334eb41b 133 }
hudakz 14:7648334eb41b 134
hudakz 14:7648334eb41b 135 prefix_length = strtoul(ptr + 1, 0, 10);
hudakz 14:7648334eb41b 136 if (prefix_length < 0 || prefix_length > 128) {
hudakz 14:7648334eb41b 137 /* prefix value illegal */
hudakz 14:7648334eb41b 138 return -1;
hudakz 14:7648334eb41b 139 }
hudakz 14:7648334eb41b 140
hudakz 14:7648334eb41b 141 *prefix_len_out = prefix_length;
hudakz 14:7648334eb41b 142 }
hudakz 14:7648334eb41b 143 }
hudakz 14:7648334eb41b 144
hudakz 14:7648334eb41b 145 if (!stoip6(ip6addr, addr_len, dest)) {
hudakz 14:7648334eb41b 146 /* parser failure */
hudakz 14:7648334eb41b 147 return -1;
hudakz 14:7648334eb41b 148 }
hudakz 14:7648334eb41b 149
hudakz 14:7648334eb41b 150 return 0;
hudakz 14:7648334eb41b 151 }
hudakz 14:7648334eb41b 152
hudakz 14:7648334eb41b 153 static bool is_hex(char c)
hudakz 14:7648334eb41b 154 {
hudakz 14:7648334eb41b 155 // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A'
hudakz 14:7648334eb41b 156 if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') {
hudakz 14:7648334eb41b 157 return true;
hudakz 14:7648334eb41b 158 }
hudakz 14:7648334eb41b 159
hudakz 14:7648334eb41b 160 if (c >= '0' && c <= '9') {
hudakz 14:7648334eb41b 161 return true;
hudakz 14:7648334eb41b 162 }
hudakz 14:7648334eb41b 163
hudakz 14:7648334eb41b 164 return false;
hudakz 14:7648334eb41b 165 }
hudakz 14:7648334eb41b 166
hudakz 14:7648334eb41b 167 static uint16_t hex(const char *p)
hudakz 14:7648334eb41b 168 {
hudakz 14:7648334eb41b 169 uint16_t val = 0;
hudakz 14:7648334eb41b 170
hudakz 14:7648334eb41b 171 for (;;) {
hudakz 14:7648334eb41b 172 char c = *p++;
hudakz 14:7648334eb41b 173 if ((c >= '0') && (c <= '9')) {
hudakz 14:7648334eb41b 174 val = (val << 4) | (c - '0');
hudakz 14:7648334eb41b 175 } else if ((c >= 'A') && (c <= 'F')) {
hudakz 14:7648334eb41b 176 val = (val << 4) | (10 + (c - 'A'));
hudakz 14:7648334eb41b 177 } else if ((c >= 'a') && (c <= 'f')) {
hudakz 14:7648334eb41b 178 val = (val << 4) | (10 + (c - 'a'));
hudakz 14:7648334eb41b 179 } else {
hudakz 14:7648334eb41b 180 break; // Non hex character
hudakz 14:7648334eb41b 181 }
hudakz 14:7648334eb41b 182 }
hudakz 14:7648334eb41b 183 return val;
hudakz 14:7648334eb41b 184 }
hudakz 14:7648334eb41b 185 #endif