Fork for fixes
Embed:
(wiki syntax)
Show/hide line numbers
os2_stoip6.c
00001 /* 00002 * Copyright (c) 2014-2015 ARM Limited. All rights reserved. 00003 * SPDX-License-Identifier: Apache-2.0 00004 * Licensed under the Apache License, Version 2.0 (the License); you may 00005 * not use this file except in compliance with the License. 00006 * You may obtain a copy of the License at 00007 * 00008 * http://www.apache.org/licenses/LICENSE-2.0 00009 * 00010 * Unless required by applicable law or agreed to in writing, software 00011 * distributed under the License is distributed on an AS IS BASIS, WITHOUT 00012 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 * See the License for the specific language governing permissions and 00014 * limitations under the License. 00015 */ 00016 #include "mbed_version.h" 00017 00018 #if MBED_MAJOR_VERSION == 2 00019 00020 #include <string.h> 00021 #include <stdlib.h> 00022 #include <stdint.h> 00023 #include "common_functions.h" 00024 #include "ip6string.h" 00025 00026 static uint16_t hex(const char *p); 00027 static bool is_hex(char c); 00028 00029 /** 00030 * Convert numeric IPv6 address string to a binary. 00031 * IPv4 tunnelling addresses are not covered. 00032 * \param ip6addr IPv6 address in string format. 00033 * \param len Length of ipv6 string. 00034 * \param dest buffer for address. MUST be 16 bytes. 00035 * \return boolean set to true if conversion succeed, false if it didn't 00036 */ 00037 bool stoip6(const char *ip6addr, size_t len, void *dest) 00038 { 00039 uint8_t *addr; 00040 const char *p, *q; 00041 int_fast8_t field_no, coloncolon = -1; 00042 00043 addr = dest; 00044 00045 if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses 00046 goto error; 00047 } 00048 00049 // First go forward the string, until end, noting :: position if any 00050 // We're decrementing `len` as we go forward, and stop when it reaches 0 00051 for (field_no = 0, p = ip6addr; len && *p; p = q + 1) { 00052 00053 for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end 00054 if (!is_hex(*q++)) { // There must only be hex characters besides ':' 00055 goto error; 00056 } 00057 } 00058 00059 if ((q - p) > 4) { // We can't have more than 4 hex digits per segment 00060 goto error; 00061 } 00062 00063 if (field_no == 8) { // If the address goes farther than 8 segments 00064 goto error; 00065 } 00066 00067 // Convert and write this part, (high-endian AKA network byte order) 00068 addr = common_write_16_bit(hex(p), addr); 00069 field_no++; 00070 00071 // We handle the colons 00072 if (len) { 00073 // Check if we reached "::" 00074 if (q[0] == ':' && q[1] == ':') { 00075 if (coloncolon != -1) { // We are not supposed to see "::" more than once per address 00076 goto error; 00077 } 00078 coloncolon = field_no; 00079 q++; 00080 len -= 2; 00081 } else { 00082 len -= 1; 00083 } 00084 } 00085 } 00086 00087 if (coloncolon != -1) { 00088 /* Insert zeros in the appropriate place */ 00089 uint_fast8_t head_size = 2 * coloncolon; 00090 uint_fast8_t inserted_size = 2 * (8 - field_no); 00091 uint_fast8_t tail_size = 16 - head_size - inserted_size; 00092 addr = dest; 00093 memmove(addr + head_size + inserted_size, addr + head_size, tail_size); 00094 memset(addr + head_size, 0, inserted_size); 00095 } else if (field_no != 8) { // Report an error if we didn't get 8 fields 00096 goto error; 00097 } 00098 return true; 00099 00100 error: 00101 // Fill the output buffer with 0 so we stick to the old failure behavior. 00102 // We are however more agressive and wipe the entire address, and do so more often. 00103 memset(dest, 0, 16); 00104 return false; 00105 } 00106 00107 unsigned char sipv6_prefixlength(const char *ip6addr) 00108 { 00109 char *ptr = strchr(ip6addr, '/'); 00110 if (ptr) { 00111 return (unsigned char)strtoul(ptr + 1, 0, 10); 00112 } 00113 return 0; 00114 } 00115 00116 int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out) 00117 { 00118 size_t addr_len, total_len; 00119 int_fast16_t prefix_length; 00120 00121 if (prefix_len_out) { 00122 *prefix_len_out = -1; 00123 } 00124 00125 total_len = addr_len = strlen(ip6addr); 00126 const char *ptr = strchr(ip6addr, '/'); 00127 if (ptr) { 00128 addr_len = ptr - ip6addr; 00129 if (prefix_len_out) { 00130 if (total_len - addr_len > 3) { 00131 /* too many digits in prefix */ 00132 return -1; 00133 } 00134 00135 prefix_length = strtoul(ptr + 1, 0, 10); 00136 if (prefix_length < 0 || prefix_length > 128) { 00137 /* prefix value illegal */ 00138 return -1; 00139 } 00140 00141 *prefix_len_out = prefix_length; 00142 } 00143 } 00144 00145 if (!stoip6(ip6addr, addr_len, dest)) { 00146 /* parser failure */ 00147 return -1; 00148 } 00149 00150 return 0; 00151 } 00152 00153 static bool is_hex(char c) 00154 { 00155 // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A' 00156 if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') { 00157 return true; 00158 } 00159 00160 if (c >= '0' && c <= '9') { 00161 return true; 00162 } 00163 00164 return false; 00165 } 00166 00167 static uint16_t hex(const char *p) 00168 { 00169 uint16_t val = 0; 00170 00171 for (;;) { 00172 char c = *p++; 00173 if ((c >= '0') && (c <= '9')) { 00174 val = (val << 4) | (c - '0'); 00175 } else if ((c >= 'A') && (c <= 'F')) { 00176 val = (val << 4) | (10 + (c - 'A')); 00177 } else if ((c >= 'a') && (c <= 'f')) { 00178 val = (val << 4) | (10 + (c - 'a')); 00179 } else { 00180 break; // Non hex character 00181 } 00182 } 00183 return val; 00184 } 00185 #endif
Generated on Fri Jul 15 2022 22:55:10 by 1.7.2