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
Library for ENC28J60 Ethernet modules.
Ported to mbed from Norbert Truchsess's UIPEthernet library for Arduino. Thank you Norbert!
- Full support for persistent (streaming) TCP/IP and UDP connections Client and Server each, ARP, ICMP, DHCP and DNS.
- Works with both Mbed OS 2 and Mbed OS 5.
Usage:
- Import the library into your project.
- Add
#include "UipEthernet.h"
tomain.cpp
- Create one instance of the UipEthernet class initialized with the MAC address you'd like to use and SPI pins of the connected Mbed board.
Example programs:
Import programWebSwitch_ENC28J60
HTTP Server serving a simple webpage which enables to remotely turn a digital output on/off. Compile, download, run and type 'IP_address/secret/' (don't forget the last '/') into your web browser and hit ENTER.
Import programHTTPServer_Echo_ENC28J60
A simple HTTP server echoing received requests. Ethernet connection is over an ENC28J60 board. Usage: Type the server's IP address into you web browser and hit <ENTER>.
Import programTcpServer_ENC28J60
Simple TCP/IP Server using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programTcpClient_ENC28J60
Simple TCP/IP Client using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programUdpServer_ENC28J60
Simple UDP Server using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programUdpClient_ENC28J60
Simple UDP Client using the UIPEthernet library for ENC28J60 Ethernet boards.
Import programMQTT_Hello_ENC28J60
MQTT Client example program. Ethernet connection is via an ENC28J60 module.
Revision 16:269f652b4d0b, committed 2020-06-05
- Comitter:
- hudakz
- Date:
- Fri Jun 05 15:12:21 2020 +0000
- Parent:
- 15:53715cc81c63
- Child:
- 17:1123c3fe86ca
- Commit message:
- Library for ENC28J60 Ethernet modules.
Changed in this revision
--- a/DnsClient.cpp Sat Sep 07 17:42:42 2019 +0000 +++ b/DnsClient.cpp Fri Jun 05 15:12:21 2020 +0000 @@ -7,6 +7,7 @@ #include "DnsClient.h" #include <string.h> #include "mbed.h" +#include "mbed_version.h" #define SOCKET_NONE 255 @@ -284,7 +285,11 @@ while (iUdp.parsePacket() <= 0) { if (timer.read() > aTimeout) return TIMED_OUT; +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif } // We've had a reply!
--- a/IpAddress.h Sat Sep 07 17:42:42 2019 +0000 +++ b/IpAddress.h Fri Jun 05 15:12:21 2020 +0000 @@ -22,6 +22,7 @@ #define IPADDRESS_h #include <stdio.h> +#include "SocketAddress.h" // A class to make it easier to handle and pass around IP addresses @@ -55,6 +56,8 @@ // Returns IP Address as string of char const char* toString(char* buf); + void toSocketAddress(SocketAddress* sockAddr) { sockAddr->set_ip_bytes((const void*)_address, NSAPI_IPv4); } + // Access the raw byte array containing the address. Because this returns a pointer // to the internal structure rather than a copy of the address this function should only // be used when you know that the usage of the returned uint8_t* will be transient and not
--- a/UipEthernet.cpp Sat Sep 07 17:42:42 2019 +0000 +++ b/UipEthernet.cpp Fri Jun 05 15:12:21 2020 +0000 @@ -113,7 +113,7 @@ * @param * @retval */ -int UipEthernet::connect(unsigned long timeout) +int UipEthernet::connect(unsigned long timeout /*=60*/) { // Inicialize static pointer to the UIPEthernet instance ethernet = this; @@ -323,6 +323,17 @@ * @param * @retval */ +void UipEthernet::get_ip_address(SocketAddress* addr) +{ + localIP().toSocketAddress(addr); +} + +/** + * @brief + * @note + * @param + * @retval + */ const char* UipEthernet::get_netmask() { static char buf[16]; @@ -335,6 +346,17 @@ * @param * @retval */ +void UipEthernet::get_netmask(SocketAddress* addr) +{ + return subnetMask().toSocketAddress(addr); +} + +/** + * @brief + * @note + * @param + * @retval + */ const char* UipEthernet::get_gateway() { static char buf[16]; @@ -347,6 +369,17 @@ * @param * @retval */ +void UipEthernet::get_gateway(SocketAddress* addr) +{ + return gatewayIP().toSocketAddress(addr); +} + +/** + * @brief + * @note + * @param + * @retval + */ void UipEthernet::tick() { if (inPacket == NOBLOCK) {
--- a/UipEthernet.h Sat Sep 07 17:42:42 2019 +0000 +++ b/UipEthernet.h Fri Jun 05 15:12:21 2020 +0000 @@ -63,8 +63,11 @@ IpAddress gatewayIP(); IpAddress dnsServerIP(); const char* get_ip_address(); + void get_ip_address(SocketAddress* addr); const char* get_netmask(); + void get_netmask(SocketAddress* addr); const char* get_gateway(); + void get_gateway(SocketAddress* addr); static uint16_t chksum(uint16_t sum, const uint8_t* data, uint16_t len); static uint16_t ipchksum(); bool stoip4(const char *ip4addr, size_t len, void *dest);
--- a/utility/Enc28j60Eth.cpp Sat Sep 07 17:42:42 2019 +0000 +++ b/utility/Enc28j60Eth.cpp Fri Jun 05 15:12:21 2020 +0000 @@ -25,6 +25,7 @@ */ #include "Enc28j60Eth.h" #include "mbed.h" +#include "mbed_version.h" extern "C" { @@ -63,7 +64,11 @@ _cs = 1; _spi.format(8, 0); // 8-bit, mode 0 _spi.frequency(10000000); // 10 Mbit/s - wait_ms(100); // for stable state +#if MBED_MAJOR_VERSION == 2 + wait_ms(100); +#else + thread_sleep_for(100); +#endif // perform system reset writeOp(ENC28J60_SOFT_RESET, 0, ENC28J60_SOFT_RESET); @@ -72,7 +77,11 @@ // while(!(readReg(ESTAT) & ESTAT_CLKRDY)); // The CLKRDY does not work. See Rev. B4 Silicon Errata point. // Just wait. +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif // do bank 0 stuff // initialize receive buffer @@ -707,9 +716,17 @@ void Enc28j60Eth::powerOff() { writeOp(ENC28J60_BIT_FIELD_CLR, ECON1, ECON1_RXEN); +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_VRPS); +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif writeOp(ENC28J60_BIT_FIELD_SET, ECON2, ECON2_PWRSV); } @@ -722,9 +739,17 @@ void Enc28j60Eth::powerOn() { writeOp(ENC28J60_BIT_FIELD_CLR, ECON2, ECON2_PWRSV); +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif writeOp(ENC28J60_BIT_FIELD_SET, ECON1, ECON1_RXEN); +#if MBED_MAJOR_VERSION == 2 wait_ms(50); +#else + thread_sleep_for(50); +#endif } /**
--- a/utility/ip4tos.c Sat Sep 07 17:42:42 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,78 +0,0 @@ -/* - * Copyright (c) 2014-2018 ARM Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "mbed_version.h" - -#if MBED_MAJOR_VERSION == 2 - -#include <stdio.h> -#include <string.h> -#include "common_functions.h" -#include "ip4string.h" - -static void ipv4_itoa(char *string, uint8_t byte); - -/** - * Print binary IPv4 address to a string. - * String must contain enough room for full address, 16 bytes exact. - * \param addr IPv4 address. - * \p buffer to write string to. - */ -uint_fast8_t ip4tos(const void *ip4addr, char *p) -{ - uint_fast8_t outputPos = 0; - const uint8_t *byteArray = ip4addr; - - for (uint_fast8_t component = 0; component < 4; ++component) { - //Convert the byte to string - ipv4_itoa(&p[outputPos], byteArray[component]); - - //Move outputPos to the end of the string - while (p[outputPos] != '\0') { - outputPos += 1; - } - - //Append a dot if this is not the last digit - if (component < 3) { - p[outputPos++] = '.'; - } - } - - // Return length of generated string, excluding the terminating null character - return outputPos; -} - -static void ipv4_itoa(char *string, uint8_t byte) -{ - char *baseString = string; - - //Write the digits to the buffer from the least significant to the most - // This is the incorrect order but we will swap later - do { - *string++ = '0' + byte % 10; - byte /= 10; - } while (byte); - - //We put the final \0, then go back one step on the last digit for the swap - *string-- = '\0'; - - //We now swap the digits - while (baseString < string) { - uint8_t tmp = *string; - *string-- = *baseString; - *baseString++ = tmp; - } -} -#endif
--- a/utility/ip6tos.c Sat Sep 07 17:42:42 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * Copyright (c) 2014-2015 ARM Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "mbed_version.h" - -#if MBED_MAJOR_VERSION == 2 - -#include <stdio.h> -#include <string.h> -#include "common_functions.h" -#include "ip6string.h" - -/** - * Print binary IPv6 address to a string. - * String must contain enough room for full address, 40 bytes exact. - * IPv4 tunneling addresses are not covered. - * \param addr IPv6 address. - * \p buffer to write string to. - */ -uint_fast8_t ip6tos(const void *ip6addr, char *p) -{ - char *p_orig = p; - uint_fast8_t zero_start = 255, zero_len = 1; - const uint8_t *addr = ip6addr; - uint_fast16_t part; - - /* Follow RFC 5952 - pre-scan for longest run of zeros */ - for (uint_fast8_t n = 0; n < 8; n++) { - part = *addr++; - part = (part << 8) | *addr++; - if (part != 0) { - continue; - } - - /* We're at the start of a run of zeros - scan to non-zero (or end) */ - uint_fast8_t n0 = n; - for (n = n0 + 1; n < 8; n++) { - part = *addr++; - part = (part << 8) | *addr++; - if (part != 0) { - break; - } - } - - /* Now n0->initial zero of run, n->after final zero in run. Is this the - * longest run yet? If equal, we stick with the previous one - RFC 5952 - * S4.2.3. Note that zero_len being initialised to 1 stops us - * shortening a 1-part run (S4.2.2.) - */ - if (n - n0 > zero_len) { - zero_start = n0; - zero_len = n - n0; - } - - /* Continue scan for initial zeros from part n+1 - we've already - * consumed part n, and know it's non-zero. */ - } - - /* Now go back and print, jumping over any zero run */ - addr = ip6addr; - for (uint_fast8_t n = 0; n < 8;) { - if (n == zero_start) { - if (n == 0) { - *p++ = ':'; - } - *p++ = ':'; - addr += 2 * zero_len; - n += zero_len; - continue; - } - - part = *addr++; - part = (part << 8) | *addr++; - n++; - - p += sprintf(p, "%"PRIxFAST16, part); - - /* One iteration writes "part:" rather than ":part", and has the - * explicit check for n == 8 below, to allow easy extension for - * IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just - * run the same loop for 6 parts, and output would then finish with the - * required : or ::, ready for "a.b.c.d" to be tacked on. - */ - if (n != 8) { - *p++ = ':'; - } - } - *p = '\0'; - - // Return length of generated string, excluding the terminating null character - return p - p_orig; -} - -uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p) -{ - char *wptr = p; - uint8_t addr[16] = {0}; - - if (prefix_len > 128) { - return 0; - } - - // Generate prefix part of the string - bitcopy(addr, prefix, prefix_len); - wptr += ip6tos(addr, wptr); - // Add the prefix length part of the string - wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len); - - // Return total length of generated string - return wptr - p; -} -#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/os2_ip4tos.c Fri Jun 05 15:12:21 2020 +0000 @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2014-2018 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_version.h" + +#if MBED_MAJOR_VERSION == 2 + +#include <stdio.h> +#include <string.h> +#include "common_functions.h" +#include "ip4string.h" + +static void ipv4_itoa(char *string, uint8_t byte); + +/** + * Print binary IPv4 address to a string. + * String must contain enough room for full address, 16 bytes exact. + * \param addr IPv4 address. + * \p buffer to write string to. + */ +uint_fast8_t ip4tos(const void *ip4addr, char *p) +{ + uint_fast8_t outputPos = 0; + const uint8_t *byteArray = ip4addr; + + for (uint_fast8_t component = 0; component < 4; ++component) { + //Convert the byte to string + ipv4_itoa(&p[outputPos], byteArray[component]); + + //Move outputPos to the end of the string + while (p[outputPos] != '\0') { + outputPos += 1; + } + + //Append a dot if this is not the last digit + if (component < 3) { + p[outputPos++] = '.'; + } + } + + // Return length of generated string, excluding the terminating null character + return outputPos; +} + +static void ipv4_itoa(char *string, uint8_t byte) +{ + char *baseString = string; + + //Write the digits to the buffer from the least significant to the most + // This is the incorrect order but we will swap later + do { + *string++ = '0' + byte % 10; + byte /= 10; + } while (byte); + + //We put the final \0, then go back one step on the last digit for the swap + *string-- = '\0'; + + //We now swap the digits + while (baseString < string) { + uint8_t tmp = *string; + *string-- = *baseString; + *baseString++ = tmp; + } +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/os2_ip6tos.c Fri Jun 05 15:12:21 2020 +0000 @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_version.h" + +#if MBED_MAJOR_VERSION == 2 + +#include <stdio.h> +#include <string.h> +#include "common_functions.h" +#include "ip6string.h" + +/** + * Print binary IPv6 address to a string. + * String must contain enough room for full address, 40 bytes exact. + * IPv4 tunneling addresses are not covered. + * \param addr IPv6 address. + * \p buffer to write string to. + */ +uint_fast8_t ip6tos(const void *ip6addr, char *p) +{ + char *p_orig = p; + uint_fast8_t zero_start = 255, zero_len = 1; + const uint8_t *addr = ip6addr; + uint_fast16_t part; + + /* Follow RFC 5952 - pre-scan for longest run of zeros */ + for (uint_fast8_t n = 0; n < 8; n++) { + part = *addr++; + part = (part << 8) | *addr++; + if (part != 0) { + continue; + } + + /* We're at the start of a run of zeros - scan to non-zero (or end) */ + uint_fast8_t n0 = n; + for (n = n0 + 1; n < 8; n++) { + part = *addr++; + part = (part << 8) | *addr++; + if (part != 0) { + break; + } + } + + /* Now n0->initial zero of run, n->after final zero in run. Is this the + * longest run yet? If equal, we stick with the previous one - RFC 5952 + * S4.2.3. Note that zero_len being initialised to 1 stops us + * shortening a 1-part run (S4.2.2.) + */ + if (n - n0 > zero_len) { + zero_start = n0; + zero_len = n - n0; + } + + /* Continue scan for initial zeros from part n+1 - we've already + * consumed part n, and know it's non-zero. */ + } + + /* Now go back and print, jumping over any zero run */ + addr = ip6addr; + for (uint_fast8_t n = 0; n < 8;) { + if (n == zero_start) { + if (n == 0) { + *p++ = ':'; + } + *p++ = ':'; + addr += 2 * zero_len; + n += zero_len; + continue; + } + + part = *addr++; + part = (part << 8) | *addr++; + n++; + + p += sprintf(p, "%"PRIxFAST16, part); + + /* One iteration writes "part:" rather than ":part", and has the + * explicit check for n == 8 below, to allow easy extension for + * IPv4-in-IPv6-type addresses ("xxxx::xxxx:a.b.c.d"): we'd just + * run the same loop for 6 parts, and output would then finish with the + * required : or ::, ready for "a.b.c.d" to be tacked on. + */ + if (n != 8) { + *p++ = ':'; + } + } + *p = '\0'; + + // Return length of generated string, excluding the terminating null character + return p - p_orig; +} + +uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p) +{ + char *wptr = p; + uint8_t addr[16] = {0}; + + if (prefix_len > 128) { + return 0; + } + + // Generate prefix part of the string + bitcopy(addr, prefix, prefix_len); + wptr += ip6tos(addr, wptr); + // Add the prefix length part of the string + wptr += sprintf(wptr, "/%"PRIuFAST8, prefix_len); + + // Return total length of generated string + return wptr - p; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/os2_stoip4.c Fri Jun 05 15:12:21 2020 +0000 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014-2018 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_version.h" + +#if MBED_MAJOR_VERSION == 2 + +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include "common_functions.h" +#include "ip4string.h" + +/** + * Convert numeric IPv4 address string to a binary. + * \param ip4addr IPv4 address in string format. + * \param len Length of IPv4 string, maximum of 16.. + * \param dest buffer for address. MUST be 4 bytes. + * \return boolean set to true if conversion succeded, false if it didn't + */ +bool stoip4(const char *ip4addr, size_t len, void *dest) +{ + uint8_t *addr = dest; + + if (len > 16) { // Too long, not possible + return false; + } + + uint_fast8_t stringLength = 0, byteCount = 0; + + //Iterate over each component of the IP. The exit condition is in the middle of the loop + while (true) { + + //No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z) + if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') { + return false; + } + + //For each component, we convert it to the raw value + uint_fast16_t byte = 0; + while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') { + byte *= 10; + byte += ip4addr[stringLength++] - '0'; + + //We go over the maximum value for an IPv4 component + if (byte > 0xff) { + return false; + } + } + + //Append the component + addr[byteCount++] = (uint8_t) byte; + + //If we're at the end, we leave the loop. It's the only way to reach the `true` output + if (byteCount == 4) { + break; + } + + //If the next character is invalid, we return false + if (stringLength == len || ip4addr[stringLength++] != '.') { + return false; + } + } + + return stringLength == len || ip4addr[stringLength] == '\0'; +} +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/os2_stoip6.c Fri Jun 05 15:12:21 2020 +0000 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2014-2015 ARM Limited. All rights reserved. + * SPDX-License-Identifier: Apache-2.0 + * Licensed under the Apache License, Version 2.0 (the License); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an AS IS BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed_version.h" + +#if MBED_MAJOR_VERSION == 2 + +#include <string.h> +#include <stdlib.h> +#include <stdint.h> +#include "common_functions.h" +#include "ip6string.h" + +static uint16_t hex(const char *p); +static bool is_hex(char c); + +/** + * Convert numeric IPv6 address string to a binary. + * IPv4 tunnelling addresses are not covered. + * \param ip6addr IPv6 address in string format. + * \param len Length of ipv6 string. + * \param dest buffer for address. MUST be 16 bytes. + * \return boolean set to true if conversion succeed, false if it didn't + */ +bool stoip6(const char *ip6addr, size_t len, void *dest) +{ + uint8_t *addr; + const char *p, *q; + int_fast8_t field_no, coloncolon = -1; + + addr = dest; + + if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses + goto error; + } + + // First go forward the string, until end, noting :: position if any + // We're decrementing `len` as we go forward, and stop when it reaches 0 + for (field_no = 0, p = ip6addr; len && *p; p = q + 1) { + + for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end + if (!is_hex(*q++)) { // There must only be hex characters besides ':' + goto error; + } + } + + if ((q - p) > 4) { // We can't have more than 4 hex digits per segment + goto error; + } + + if (field_no == 8) { // If the address goes farther than 8 segments + goto error; + } + + // Convert and write this part, (high-endian AKA network byte order) + addr = common_write_16_bit(hex(p), addr); + field_no++; + + // We handle the colons + if (len) { + // Check if we reached "::" + if (q[0] == ':' && q[1] == ':') { + if (coloncolon != -1) { // We are not supposed to see "::" more than once per address + goto error; + } + coloncolon = field_no; + q++; + len -= 2; + } else { + len -= 1; + } + } + } + + if (coloncolon != -1) { + /* Insert zeros in the appropriate place */ + uint_fast8_t head_size = 2 * coloncolon; + uint_fast8_t inserted_size = 2 * (8 - field_no); + uint_fast8_t tail_size = 16 - head_size - inserted_size; + addr = dest; + memmove(addr + head_size + inserted_size, addr + head_size, tail_size); + memset(addr + head_size, 0, inserted_size); + } else if (field_no != 8) { // Report an error if we didn't get 8 fields + goto error; + } + return true; + +error: + // Fill the output buffer with 0 so we stick to the old failure behavior. + // We are however more agressive and wipe the entire address, and do so more often. + memset(dest, 0, 16); + return false; +} + +unsigned char sipv6_prefixlength(const char *ip6addr) +{ + char *ptr = strchr(ip6addr, '/'); + if (ptr) { + return (unsigned char)strtoul(ptr + 1, 0, 10); + } + return 0; +} + +int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out) +{ + size_t addr_len, total_len; + int_fast16_t prefix_length; + + if (prefix_len_out) { + *prefix_len_out = -1; + } + + total_len = addr_len = strlen(ip6addr); + const char *ptr = strchr(ip6addr, '/'); + if (ptr) { + addr_len = ptr - ip6addr; + if (prefix_len_out) { + if (total_len - addr_len > 3) { + /* too many digits in prefix */ + return -1; + } + + prefix_length = strtoul(ptr + 1, 0, 10); + if (prefix_length < 0 || prefix_length > 128) { + /* prefix value illegal */ + return -1; + } + + *prefix_len_out = prefix_length; + } + } + + if (!stoip6(ip6addr, addr_len, dest)) { + /* parser failure */ + return -1; + } + + return 0; +} + +static bool is_hex(char c) +{ + // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A' + if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') { + return true; + } + + if (c >= '0' && c <= '9') { + return true; + } + + return false; +} + +static uint16_t hex(const char *p) +{ + uint16_t val = 0; + + for (;;) { + char c = *p++; + if ((c >= '0') && (c <= '9')) { + val = (val << 4) | (c - '0'); + } else if ((c >= 'A') && (c <= 'F')) { + val = (val << 4) | (10 + (c - 'A')); + } else if ((c >= 'a') && (c <= 'f')) { + val = (val << 4) | (10 + (c - 'a')); + } else { + break; // Non hex character + } + } + return val; +} +#endif
--- a/utility/stoip4.c Sat Sep 07 17:42:42 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2014-2018 ARM Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "mbed_version.h" - -#if MBED_MAJOR_VERSION == 2 - -#include <string.h> -#include <stdlib.h> -#include <stdint.h> -#include "common_functions.h" -#include "ip4string.h" - -/** - * Convert numeric IPv4 address string to a binary. - * \param ip4addr IPv4 address in string format. - * \param len Length of IPv4 string, maximum of 16.. - * \param dest buffer for address. MUST be 4 bytes. - * \return boolean set to true if conversion succeded, false if it didn't - */ -bool stoip4(const char *ip4addr, size_t len, void *dest) -{ - uint8_t *addr = dest; - - if (len > 16) { // Too long, not possible - return false; - } - - uint_fast8_t stringLength = 0, byteCount = 0; - - //Iterate over each component of the IP. The exit condition is in the middle of the loop - while (true) { - - //No valid character (IPv4 addresses don't have implicit 0, that is x.y..z being read as x.y.0.z) - if (stringLength == len || ip4addr[stringLength] < '0' || ip4addr[stringLength] > '9') { - return false; - } - - //For each component, we convert it to the raw value - uint_fast16_t byte = 0; - while (stringLength < len && ip4addr[stringLength] >= '0' && ip4addr[stringLength] <= '9') { - byte *= 10; - byte += ip4addr[stringLength++] - '0'; - - //We go over the maximum value for an IPv4 component - if (byte > 0xff) { - return false; - } - } - - //Append the component - addr[byteCount++] = (uint8_t) byte; - - //If we're at the end, we leave the loop. It's the only way to reach the `true` output - if (byteCount == 4) { - break; - } - - //If the next character is invalid, we return false - if (stringLength == len || ip4addr[stringLength++] != '.') { - return false; - } - } - - return stringLength == len || ip4addr[stringLength] == '\0'; -} -#endif
--- a/utility/stoip6.c Sat Sep 07 17:42:42 2019 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2014-2015 ARM Limited. All rights reserved. - * SPDX-License-Identifier: Apache-2.0 - * Licensed under the Apache License, Version 2.0 (the License); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an AS IS BASIS, WITHOUT - * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -#include "mbed_version.h" - -#if MBED_MAJOR_VERSION == 2 - -#include <string.h> -#include <stdlib.h> -#include <stdint.h> -#include "common_functions.h" -#include "ip6string.h" - -static uint16_t hex(const char *p); -static bool is_hex(char c); - -/** - * Convert numeric IPv6 address string to a binary. - * IPv4 tunnelling addresses are not covered. - * \param ip6addr IPv6 address in string format. - * \param len Length of ipv6 string. - * \param dest buffer for address. MUST be 16 bytes. - * \return boolean set to true if conversion succeed, false if it didn't - */ -bool stoip6(const char *ip6addr, size_t len, void *dest) -{ - uint8_t *addr; - const char *p, *q; - int_fast8_t field_no, coloncolon = -1; - - addr = dest; - - if (len > 39) { // Too long, not possible. We do not support IPv4-mapped IPv6 addresses - goto error; - } - - // First go forward the string, until end, noting :: position if any - // We're decrementing `len` as we go forward, and stop when it reaches 0 - for (field_no = 0, p = ip6addr; len && *p; p = q + 1) { - - for (q = p; len && *q && (*q != ':'); len -= 1) { // Seek for ':' or end - if (!is_hex(*q++)) { // There must only be hex characters besides ':' - goto error; - } - } - - if ((q - p) > 4) { // We can't have more than 4 hex digits per segment - goto error; - } - - if (field_no == 8) { // If the address goes farther than 8 segments - goto error; - } - - // Convert and write this part, (high-endian AKA network byte order) - addr = common_write_16_bit(hex(p), addr); - field_no++; - - // We handle the colons - if (len) { - // Check if we reached "::" - if (q[0] == ':' && q[1] == ':') { - if (coloncolon != -1) { // We are not supposed to see "::" more than once per address - goto error; - } - coloncolon = field_no; - q++; - len -= 2; - } else { - len -= 1; - } - } - } - - if (coloncolon != -1) { - /* Insert zeros in the appropriate place */ - uint_fast8_t head_size = 2 * coloncolon; - uint_fast8_t inserted_size = 2 * (8 - field_no); - uint_fast8_t tail_size = 16 - head_size - inserted_size; - addr = dest; - memmove(addr + head_size + inserted_size, addr + head_size, tail_size); - memset(addr + head_size, 0, inserted_size); - } else if (field_no != 8) { // Report an error if we didn't get 8 fields - goto error; - } - return true; - -error: - // Fill the output buffer with 0 so we stick to the old failure behavior. - // We are however more agressive and wipe the entire address, and do so more often. - memset(dest, 0, 16); - return false; -} - -unsigned char sipv6_prefixlength(const char *ip6addr) -{ - char *ptr = strchr(ip6addr, '/'); - if (ptr) { - return (unsigned char)strtoul(ptr + 1, 0, 10); - } - return 0; -} - -int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out) -{ - size_t addr_len, total_len; - int_fast16_t prefix_length; - - if (prefix_len_out) { - *prefix_len_out = -1; - } - - total_len = addr_len = strlen(ip6addr); - const char *ptr = strchr(ip6addr, '/'); - if (ptr) { - addr_len = ptr - ip6addr; - if (prefix_len_out) { - if (total_len - addr_len > 3) { - /* too many digits in prefix */ - return -1; - } - - prefix_length = strtoul(ptr + 1, 0, 10); - if (prefix_length < 0 || prefix_length > 128) { - /* prefix value illegal */ - return -1; - } - - *prefix_len_out = prefix_length; - } - } - - if (!stoip6(ip6addr, addr_len, dest)) { - /* parser failure */ - return -1; - } - - return 0; -} - -static bool is_hex(char c) -{ - // 'A' (0x41) and 'a' (0x61) are mapped in the ASCII table in such a way that masking the 0x20 bit turn 'a' in 'A' - if ((c & ~0x20) >= 'A' && (c & ~0x20) <= 'F') { - return true; - } - - if (c >= '0' && c <= '9') { - return true; - } - - return false; -} - -static uint16_t hex(const char *p) -{ - uint16_t val = 0; - - for (;;) { - char c = *p++; - if ((c >= '0') && (c <= '9')) { - val = (val << 4) | (c - '0'); - } else if ((c >= 'A') && (c <= 'F')) { - val = (val << 4) | (10 + (c - 'A')); - } else if ((c >= 'a') && (c <= 'f')) { - val = (val << 4) | (10 + (c - 'a')); - } else { - break; // Non hex character - } - } - return val; -} -#endif