Mbed library for ENC28J60 Ethernet modules. Full support for TCP/IP and UDP Server, Client and HTTP server (webserver). DHCP and DNS is included.

Dependents:   mBuino_ENC28_MQTT Nucleo_Web_ENC28J60 Nucleo_Web_ENC28J60_ADC Serial_over_Ethernet ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers os2_stoip6.c Source File

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