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.
Dependents: TYBLE16_simple_data_logger TYBLE16_MP3_Air
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 Tue Jul 12 2022 13:54:54 by
