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 14:7648334eb41b, committed 2019-09-03
- Comitter:
- hudakz
- Date:
- Tue Sep 03 09:16:55 2019 +0000
- Parent:
- 13:95c00132cd98
- Child:
- 15:53715cc81c63
- Commit message:
- UDP socket improved.
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SocketAddress.cpp Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,349 @@ +/* Socket + * Copyright (c) 2015 ARM Limited + * + * 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 "SocketAddress.h" +//#include "NetworkInterface.h" +//#include "NetworkStack.h" +#include <string.h> +#include <stdio.h> +#include "ip4string.h" +#include "ip6string.h" + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::SocketAddress(nsapi_addr_t addr, uint16_t port) +{ + mem_init(); + _ip_address = NULL; + set_addr(addr); + set_port(port); +} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::SocketAddress(const char* addr, uint16_t port) +{ + mem_init(); + _ip_address = NULL; + set_ip_address(addr); + set_port(port); +} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::SocketAddress(const void* bytes, nsapi_version_t version, uint16_t port) +{ + mem_init(); + _ip_address = NULL; + set_ip_bytes(bytes, version); + set_port(port); +} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::SocketAddress(const SocketAddress& addr) +{ + mem_init(); + _ip_address = NULL; + set_addr(addr.get_addr()); + set_port(addr.get_port()); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void SocketAddress::mem_init(void) +{ + _addr.version = NSAPI_UNSPEC; + memset(_addr.bytes, 0, NSAPI_IP_BYTES); + _port = 0; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool SocketAddress::set_ip_address(const char* addr) +{ + delete[] _ip_address; + _ip_address = NULL; + + if (addr && stoip4(addr, strlen(addr), _addr.bytes)) { + _addr.version = NSAPI_IPv4; + return true; + } + else + if (addr && stoip6(addr, strlen(addr), _addr.bytes)) { + _addr.version = NSAPI_IPv6; + return true; + } + else { + _addr = nsapi_addr_t(); + return false; + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +void SocketAddress::set_ip_bytes(const void* bytes, nsapi_version_t version) +{ + nsapi_addr_t addr; + + addr = nsapi_addr_t(); + addr.version = version; + if (version == NSAPI_IPv6) { + memcpy(addr.bytes, bytes, NSAPI_IPv6_BYTES); + } + else + if (version == NSAPI_IPv4) { + memcpy(addr.bytes, bytes, NSAPI_IPv4_BYTES); + } + + set_addr(addr); +} + +/** + * @brief + * @note + * @param + * @retval + */ +void SocketAddress::set_addr(nsapi_addr_t addr) +{ + delete[] _ip_address; + _ip_address = NULL; + _addr = addr; +} + +/** + * @brief + * @note + * @param + * @retval + */ +void SocketAddress::set_port(uint16_t port) +{ + _port = port; +} + +/** + * @brief + * @note + * @param + * @retval + */ +const char* SocketAddress::get_ip_address() const +{ + if (_addr.version == NSAPI_UNSPEC) { + return NULL; + } + + if (!_ip_address) { + _ip_address = new char[NSAPI_IP_SIZE]; + if (_addr.version == NSAPI_IPv4) { + ip4tos(_addr.bytes, _ip_address); + } + else + if (_addr.version == NSAPI_IPv6) { + ip6tos(_addr.bytes, _ip_address); + } + } + + return _ip_address; +} + +/** + * @brief + * @note + * @param + * @retval + */ +const void* SocketAddress::get_ip_bytes() const +{ + return _addr.bytes; +} + +/** + * @brief + * @note + * @param + * @retval + */ +nsapi_version_t SocketAddress::get_ip_version() const +{ + return _addr.version; +} + +/** + * @brief + * @note + * @param + * @retval + */ +nsapi_addr_t SocketAddress::get_addr() const +{ + return _addr; +} + +/** + * @brief + * @note + * @param + * @retval + */ +uint16_t SocketAddress::get_port() const +{ + return _port; +} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::operator bool() const +{ + if (_addr.version == NSAPI_IPv4) { + for (int i = 0; i < NSAPI_IPv4_BYTES; i++) { + if (_addr.bytes[i]) { + return true; + } + } + + return false; + } + else + if (_addr.version == NSAPI_IPv6) { + for (int i = 0; i < NSAPI_IPv6_BYTES; i++) { + if (_addr.bytes[i]) { + return true; + } + } + + return false; + } + else { + return false; + } +} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress &SocketAddress::operator=(const SocketAddress& addr) +{ + delete[] _ip_address; + _ip_address = NULL; + set_addr(addr.get_addr()); + set_port(addr.get_port()); + return *this; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool operator==(const SocketAddress& a, const SocketAddress& b) +{ + if (!a && !b) { + return true; + } + else + if (a._addr.version != b._addr.version) { + return false; + } + else + if (a._addr.version == NSAPI_IPv4) { + return memcmp(a._addr.bytes, b._addr.bytes, NSAPI_IPv4_BYTES) == 0; + } + else + if (a._addr.version == NSAPI_IPv6) { + return memcmp(a._addr.bytes, b._addr.bytes, NSAPI_IPv6_BYTES) == 0; + } + + MBED_UNREACHABLE; +} + +/** + * @brief + * @note + * @param + * @retval + */ +bool operator!=(const SocketAddress& a, const SocketAddress& b) +{ + return !(a == b); +} + +//void SocketAddress::_SocketAddress(NetworkStack *iface, const char *host, uint16_t port) +//{ +// _ip_address = NULL; +// // gethostbyname must check for literals, so can call it directly +// int err = iface->gethostbyname(host, this); +// _port = port; +// if (err) { +// _addr = nsapi_addr_t(); +// _port = 0; +// } +//} + +/** + * @brief + * @note + * @param + * @retval + */ +SocketAddress::~SocketAddress() +{ + delete[] _ip_address; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SocketAddress.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,192 @@ +/* + * Copyright (c) 2015 ARM Limited + * + * 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. + */ + +/** @file SocketAddress.h SocketAddress class */ +/** \addtogroup netsocket + * @{*/ + +#ifndef SOCKET_ADDRESS_H +#define SOCKET_ADDRESS_H + +#include "nsapi_types.h" +#include "mbed_toolchain.h" + +// Predeclared classes +class NetworkStack; +class NetworkInterface; + +/** SocketAddress class + * + * Representation of an IP address and port pair. + */ +class SocketAddress { +public: + /** Create a SocketAddress from a hostname and port + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * On failure, the IP address and port will be set to zero + * + * @tparam S Type of the Network stack + * @param stack Network stack to use for DNS resolution + * @param host Hostname to resolve + * @param port Optional 16-bit port, defaults to 0 + * @deprecated + * Constructors hide possible errors. Replaced by + * NetworkInterface::gethostbyname. + */ + template <typename S> + MBED_DEPRECATED_SINCE("mbed-os-5.1.3", + "Constructors hide possible errors. Replaced by " + "NetworkInterface::gethostbyname.") + SocketAddress(S *stack, const char *host, uint16_t port = 0) + { + _SocketAddress(nsapi_create_stack(stack), host, port); + } + + /** Create a SocketAddress from a raw IP address and port + * + * @note To construct from a host name, use NetworkInterface::gethostbyname + * + * @param addr Raw IP address + * @param port Optional 16-bit port, defaults to 0 + */ + SocketAddress(nsapi_addr_t addr = nsapi_addr_t(), uint16_t port = 0); + + /** Create a SocketAddress from an IP address and port + * + * @param addr Null-terminated representation of the IP address + * @param port Optional 16-bit port, defaults to 0 + */ + SocketAddress(const char *addr, uint16_t port = 0); + + /** Create a SocketAddress from raw IP bytes, IP version, and port + * + * @param bytes Raw IP address in big-endian order + * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 + * @param port Optional 16-bit port, defaults to 0 + */ + SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port = 0); + + /** Create a SocketAddress from another SocketAddress + * + * @param addr SocketAddress to copy + */ + SocketAddress(const SocketAddress &addr); + + /** Destructor */ + ~SocketAddress(); + + /** Set the IP address + * + * @param addr Null-terminated represention of the IP address + * @return True if address is a valid representation of an IP address, + * otherwise False and SocketAddress is set to null + */ + bool set_ip_address(const char *addr); + + /** Set the raw IP bytes and IP version + * + * @param bytes Raw IP address in big-endian order + * @param version IP address version, NSAPI_IPv4 or NSAPI_IPv6 + */ + void set_ip_bytes(const void *bytes, nsapi_version_t version); + + /** Set the raw IP address + * + * @param addr Raw IP address + */ + void set_addr(nsapi_addr_t addr); + + /** Set the port + * + * @param port 16-bit port + */ + void set_port(uint16_t port); + + /** Get the human-readable IP address + * + * Allocates memory for a string and converts binary address to + * human-readable format. String is freed in the destructor. + * + * @return Null-terminated representation of the IP Address + */ + const char *get_ip_address() const; + + /** Get the raw IP bytes + * + * @return Raw IP address in big-endian order + */ + const void *get_ip_bytes() const; + + /** Get the IP address version + * + * @return IP address version, NSAPI_IPv4 or NSAPI_IPv6 + */ + nsapi_version_t get_ip_version() const; + + /** Get the raw IP address + * + * @return Raw IP address + */ + nsapi_addr_t get_addr() const; + + /** Get the port + * + * @return The 16-bit port + */ + uint16_t get_port() const; + + /** Test if address is zero + * + * @return True if address is not zero + */ + operator bool() const; + + /** Copy address from another SocketAddress + * + * @param addr SocketAddress to copy + */ + SocketAddress &operator=(const SocketAddress &addr); + + /** Compare two addresses for equality + * + * @return True if both addresses are equal + */ + friend bool operator==(const SocketAddress &a, const SocketAddress &b); + + /** Compare two addresses for equality + * + * @return True if both addresses are not equal + */ + friend bool operator!=(const SocketAddress &a, const SocketAddress &b); + +private: + //void _SocketAddress(NetworkStack *iface, const char *host, uint16_t port); + + /** Initialize memory */ + void mem_init(void); + + mutable char *_ip_address; + nsapi_addr_t _addr; + uint16_t _port; +}; + + +#endif + +/** @}*/
--- a/UdpSocket.cpp Sat Aug 31 20:34:52 2019 +0000 +++ b/UdpSocket.cpp Tue Sep 03 09:16:55 2019 +0000 @@ -30,13 +30,47 @@ #define UIP_ARPHDRSIZE 42 #define UDPBUF ((struct uip_udpip_hdr*) &uip_buf[UIP_LLH_LEN]) -// Constructor +/** + * @brief + * @note + * @param + * @retval + */ UdpSocket::UdpSocket() : - _uip_udp_conn(NULL) + _uip_udp_conn(NULL), + _timeout_ms(1000) { memset(&appdata, 0, sizeof(appdata)); } +/** + * @brief + * @note + * @param + * @retval + */ +UdpSocket::UdpSocket(int timeout_ms) : + _uip_udp_conn(NULL), + _timeout_ms(timeout_ms) +{ + memset(&appdata, 0, sizeof(appdata)); +} + +/** + * @brief + * @note + * @param + * @retval + */ +UdpSocket::UdpSocket(UipEthernet* net, int timeout_ms /*= 1000*/ ) : + _uip_udp_conn(NULL), + _timeout_ms(timeout_ms) +{ + memset(&appdata, 0, sizeof(appdata)); + if (UipEthernet::ethernet != net) + UipEthernet::ethernet = net; +} + // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use uint8_t UdpSocket::begin(uint16_t port) { @@ -67,6 +101,17 @@ } } +/** + * @brief + * @note + * @param + * @retval + */ +void UdpSocket::close() +{ + stop(); +} + // Sending UDP packets // Start building up a packet to send to the remote host specific in ip and port @@ -222,13 +267,13 @@ } // Number of bytes remaining in the current packet -int UdpSocket::available() +size_t UdpSocket::available() { UipEthernet::ethernet->tick(); return UipEthernet::ethernet->enc28j60Eth.blockSize(appdata.packet_in); } -// Read a single byte from the current packet +// Read a single byte from the current packet. Returns -1 if no byte is available. int UdpSocket::read() { static unsigned char c; @@ -242,7 +287,7 @@ // Read up to len bytes from the current packet and place them into buffer // Returns the number of bytes read, or 0 if none are available -int UdpSocket::read(unsigned char* buffer, size_t len) +size_t UdpSocket::read(unsigned char* buffer, size_t len) { UipEthernet::ethernet->tick(); if (appdata.packet_in != NOBLOCK) { @@ -372,3 +417,116 @@ UipEthernet::ethernet->network_send(); } #endif + +/** + * @brief + * @note + * @param + * @retval + */ +nsapi_size_or_error_t UdpSocket::sendto(const char* host, uint16_t port, const void* data, size_t size) +{ + DnsClient dns; + IpAddress address; + uint32_t address_bytes; + + dns.begin(UipEthernet::ethernet->dnsServerIP()); + if (dns.getHostByName(host, address) == 1) { + address_bytes = address; + _remote_addr = SocketAddress(&address_bytes, NSAPI_IPv4, port); + } + else { + _remote_addr = SocketAddress(host, port); + } + + if (beginPacket(host, port) == 0) { + stop(); + return NSAPI_ERROR_NO_ADDRESS; + } + + if (write((uint8_t*)data, size) == 0) { + stop(); + return NSAPI_ERROR_WOULD_BLOCK; + }; + + if (endPacket() <= 0) { + stop(); + return NSAPI_ERROR_WOULD_BLOCK; + } + + return NSAPI_ERROR_OK; +} + +/** + * @brief + * @note + * @param + * @retval + */ +nsapi_size_or_error_t UdpSocket::sendto(const SocketAddress& address, const void* data, size_t size) +{ + IpAddress ip_addr(address.get_addr().bytes); + uint16_t port = address.get_port(); + + _remote_addr = address; + + if (beginPacket(ip_addr, port) == 0) { + stop(); + return NSAPI_ERROR_NO_ADDRESS; + } + + if (write((uint8_t*)data, size) == 0) { + stop(); + return NSAPI_ERROR_WOULD_BLOCK; + }; + + if (endPacket() <= 0) { + stop(); + return NSAPI_ERROR_WOULD_BLOCK; + } + + return NSAPI_ERROR_OK; +} + +/** + * @brief + * @note + * @param + * @retval + */ +nsapi_size_or_error_t UdpSocket::recvfrom(SocketAddress* address, void* data, size_t size) +{ + *address = _remote_addr; + + Timer timer; + int success; + + timer.start(); + do { + success = parsePacket(); + } while (!success && (timer.read_ms() < _timeout_ms)); + + if (!success) { + stop(); + return NSAPI_ERROR_WOULD_BLOCK; + } + + size_t n; + size_t recv_count = 0; + uint8_t* pos = (uint8_t*)data; + + do { + if (recv_count + available() <= size) { + n = read(pos, available()); + pos += n; + recv_count += n; + } + else { + return NSAPI_ERROR_NO_MEMORY; + } + } while ((available() > 0) && (recv_count < size)); + + flush(); + + return NSAPI_ERROR_OK; +}
--- a/UdpSocket.h Sat Aug 31 20:34:52 2019 +0000 +++ b/UdpSocket.h Tue Sep 03 09:16:55 2019 +0000 @@ -22,6 +22,7 @@ #define UDPSOCKET_h #include "mbed.h" +#include "SocketAddress.h" #include "utility/Udp.h" #include "IpAddress.h" #include "utility/MemPool.h" @@ -42,16 +43,23 @@ bool send; } uip_udp_userdata_t; +class UipEthernet; + class UdpSocket : public Udp { private: + uip_udp_userdata_t appdata; struct uip_udp_conn* _uip_udp_conn; - uip_udp_userdata_t appdata; + SocketAddress _remote_addr; + int _timeout_ms; public: - UdpSocket(); // Constructor - virtual ~UdpSocket() { } // Virtual destructor - uint8_t begin(uint16_t); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use - void stop(); // Finish with the UDP socket + UdpSocket(); // Constructor + UdpSocket(int timeout_ms); // Constructor + UdpSocket(UipEthernet* ethernet, int timeout_ms = 1000); + virtual ~UdpSocket() { } // Virtual destructor + uint8_t begin(uint16_t port); // initialize, start listening on specified port. Returns 1 if successful, 0 if there are no sockets available to use + void stop(); // Finish with the UDP socket + void close(); // Close the UDP socket // Sending UDP packets // Start building up a packet to send to the remote host specific in ip and port // Returns 1 if successful, 0 if there was a problem with the supplied IP address or port @@ -77,18 +85,18 @@ int parsePacket(); // Number of bytes remaining in the current packet - int available(); + size_t available(); // Read a single byte from the current packet int read(); // Read up to len bytes from the current packet and place them into buffer // Returns the number of bytes read, or 0 if none are available - int read(unsigned char* buffer, size_t len); + size_t read(unsigned char* buffer, size_t len); // Read up to len characters from the current packet and place them into buffer // Returns the number of characters read, or 0 if none are available - int read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); } + size_t read(char* buffer, size_t len) { return read((unsigned char*)buffer, len); } // Return the next byte from the current packet without moving on to the next byte int peek(); @@ -99,6 +107,14 @@ // Return the port of the host who sent the current incoming packet uint16_t remotePort(); + + // Send data to the specified host and port. + nsapi_size_or_error_t sendto (const char *host, uint16_t port, const void *data, size_t size); + // Send data to the specified address. + nsapi_size_or_error_t sendto (const SocketAddress &address, const void *data, size_t size); + // Receive a datagram and store the source address in address if it's not NULL. + nsapi_size_or_error_t recvfrom (SocketAddress *address, void *data, size_t size); + private: friend void uipudp_appcall();
--- a/UipEthernet.cpp Sat Aug 31 20:34:52 2019 +0000 +++ b/UipEthernet.cpp Tue Sep 03 09:16:55 2019 +0000 @@ -136,12 +136,14 @@ dhcpClient.getGatewayIp(), dhcpClient.getSubnetMask() ); + + return 0; } - return ret; + return -1; } else { - return 1; + return 0; } }
--- a/UipEthernet.h Sat Aug 31 20:34:52 2019 +0000 +++ b/UipEthernet.h Tue Sep 03 09:16:55 2019 +0000 @@ -37,6 +37,7 @@ { #include "utility/uip_timer.h" #include "utility/uip.h" +#include "utility/util.h" } #define UIPETHERNET_FREEPACKET 1 #define UIPETHERNET_SENDPACKET 2
--- a/utility/Enc28j60Eth.cpp Sat Aug 31 20:34:52 2019 +0000 +++ b/utility/Enc28j60Eth.cpp Tue Sep 03 09:16:55 2019 +0000 @@ -244,7 +244,7 @@ * @param * @retval */ -memaddress Enc28j60Eth::blockSize(memhandle handle) +size_t Enc28j60Eth::blockSize(memhandle handle) { return handle == NOBLOCK ? 0 : handle == UIP_RECEIVEBUFFERHANDLE ? receivePkt.size : blocks[handle].size; }
--- a/utility/Enc28j60Eth.h Sat Aug 31 20:34:52 2019 +0000 +++ b/utility/Enc28j60Eth.h Tue Sep 03 09:16:55 2019 +0000 @@ -65,7 +65,7 @@ void init(uint8_t* macaddr); memhandle receivePacket(); void freePacket(); - memaddress blockSize(memhandle handle); + size_t blockSize(memhandle handle); void sendPacket(memhandle handle); uint16_t readPacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len); uint16_t writePacket(memhandle handle, memaddress position, uint8_t* buffer, uint16_t len);
--- a/utility/Udp.h Sat Aug 31 20:34:52 2019 +0000 +++ b/utility/Udp.h Tue Sep 03 09:16:55 2019 +0000 @@ -67,21 +67,21 @@ virtual int parsePacket(void) = 0; // Number of bytes remaining in the current packet - virtual int available(void) = 0; + virtual size_t available(void) = 0; - // Read a single byte from the current packet + // Read a single byte from the current packet. Returns -1 if no byte is available. virtual int read(void) = 0; // Read up to len bytes from the current packet and place them into buffer // Returns the number of bytes read, or 0 if none are available - virtual int read(unsigned char* buffer, size_t len) = 0; + virtual size_t read(unsigned char* buffer, size_t len) = 0; // Read up to len characters from the current packet and place them into buffer // Returns the number of characters read, or 0 if none are available - virtual int read(char* buffer, size_t len) = 0; + virtual size_t read(char* buffer, size_t len) = 0; // Return the next byte from the current packet without moving on to the next byte - virtual int peek(void) = 0; + virtual int peek(void) = 0; // returns -1 if fails virtual void flush(void) = 0; // Finish reading the current packet // Return the IP address of the host who sent the current incoming packet @@ -90,6 +90,6 @@ // Return the port of the host who sent the current incoming packet virtual uint16_t remotePort(void) = 0; protected: - uint8_t* rawIPAddress(IpAddress& addr) { return addr.rawAddress(); }; + uint8_t* rawIPAddress(IpAddress& addr) { return addr.rawAddress(); } }; #endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/common_functions.c Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,93 @@ +/* + * 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. + */ + +/* + * Most functions can be inlined, and definitions are in common_functions.h. + * Define COMMON_FUNCTIONS_FN before including it to generate external definitions. + */ + +#include "mbed_version.h" + +#if MBED_MAJOR_VERSION == 2 + +#define COMMON_FUNCTIONS_FN extern + +#include "common_functions.h" + +#include <string.h> + +/* Returns mask for <split_value> (0-8) most-significant bits of a byte */ +static inline uint8_t context_split_mask(uint_fast8_t split_value) +{ + return (uint8_t) - (0x100u >> split_value); +} + +bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (bytes && memcmp(a, b, bytes)) { + return false; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + if ((a[bytes] & split_bit) != (b[bytes] & split_bit)) { + return false; + } + } + + return true; +} + +uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (bytes) { + dst = (uint8_t *) memcpy(dst, src, bytes) + bytes; + src += bytes; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + *dst = (*src & split_bit) | (*dst & ~ split_bit); + } + + return dst; +} + +uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits) +{ + uint_fast8_t bytes = bits / 8; + bits %= 8; + + if (bytes) { + dst = (uint8_t *) memcpy(dst, src, bytes) + bytes; + src += bytes; + } + + if (bits) { + uint_fast8_t split_bit = context_split_mask(bits); + *dst = (*src & split_bit); + } + + return dst; +} + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/common_functions.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,638 @@ +/* + * 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. + */ +#ifndef COMMON_FUNCTIONS_H_ +#define COMMON_FUNCTIONS_H_ + +#include "ns_types.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Common write 64-bit variable to 8-bit pointer. + * + * Write 64 bits in big-endian (network) byte order. + * + * \param value 64-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8]); + +/* + * Common read 64-bit variable from 8-bit pointer. + * + * Read 64 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 64-bit variable + */ +NS_INLINE uint64_t common_read_64_bit(const uint8_t data_buf[__static 8]); + +/* + * Common write 32-bit variable to 8-bit pointer. + * + * Write 32 bits in big-endian (network) byte order. + * + * \param value 32-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]); + +/* + * Common read 32-bit variable from 8-bit pointer. + * + * Read 32 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 32-bit variable + */ +NS_INLINE uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]); + +/* + * Common write 32-bit variable to 8-bit pointer. + * + * Write 32 bits in little-endian byte order. + * + * \param value 32-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4]); + +/* + * Common read 32-bit variable from 8-bit pointer. + * + * Read 32 bits in little-endian byte order. + * + * \param data_buf pointer where data to be read + * + * \return 32-bit variable + */ +NS_INLINE uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4]); + +/* + * Common write 24-bit variable to 8-bit pointer. + * + * Write 24 bits in big-endian (network) byte order. + * + * \param value 24-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3]); + +/* + * Common read 24-bit variable from 8-bit pointer. + * + * Read 24 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 24-bit variable + */ +NS_INLINE uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3]); + +/* + * Common write 24-bit variable to 8-bit pointer. + * + * Write 24 bits in little-endian byte order. + * + * \param value 24-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_24_bit_inverse(uint_fast24_t value, uint8_t ptr[__static 3]); + +/* + * Common read 24-bit variable from 8-bit pointer. + * + * Read 24 bits in little-endian byte order. + * + * \param data_buf pointer where data to be read + * + * \return 24-bit variable + */ +NS_INLINE uint_fast24_t common_read_24_bit_inverse(const uint8_t data_buf[__static 3]); + +/* + * Common write 16-bit variable to 8-bit pointer. + * + * Write 16 bits in big-endian (network) byte order. + * + * \param value 16-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]); + +/* + * Common read 16-bit variable from 8-bit pointer. + * + * Read 16 bits in big-endian (network) byte order. + * + * \param data_buf pointer where data to be read + * + * \return 16-bit variable + */ +NS_INLINE uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]); + +/* + * Common write 16-bit variable to 8-bit pointer. + * + * Write 16 bits in little-endian byte order. + * + * \param value 16-bit variable + * \param ptr pointer where data to be written + * + * \return updated pointer + */ +NS_INLINE uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]); + +/* + * Common read 16-bit variable from 8-bit pointer. + * + * Read 16 bits in little-endian byte order. + * + * \param data_buf pointer where data to be read + * + * \return 16-bit variable + */ +NS_INLINE uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2]); + +/* + * Count bits in a byte + * + * \param value byte to inspect + * + * \return number of 1-bits in byte + */ +NS_INLINE uint_fast8_t common_count_bits(uint8_t value); + +/* + * Count leading zeros in a byte + * + * \deprecated Use common_count_leading_zeros_8 + * + * \param value byte to inspect + * + * \return number of leading zeros in byte (0-8) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros(uint8_t value); + +/* + * Count leading zeros in a byte + * + * \param value byte to inspect + * + * \return number of leading zeros in byte (0-8) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_8(uint8_t value); + +/* + * Count leading zeros in a 16-bit value + * + * \param value value to inspect + * + * \return number of leading zeros in byte (0-16) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_16(uint16_t value); + +/* + * Count leading zeros in a 32-bit value + * + * \param value value to inspect + * + * \return number of leading zeros in byte (0-32) + */ +NS_INLINE uint_fast8_t common_count_leading_zeros_32(uint32_t value); + +/* + * Compare 8-bit serial numbers + * + * Compare two 8-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_8(uint8_t s1, uint8_t s2); + +/* + * Compare 16-bit serial numbers + * + * Compare two 16-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_16(uint16_t s1, uint16_t s2); + +/* + * Compare 32-bit serial numbers + * + * Compare two 32-bit serial numbers, according to RFC 1982 Serial Number + * Arithmetic. + * + * \param s1 first serial number + * \param s2 second serial number + * + * \return true if s1 > s2 + * \return false if s1 <= s2, or the comparison is undefined + */ +NS_INLINE bool common_serial_number_greater_32(uint32_t s1, uint32_t s2); + +/* + * Test a bit in an bit array. + * + * Check whether a particular bit is set in a bit string. The bit array + * is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + * + * \return true if the bit is set + */ +NS_INLINE bool bit_test(const uint8_t *bitset, uint_fast8_t bit); + +/* + * Set a bit in an bit array. + * + * Set a bit in a bit array. The array is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + */ +NS_INLINE void bit_set(uint8_t *bitset, uint_fast8_t bit); + +/* + * Clear a bit in an bit array. + * + * Clear a bit in a bit array. The bit array is in big-endian (network) bit order. + * + * \param bitset pointer to bit array + * \param bit index of bit - 0 is the most significant bit of the first byte + */ +NS_INLINE void bit_clear(uint8_t *bitset, uint_fast8_t bit); + +/* + * Compare two bitstrings. + * + * Compare two bitstrings of specified length. The bit strings are in + * big-endian (network) bit order. + * + * \param a pointer to first string + * \param b pointer to second string + * \param bits number of bits to compare + * + * \return true if the strings compare equal + */ +bool bitsequal(const uint8_t *a, const uint8_t *b, uint_fast8_t bits); + +/* + * Copy a bitstring + * + * Copy a bitstring of specified length. The bit string is in big-endian + * (network) bit order. Bits beyond the bitlength at the destination are not + * modified. + * + * For example, copying 4 bits sets the first 4 bits of dst[0] from src[0], + * the lower 4 bits of dst[0] are unmodified. + * + * \param dst destination pointer + * \param src source pointer + * \param bits number of bits to copy + * + * \return the value of dst + */ +uint8_t *bitcopy(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits); + +/* + * Copy a bitstring and pad last byte with zeros + * + * Copy a bitstring of specified length. The bit string is in big-endian + * (network) bit order. Bits beyond the bitlength in the last destination byte are + * zeroed. + * + * For example, copying 4 bits sets the first 4 bits of dst[0] from src[0], and + * the lower 4 bits of dst[0] are set to 0. + * + * \param dst destination pointer + * \param src source pointer + * \param bits number of bits to copy + * + * \return the value of dst + */ +uint8_t *bitcopy0(uint8_t *restrict dst, const uint8_t *restrict src, uint_fast8_t bits); + +/* Provide definitions, either for inlining, or for common_functions.c */ +#if defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN +#ifndef COMMON_FUNCTIONS_FN +#define COMMON_FUNCTIONS_FN NS_INLINE +#endif + +COMMON_FUNCTIONS_FN uint8_t *common_write_64_bit(uint64_t value, uint8_t ptr[__static 8]) +{ + *ptr++ = value >> 56; + *ptr++ = value >> 48; + *ptr++ = value >> 40; + *ptr++ = value >> 32; + *ptr++ = value >> 24; + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint64_t common_read_64_bit(const uint8_t data_buf[__static 8]) +{ + uint64_t temp_64; + temp_64 = (uint64_t)(*data_buf++) << 56; + temp_64 += (uint64_t)(*data_buf++) << 48; + temp_64 += (uint64_t)(*data_buf++) << 40; + temp_64 += (uint64_t)(*data_buf++) << 32; + temp_64 += (uint64_t)(*data_buf++) << 24; + temp_64 += (uint64_t)(*data_buf++) << 16; + temp_64 += (uint64_t)(*data_buf++) << 8; + temp_64 += *data_buf++; + return temp_64; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit(uint32_t value, uint8_t ptr[__static 4]) +{ + *ptr++ = value >> 24; + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint32_t common_read_32_bit(const uint8_t data_buf[__static 4]) +{ + uint32_t temp_32; + temp_32 = (uint32_t)(*data_buf++) << 24; + temp_32 += (uint32_t)(*data_buf++) << 16; + temp_32 += (uint32_t)(*data_buf++) << 8; + temp_32 += *data_buf++; + return temp_32; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_32_bit_inverse(uint32_t value, uint8_t ptr[__static 4]) +{ + *ptr++ = value; + *ptr++ = value >> 8; + *ptr++ = value >> 16; + *ptr++ = value >> 24; + return ptr; +} + +COMMON_FUNCTIONS_FN uint32_t common_read_32_bit_inverse(const uint8_t data_buf[__static 4]) +{ + uint32_t temp_32; + temp_32 = *data_buf++; + temp_32 += (uint32_t)(*data_buf++) << 8; + temp_32 += (uint32_t)(*data_buf++) << 16; + temp_32 += (uint32_t)(*data_buf++) << 24; + return temp_32; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_24_bit(uint_fast24_t value, uint8_t ptr[__static 3]) +{ + *ptr++ = value >> 16; + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint_fast24_t common_read_24_bit(const uint8_t data_buf[__static 3]) +{ + uint_fast24_t temp_24; + temp_24 = (uint_fast24_t)(*data_buf++) << 16; + temp_24 += (uint_fast24_t)(*data_buf++) << 8; + temp_24 += *data_buf++; + return temp_24; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_24_bit_inverse(uint_fast24_t value, uint8_t ptr[__static 3]) +{ + *ptr++ = value; + *ptr++ = value >> 8; + *ptr++ = value >> 16; + return ptr; +} + +COMMON_FUNCTIONS_FN uint_fast24_t common_read_24_bit_inverse(const uint8_t data_buf[__static 3]) +{ + uint_fast24_t temp_24; + temp_24 = *data_buf++; + temp_24 += (uint_fast24_t)(*data_buf++) << 8; + temp_24 += (uint_fast24_t)(*data_buf++) << 16; + return temp_24; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit(uint16_t value, uint8_t ptr[__static 2]) +{ + *ptr++ = value >> 8; + *ptr++ = value; + return ptr; +} + +COMMON_FUNCTIONS_FN uint16_t common_read_16_bit(const uint8_t data_buf[__static 2]) +{ + uint16_t temp_16; + temp_16 = (uint16_t)(*data_buf++) << 8; + temp_16 += *data_buf++; + return temp_16; +} + +COMMON_FUNCTIONS_FN uint8_t *common_write_16_bit_inverse(uint16_t value, uint8_t ptr[__static 2]) +{ + *ptr++ = value; + *ptr++ = value >> 8; + return ptr; +} + +COMMON_FUNCTIONS_FN uint16_t common_read_16_bit_inverse(const uint8_t data_buf[__static 2]) +{ + uint16_t temp_16; + temp_16 = *data_buf++; + temp_16 += (uint16_t)(*data_buf++) << 8; + return temp_16; +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_bits(uint8_t value) +{ + /* First step sets each bit pair to be count of bits (00,01,10) */ + /* [00-00 = 00, 01-00 = 01, 10-01 = 01, 11-01 = 10] */ + uint_fast8_t count = value - ((value >> 1) & 0x55); + /* Add bit pairs to make each nibble contain count of bits (0-4) */ + count = (count & 0x33) + ((count >> 2) & 0x33); + /* Final result is sum of nibbles (0-8) */ + count = (count >> 4) + (count & 0x0F); + return count; +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros(uint8_t value) +{ + return common_count_leading_zeros_8(value); +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_8(uint8_t value) +{ +#ifdef __CC_ARM + return value ? __clz((unsigned int) value << 24) : 8; +#elif defined __GNUC__ + return value ? __builtin_clz((unsigned int) value << 24) : 8; +#else + uint_fast8_t cnt = 0; + if (value == 0) { + return 8; + } + if ((value & 0xF0) == 0) { + value <<= 4; + cnt += 4; + } + if ((value & 0xC0) == 0) { + value <<= 2; + cnt += 2; + } + if ((value & 0x80) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_16(uint16_t value) +{ +#ifdef __CC_ARM + return value ? __clz((unsigned int) value << 16) : 16; +#elif defined __GNUC__ + return value ? __builtin_clz((unsigned int) value << 16) : 16; +#else + uint_fast8_t cnt = 0; + if (value == 0) { + return 16; + } + if ((value & 0xFF00) == 0) { + value <<= 8; + cnt += 8; + } + if ((value & 0xF000) == 0) { + value <<= 4; + cnt += 4; + } + if ((value & 0xC000) == 0) { + value <<= 2; + cnt += 2; + } + if ((value & 0x8000) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN uint_fast8_t common_count_leading_zeros_32(uint32_t value) +{ +#ifdef __CC_ARM + return __clz(value); +#elif defined __GNUC__ + return value ? __builtin_clz(value) : 32; +#else + uint_fast8_t cnt = 0; + if (value == 0) { + return 32; + } + if ((value & 0xFFFF0000) == 0) { + value <<= 16; + cnt += 16; + } + if ((value & 0xFF000000) == 0) { + value <<= 8; + cnt += 8; + } + if ((value & 0xF0000000) == 0) { + value <<= 4; + cnt += 4; + } + if ((value & 0xC0000000) == 0) { + value <<= 2; + cnt += 2; + } + if ((value & 0x80000000) == 0) { + cnt += 1; + } + + return cnt; +#endif +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_8(uint8_t s1, uint8_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT8_C(0x80)) || (s1 < s2 && s2 - s1 > UINT8_C(0x80)); +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_16(uint16_t s1, uint16_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT16_C(0x8000)) || (s1 < s2 && s2 - s1 > UINT16_C(0x8000)); +} + +COMMON_FUNCTIONS_FN bool common_serial_number_greater_32(uint32_t s1, uint32_t s2) +{ + return (s1 > s2 && s1 - s2 < UINT32_C(0x80000000)) || (s1 < s2 && s2 - s1 > UINT32_C(0x80000000)); +} + +COMMON_FUNCTIONS_FN bool bit_test(const uint8_t *bitset, uint_fast8_t bit) +{ + return bitset[bit >> 3] & (0x80 >> (bit & 7)); +} + +COMMON_FUNCTIONS_FN void bit_set(uint8_t *bitset, uint_fast8_t bit) +{ + bitset[bit >> 3] |= (0x80 >> (bit & 7)); +} + +COMMON_FUNCTIONS_FN void bit_clear(uint8_t *bitset, uint_fast8_t bit) +{ + bitset[bit >> 3] &= ~(0x80 >> (bit & 7)); +} + +#endif /* defined NS_ALLOW_INLINING || defined COMMON_FUNCTIONS_FN */ + +#ifdef __cplusplus +} +#endif +#endif /*__COMMON_FUNCTIONS_H_*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/ip4string.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,48 @@ +/* + * 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. + */ +#ifndef IP4STRING_H +#define IP4STRING_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +/** + * Print binary IPv4 address to a string. + * + * String must contain enough room for full address, 16 bytes exact. + * + * \param ip4addr IPv4 address. + * \param p buffer to write string to. + * \return length of generated string excluding the terminating null character + */ +uint_fast8_t ip4tos(const void *ip4addr, char *p); + +/** + * 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 succeed, false if it didn't + */ +bool stoip4(const char *ip4addr, size_t len, void *dest); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/ip4tos.c Tue Sep 03 09:16:55 2019 +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/ip6string.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,89 @@ +/* + * 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. + */ +#ifndef IP6STRING_H +#define IP6STRING_H +#ifdef __cplusplus +extern "C" { +#endif + +#include "ns_types.h" + +#define MAX_IPV6_STRING_LEN_WITH_TRAILING_NULL 40 + +/** + * 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 ip6addr IPv6 address. + * \param p buffer to write string to. + * \return length of generated string excluding the terminating null character + */ +uint_fast8_t ip6tos(const void *ip6addr, char *p); + +/** + * Print binary IPv6 prefix to a string. + * + * String buffer `p` must contain enough room for a full address and prefix length, 44 bytes exact. + * Bits in the `prefix` buffer beyond `prefix_len` bits are not shown and only the bytes containing the + * prefix bits are read. I.e. for a 20 bit prefix 3 bytes are read, and for a 0 bit prefix 0 bytes are + * read (thus if `prefix_len` is zero, `prefix` can be NULL). + * `prefix_len` must be 0 to 128. + * + * \param prefix IPv6 prefix. + * \param prefix_len length of `prefix` in bits. + * \param p buffer to write string to. + * \return length of generated string excluding the terminating null character, or 0 for an error, such as 'prefix_len' > 128 + */ +uint_fast8_t ip6_prefix_tos(const void *prefix, uint_fast8_t prefix_len, char *p); + +/** + * Convert numeric IPv6 address string to a binary. + * + * IPv4 tunneling addresses are not covered. + * + * \param ip6addr IPv6 address in string format. + * \param len Lenght of ipv6 string, maximum of 41. + * \param dest buffer for address. MUST be 16 bytes. Filled with 0 on error. + * \return boolean set to true if conversion succeed, false if it didn't + */ +bool stoip6(const char *ip6addr, size_t len, void *dest); +/** + * Find out numeric IPv6 address prefix length. + * + * \param ip6addr IPv6 address in string format + * \return prefix length or 0 if it not given + */ +unsigned char sipv6_prefixlength(const char *ip6addr); + +/** + * Convert numeric IPv6 address string with prefix to a binary. + * + * IPv4 tunneling addresses are not covered. + * + * \param ip6addr IPv6 address in string format. + * \param dest buffer for address. MUST be 16 bytes. + * \param prefix_len_out length of prefix, is set to -1 if no prefix given + * + * \return 0 on success, negative value otherwise. prefix_len_out contains prefix length. + */ +int stoip6_prefix(const char *ip6addr, void *dest, int_fast16_t *prefix_len_out); + +#ifdef __cplusplus +} +#endif +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/ip6tos.c Tue Sep 03 09:16:55 2019 +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/ns_types.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,411 @@ +/* + * 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. + */ +/* + * ns_types.h - Basic compiler and type setup for Nanostack libraries. + */ +#ifndef NS_TYPES_H_ +#define NS_TYPES_H_ + +/** \file + * \brief Basic compiler and type setup + * + * We currently assume C99 or later. + * + * C99 features being relied on: + * + * - <inttypes.h> and <stdbool.h> + * - inline (with C99 semantics, not C++ as per default GCC); + * - designated initialisers; + * - compound literals; + * - restrict; + * - [static N] in array parameters; + * - declarations in for statements; + * - mixing declarations and statements + * + * Compilers should be set to C99 or later mode when building Nanomesh source. + * For GCC this means "-std=gnu99" (C99 with usual GNU extensions). + * + * Also, a little extra care is required for public header files that could be + * included from C++, especially as C++ lacks some C99 features. + * + * (TODO: as this is exposed to API users, do we need a predefine to distinguish + * internal and external use, for finer control? Not yet, but maybe...) + */ + +/* Make sure <stdint.h> defines its macros if C++ */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS +#endif +#ifndef __STDC_CONSTANT_MACROS +#define __STDC_CONSTANT_MACROS +#endif + +#include <stddef.h> +#include <inttypes.h> // includes <stdint.h>; debugf() users need PRIu32 etc +#include <stdbool.h> + +/* + * Create the optional <stdint.h> 24-bit types if they don't exist (worth trying + * to use them, as they could exist and be more efficient than 32-bit on 8-bit + * systems...) + */ +#ifndef UINT_LEAST24_MAX +typedef uint_least32_t uint_least24_t; +#define UINT_LEAST24_MAX UINT_LEAST32_MAX +#define UINT24_C(x) UINT32_C(x) +#define PRIoLEAST24 PRIoLEAST32 +#define PRIuLEAST24 PRIuLEAST32 +#define PRIxLEAST24 PRIxLEAST32 +#define PRIXLEAST24 PRIXLEAST32 +#endif + +#ifndef INT_LEAST24_MAX +typedef int_least32_t int_least24_t; +#define INT_LEAST24_MIN INT_LEAST32_MIN +#define INT_LEAST24_MAX INT_LEAST32_MAX +#define INT24_C(x) INT32_C(x) +#define PRIdLEAST24 PRIdLEAST32 +#define PRIiLEAST24 PRIiLEAST32 +#endif + +#ifndef UINT_FAST24_MAX +typedef uint_fast32_t uint_fast24_t; +#define UINT_FAST24_MAX UINT_FAST32_MAX +#define PRIoFAST24 PRIoFAST32 +#define PRIuFAST24 PRIuFAST32 +#define PRIxFAST24 PRIxFAST32 +#define PRIXFAST24 PRIXFAST32 +#endif + +#ifndef INT_FAST24_MAX +typedef int_fast32_t int_fast24_t; +#define INT_FAST24_MIN INT_FAST32_MIN +#define INT_FAST24_MAX INT_FAST32_MAX +#define PRIdFAST24 PRIdFAST32 +#define PRIiFAST24 PRIiFAST32 +#endif + +/* Function attribute - C11 "noreturn" or C++11 "[[noreturn]]" */ +#ifndef NS_NORETURN +#if defined __cplusplus && __cplusplus >= 201103L +#define NS_NORETURN [[noreturn]] +#elif !defined __cplusplus && __STDC_VERSION__ >= 201112L +#define NS_NORETURN _Noreturn +#elif defined __GNUC__ +#define NS_NORETURN __attribute__((__noreturn__)) +#elif defined __CC_ARM +#define NS_NORETURN __declspec(noreturn) +#elif defined __IAR_SYSTEMS_ICC__ +#define NS_NORETURN __noreturn +#else +#define NS_NORETURN +#endif +#endif + +/* C11's "alignas" macro, emulated for integer expressions if necessary */ +#ifndef __alignas_is_defined +#if defined __CC_ARM || defined __TASKING__ +#define alignas(n) __align(n) +#define __alignas_is_defined 1 +#elif (defined __STDC_VERSION__ && __STDC_VERSION__ >= 201112L) || (defined __cplusplus && __cplusplus >= 201103L) +# if defined __ARMCC_VERSION && __ARMCC_VERSION < 6120000 +/* Workaround for Arm Compiler versions prior to 6.12 */ +# if !defined __cplusplus +# define alignas _Alignas +# endif +# define __alignas_is_defined 1 +# else +# include <stdalign.h> +# endif +#elif defined __GNUC__ +#define alignas(n) __attribute__((__aligned__(n))) +#define __alignas_is_defined 1 +#elif defined __IAR_SYSTEMS_ICC__ +/* Does this really just apply to the next variable? */ +#define alignas(n) __Alignas(data_alignment=n) +#define __Alignas(x) _Pragma(#x) +#define __alignas_is_defined 1 +#endif +#endif + +/** + * Marker for functions or objects that may be unused, suppressing warnings. + * Place after the identifier: + * ~~~ + * static int X MAYBE_UNUSED = 3; + * static int foo(void) MAYBE_UNUSED; + * ~~~ + */ +#if defined __CC_ARM || defined __GNUC__ +#define MAYBE_UNUSED __attribute__((unused)) +#else +#define MAYBE_UNUSED +#endif + +/* + * C++ (even C++11) doesn't provide restrict: define away or provide + * alternative. + */ +#ifdef __cplusplus +#ifdef __GNUC__ +#define restrict __restrict +#else +#define restrict +#endif +#endif /* __cplusplus */ + + +/** + * C++ doesn't allow "static" in function parameter types: ie + * ~~~ + * entry_t *find_entry(const uint8_t address[static 16]) + * ~~~ + * If a header file may be included from C++, use this __static define instead. + * + * (Syntax introduced in C99 - `uint8_t address[16]` in a prototype was always + * equivalent to `uint8_t *address`, but the C99 addition of static tells the + * compiler that address is never NULL, and always points to at least 16 + * elements. This adds no new type-checking, but the information could aid + * compiler optimisation, and it can serve as documentation). + */ +#ifdef __cplusplus +#define __static +#else +#define __static static +#endif + +#ifdef __GNUC__ +#define NS_GCC_VERSION (__GNUC__ * 10000 \ + + __GNUC_MINOR__ * 100 \ + + __GNUC_PATCHLEVEL__) +#endif + +/** \brief Compile-time assertion + * + * C11 provides _Static_assert, as does GCC even in C99 mode (and + * as a freestanding implementation, we can't rely on <assert.h> to get + * the static_assert macro). + * C++11 provides static_assert as a keyword, as does G++ in C++0x mode. + * + * The assertion acts as a declaration that can be placed at file scope, in a + * code block (except after a label), or as a member of a struct/union. It + * produces a compiler error if "test" evaluates to 0. + * + * Note that this *includes* the required semicolon when defined, else it + * is totally empty, permitting use in structs. (If the user provided the `;`, + * it would leave an illegal stray `;` if unavailable). + */ +#ifdef __cplusplus +# if __cplusplus >= 201103L || __cpp_static_assert >= 200410 +# define NS_STATIC_ASSERT(test, str) static_assert(test, str); +# elif defined __GXX_EXPERIMENTAL_CXX0X__ && NS_GCC_VERSION >= 40300 +# define NS_STATIC_ASSERT(test, str) __extension__ static_assert(test, str); +# else +# define NS_STATIC_ASSERT(test, str) +# endif +#else /* C */ +# if __STDC_VERSION__ >= 201112L +# define NS_STATIC_ASSERT(test, str) _Static_assert(test, str); +# elif defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +# ifdef _Static_assert +/* + * Some versions of glibc cdefs.h (which comes in via <stdint.h> above) + * attempt to define their own _Static_assert (if GCC < 4.6 or + * __STRICT_ANSI__) using an extern declaration, which doesn't work in a + * struct/union. + * + * For GCC >= 4.6 and __STRICT_ANSI__, we can do better - just use + * the built-in _Static_assert with __extension__. We have to do this, as + * ns_list.h needs to use it in a union. No way to get at it though, without + * overriding their define. + */ +# undef _Static_assert +# define _Static_assert(x, y) __extension__ _Static_assert(x, y) +# endif +# define NS_STATIC_ASSERT(test, str) __extension__ _Static_assert(test, str); +# else +# define NS_STATIC_ASSERT(test, str) +#endif +#endif + +/** \brief Pragma to suppress warnings about unusual pointer values. + * + * Useful if using "poison" values. + */ +#ifdef __IAR_SYSTEMS_ICC__ +#define NS_FUNNY_INTPTR_OK _Pragma("diag_suppress=Pe1053") +#define NS_FUNNY_INTPTR_RESTORE _Pragma("diag_default=Pe1053") +#else +#define NS_FUNNY_INTPTR_OK +#define NS_FUNNY_INTPTR_RESTORE +#endif + +/** \brief Pragma to suppress warnings about always true/false comparisons + */ +#if defined __GNUC__ && NS_GCC_VERSION >= 40600 && !defined __CC_ARM +#define NS_FUNNY_COMPARE_OK _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wtype-limits\"") +#define NS_FUNNY_COMPARE_RESTORE _Pragma("GCC diagnostic pop") +#else +#define NS_FUNNY_COMPARE_OK +#define NS_FUNNY_COMPARE_RESTORE +#endif + +/** \brief Pragma to suppress warnings arising from dummy definitions. + * + * Useful when you have function-like macros that returning constants + * in cut-down builds. Can be fairly cavalier about disabling as we + * do not expect every build to use this macro. Generic builds of + * components should ensure this is not included by only using it in + * a ifdef blocks providing dummy definitions. + */ +#ifdef __CC_ARM +// statement is unreachable(111), controlling expression is constant(236), expression has no effect(174), +// function was declared but never referenced(177), variable was set but never used(550) +#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=111,236,174,177,550") +#elif defined __IAR_SYSTEMS_ICC__ +// controlling expression is constant +#define NS_DUMMY_DEFINITIONS_OK _Pragma("diag_suppress=Pe236") +#else +#define NS_DUMMY_DEFINITIONS_OK +#endif + +/** \brief Convert pointer to member to pointer to containing structure */ +#define NS_CONTAINER_OF(ptr, type, member) \ + ((type *) ((char *) (ptr) - offsetof(type, member))) + +/* + * Inlining could cause problems when mixing with C++; provide a mechanism to + * disable it. This could also be turned off for other reasons (although + * this can usually be done through a compiler flag, eg -O0 on gcc). + */ +#ifndef __cplusplus +#define NS_ALLOW_INLINING +#endif + +/* There is inlining problem in GCC version 4.1.x and we know it works in 4.6.3 */ +#if defined __GNUC__ && NS_GCC_VERSION < 40600 +#undef NS_ALLOW_INLINING +#endif + +/** \brief Mark a potentially-inlineable function. + * + * We follow C99 semantics, which requires precisely one external definition. + * To also allow inlining to be totally bypassed under control of + * NS_ALLOW_INLINING, code can be structured as per the example of ns_list: + * + * foo.h + * ----- + * ~~~ + * NS_INLINE int my_func(int); + * + * #if defined NS_ALLOW_INLINING || defined FOO_FN + * #ifndef FOO_FN + * #define FOO_FN NS_INLINE + * #endif + * FOO_FN int my_func(int a) + * { + * definition; + * } + * #endif + * ~~~ + * foo.c + * ----- + * ~~~ + * #define FOO_FN extern + * #include "foo.h" + * ~~~ + * Which generates: + * ~~~ + * NS_ALLOW_INLINING set NS_ALLOW_INLINING unset + * ===================== ======================= + * Include foo.h Include foo.h + * ------------- ------------- + * inline int my_func(int); int my_func(int); + * + * // inline definition + * inline int my_func(int a) + * { + * definition; + * } + * + * Compile foo.c Compile foo.c + * ------------- ------------- + * (from .h) inline int my_func(int); int my_func(int); + * + * // external definition + * // because of no "inline" // normal external definition + * extern int my_func(int a) extern int my_func(int a) + * { { + * definition; definition; + * } } + * ~~~ + * + * Note that even with inline keywords, whether the compiler inlines or not is + * up to it. For example, gcc at "-O0" will not inline at all, and will always + * call the real functions in foo.o, just as if NS_ALLOW_INLINING was unset. + * At "-O2", gcc could potentially inline everything, meaning that foo.o is not + * referenced at all. + * + * Alternatively, you could use "static inline", which gives every caller its + * own internal definition. This is compatible with C++ inlining (which expects + * the linker to eliminate duplicates), but in C it's less efficient if the code + * ends up non-inlined, and it's harder to breakpoint. I don't recommend it + * except for the most trivial functions (which could then probably be macros). + */ +#ifdef NS_ALLOW_INLINING +#define NS_INLINE inline +#else +#define NS_INLINE +#endif + +#if defined __SDCC_mcs51 || defined __ICC8051__ || defined __C51__ + +/* The 8051 environments: SDCC (historic), IAR (current), Keil (future?) */ + +#define NS_LARGE __xdata +#define NS_LARGE_PTR __xdata +#ifdef __ICC8051__ +#define NS_REENTRANT +#define NS_REENTRANT_PREFIX __idata_reentrant +#else +#define NS_REENTRANT __reentrant +#define NS_REENTRANT_PREFIX +#endif +#define NS_NEAR_FUNC __near_func + +#else + +/* "Normal" systems. Define it all away. */ +#define NS_LARGE +#define NS_LARGE_PTR +#define NS_REENTRANT +#define NS_REENTRANT_PREFIX +#define NS_NEAR_FUNC + +#endif + +/** \brief Scatter-gather descriptor + * + * Slightly optimised for small platforms - we assume we won't need any + * element bigger than 64K. + */ +typedef struct ns_iovec { + void *iov_base; + uint_fast16_t iov_len; +} ns_iovec_t; + +#endif /* NS_TYPES_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/nsapi_types.h Tue Sep 03 09:16:55 2019 +0000 @@ -0,0 +1,624 @@ + +/** \addtogroup netsocket */ +/** @{*/ +/* nsapi.h - The network socket API + * Copyright (c) 2015 ARM Limited + * + * 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. + */ + +#ifndef NSAPI_TYPES_H +#define NSAPI_TYPES_H + +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + + +/** Enum of standardized error codes + * + * Valid error codes have negative values and may + * be returned by any network operation. + * + * @enum nsapi_error + */ +enum nsapi_error { + NSAPI_ERROR_OK = 0, /*!< no error */ + NSAPI_ERROR_WOULD_BLOCK = -3001, /*!< no data is not available but call is non-blocking */ + NSAPI_ERROR_UNSUPPORTED = -3002, /*!< unsupported functionality */ + NSAPI_ERROR_PARAMETER = -3003, /*!< invalid configuration */ + NSAPI_ERROR_NO_CONNECTION = -3004, /*!< not connected to a network */ + NSAPI_ERROR_NO_SOCKET = -3005, /*!< socket not available for use */ + NSAPI_ERROR_NO_ADDRESS = -3006, /*!< IP address is not known */ + NSAPI_ERROR_NO_MEMORY = -3007, /*!< memory resource not available */ + NSAPI_ERROR_NO_SSID = -3008, /*!< ssid not found */ + NSAPI_ERROR_DNS_FAILURE = -3009, /*!< DNS failed to complete successfully */ + NSAPI_ERROR_DHCP_FAILURE = -3010, /*!< DHCP failed to complete successfully */ + NSAPI_ERROR_AUTH_FAILURE = -3011, /*!< connection to access point failed */ + NSAPI_ERROR_DEVICE_ERROR = -3012, /*!< failure interfacing with the network processor */ + NSAPI_ERROR_IN_PROGRESS = -3013, /*!< operation (eg connect) in progress */ + NSAPI_ERROR_ALREADY = -3014, /*!< operation (eg connect) already in progress */ + NSAPI_ERROR_IS_CONNECTED = -3015, /*!< socket is already connected */ + NSAPI_ERROR_CONNECTION_LOST = -3016, /*!< connection lost */ + NSAPI_ERROR_CONNECTION_TIMEOUT = -3017, /*!< connection timed out */ + NSAPI_ERROR_ADDRESS_IN_USE = -3018, /*!< Address already in use */ + NSAPI_ERROR_TIMEOUT = -3019, /*!< operation timed out */ + NSAPI_ERROR_BUSY = -3020, /*!< device is busy and cannot accept new operation */ +}; + + +/** Enum of connection status types + * + * Valid error codes have negative values. + * + * @enum nsapi_connection_status + */ +typedef enum nsapi_connection_status { + NSAPI_STATUS_LOCAL_UP = 0, /*!< local IP address set */ + NSAPI_STATUS_GLOBAL_UP = 1, /*!< global IP address set */ + NSAPI_STATUS_DISCONNECTED = 2, /*!< no connection to network */ + NSAPI_STATUS_CONNECTING = 3, /*!< connecting to network */ + NSAPI_STATUS_ERROR_UNSUPPORTED = NSAPI_ERROR_UNSUPPORTED +} nsapi_connection_status_t; + + +/** Enum of event types + * + * Event callbacks are accompanied with an event-dependent parameter passed as an intptr_t. + * + * @enum nsapi_event + */ +typedef enum nsapi_event { + NSAPI_EVENT_CONNECTION_STATUS_CHANGE = 0, /*!< network connection status has changed, the parameter = new status (nsapi_connection_status_t) */ + NSAPI_EVENT_CELLULAR_STATUS_BASE = 0x1000, /*!< Cellular modem status has changed, See the enum values from enum cellular_connection_status_t in /features/cellular/framework/common/CellularCommon.h */ + NSAPI_EVENT_CELLULAR_STATUS_END = 0x1FFF /*!< cellular modem status has changed, See the enum values from enum cellular_connection_status_t in /features/cellular/framework/common/CellularCommon.h */ +} nsapi_event_t; + + +/** Type used to represent error codes + * + * This is a separate type from enum nsapi_error to avoid breaking + * compatibility in type-sensitive overloads + */ +typedef signed int nsapi_error_t; + +/** Type used to represent the size of data passed through sockets + */ +typedef unsigned int nsapi_size_t; + +/** Type used to represent either a size or error passed through sockets + * + * A valid nsapi_size_or_error_t is either a non-negative size or a + * negative error code from the nsapi_error_t + */ +typedef signed int nsapi_size_or_error_t; + +/** Type used to represent either a value or error + * + * A valid nsapi_value_or_error_t is either a non-negative value or a + * negative error code from the nsapi_error_t + */ +typedef signed int nsapi_value_or_error_t; + +/** Enum of encryption types + * + * The security type specifies a particular security to use when + * connected to a WiFi network + */ +typedef enum nsapi_security { + NSAPI_SECURITY_NONE = 0x0, /*!< open access point */ + NSAPI_SECURITY_WEP = 0x1, /*!< phrase conforms to WEP */ + NSAPI_SECURITY_WPA = 0x2, /*!< phrase conforms to WPA */ + NSAPI_SECURITY_WPA2 = 0x3, /*!< phrase conforms to WPA2 */ + NSAPI_SECURITY_WPA_WPA2 = 0x4, /*!< phrase conforms to WPA/WPA2 */ + NSAPI_SECURITY_PAP = 0x5, /*!< phrase conforms to PPP authentication context */ + NSAPI_SECURITY_CHAP = 0x6, /*!< phrase conforms to PPP authentication context */ + NSAPI_SECURITY_EAP_TLS = 0x7, /*!< phrase conforms to EAP-TLS */ + NSAPI_SECURITY_PEAP = 0x8, /*!< phrase conforms to PEAP */ + NSAPI_SECURITY_UNKNOWN = 0xFF, /*!< unknown/unsupported security in scan results */ +} nsapi_security_t; + +/** Size of 2 char network interface name from driver + */ +#define NSAPI_INTERFACE_PREFIX_SIZE 2 + +/** Maximum size of network interface name + */ +#define NSAPI_INTERFACE_NAME_MAX_SIZE 6 + +/** Maximum size of IP address representation + */ +#define NSAPI_IP_SIZE NSAPI_IPv6_SIZE + +/** Maximum number of bytes for IP address + */ +#define NSAPI_IP_BYTES NSAPI_IPv6_BYTES + +/** Maximum size of MAC address representation + */ +#define NSAPI_MAC_SIZE 18 + +/** Maximum number of bytes for MAC address + */ +#define NSAPI_MAC_BYTES 6 + +/** Size of IPv4 representation + */ +#define NSAPI_IPv4_SIZE 16 + +/** Number of bytes in IPv4 address + */ +#define NSAPI_IPv4_BYTES 4 + +/** Size of IPv6 representation + */ +#define NSAPI_IPv6_SIZE 40 + +/** Number of bytes in IPv6 address + */ +#define NSAPI_IPv6_BYTES 16 + +/** Enum of IP address versions + * + * The IP version specifies the type of an IP address. + * + * @enum nsapi_version + */ +typedef enum nsapi_version { + NSAPI_UNSPEC, /*!< Address is unspecified */ + NSAPI_IPv4, /*!< Address is IPv4 */ + NSAPI_IPv6, /*!< Address is IPv6 */ +} nsapi_version_t; + +/** IP address structure for passing IP addresses by value + */ +typedef struct nsapi_addr { + /** IP version + * - NSAPI_IPv4 + * - NSAPI_IPv6 + * - NSAPI_UNSPEC + */ + nsapi_version_t version; + + /** IP address + * The raw bytes of the IP address stored in big-endian format + */ + uint8_t bytes[NSAPI_IP_BYTES]; +} nsapi_addr_t; + + +/** Opaque handle for network sockets + */ +typedef void *nsapi_socket_t; + + +/** Enum of socket protocols + * + * The socket protocol specifies a particular protocol to + * be used with a newly created socket. + * + * @enum nsapi_protocol + */ +typedef enum nsapi_protocol { + NSAPI_TCP, /*!< Socket is of TCP type */ + NSAPI_UDP, /*!< Socket is of UDP type */ +} nsapi_protocol_t; + +/** Enum of standardized stack option levels + * for use with NetworkStack::setstackopt and getstackopt. + * + * @enum nsapi_stack_level + */ +typedef enum nsapi_stack_level { + NSAPI_STACK = 5000, /*!< Stack option level - see nsapi_stack_option_t for options */ +} nsapi_stack_level_t; + +/** Enum of standardized stack option names for level NSAPI_STACK + * of NetworkStack::setstackopt and getstackopt. + * + * These options may not be supported on all stacks, in which + * case NSAPI_ERROR_UNSUPPORTED may be returned. + * + * @enum nsapi_stack_option + */ +typedef enum nsapi_stack_option { + NSAPI_IPV4_MRU, /*!< Sets/gets size of largest IPv4 fragmented datagram to reassemble */ + NSAPI_IPV6_MRU, /*!< Sets/gets size of largest IPv6 fragmented datagram to reassemble */ +} nsapi_stack_option_t; + +/** Enum of standardized socket option levels + * for use with Socket::setsockopt and getsockopt. + * + * @enum nsapi_socket_level + */ +typedef enum nsapi_socket_level { + NSAPI_SOCKET = 7000, /*!< Socket option level - see nsapi_socket_option_t for options */ +} nsapi_socket_level_t; + +/** Enum of standardized socket option names for level NSAPI_SOCKET + * of Socket::setsockopt and getsockopt. + * + * These options may not be supported on all stacks, in which + * case NSAPI_ERROR_UNSUPPORTED may be returned. + * + * @enum nsapi_socket_option + */ +typedef enum nsapi_socket_option { + NSAPI_REUSEADDR, /*!< Allow bind to reuse local addresses */ + NSAPI_KEEPALIVE, /*!< Enables sending of keepalive messages */ + NSAPI_KEEPIDLE, /*!< Sets timeout value to initiate keepalive */ + NSAPI_KEEPINTVL, /*!< Sets timeout value for keepalive */ + NSAPI_LINGER, /*!< Keeps close from returning until queues empty */ + NSAPI_SNDBUF, /*!< Sets send buffer size */ + NSAPI_RCVBUF, /*!< Sets recv buffer size */ + NSAPI_ADD_MEMBERSHIP, /*!< Add membership to multicast address */ + NSAPI_DROP_MEMBERSHIP, /*!< Drop membership to multicast address */ + NSAPI_BIND_TO_DEVICE, /*!< Bind socket network interface name*/ +} nsapi_socket_option_t; + +/** Supported IP protocol versions of IP stack + * + * @enum nsapi_ip_stack + */ +typedef enum nsapi_ip_stack { + DEFAULT_STACK = 0, + IPV4_STACK, + IPV6_STACK, + IPV4V6_STACK +} nsapi_ip_stack_t; + +/* Backwards compatibility - previously didn't distinguish stack and socket options */ +typedef nsapi_socket_level_t nsapi_level_t; +typedef nsapi_socket_option_t nsapi_option_t; + +/** nsapi_wifi_ap structure + * + * Structure representing a WiFi Access Point + */ +typedef struct nsapi_wifi_ap { + char ssid[33]; /* 32 is what 802.11 defines as longest possible name; +1 for the \0 */ + uint8_t bssid[6]; + nsapi_security_t security; + int8_t rssi; + uint8_t channel; +} nsapi_wifi_ap_t; + + +/** nsapi_stack structure + * + * Stack structure representing a specific instance of a stack. + */ +typedef struct nsapi_stack { + /** Network stack operation table + * + * Provides access to the underlying api of the stack. This is not + * flattened into the nsapi_stack to allow allocation in read-only + * memory. + */ + const struct nsapi_stack_api *stack_api; + + /** Opaque handle for network stacks + */ + void *stack; + + // Internal nsapi buffer + unsigned _stack_buffer[16]; +} nsapi_stack_t; + +/** nsapi_ip_mreq structure + */ +typedef struct nsapi_ip_mreq { + nsapi_addr_t imr_multiaddr; /* IP multicast address of group */ + nsapi_addr_t imr_interface; /* local IP address of interface */ +} nsapi_ip_mreq_t; + +/** nsapi_stack_api structure + * + * Common api structure for network stack operations. A network stack + * can provide a nsapi_stack_api structure filled out with the + * appropriate implementation. + * + * Unsupported operations can be left as null pointers. + */ +typedef struct nsapi_stack_api { + /** Get the local IP address + * + * @param stack Stack handle + * @return Local IP Address or null address if not connected + */ + nsapi_addr_t (*get_ip_address)(nsapi_stack_t *stack); + + /** Translates a hostname to an IP address + * + * The hostname may be either a domain name or an IP address. If the + * hostname is an IP address, no network transactions will be performed. + * + * If no stack-specific DNS resolution is provided, the hostname + * will be resolve using a UDP socket on the stack. + * + * @param stack Stack handle + * @param addr Destination for the host IP address + * @param host Hostname to resolve + * @param version Address family + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*gethostbyname)(nsapi_stack_t *stack, const char *host, nsapi_addr_t *addr, nsapi_version_t version); + + /** Add a domain name server to list of servers to query + * + * @param addr Destination for the host address + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*add_dns_server)(nsapi_stack_t *stack, nsapi_addr_t addr); + + /** Set stack-specific stack options + * + * The setstackopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the stack is unmodified. + * + * @param stack Stack handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*setstackopt)(nsapi_stack_t *stack, int level, + int optname, const void *optval, unsigned optlen); + + /** Get stack-specific stack options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param stack Stack handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*getstackopt)(nsapi_stack_t *stack, int level, + int optname, void *optval, unsigned *optlen); + + /** Opens a socket + * + * Creates a network socket and stores it in the specified handle. + * The handle must be passed to following calls on the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * @param stack Stack context + * @param socket Destination for the handle to a newly created socket + * @param proto Protocol of socket to open, NSAPI_TCP or NSAPI_UDP + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*socket_open)(nsapi_stack_t *stack, nsapi_socket_t *socket, + nsapi_protocol_t proto); + + /** Close the socket + * + * Closes any open connection and deallocates any memory associated + * with the socket. + * + * @param stack Stack handle + * @param socket Socket handle + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*socket_close)(nsapi_stack_t *stack, nsapi_socket_t socket); + + /** Bind a specific address to a socket + * + * Binding a socket specifies the address and port on which to receive + * data. If the IP address is zeroed, only the port is bound. + * + * @param stack Stack handle + * @param socket Socket handle + * @param addr Local address to bind, may be null + * @param port Local port to bind + * @return 0 on success, negative error code on failure. + */ + nsapi_error_t (*socket_bind)(nsapi_stack_t *stack, nsapi_socket_t socket, + nsapi_addr_t addr, uint16_t port); + + /** Listen for connections on a TCP socket + * + * Marks the socket as a passive socket that can be used to accept + * incoming connections. + * + * @param stack Stack handle + * @param socket Socket handle + * @param backlog Number of pending connections that can be queued + * simultaneously + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*socket_listen)(nsapi_stack_t *stack, nsapi_socket_t socket, int backlog); + + /** Connects TCP socket to a remote host + * + * Initiates a connection to a remote server specified by the + * indicated address. + * + * @param stack Stack handle + * @param socket Socket handle + * @param addr The address of the remote host + * @param port The port of the remote host + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*socket_connect)(nsapi_stack_t *stack, nsapi_socket_t socket, + nsapi_addr_t addr, uint16_t port); + + /** Accepts a connection on a TCP socket + * + * The server socket must be bound and set to listen for connections. + * On a new connection, creates a network socket and stores it in the + * specified handle. The handle must be passed to following calls on + * the socket. + * + * A stack may have a finite number of sockets, in this case + * NSAPI_ERROR_NO_SOCKET is returned if no socket is available. + * + * This call is non-blocking. If accept would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param stack Stack handle + * @param server Socket handle to server to accept from + * @param socket Destination for a handle to the newly created socket + * @param addr Destination for the address of the remote host + * @param port Destination for the port of the remote host + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*socket_accept)(nsapi_stack_t *stack, nsapi_socket_t server, + nsapi_socket_t *socket, nsapi_addr_t *addr, uint16_t *port); + + /** Send data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes sent from the buffer. + * + * This call is non-blocking. If send would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param stack Stack handle + * @param socket Socket handle + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + nsapi_size_or_error_t (*socket_send)(nsapi_stack_t *stack, nsapi_socket_t socket, + const void *data, nsapi_size_t size); + + /** Receive data over a TCP socket + * + * The socket must be connected to a remote host. Returns the number of + * bytes received into the buffer. + * + * This call is non-blocking. If recv would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param stack Stack handle + * @param socket Socket handle + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + nsapi_size_or_error_t (*socket_recv)(nsapi_stack_t *stack, nsapi_socket_t socket, + void *data, nsapi_size_t size); + + /** Send a packet over a UDP socket + * + * Sends data to the specified address. Returns the number of bytes + * sent from the buffer. + * + * This call is non-blocking. If sendto would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param stack Stack handle + * @param socket Socket handle + * @param addr The address of the remote host + * @param port The port of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + nsapi_size_or_error_t (*socket_sendto)(nsapi_stack_t *stack, nsapi_socket_t socket, + nsapi_addr_t addr, uint16_t port, const void *data, nsapi_size_t size); + + /** Receive a packet over a UDP socket + * + * Receives data and stores the source address in address if address + * is not NULL. Returns the number of bytes received into the buffer. + * + * This call is non-blocking. If recvfrom would block, + * NSAPI_ERROR_WOULD_BLOCK is returned immediately. + * + * @param stack Stack handle + * @param socket Socket handle + * @param addr Destination for the address of the remote host + * @param port Destination for the port of the remote host + * @param data Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + nsapi_size_or_error_t (*socket_recvfrom)(nsapi_stack_t *stack, nsapi_socket_t socket, + nsapi_addr_t *addr, uint16_t *port, void *buffer, nsapi_size_t size); + + /** Register a callback on state change of the socket + * + * The specified callback will be called on state changes such as when + * the socket can recv/send/accept successfully and on when an error + * occurs. The callback may also be called spuriously without reason. + * + * The callback may be called in an interrupt context and should not + * perform expensive operations such as recv/send calls. + * + * @param stack Stack handle + * @param socket Socket handle + * @param callback Function to call on state change + * @param data Argument to pass to callback + */ + void (*socket_attach)(nsapi_stack_t *stack, nsapi_socket_t socket, + void (*callback)(void *), void *data); + + /** Set stack-specific socket options + * + * The setsockopt allow an application to pass stack-specific hints + * to the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and the socket is unmodified. + * + * @param stack Stack handle + * @param socket Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*setsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, + int optname, const void *optval, unsigned optlen); + + /** Get stack-specific socket options + * + * The getstackopt allow an application to retrieve stack-specific hints + * from the underlying stack. For unsupported options, + * NSAPI_ERROR_UNSUPPORTED is returned and optval is unmodified. + * + * @param stack Stack handle + * @param socket Socket handle + * @param level Stack-specific protocol level + * @param optname Stack-specific option identifier + * @param optval Destination for option value + * @param optlen Length of the option value + * @return 0 on success, negative error code on failure + */ + nsapi_error_t (*getsockopt)(nsapi_stack_t *stack, nsapi_socket_t socket, int level, + int optname, void *optval, unsigned *optlen); +} nsapi_stack_api_t; + + +#ifdef __cplusplus +} +#endif + +#endif + +/** @}*/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utility/stoip4.c Tue Sep 03 09:16:55 2019 +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/stoip6.c Tue Sep 03 09:16:55 2019 +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/uip.h Sat Aug 31 20:34:52 2019 +0000 +++ b/utility/uip.h Tue Sep 03 09:16:55 2019 +0000 @@ -1203,29 +1203,19 @@ struct uip_conn { uip_ipaddr_t ripaddr; /**< The IP address of the remote host. */ - u16_t lport; /**< The local TCP port, in network byte order. */ - u16_t rport; /**< The local remote TCP port, in network byte - order. */ - - u8_t rcv_nxt[4]; /**< The sequence number that we expect to - receive next. */ - u8_t snd_nxt[4]; /**< The sequence number that was last sent by - us. */ + u16_t rport; /**< The local remote TCP port, in network byte order. */ + u8_t rcv_nxt[4]; /**< The sequence number that we expect to receive next. */ + u8_t snd_nxt[4]; /**< The sequence number that was last sent by us. */ u16_t len; /**< Length of the data that was previously sent. */ - u16_t mss; /**< Current maximum segment size for the - connection. */ - u16_t initialmss; /**< Initial maximum segment size for the - connection. */ - u8_t sa; /**< Retransmission time-out calculation state - variable. */ - u8_t sv; /**< Retransmission time-out calculation state - variable. */ + u16_t mss; /**< Current maximum segment size for the connection. */ + u16_t initialmss; /**< Initial maximum segment size for the connection. */ + u8_t sa; /**< Retransmission time-out calculation state variable. */ + u8_t sv; /**< Retransmission time-out calculation state variable. */ u8_t rto; /**< Retransmission time-out. */ u8_t tcpstateflags; /**< TCP state and flags. */ u8_t timer; /**< The retransmission timer. */ - u8_t nrtx; /**< The number of retransmissions for the last - segment sent. */ + u8_t nrtx; /**< The number of retransmissions for the last segment sent. */ /** The application state. */ uip_tcp_appstate_t appstate; @@ -1286,48 +1276,34 @@ { struct { - uip_stats_t drop; /**< Number of dropped packets at the IP - layer. */ - uip_stats_t recv; /**< Number of received packets at the IP - layer. */ - uip_stats_t sent; /**< Number of sent packets at the IP - layer. */ - uip_stats_t vhlerr; /**< Number of packets dropped due to wrong - IP version or header length. */ - uip_stats_t hblenerr; /**< Number of packets dropped due to wrong - IP length, high byte. */ - uip_stats_t lblenerr; /**< Number of packets dropped due to wrong - IP length, low byte. */ - uip_stats_t fragerr; /**< Number of packets dropped since they - were IP fragments. */ - uip_stats_t chkerr; /**< Number of packets dropped due to IP - checksum errors. */ - uip_stats_t protoerr; /**< Number of packets dropped since they - were neither ICMP, UDP nor TCP. */ + uip_stats_t drop; /**< Number of dropped packets at the IP layer. */ + uip_stats_t recv; /**< Number of received packets at the IP layer. */ + uip_stats_t sent; /**< Number of sent packets at the IP layer. */ + uip_stats_t vhlerr; /**< Number of packets dropped due to wrong IP version or header length. */ + uip_stats_t hblenerr; /**< Number of packets dropped due to wrong IP length, high byte. */ + uip_stats_t lblenerr; /**< Number of packets dropped due to wrong IP length, low byte. */ + uip_stats_t fragerr; /**< Number of packets dropped since they were IP fragments. */ + uip_stats_t chkerr; /**< Number of packets dropped due to IP checksum errors. */ + uip_stats_t protoerr; /**< Number of packets dropped since they were neither ICMP, UDP nor TCP. */ } ip; /**< IP statistics. */ struct { uip_stats_t drop; /**< Number of dropped ICMP packets. */ uip_stats_t recv; /**< Number of received ICMP packets. */ uip_stats_t sent; /**< Number of sent ICMP packets. */ - uip_stats_t typeerr; /**< Number of ICMP packets with a wrong - type. */ + uip_stats_t typeerr; /**< Number of ICMP packets with a wrong type. */ } icmp; /**< ICMP statistics. */ struct { uip_stats_t drop; /**< Number of dropped TCP segments. */ uip_stats_t recv; /**< Number of recived TCP segments. */ uip_stats_t sent; /**< Number of sent TCP segments. */ - uip_stats_t chkerr; /**< Number of TCP segments with a bad - checksum. */ - uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK - number. */ + uip_stats_t chkerr; /**< Number of TCP segments with a bad checksum. */ + uip_stats_t ackerr; /**< Number of TCP segments with a bad ACK number. */ uip_stats_t rst; /**< Number of recevied TCP RST (reset) segments. */ uip_stats_t rexmit; /**< Number of retransmitted TCP segments. */ - uip_stats_t syndrop; /**< Number of dropped SYNs due to too few - connections was avaliable. */ - uip_stats_t synrst; /**< Number of SYNs for closed ports, - triggering a RST. */ + uip_stats_t syndrop; /**< Number of dropped SYNs due to too few connections was avaliable. */ + uip_stats_t synrst; /**< Number of SYNs for closed ports, triggering a RST. */ } tcp; /**< TCP statistics. */ #if UIP_UDP struct @@ -1335,8 +1311,7 @@ uip_stats_t drop; /**< Number of dropped UDP segments. */ uip_stats_t recv; /**< Number of recived UDP segments. */ uip_stats_t sent; /**< Number of sent UDP segments. */ - uip_stats_t chkerr; /**< Number of UDP segments with a bad - checksum. */ + uip_stats_t chkerr; /**< Number of UDP segments with a bad checksum. */ } udp; /**< UDP statistics. */ #endif /* UIP_UDP */ }; @@ -1368,40 +1343,40 @@ should *NOT* be accessed directly, but only through the UIP functions/macros. */ -#define UIP_ACKDATA 1 /* Signifies that the outstanding data was - acked and the application should send - out new data instead of retransmitting - the last data. */ +#define UIP_ACKDATA 1 /* Signifies that the outstanding data was + acked and the application should send + out new data instead of retransmitting + the last data. */ -#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent - us new data. */ +#define UIP_NEWDATA 2 /* Flags the fact that the peer has sent + us new data. */ -#define UIP_REXMIT 4 /* Tells the application to retransmit the - data that was last sent. */ +#define UIP_REXMIT 4 /* Tells the application to retransmit the + ata that was last sent. */ -#define UIP_POLL 8 /* Used for polling the application, to - check if the application has data that - it wants to send. */ +#define UIP_POLL 8 /* Used for polling the application, to + check if the application has data that + it wants to send. */ -#define UIP_CLOSE 16 /* The remote host has closed the - connection, thus the connection has - gone away. Or the application signals - that it wants to close the - connection. */ +#define UIP_CLOSE 16 /* The remote host has closed the + connection, thus the connection has + gone away. Or the application signals + that it wants to close the + connection. */ -#define UIP_ABORT 32 /* The remote host has aborted the - connection, thus the connection has - gone away. Or the application signals - that it wants to abort the - connection. */ +#define UIP_ABORT 32 /* The remote host has aborted the + connection, thus the connection has + gone away. Or the application signals + that it wants to abort the + connection. */ -#define UIP_CONNECTED 64 /* We have got a connection from a remote - host and have set up a new connection - for it, or an active connection has - been successfully established. */ +#define UIP_CONNECTED 64 /* We have got a connection from a remote + host and have set up a new connection + for it, or an active connection has + been successfully established. */ -#define UIP_TIMEDOUT 128 /* The connection has been aborted due to - too many retransmissions. */ +#define UIP_TIMEDOUT 128 /* The connection has been aborted due to + too many retransmissions. */ /* uip_process(flag): * @@ -1416,14 +1391,15 @@ timer has fired. These values are never used directly, but only in the macrose defined in this file. */ -#define UIP_DATA 1 /* Tells UIP that there is incoming +#define UIP_DATA 1 /* Tells UIP that there is incoming data in the uip_buf buffer. The length of the data is stored in the global variable uip_len. - */ -#define UIP_TIMER 2 /* Tells UIP that the periodic timer has fired. */ -#define UIP_POLL_REQUEST 3 /* Tells UIP that a connection should be polled. */ -#define UIP_UDP_SEND_CONN 4 /* Tells UIP that a UDP datagram should be constructed in the uip_buf buffer. */ + */ +#define UIP_TIMER 2 /* Tells UIP that the periodic timer has fired. */ +#define UIP_POLL_REQUEST 3 /* Tells UIP that a connection should be polled. */ +#define UIP_UDP_SEND_CONN 4 /* Tells UIP that a UDP datagram should be constructed + in the uip_buf buffer. */ #if UIP_UDP #define UIP_UDP_TIMER 5
--- a/utility/uipethernet-conf.h Sat Aug 31 20:34:52 2019 +0000 +++ b/utility/uipethernet-conf.h Tue Sep 03 09:16:55 2019 +0000 @@ -4,14 +4,14 @@ /* for TCP */ #define UIP_SOCKET_NUMPACKETS 5 -#define UIP_MAX_CONNECTIONS 4 +#define UIP_MAX_CONNECTIONS 5 /* for UDP * set UIP_CONF_UDP to 0 to disable UDP (saves aprox. 5kb flash) */ #define UIP_CONF_UDP 1 #define UIP_CONF_BROADCAST 1 -#define UIP_CONF_UDP_CONNS 4 +#define UIP_CONF_UDP_CONNS 5 /* number of attempts on write before returning number of bytes sent so far * set to -1 to block until connection is closed by timeout */