Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
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 <string.h> 00017 #include <stdlib.h> 00018 #include <stdint.h> 00019 #include "common_functions.h" 00020 #include "ip6string.h" 00021 00022 static uint16_t hex(const char *p); 00023 static bool is_hex(char c); 00024 00025 /** 00026 * Convert numeric IPv6 address string to a binary. 00027 * IPv4 tunnelling addresses are not covered. 00028 * \param ip6addr IPv6 address in string format. 00029 * \param len Length of ipv6 string. 00030 * \param dest buffer for address. MUST be 16 bytes. 00031 * \return boolean set to true if conversion succeed, false if it didn't 00032 */ 00033 bool stoip6(const char *ip6addr, size_t len, void *dest) 00034 { 00035 uint8_t *addr; 00036 const char *p, *q; 00037 int_fast8_t field_no, coloncolon = -1; 00038 00039 addr = dest; 00040 00041 if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses 00042 goto error; 00043 } 00044 00045 // First go forward the string, until end, noting :: position if any 00046 // We're decrementing `len` as we go forward, and stop when it reaches 0 00047 for (field_no = 0, p = ip6addr; len && *p; p = q + 1) { 00048 00049 for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end 00050 if (!is_hex(*q++)) { // There must only be hex characters besides ':' 00051 goto error; 00052 } 00053 } 00054 00055 if ((q - p) > 4) { // We can't have more than 4 hex digits per segment 00056 goto error; 00057 } 00058 00059 if (field_no == 8) { // If the address goes farther than 8 segments 00060 goto error; 00061 } 00062 00063 // Convert and write this part, (high-endian AKA network byte order) 00064 addr = common_write_16_bit(hex(p), addr); 00065 field_no++; 00066 00067 // We handle the colons 00068 if (len) { 00069 // Check if we reached "::" 00070 if (q[0] == ':' && q[1] == ':') { 00071 if (coloncolon != -1) { // We are not supposed to see "::" more than once per address 00072 goto error; 00073 } 00074 coloncolon = field_no; 00075 q++; 00076 len -= 2; 00077 } else { 00078 len -= 1; 00079 } 00080 } 00081 } 00082 00083 if (coloncolon != -1) { 00084 /* Insert zeros in the appropriate place */ 00085 uint_fast8_t head_size = 2 * coloncolon; 00086 uint_fast8_t inserted_size = 2 * (8 - field_no); 00087 uint_fast8_t tail_size = 16 - head_size - inserted_size; 00088 addr = dest; 00089 memmove(addr + head_size + inserted_size, addr + head_size, tail_size); 00090 memset(addr + head_size, 0, inserted_size); 00091 } else if (field_no != 8) { // Report an error if we didn't get 8 fields 00092 goto error; 00093 } 00094 return true; 00095 00096 error: 00097 // Fill the output buffer with 0 so we stick to the old failure behavior. 00098 // We are however more agressive and wipe the entire address, and do so more often. 00099 memset(dest, 0, 16); 00100 return false; 00101 } 00102 00103 unsigned char sipv6_prefixlength(const char *ip6addr) 00104 { 00105 char *ptr = strchr(ip6addr, '/'); 00106 if (ptr) { 00107 return (unsigned char)strtoul(ptr + 1, 0, 10); 00108 } 00109 return 0; 00110 } 00111 00112 int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out) 00113 { 00114 size_t addr_len, total_len; 00115 int_fast16_t prefix_length; 00116 00117 if (prefix_len_out) { 00118 *prefix_len_out = -1; 00119 } 00120 00121 total_len = addr_len = strlen(ip6addr); 00122 const char *ptr = strchr(ip6addr, '/'); 00123 if (ptr) { 00124 addr_len = ptr - ip6addr; 00125 if (prefix_len_out) { 00126 if (total_len - addr_len > 3) { 00127 /* too many digits in prefix */ 00128 return -1; 00129 } 00130 00131 prefix_length = strtoul(ptr + 1, 0, 10); 00132 if (prefix_length < 0 || prefix_length > 128) { 00133 /* prefix value illegal */ 00134 return -1; 00135 } 00136 00137 *prefix_len_out = prefix_length; 00138 } 00139 } 00140 00141 if (!stoip6(ip6addr, addr_len, dest)) { 00142 /* parser failure */ 00143 return -1; 00144 } 00145 00146 return 0; 00147 } 00148 00149 static bool is_hex(char c) 00150 { 00151 // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A' 00152 if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') { 00153 return true; 00154 } 00155 00156 if (c >= '0' && c <= '9') { 00157 return true; 00158 } 00159 00160 return false; 00161 } 00162 00163 static uint16_t hex(const char *p) 00164 { 00165 uint16_t val = 0; 00166 00167 for (;;) { 00168 char c = *p++; 00169 if ((c >= '0') && (c <= '9')) { 00170 val = (val << 4) | (c - '0'); 00171 } else if ((c >= 'A') && (c <= 'F')) { 00172 val = (val << 4) | (10 + (c - 'A')); 00173 } else if ((c >= 'a') && (c <= 'f')) { 00174 val = (val << 4) | (10 + (c - 'a')); 00175 } else { 00176 break; // Non hex character 00177 } 00178 } 00179 return val; 00180 }
Generated on Mon Aug 29 2022 19:53:42 by
