Free (GPLv2) TCP/IP stack developed by TASS Belgium
Fork of PicoTCP by
Revision 28:394d88a116b2, committed 2013-06-16
- Comitter:
- daniele
- Date:
- Sun Jun 16 20:19:33 2013 +0000
- Parent:
- 27:26c168f5aa97
- Child:
- 29:1a47b7151851
- Commit message:
- Updated from masterbranch
Changed in this revision
--- a/EthernetInterface/EthernetInterface.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,182 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "EthernetInterface.h" -#include "Queue.h" -#include "wrapper.h" -#include "proxy_endpoint.h" -#include "pico_dev_mbed_emac.h" -#include "mbed.h" -#include "PicoCondition.h" -extern "C"{ -#include "pico_stack.h" -#include "pico_config.h" -#include "cmsis_os.h" -#include "pico_dhcp_client.h" -#include "pico_dns_client.h" - -void (*linkCb)(uint32_t link) = NULL; -} - -//DigitalOutput led(LED3); -/* TCP/IP and Network Interface Initialisation */ -static struct pico_device *lpc_eth; - -static uint32_t dhcp_xid = 0; -static PicoCondition dhcp_mx; -static int dhcp_retval = -1; - -static char mac_addr[19]; -static char ip_addr[17] = "\0"; -static char gw_addr[17] = "\0"; -static bool use_dhcp = false; -static bool is_initialized = false; - -static void dhcp_cb(void *cli, int code) -{ - void *id = NULL; - struct pico_ip4 address, gateway, zero = {}; - printf("DHCP callback : %d\n",code); - if (PICO_DHCP_SUCCESS != code) - goto fail; - - id = pico_dhcp_get_identifier(dhcp_xid); - if (!id) - goto fail; - address = pico_dhcp_get_address(id); - gateway = pico_dhcp_get_gateway(id); - //if (address) ? // still needed - pico_ipv4_to_string(ip_addr, address.addr); - printf("IP assigned : %s\n",ip_addr); - - if (gateway.addr != 0) { - pico_ipv4_to_string(gw_addr, gateway.addr); - printf("Default gateway assigned : %s\n",gw_addr); - pico_ipv4_route_add(zero, zero, gateway, 1, NULL); - } - printf("Unlocking\n"); - dhcp_mx.unlock(); - dhcp_retval = 0; - printf("Returning\n"); - return; - -fail: - printf("DHCP request failed!\n"); - dhcp_retval = -1; - dhcp_mx.unlock(); -} - -static void init_eth(void) -{ - if (!is_initialized) { - pico_stack_init(); - picotcp_init(); - lpc_eth = pico_emac_create("mbed0"); - is_initialized = true; - pico_dns_client_init(); - } - if (lpc_eth) { - snprintf(mac_addr, 19, "%02X:%02X:%02X:%02X:%02X:%02X", lpc_eth->eth->mac.addr[0], lpc_eth->eth->mac.addr[1], - lpc_eth->eth->mac.addr[2], lpc_eth->eth->mac.addr[3], lpc_eth->eth->mac.addr[4], lpc_eth->eth->mac.addr[5]); - } - printf("Lpc init : %x\n",lpc_eth); -} - -int EthernetInterface::init() -{ - init_eth(); - /* use dhcp to retrieve address and gateway. */ - use_dhcp = true; - return 0; -} - -int EthernetInterface::init(const char* ip, const char* mask, const char* gateway) { - pico_ip4 pico_addr, pico_netmask, pico_gw = {0}, zero = {0}; - - init_eth(); - - use_dhcp = false; - strcpy(ip_addr, ip); - - pico_string_to_ipv4(ip, &pico_addr.addr); - pico_string_to_ipv4(mask, &pico_netmask.addr); - if (gateway) { - pico_string_to_ipv4(ip, &pico_gw.addr); - } - pico_ipv4_link_add(lpc_eth, pico_addr, pico_netmask); - - if (pico_gw.addr) - pico_ipv4_route_add(zero, zero, pico_gw, 1, NULL); - - return 0; -} - -int EthernetInterface::connect(unsigned int timeout_ms) { - //dhcp_mx.lock(); do we still need this ? - if (use_dhcp) { - if (pico_dhcp_initiate_negotiation(lpc_eth, &dhcp_cb, &dhcp_xid) < 0) - return -1; - - dhcp_mx.lock(timeout_ms); // wait for a sign - printf("dhcp wake up!\n"); - return dhcp_retval; - - } else { - return 0; - } -} - -int EthernetInterface::disconnect() { - if (use_dhcp) { - } - pico_device_destroy(lpc_eth); - lpc_eth = NULL; - return 0; -} - -char* EthernetInterface::getMACAddress() { - return mac_addr; -} - -char* EthernetInterface::getIPAddress() { - return ip_addr; -} - -int EthernetInterface::registerLinkStatus(void (*cb)(uint32_t linkStatus)) -{ - ::linkCb = cb; - return 0; -} - -int EthernetInterface::setDnsServer(const char * name) -{ - struct pico_ip4 addr; - pico_string_to_ipv4(name,&addr.addr); - return pico_dns_client_nameserver(&addr,PICO_DNS_NS_ADD); -}
--- a/EthernetInterface/EthernetInterface.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,109 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef ETHERNETINTERFACE_H_ -#define ETHERNETINTERFACE_H_ - -#if !defined(TARGET_LPC1768) -#error The Ethernet Interface library is supported only on the mbed NXP LPC1768 -#endif - -#include "rtos.h" - -#ifdef __cplusplus -extern "C" { -#endif - extern void (*linkCb)(uint32_t link); -#ifdef __cplusplus -} -#endif - /** Interface using Ethernet to connect to an IP-based network - * - */ -class EthernetInterface { -public: - /** Initialize the interface with DHCP. - * Initialize the interface and configure it to use DHCP (no connection at this point). - * \return 0 on success, a negative number on failure - */ - static int init(); //With DHCP - - /** Initialize the interface with a static IP address. - * Initialize the interface and configure it with the following static configuration (no connection at this point). - * \param ip the IP address to use - * \param mask the IP address mask - * \param gateway the gateway to use - * \return 0 on success, a negative number on failure - */ - static int init(const char* ip, const char* mask, const char* gateway); - - /** Connect - * Bring the interface up, start DHCP if needed. - * \param timeout_ms timeout in ms (default: (10)s). - * \return 0 on success, a negative number on failure - */ - static int connect(unsigned int timeout_ms=15000); - - /** Disconnect - * Bring the interface down - * \return 0 on success, a negative number on failure - */ - static int disconnect(); - - /** Get the MAC address of your Ethernet interface - * \return a pointer to a string containing the MAC address - */ - static char* getMACAddress(); - - /** Get the IP address of your Ethernet interface - * \return a pointer to a string containing the IP address - */ - static char* getIPAddress(); - - - /** Register a callback to tell the status of the link. - * \return 0 if callback was registered. - */ - static int registerLinkStatus(void (*cb)(uint32_t linkStatus)); - - - /** Register a callback to tell the status of the link. - * \return 0 if callback was registered. - */ - static int setDnsServer(const char *); - -}; - -#include "TCPSocketConnection.h" -#include "TCPSocketServer.h" - -#include "Endpoint.h" -#include "UDPSocket.h" - -#endif /* ETHERNETINTERFACE_H_ */
--- a/Socket/Endpoint.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "Socket/Socket.h" -#include "Socket/Endpoint.h" -#include "wrapper.h" -#include "proxy_endpoint.h" - -extern "C" -{ -#include "pico_ipv4.h" -} -#include <cstring> -#include <cstdio> - -Endpoint::Endpoint() { - reset_address(); -} -Endpoint::~Endpoint() {} - -void Endpoint::reset_address(void) { - memset(&_remoteHost,0,sizeof(_remoteHost)); -} - -#include "stdio.h" - -int Endpoint::set_address(const char* host, const int port) { - _remoteHost.sin_port = short_be(port); - pico_string_to_ipv4(host,&_remoteHost.sin_addr.s_addr); - memcpy(_ipAddress,host, strlen(host)+1); - return 0; -} - -char* Endpoint::get_address() { - return _ipAddress; -} - -int Endpoint::get_port() { - return short_be(_remoteHost.sin_port); -}
--- a/Socket/Endpoint.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef ENDPOINT_H -#define ENDPOINT_H - -class UDPSocket; - -/** -IP Endpoint (address, port) -*/ -class Endpoint { - friend class UDPSocket; - -public: - /** IP Endpoint (address, port) - */ - Endpoint(void); - - ~Endpoint(void); - - /** Reset the address of this endpoint - */ - void reset_address(void); - - /** Set the address of this endpoint - \param host The endpoint address (it can either be an IP Address or a hostname that will be resolved with DNS). - \param port The endpoint port - \return 0 on success, -1 on failure (when an hostname cannot be resolved by DNS). - */ - int set_address(const char* host, const int port); - - /** Get the IP address of this endpoint - \return The IP address of this endpoint. - */ - char* get_address(void); - - /** Get the port of this endpoint - \return The port of this endpoint - */ - int get_port(void); - -protected: - char _ipAddress[17]; - struct sockaddr_in _remoteHost; - -}; - -#endif
--- a/Socket/Socket.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "Socket/Socket.h" -#include "wrapper.h" -#include "proxy_endpoint.h" -#include <cstring> - -using std::memset; - -Socket::Socket() : _ep(NULL), _blocking(true) -{ - //set_blocking(true,1500); // ? -} - -void Socket::set_blocking(bool blocking, unsigned int timeout) { - _blocking = blocking; - _timeout = timeout; -} - -int Socket::init_socket(int type) { - if (_ep != NULL) - { - printf("Sock open already...\n"); - return -1; - } - struct stack_endpoint *ep = picotcp_socket(AF_INET, type, 0); - if (!ep) - { - printf("Error opening socket...\n"); - return -1; - } - _ep = ep; - return 0; -} - -int Socket::set_option(int level, int optname, const void *optval, socklen_t optlen) { - return picotcp_setsockopt(_ep, optname, (void *)optval); -} - -int Socket::get_option(int level, int optname, void *optval, socklen_t *optlen) { - return picotcp_getsockopt(_ep, optname, optval); -} - -int Socket::select(struct timeval *timeout, bool read, bool write) { - return picotcp_select(_ep, timeout, read, write); -} - -int Socket::wait_readable(TimeInterval& timeout) { - return (select(&timeout._time, true, false) == 0 ? -1 : 0); -} - -int Socket::wait_writable(TimeInterval& timeout) { - return (select(&timeout._time, false, true) == 0 ? -1 : 0); -} - -int Socket::close() { - if (_ep == NULL) - return -1; - picotcp_close(_ep); - return 0; -} - -Socket::~Socket() { - if(_ep) - picotcp_close(_ep); -} - -TimeInterval::TimeInterval(unsigned int ms) { - _time.tv_sec = ms / 1000; - _time.tv_usec = (ms - (_time.tv_sec * 1000)) * 1000; -}
--- a/Socket/Socket.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,124 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef SOCKET_H_ -#define SOCKET_H_ - -#ifdef __cplusplus -extern "C" { -#endif - #include "pico_dns_client.h" -#ifdef __cplusplus -} -#endif - -#include "wrapper.h" -#include "proxy_endpoint.h" - -class TimeInterval; - -/** Socket file descriptor and select wrapper - */ -class Socket { -public: - /** Socket - */ - Socket(); - - /** Set blocking or non-blocking mode of the socket and a timeout on - blocking socket operations - \param blocking true for blocking mode, false for non-blocking mode. - \param timeout timeout in ms [Default: (1500)ms]. - */ - void set_blocking(bool blocking, unsigned int timeout=1500); - - /** Set socket options - \param level stack level (see: lwip/sockets.h) - \param optname option ID - \param optval option value - \param socklen_t length of the option value - \return 0 on success, -1 on failure - */ - int set_option(int level, int optname, const void *optval, socklen_t optlen); - - /** Get socket options - \param level stack level (see: lwip/sockets.h) - \param optname option ID - \param optval buffer pointer where to write the option value - \param socklen_t length of the option value - \return 0 on success, -1 on failure - */ - int get_option(int level, int optname, void *optval, socklen_t *optlen); - - /** Close the socket file descriptor - */ - int close(); - - ~Socket(); - -protected: - struct stack_endpoint *_ep; - int init_socket(int type); - - int wait_readable(TimeInterval& timeout); - int wait_writable(TimeInterval& timeout); - - bool _blocking; - unsigned int _timeout; - -private: - int select(struct timeval *timeout, bool read, bool write); -}; - -/** Time interval class used to specify timeouts - */ -class TimeInterval { - friend class Socket; - -public: - /** Time Interval - \param ms time interval expressed in milliseconds - */ - TimeInterval(unsigned int ms); - -private: - struct timeval _time; - struct stack_endpoint * _ep; -}; - - -inline struct hostent *gethostbyname(const char *name) { - return picotcp_gethostbyname(name); - -} -/* DNS -inline int gethostbyname_r(const char *name, struct hostent *ret, char *buf, size_t buflen, struct hostent **result, int *h_errnop) { - return picotcp_gethostbyname_r(name, ret, buf, buflen, result, h_errnop); -}*/ -#endif /* SOCKET_H_ */
--- a/Socket/TCPSocketConnection.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#include "TCPSocketConnection.h" -#include "wrapper.h" -#include <cstring> - -using std::memset; -using std::memcpy; - -TCPSocketConnection::TCPSocketConnection() : - _is_connected(false) { -} - -int TCPSocketConnection::connect(const char* host, const int port) { - if (init_socket(SOCK_STREAM) < 0) - { - printf("init_socket\n"); - return -1; - } - - if (set_address(host, port) != 0) - { - printf("set_address\n"); - return -1; - } - - if (picotcp_connect(_ep, (struct sockaddr *) &_remoteHost, sizeof(_remoteHost)) < 0) { - close(); - return -1; - } - _is_connected = true; - - return 0; -} - -bool TCPSocketConnection::is_connected(void) { - return _is_connected; -} - -int TCPSocketConnection::send(char* data, int length) { - int ret; - if ((_ep < 0) || !_is_connected) - return -1; - - if (!_blocking) { - TimeInterval timeout(_timeout); - if (wait_writable(timeout) != 0) - { - printf("Failed\n"); - return -1; - } - } - ret = picotcp_write(_ep, data, length); - if (ret < length) { - _ep->revents &= (~PICO_SOCK_EV_WR); - printf("Short write\n"); - } - return ret; -} - -// -1 if unsuccessful, else number of bytes written -int TCPSocketConnection::send_all(char* data, int length) { - int ret; - if ((_ep < 0) || !_is_connected) - return -1; - - if (!_blocking) { - TimeInterval timeout(_timeout); - // Wait for socket to be writeable - if (wait_writable(timeout) != 0) { - return 0; - } - } - ret = picotcp_write(_ep, data, length); - if (ret < length) { - _ep->revents &= (~PICO_SOCK_EV_WR); - //printf("Short write\n"); - } - return ret; -} - -int TCPSocketConnection::receive(char* data, int length) { - int ret; - if ((_ep < 0) || !_is_connected) - return -1; - - if (!_blocking) { - TimeInterval timeout(_timeout); - if (wait_readable(timeout) != 0) - { - printf("Failed receiving\n"); - return -1; - } - } - ret = picotcp_read(_ep, data, length); - if (ret < length) { - _ep->revents &= (~PICO_SOCK_EV_RD); - //printf("Short read\n"); - } - return ret; -} - -// -1 if unsuccessful, else number of bytes received -int TCPSocketConnection::receive_all(char* data, int length) { - return receive(data, length); -}
--- a/Socket/TCPSocketConnection.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,92 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef TCPSOCKET_H -#define TCPSOCKET_H - -#include "Socket/Socket.h" -#include "Socket/Endpoint.h" - -/** -TCP socket connection -*/ -class TCPSocketConnection : public Socket, public Endpoint { - friend class TCPSocketServer; - -public: - /** TCP socket connection - */ - TCPSocketConnection(); - - /** Connects this TCP socket to the server - \param host The host to connect to. It can either be an IP Address or a hostname that will be resolved with DNS. - \param port The host's port to connect to. - \return 0 on success, -1 on failure. - */ - int connect(const char* host, const int port); - - /** Check if the socket is connected - \return true if connected, false otherwise. - */ - bool is_connected(void); - - /** Send data to the remote host. - \param data The buffer to send to the host. - \param length The length of the buffer to send. - \return the number of written bytes on success (>=0) or -1 on failure - */ - int send(char* data, int length); - - /** Send all the data to the remote host. - \param data The buffer to send to the host. - \param length The length of the buffer to send. - \return the number of written bytes on success (>=0) or -1 on failure - */ - int send_all(char* data, int length); - - /** Receive data from the remote host. - \param data The buffer in which to store the data received from the host. - \param length The maximum length of the buffer. - \return the number of received bytes on success (>=0) or -1 on failure - */ - int receive(char* data, int length); - - /** Receive all the data from the remote host. - \param data The buffer in which to store the data received from the host. - \param length The maximum length of the buffer. - \return the number of received bytes on success (>=0) or -1 on failure - */ - int receive_all(char* data, int length); - -private: - bool _is_connected; - -}; - -#endif
--- a/Socket/TCPSocketServer.cpp Sun Jun 16 02:31:38 2013 +0000 +++ b/Socket/TCPSocketServer.cpp Sun Jun 16 20:19:33 2013 +0000 @@ -70,6 +70,7 @@ } int TCPSocketServer::accept(TCPSocketConnection& connection) { + char *address; if (_ep < 0) return -1; @@ -87,5 +88,8 @@ } connection.set_blocking(true,1500); connection._is_connected = true; + address = (char *)malloc(80); + pico_ipv4_to_string(address, connection._remoteHost.sin_addr.s_addr); + connection.set_address(address, connection._remoteHost.sin_port); return 0; }
--- a/Socket/TCPSocketServer.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,64 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -#ifndef TCPSOCKETSERVER_H -#define TCPSOCKETSERVER_H - -#include "Socket/Socket.h" -#include "wrapper.h" -#include "TCPSocketConnection.h" - -/** TCP Server. - */ -class TCPSocketServer : public Socket { - public: - /** Instantiate a TCP Server. - */ - TCPSocketServer(); - - /** Bind a socket to a specific port. - \param port The port to listen for incoming connections on. - \return 0 on success, -1 on failure. - */ - int bind(int port); - - /** Start listening for incoming connections. - \param backlog number of pending connections that can be queued up at any - one time [Default: 1]. - \return 0 on success, -1 on failure. - */ - int listen(int backlog=1); - - /** Accept a new connection. - \param connection A TCPSocketConnection instance that will handle the incoming connection. - \return 0 on success, -1 on failure. - */ - int accept(TCPSocketConnection& connection); -}; - -#endif
--- a/Socket/UDPSocket.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,106 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#include "Socket/UDPSocket.h" -#include "wrapper.h" -#include "proxy_endpoint.h" - -#include <cstring> - -using std::memset; - -UDPSocket::UDPSocket() { -} - -int UDPSocket::init(void) { - return init_socket(SOCK_DGRAM); -} - -// Server initialization -int UDPSocket::bind(int port) { - if (init_socket(SOCK_DGRAM) < 0) - return -1; - - struct sockaddr_in localHost; - std::memset(&localHost, 0, sizeof(localHost)); - - localHost.sin_family = AF_INET; - localHost.sin_port = short_be(port); - localHost.sin_addr.s_addr = INADDR_ANY; - - if (picotcp_bind(_ep, (struct sockaddr *) &localHost, (socklen_t)sizeof(localHost)) < 0) { - close(); - return -1; - } - - return 0; -} - -int UDPSocket::join_multicast_group(EthernetInterface& eth, const char* address) { - - return picotcp_join_multicast(_ep,address,eth.getIPAddress()); -} - -int UDPSocket::set_broadcasting(void) { - int option = 1; - return set_option(SOL_SOCKET, SO_BROADCAST, &option, sizeof(option)); -} - -// -1 if unsuccessful, else number of bytes written -int UDPSocket::sendTo(Endpoint &remote, char *packet, int length) { - if (_ep < 0) - { - printf("Error on socket descriptor \n"); - return -1; - } - - /* This is not needed for our udp sock ? - if (_blocking) { - TimeInterval timeout(_timeout); - if (wait_writable(timeout) != 0) - return 0; - }*/ - - return picotcp_sendto(_ep, packet, length, (struct sockaddr *) &remote._remoteHost, sizeof(remote._remoteHost)); -} - -// -1 if unsuccessful, else number of bytes received -int UDPSocket::receiveFrom(Endpoint &remote, char *buffer, int length) { - if (_ep < 0) - return -1; - - if (!_blocking) { - TimeInterval timeout(_timeout); - if (wait_readable(timeout) != 0) - return 0; - } - //remote.reset_address(); why is this needed ? - socklen_t remoteHostLen = sizeof(remote._remoteHost); - return picotcp_recvfrom(_ep, buffer, length, (struct sockaddr*) &remote._remoteHost, &remoteHostLen); -}
--- a/Socket/UDPSocket.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * - * PicoTCP Socket interface for mbed. - * Copyright (C) 2013 TASS Belgium NV - * - * Released under GPL v2 - * - * Other licensing models might apply at the sole discretion of the copyright holders. - * - * - * This software is based on the mbed.org EthernetInterface implementation: - * Copyright (C) 2012 mbed.org, MIT License - * - * Permission is hereby granted, free of charge, to any person obtaining a copy of this software - * and associated documentation files (the "Software"), to deal in the Software without restriction, - * including without limitation the rights to use, copy, modify, merge, publish, distribute, - * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in all copies or - * substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING - * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, - * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ - -#ifndef UDPSOCKET_H -#define UDPSOCKET_H - -#include "Socket/Socket.h" -#include "Socket/Endpoint.h" -#include "EthernetInterface.h" -#include <cstdint> - -/** -UDP Socket -*/ -class UDPSocket : public Socket { - -public: - /** Instantiate an UDP Socket. - */ - UDPSocket(); - - /** Init the UDP Client Socket without binding it to any specific port - \return 0 on success, -1 on failure. - */ - int init(void); - - /** Bind a UDP Server Socket to a specific port - \param port The port to listen for incoming connections on - \return 0 on success, -1 on failure. - */ - int bind(int port); - - /** Join the multicast group at the given address - \param address The address of the multicast group - \return 0 on success, -1 on failure. - */ - int join_multicast_group(EthernetInterface& eth, const char* address); - - /** Set the socket in broadcasting mode - \return 0 on success, -1 on failure. - */ - int set_broadcasting(void); - - /** Send a packet to a remote endpoint - \param remote The remote endpoint - \param packet The packet to be sent - \param length The length of the packet to be sent - \return the number of written bytes on success (>=0) or -1 on failure - */ - int sendTo(Endpoint &remote, char *packet, int length); - - /** Receive a packet from a remote endpoint - \param remote The remote endpoint - \param buffer The buffer for storing the incoming packet data. If a packet - is too long to fit in the supplied buffer, excess bytes are discarded - \param length The length of the buffer - \return the number of received bytes on success (>=0) or -1 on failure - */ - int receiveFrom(Endpoint &remote, char *buffer, int length); -}; - -#endif
--- a/Socket/bsd/proxy_endpoint.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,113 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2013 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Daniele Lacamera <daniele.lacamera@tass.be> -*********************************************************************/ - -#ifndef __PICOTCP_BSD_LAYER -#define __PICOTCP_BSD_LAYER - -extern "C" { -#include "pico_stack.h" -#include "pico_tree.h" -#include "pico_dns_client.h" -#include "pico_socket.h" -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_config.h" -#include "pico_ipv4.h" -#include "pico_device.h" -}; -#include "mbed.h" -#include "rtos.h" -#include "Queue.h" -#include "PicoCondition.h" - -struct sockaddr; - -struct ip_addr_s { - uint32_t s_addr; -}; - -typedef struct ip_addr_s ip_addr_t; - -struct sockaddr_in -{ - ip_addr_t sin_addr; - uint16_t sin_family; - uint16_t sin_port; -}; - -struct timeval { - uint32_t tv_sec; - uint32_t tv_usec; -}; - -/* Description of data base entry for a single host. */ -struct hostent -{ - char *h_name; /* Official name of host. */ - char **h_aliases; /* Alias list. */ - int h_addrtype; /* Host address type. */ - int h_length; /* Length of address. */ - char **h_addr_list; /* List of addresses from name server. */ -# define h_addr h_addr_list[0] /* Address, for backward compatibility.*/ -}; - -#ifndef PF_INET -#define PF_INET 2 -#define PF_INET6 10 -#define AF_INET PF_INET -#define AF_INET6 PF_INET6 - -#define SOCK_STREAM 1 -#define SOCK_DGRAM 2 - -#define SOL_SOCKET 1 -#define SO_BROADCAST 6 - -#define INADDR_ANY 0u - -#endif - -enum socket_state_e { - SOCK_OPEN, - SOCK_BOUND, - SOCK_LISTEN, - SOCK_CONNECTED, - SOCK_CLOSED -}; - -typedef int socklen_t; - -void picotcp_init(void); - -struct stack_endpoint * picotcp_socket(uint16_t net, uint16_t proto, uint16_t flags); -int picotcp_state(struct stack_endpoint *); -int picotcp_bind(struct stack_endpoint *, struct sockaddr *local_addr, socklen_t len); - -int picotcp_listen(struct stack_endpoint *, int queue); -int picotcp_connect(struct stack_endpoint *, struct sockaddr *srv_addr, socklen_t len); -struct stack_endpoint * picotcp_accept(struct stack_endpoint *, struct sockaddr *orig, socklen_t *); -int picotcp_select(struct stack_endpoint *, struct timeval *timeout, int read, int write); - -int picotcp_send(struct stack_endpoint *,void * buff, int len, int flags); -int picotcp_recv(struct stack_endpoint *,void * buff, int len, int flags); -int picotcp_sendto(struct stack_endpoint *,void * buff, int len, struct sockaddr*,socklen_t); -int picotcp_recvfrom(struct stack_endpoint *,void * buff, int len, struct sockaddr *, socklen_t *); -int picotcp_read(struct stack_endpoint *,void *buf, int len); -int picotcp_write(struct stack_endpoint *,void *buf, int len); -int picotcp_setsockopt(struct stack_endpoint *, int option, void *value); -int picotcp_getsockopt(struct stack_endpoint *, int option, void *value); -struct hostent * picotcp_gethostbyname(const char *url); -char * picotcp_gethostbyaddr(const char *ip); -int picotcp_close(struct stack_endpoint *); -// set blocking -int picotcp_setblocking(struct stack_endpoint *,int blocking); -int picotcp_join_multicast(struct stack_endpoint *,const char* address,const char* local); - -int picotcp_async_interrupt(void *); - - -#endif
--- a/Socket/bsd/stack_endpoint.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,367 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Daniele Lacamera -*********************************************************************/ - -#include "wrapper.h" -#include "rtos.h" -#include "cmsis_os.h" -#include "mbed.h" -#include "Socket.h" -#include "Mutex.h" - -//#define ptsock_dbg printf -#define ptsock_dbg(...) - -int in_the_stack = 0; -Mutex *PicoTcpLock; -Queue<void,10> *PicoTcpEvents; - -static struct stack_endpoint *ep_accepting; -static Thread * serverThread = NULL; - -#define pt_proxy_dbg(...) - -/* Testing ng blocking mechanism */ - -/* - * backend of select function, used in blocking (like picotcp_read()...) - * calls. Sleeps on the message queue - * - * - * WARNING: PicoTcpLock (big stack lock) must be acquired before entering this. - */ - -static inline int __critical_select(struct stack_endpoint *ep, uint32_t time) -{ - int retval = 0; - uint16_t ev = ep->revents; - uint32_t in_time = PICO_TIME_MS(); - - PicoTcpLock->unlock(); - while ((ep->events & ep->revents) == 0) { - ep->queue->get(time); - if ((time != osWaitForever) && (PICO_TIME_MS() > in_time + time)) { - printf("TIMEOUT in critical select... (ev:%04x rev:%04x \n", ep->events, ep->revents); - PicoTcpLock->lock(); - return 0; - } - } - PicoTcpLock->lock(); - return 1; -} - -static void wakeup(uint16_t ev, struct pico_socket *s) -{ - struct stack_endpoint *ep = (struct stack_endpoint *)s->priv; - if (!ep) { - if (ep_accepting != NULL) { - printf("Delivering %02x to accepting socket...\n", ev); - ep = ep_accepting; - } else { - printf("WAKEUP: socket not found! ev=%04x\n", ev); - return; - } - } - ep->revents |= ev; - - if ((ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN)) { - ep->connected = 0; - } - if ((ev & PICO_SOCK_EV_CONN) || (ev & PICO_SOCK_EV_RD)) { - ep->connected = 1; - } - ep->queue->put((void *)0); -} - - -struct stack_endpoint *picotcp_socket(uint16_t net, uint16_t proto, uint16_t timeout) -{ - struct stack_endpoint *ep = (struct stack_endpoint *)pico_zalloc(sizeof(struct stack_endpoint)); - uint16_t p_net = ((net == AF_INET6)?PICO_PROTO_IPV6:PICO_PROTO_IPV4); - uint16_t p_proto = ((proto == SOCK_DGRAM)?PICO_PROTO_UDP:PICO_PROTO_TCP); - PicoTcpLock->lock(); - ep->s = pico_socket_open( p_net, p_proto, &wakeup ); - if (ep->s == NULL) { - delete(ep->queue); - pico_free(ep); - ep = NULL; - printf("Error opening socket!\n"); - } else { - ep->s->priv = ep; - printf("Added socket (open)\n"); - ep->queue = new Queue<void,1>(); - } - PicoTcpLock->unlock(); - return ep; -} - - -int picotcp_state(struct stack_endpoint *ep) -{ -/* TODO: return one of: - SOCK_OPEN, - SOCK_BOUND, - SOCK_LISTEN, - SOCK_CONNECTED, - SOCK_CLOSED -*/ - return ep->state; -} - -int picotcp_bind(struct stack_endpoint *ep, struct sockaddr *_local_addr, socklen_t len) -{ - int ret; - struct sockaddr_in *local_addr; - local_addr = (struct sockaddr_in *)_local_addr; - - PicoTcpLock->lock(); - ret = pico_socket_bind(ep->s, (struct pico_ip4 *)(&local_addr->sin_addr.s_addr), &local_addr->sin_port); - PicoTcpLock->unlock(); - return ret; -} - -int picotcp_listen(struct stack_endpoint *ep, int queue) -{ - int ret; - PicoTcpLock->lock(); - ret = pico_socket_listen(ep->s, queue); - ep_accepting = (struct stack_endpoint *) pico_zalloc(sizeof(struct stack_endpoint)); - ep_accepting->queue = new Queue<void,1>(); - if (!ep_accepting) - ret = -1; - PicoTcpLock->unlock(); - return ret; -} - -int picotcp_connect(struct stack_endpoint *ep, struct sockaddr *_srv_addr, socklen_t len) -{ - int retval; - struct sockaddr_in *srv_addr; - srv_addr = (struct sockaddr_in *)_srv_addr; - PicoTcpLock->lock(); - pico_socket_connect(ep->s, (struct pico_ip4 *)(&srv_addr->sin_addr.s_addr), srv_addr->sin_port); - ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR; - __critical_select(ep, osWaitForever); - if ((ep->revents & PICO_SOCK_EV_CONN) && ep->connected) { - ep->revents &= (~PICO_SOCK_EV_CONN); - ep->revents |= PICO_SOCK_EV_WR; - ptsock_dbg("Established. sock state: %x\n", ep->s->state); - retval = 0; - } else { - retval = -1; - } - PicoTcpLock->unlock(); - return retval; -} - -struct stack_endpoint *picotcp_accept(struct stack_endpoint *ep, struct sockaddr *_cli_addr, socklen_t *len) -{ - int retval; - struct stack_endpoint *aep = ep_accepting; - struct sockaddr_in *cli_addr = (struct sockaddr_in *)_cli_addr; - ep_accepting = (struct stack_endpoint *) pico_zalloc(sizeof(struct stack_endpoint)); - if (ep_accepting) - ep_accepting->queue = new Queue<void,1>(); - - - if (!aep) - return aep; - - PicoTcpLock->lock(); - ep->events = PICO_SOCK_EV_CONN | PICO_SOCK_EV_ERR; - __critical_select(ep, osWaitForever); - if (ep->revents & PICO_SOCK_EV_CONN) { - printf("Calling Accept\n"); - aep->s = pico_socket_accept(ep->s, (struct pico_ip4 *)(&cli_addr->sin_addr.s_addr), &cli_addr->sin_port); - printf("Accept returned\n"); - aep->s->priv = aep; - ep->revents &= (~PICO_SOCK_EV_CONN); - aep->revents |= PICO_SOCK_EV_WR; - printf("Added socket (accept)\n"); - - *len = sizeof(struct sockaddr_in); - ptsock_dbg("Established. sock state: %x\n", aep->s->state); - } else { - pico_free(aep); - aep = NULL; - } - PicoTcpLock->unlock(); - return aep; -} - -int picotcp_select(struct stack_endpoint *ep, struct timeval *timeout, int read, int write) -{ - int ret; - ep->timeout |= timeout->tv_sec * 1000 + timeout->tv_usec / 1000; - ep->events = PICO_SOCK_EV_ERR; - ep->events |= PICO_SOCK_EV_FIN; - ep->events |= PICO_SOCK_EV_CLOSE; - ep->events |= PICO_SOCK_EV_CONN; - if (read) { - ep->events |= PICO_SOCK_EV_RD; - } - if (write) - ep->events |= PICO_SOCK_EV_WR; - ret = __critical_select(ep, ep->timeout); - return ret; -} - -int picotcp_send(struct stack_endpoint *ep,void * buff, int len, int flags) -{ - /* TODO */ - return -1; -} - -int picotcp_recv(struct stack_endpoint *ep,void * buff, int len, int flags) -{ - /* TODO */ - return -1; -} - -int picotcp_sendto(struct stack_endpoint *ep,void * buff, int len, struct sockaddr *a, socklen_t l) -{ - /* TODO */ - return -1; -} - -int picotcp_recvfrom(struct stack_endpoint *ep,void * buff, int len, struct sockaddr *a, socklen_t *l) -{ - /* TODO */ - return -1; -} - -int picotcp_read(struct stack_endpoint *ep,void *buf, int len) -{ - int retval = 0; - int tot_len = 0; - if (!buf || (len <= 0)) - return 0; - PicoTcpLock->lock(); - while (tot_len < len) { - retval = pico_socket_read(ep->s, ((uint8_t *)buf) + tot_len , len - tot_len); - if (retval == 0) { - if (tot_len < len) - ep->revents &= ~PICO_SOCK_EV_RD; - break; - } - if (retval < 0) { - tot_len = -1; - break; - } - tot_len += retval; - } - PicoTcpLock->unlock(); - return tot_len; -} - -int picotcp_write(struct stack_endpoint *ep,void *buf, int len) -{ - int retval = 0; - int tot_len = 0; - if (!buf || (len <= 0)) - return 0; - PicoTcpLock->lock(); - while (tot_len < len) { - retval = pico_socket_write(ep->s, ((uint8_t *)buf) + tot_len , len - tot_len); - retval = pico_socket_read(ep->s, ((uint8_t *)buf) + tot_len , len - tot_len); - if (retval == 0) { - if (tot_len < len) - ep->revents &= ~PICO_SOCK_EV_RD; - break; - } - if (retval < 0) { - tot_len = -1; - break; - } - tot_len += retval; - - } - PicoTcpLock->unlock(); - picotcp_async_interrupt(NULL); - return tot_len; -} - - -int picotcp_setsockopt(struct stack_endpoint *ep, int option, void *value) -{ - /* TODO */ - return -1; -} - -int picotcp_getsockopt(struct stack_endpoint *ep, int option, void *value) -{ - /* TODO */ - return -1; -} - -int picotcp_close(struct stack_endpoint *ep) -{ - PicoTcpLock->lock(); - pico_socket_close(ep->s); - ep->s->priv = NULL; - printf("Socket closed!\n"); - delete(ep->queue); - pico_free(ep); - PicoTcpLock->unlock(); -} - -int picotcp_join_multicast(struct stack_endpoint *ep,const char* address,const char* local) -{ - /* TODO */ - return -1; -} - - - -void pico_wrapper_loop(const void * arg) -{ - (void)arg; - int ret = 0; - struct pico_device *dev; - while(1) { - - osEvent evt = PicoTcpEvents->get(2); - - if (evt.status == osEventMessage) { - dev = (struct pico_device *)evt.value.p; - } else { - dev = NULL; - } - - if (dev && dev->dsr){ - PicoTcpLock->lock(); - dev->dsr(dev, 200); - pico_stack_tick(); - PicoTcpLock->unlock(); - } else { - if (PicoTcpLock->trylock()) { - pico_stack_tick(); - PicoTcpLock->unlock(); - } - } - } -} - -void picotcp_start(void) -{ - if (serverThread == NULL) { - PicoTcpLock = new Mutex(); - PicoTcpEvents = new Queue<void,10>(); - printf (" *** PicoTCP initialized *** \n"); - serverThread = new Thread(pico_wrapper_loop); - serverThread->set_priority(osPriorityIdle); - } -} - -void picotcp_init(void) -{ - picotcp_start(); -} - -int picotcp_async_interrupt(void *arg) -{ - PicoTcpEvents->put(arg); -}
--- a/Socket/bsd/wrapper.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -#ifndef ____WRAPPER_H -#define ____WRAPPER_H - -#ifdef __cplusplus -extern "C"{ -#endif - -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_stack.h" -#include "pico_socket.h" - -#ifdef __cplusplus -} -#endif - -#include "mbed.h" -#include "rtos.h" - -struct stack_endpoint { - uint16_t sock_fd; - struct pico_socket *s; - int connected; - int events; - int revents; - Queue<void,1> *queue;//receive queue of 1 element of type - uint32_t timeout; // this is used for timeout sockets - int state; // for pico_state -}; - -void picotcp_start(void); -struct stack_endpoint *pico_get_socket(uint16_t sockfd); -#endif
--- a/include/PicoCondition.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,45 +0,0 @@ -#ifndef __PICOMUTEX__ -#define __PICOMUTEX__ -/* -* Cross-Threading Mutex Class -*/ - -#include "mbed.h" -#include "rtos.h" -#include "Queue.h" - -class PicoCondition -{ - private: - Queue <int,1> * queue; - public: - PicoCondition() - { - queue = new Queue<int,1>(); - } - - ~PicoCondition() - { - if(queue) - { - delete queue; - queue = NULL; - } - } - - bool unlock(uint32_t millisec=0,int * ptr=NULL) - { - osStatus status; - status = queue->put(ptr, millisec); - return (status == osEventMessage || status == osOK); - } - - bool lock(uint32_t millisec=osWaitForever) - { - osEvent event = queue->get(millisec); - return (event.status == osEventMessage || event.status == osOK); - } -}; - - -#endif \ No newline at end of file
--- a/include/arch/pico_mbed.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,94 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. -Do not redistribute without a written permission by the Copyright -holders. - -File: pico_mbed.h -Author: Toon Peters -*********************************************************************/ - -#ifndef PICO_SUPPORT_MBED -#define PICO_SUPPORT_MBED -#include <stdio.h> - -//#include "mbed.h" -//#include "serial_api.h" - -/* -Debug needs initialization: -* void serial_init (serial_t *obj, PinName tx, PinName rx); -* void serial_baud (serial_t *obj, int baudrate); -* void serial_format (serial_t *obj, int data_bits, SerialParity parity, int stop_bits); -*/ - -#define dbg(...) -#define pico_zalloc(x) calloc(x, 1) -#define pico_free(x) free(x) - -#ifdef MEMORY_MEASURE // in case, comment out the two defines above me. -extern uint32_t max_mem; -extern uint32_t cur_mem; - -static inline void * pico_zalloc(int x) -{ - uint32_t *ptr; - if ((cur_mem + x )> (10 * 1024)) - return NULL; - - ptr = (uint32_t *)calloc(x + 4, 1); - *ptr = (uint32_t)x; - cur_mem += x; - if (cur_mem > max_mem) { - max_mem = cur_mem; - printf("max mem: %lu\n", max_mem); - } - return (void*)(ptr + 1); -} - -static inline void pico_free(void *x) -{ - uint32_t *ptr = (uint32_t*)(((uint8_t *)x) - 4); - cur_mem -= *ptr; - free(ptr); -} -#endif - -#define PICO_SUPPORT_MUTEX -extern void *pico_mutex_init(void); -extern void pico_mutex_lock(void*); -extern void pico_mutex_unlock(void*); - - -extern uint32_t os_time; - -static inline unsigned long PICO_TIME(void) -{ - return (unsigned long)os_time / 1000; -} - -static inline unsigned long PICO_TIME_MS(void) -{ - return (unsigned long)os_time; -} - -static inline void PICO_IDLE(void) -{ - // TODO needs implementation -} -/* -static inline void PICO_DEBUG(const char * formatter, ... ) -{ - char buffer[256]; - char *ptr; - va_list args; - va_start(args, formatter); - vsnprintf(buffer, 256, formatter, args); - ptr = buffer; - while(*ptr != '\0') - serial_putc(serial_t *obj, (int) (*(ptr++))); - va_end(args); - //TODO implement serial_t -}*/ - -#endif
--- a/include/heap.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,81 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ - -#define DECLARE_HEAP(type, orderby) \ -struct heap_##type { \ - uint32_t size; \ - uint32_t n; \ - type *top; \ -}; \ -typedef struct heap_##type heap_##type; \ -static inline int heap_insert(struct heap_##type *heap, type *el) \ -{ \ - int i; \ - type * newTop; \ - if (++heap->n >= heap->size) { \ - newTop = pico_zalloc((heap->n + 1) * sizeof(type)); \ - if(!newTop) \ - return -1; \ - if (heap->top) {\ - memcpy(newTop,heap->top,heap->n*sizeof(type)); \ - pico_free(heap->top); \ - } \ - heap->top = newTop; \ - heap->size++; \ - } \ - if (heap->n == 1) { \ - memcpy(&heap->top[1], el, sizeof(type)); \ - return 0; \ - } \ - for (i = heap->n; ((i > 1) && (heap->top[i / 2].orderby > el->orderby)); i /= 2) { \ - memcpy(&heap->top[i], &heap->top[i / 2], sizeof(type)); \ - } \ - memcpy(&heap->top[i], el, sizeof(type)); \ - return 0; \ -} \ -static inline int heap_peek(struct heap_##type *heap, type *first) \ -{ \ - type *last; \ - int i, child; \ - if(heap->n == 0) { \ - return -1; \ - } \ - memcpy(first, &heap->top[1], sizeof(type)); \ - last = &heap->top[heap->n--]; \ - for(i = 1; (i * 2) <= heap->n; i = child) { \ - child = 2 * i; \ - if ((child != heap->n) && \ - (heap->top[child + 1]).orderby \ - < (heap->top[child]).orderby) \ - child++; \ - if (last->orderby > \ - heap->top[child].orderby) \ - memcpy(&heap->top[i], &heap->top[child],\ - sizeof(type)); \ - else \ - break; \ - } \ - memcpy(&heap->top[i], last, sizeof(type)); \ - return 0; \ -} \ -static inline type *heap_first(heap_##type *heap) \ -{ \ - if (heap->n == 0) \ - return NULL; \ - return &heap->top[1]; \ -} \ -static inline heap_##type *heap_init(void) \ -{ \ - heap_##type *p = (heap_##type *)pico_zalloc(sizeof(heap_##type)); \ - return p; \ -} \ -static inline void heap_destroy(heap_##type *h) \ -{ \ - pico_free(h->top); \ - pico_free(h); \ -} \ - -
--- a/include/pico_addressing.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,52 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_ADDRESSING -#define _INCLUDE_PICO_ADDRESSING -#include <stdint.h> - - -struct pico_ip4 -{ - uint32_t addr; -}; -#define PICO_SIZE_IP4 4 - - -struct pico_ip6 -{ - uint8_t addr[16]; -}; -#define PICO_SIZE_IP6 16 - -struct pico_eth -{ - uint8_t addr[6]; - uint8_t padding[2]; -}; -#define PICO_SIZE_ETH 6 - -extern const uint8_t PICO_ETHADDR_ALL[]; - - -struct pico_trans -{ - uint16_t sport; - uint16_t dport; - -}; -#define PICO_SIZE_TRANS 8 - - -/* Here are some protocols. */ -#define PICO_PROTO_IPV4 0 -#define PICO_PROTO_ICMP4 1 -#define PICO_PROTO_IGMP 2 -#define PICO_PROTO_TCP 6 -#define PICO_PROTO_UDP 17 -#define PICO_PROTO_IPV6 41 -#define PICO_PROTO_ICMP6 58 - -#endif
--- a/include/pico_arp.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,25 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_ARP -#define _INCLUDE_PICO_ARP -#include "pico_eth.h" -#include "pico_device.h" - -int pico_arp_receive(struct pico_frame *); - - -struct pico_eth *pico_arp_get(struct pico_frame *f); -int pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst); - -#define PICO_ARP_STATUS_REACHABLE 0x00 -#define PICO_ARP_STATUS_PERMANENT 0x01 -#define PICO_ARP_STATUS_STALE 0x02 - - -struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst); -struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst); -int pico_arp_create_entry(uint8_t* hwaddr, struct pico_ip4 ipv4, struct pico_device* dev); -#endif
--- a/include/pico_config.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,34 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_CONFIG -#define _INCLUDE_PICO_CONFIG -#include <stdint.h> -#include <stdlib.h> -#include <string.h> -#include "pico_constants.h" - - -#define MBED -//#define PICO_SUPPORT_CRC -#define PICO_SUPPORT_DEVLOOP -#define PICO_SUPPORT_DHCPC -#define PICO_SUPPORT_DHCPD -#define PICO_SUPPORT_DNS_CLIENT -#define PICO_SUPPORT_HTTP_CLIENT -#define PICO_SUPPORT_HTTP -#define PICO_SUPPORT_HTTP_SERVER -#define PICO_SUPPORT_ICMP4 -#define PICO_SUPPORT_PING -#define PICO_SUPPORT_IGMP2 -//#define PICO_SUPPORT_IPFILTER -//#define PICO_SUPPORT_IPFRAG -#define PICO_SUPPORT_IPV4 -#define PICO_SUPPORT_MCAST -#define PICO_SUPPORT_NAT -#define PICO_SUPPORT_TCP -#define PICO_SUPPORT_UDP -# include "arch/pico_mbed.h" -#endif
--- a/include/pico_constants.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_CONST -#define _INCLUDE_PICO_CONST -/* Included from pico_config.h */ -/** Endian-dependant constants **/ - -extern volatile unsigned long pico_tick; - -#ifdef PICO_BIGENDIAN - -# define PICO_IDETH_IPV4 0x0800 -# define PICO_IDETH_ARP 0x0806 -# define PICO_IDETH_IPV6 0x86DD - -# define PICO_ARP_REQUEST 0x0001 -# define PICO_ARP_REPLY 0x0002 -# define PICO_ARP_HTYPE_ETH 0x0001 - -#define short_be(x) (x) -#define long_be(x) (x) - -static inline uint16_t short_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint16_t r, p0, p1; - p0 = p[0]; - p1 = p[1]; - r = (p0 << 8) + p1; - return r; -} - -static inline uint32_t long_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint32_t r, p0, p1, p2, p3; - p0 = p[0]; - p1 = p[1]; - p2 = p[2]; - p3 = p[3]; - r = (p0 << 24) + (p1 << 16) + (p2 << 8) + p3; - return r; -} - -#else - -static inline uint16_t short_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint16_t r, p0, p1; - p0 = p[0]; - p1 = p[1]; - r = (p1 << 8) + p0; - return r; -} - -static inline uint32_t long_from(void *_p) -{ - unsigned char *p = (unsigned char *)_p; - uint32_t r, p0, p1, p2, p3; - p0 = p[0]; - p1 = p[1]; - p2 = p[2]; - p3 = p[3]; - r = (p3 << 24) + (p2 << 16) + (p1 << 8) + p0; - return r; -} - - -# define PICO_IDETH_IPV4 0x0008 -# define PICO_IDETH_ARP 0x0608 -# define PICO_IDETH_IPV6 0xDD86 - -# define PICO_ARP_REQUEST 0x0100 -# define PICO_ARP_REPLY 0x0200 -# define PICO_ARP_HTYPE_ETH 0x0100 - -static inline uint16_t short_be(uint16_t le) -{ - return ((le & 0xFF) << 8) | ((le >> 8) & 0xFF); -} - -static inline uint32_t long_be(uint32_t le) -{ - uint8_t *b = (uint8_t *)≤ - uint32_t be = 0; - uint32_t b0, b1, b2; - b0 = b[0]; - b1 = b[1]; - b2 = b[2]; - be = b[3] + (b2 << 8) + (b1 << 16) + (b0 << 24); - return be; -} -#endif - - -/* Add well-known host numbers here. (bigendian constants only beyond this point) */ -#define PICO_IP4_ANY (0x00000000U) -#define PICO_IP4_BCAST (0xffffffffU) - -/* defined in modules/pico_ipv6.c */ -#ifdef PICO_SUPPORT_IPV6 -extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6]; -#endif - -static inline uint32_t pico_hash(char *name) -{ - unsigned long hash = 5381; - int c; - while ((c = *name++)) - hash = ((hash << 5) + hash) + c; /* hash * 33 + c */ - return hash; -} - -/* Debug */ -//#define PICO_SUPPORT_DEBUG_MEMORY -//#define PICO_SUPPORT_DEBUG_TOOLS -#endif
--- a/include/pico_device.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,39 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_DEVICE -#define _INCLUDE_PICO_DEVICE -#include "pico_queue.h" -#include "pico_frame.h" -#include "pico_addressing.h" -#include "pico_tree.h" -#define MAX_DEVICE_NAME 16 - - -struct pico_ethdev { - struct pico_eth mac; -}; - -struct pico_device { - char name[MAX_DEVICE_NAME]; - uint32_t hash; - uint32_t overhead; - struct pico_ethdev *eth; /* Null if non-ethernet */ - struct pico_queue *q_in; - struct pico_queue *q_out; - int (*send)(struct pico_device *self, void *buf, int len); /* Send function. Return 0 if busy */ - int (*poll)(struct pico_device *self, int loop_score); - void(*destroy)(struct pico_device *self); - int (*dsr)(struct pico_device *self, int loop_score); - int __serving_interrupt; -}; - -int pico_device_init(struct pico_device *dev, char *name, uint8_t *mac); -void pico_device_destroy(struct pico_device *dev); -int pico_devices_loop(int loop_score, int direction); -struct pico_device* pico_get_device(char* name); -int pico_device_broadcast(struct pico_frame * f); - -#endif
--- a/include/pico_eth.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_ETH -#define _INCLUDE_PICO_ETH -#include "pico_addressing.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" - - -struct __attribute__((packed)) pico_eth_hdr { - uint8_t daddr[6]; - uint8_t saddr[6]; - uint16_t proto; -}; - -#define PICO_SIZE_ETHHDR 14 - -#endif
--- a/include/pico_frame.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_FRAME -#define _INCLUDE_PICO_FRAME -#include "pico_config.h" - - -#define PICO_FRAME_FLAG_BCAST (0x01) -#define PICO_FRAME_FLAG_SACKED (0x80) -#define IS_BCAST(f) ((f->flags & PICO_FRAME_FLAG_BCAST) == PICO_FRAME_FLAG_BCAST) - - -struct pico_socket; - - -struct pico_frame { - - /* Connector for queues */ - struct pico_frame *next; - - /* Start of the whole buffer, total frame length. */ - unsigned char *buffer; - uint32_t buffer_len; - - /* For outgoing packets: this is the meaningful buffer. */ - unsigned char *start; - uint32_t len; - - /* Pointer to usage counter */ - uint32_t *usage_count; - - /* Pointer to protocol headers */ - uint8_t *datalink_hdr; - - uint8_t *net_hdr; - int net_len; - uint8_t *transport_hdr; - int transport_len; - uint8_t *app_hdr; - int app_len; - - /* Pointer to the phisical device this packet belongs to. - * Should be valid in both routing directions - */ - struct pico_device *dev; - - unsigned long timestamp; - - /* Failures due to bad datalink addressing. */ - uint16_t failure_count; - - /* Protocol over IP */ - uint8_t proto; - - /* PICO_FRAME_FLAG_* */ - uint8_t flags; - - /* Pointer to payload */ - unsigned char *payload; - int payload_len; - -#ifdef PICO_SUPPORT_IPFRAG - /* Payload fragmentation info (big endian)*/ - uint16_t frag; -#endif - - /* Pointer to socket */ - struct pico_socket *sock; - - /* Pointer to transport info, used to store remote UDP duple (IP + port) */ - void *info; - - /*Priority. "best-effort" priority, the default value is 0. Priority can be in between -10 and +10*/ - int8_t priority; -}; - -/** frame alloc/dealloc/copy **/ -void pico_frame_discard(struct pico_frame *f); -struct pico_frame *pico_frame_copy(struct pico_frame *f); -struct pico_frame *pico_frame_deepcopy(struct pico_frame *f); -struct pico_frame *pico_frame_alloc(int size); -uint16_t pico_checksum(void *inbuf, int len); -uint16_t pico_dualbuffer_checksum(void *b1, int len1, void *b2, int len2); - -static inline int pico_is_digit(char c) -{ - if (c < '0' || c > '9') - return 0; - return 1; -} - -#endif
--- a/include/pico_module_eth.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,33 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _PICO_MODULE_IPV4_H -#define _PICO_MODULE_IPV4_H - -struct pico_arp_entry { - struct eth dest; -#ifdef PICO_CONFIG_IPV4 - struct ipv4 addr_ipv4; -#endif - RB_ENTRY(pico_arp_entry) node; -}; - -/* Configured device */ -struct pico_eth_link { - struct pico_device *dev; - struct eth address; - struct eth netmask; - RB_ENTRY(pico_eth_link) node; -}; - -#ifndef IS_MODULE_ETH -# define _mod extern -#else -# define _mod -#endif -_mod struct pico_module pico_module_eth; -#undef _mod - -#endif
--- a/include/pico_protocol.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_PROTOCOL -#define _INCLUDE_PICO_PROTOCOL -#include <stdint.h> -#include "pico_queue.h" - -#define PICO_LOOP_DIR_IN 1 -#define PICO_LOOP_DIR_OUT 2 - -enum pico_layer { - PICO_LAYER_DATALINK = 2, /* Ethernet only. */ - PICO_LAYER_NETWORK = 3, /* IPv4, IPv6, ARP. Arp is there because it communicates with L2 */ - PICO_LAYER_TRANSPORT = 4, /* UDP, TCP, ICMP */ - PICO_LAYER_SOCKET = 5 /* Socket management */ -}; - -enum pico_err_e { - PICO_ERR_NOERR = 0, - PICO_ERR_EPERM, - PICO_ERR_ENOENT, - /* ... */ - PICO_ERR_EINTR = 4, - PICO_ERR_EIO, - PICO_ERR_ENXIO, - /* ... */ - PICO_ERR_EAGAIN = 11, - PICO_ERR_ENOMEM, - PICO_ERR_EACCESS, - PICO_ERR_EFAULT, - /* ... */ - PICO_ERR_EBUSY = 16, - PICO_ERR_EEXIST = 17, - /* ... */ - PICO_ERR_EINVAL = 22, - /* ... */ - PICO_ERR_EPROTO = 71, - PICO_ERR_ENOPROTOOPT = 92, - PICO_ERR_EPROTONOSUPPORT = 93, - - /* ... */ - PICO_ERR_EADDRINUSE = 98, - PICO_ERR_EADDRNOTAVAIL, - PICO_ERR_ENETUNREACH, - - /* ... */ - PICO_ERR_ECONNRESET = 104, - - /* ... */ - PICO_ERR_EISCONN = 106, - PICO_ERR_ENOTCONN, - PICO_ERR_ESHUTDOWN, - /* ... */ - PICO_ERR_ETIMEDOUT = 110, - PICO_ERR_ECONNREFUSED = 111, - PICO_ERR_EHOSTDOWN, - PICO_ERR_EHOSTUNREACH, - /* ... */ - PICO_ERR_EOPNOTSUPP = 122, - -}; - -typedef enum pico_err_e pico_err_t; -extern volatile pico_err_t pico_err; - -#define IS_IPV6(f) ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x60) -#define IS_IPV4(f) ((((uint8_t *)(f->net_hdr))[0] & 0xf0) == 0x40) - -#define MAX_PROTOCOL_NAME 16 - -struct pico_protocol { - char name[MAX_PROTOCOL_NAME]; - uint32_t hash; - enum pico_layer layer; - int proto_number; - struct pico_queue *q_in; - struct pico_queue *q_out; - struct pico_frame *(*alloc)(struct pico_protocol *self, int size); /* Frame allocation. */ - int (*push) (struct pico_protocol *self, struct pico_frame *p); /* Push function, for active outgoing pkts from above */ - int (*process_out)(struct pico_protocol *self, struct pico_frame *p); /* Send loop. */ - int (*process_in)(struct pico_protocol *self, struct pico_frame *p); /* Recv loop. */ -}; - -int pico_protocols_loop(int loop_score); -void pico_protocol_init(struct pico_protocol *p); - -int pico_protocol_datalink_loop(int loop_score, int direction); -int pico_protocol_network_loop(int loop_score, int direction); -int pico_protocol_transport_loop(int loop_score, int direction); -int pico_protocol_socket_loop(int loop_score, int direction); - -#endif
--- a/include/pico_queue.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,137 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_QUEUE -#define _INCLUDE_PICO_QUEUE -#include <stdint.h> -#include "pico_config.h" -#include "pico_frame.h" - -#define Q_LIMIT 0 - -#ifndef NULL -#define NULL ((void *)0) -#endif - -struct pico_queue { - uint32_t frames; - uint32_t size; - uint32_t max_frames; - uint32_t max_size; - struct pico_frame *head; - struct pico_frame *tail; -#ifdef PICO_SUPPORT_MUTEX - void * mutex; -#endif - uint8_t shared; -}; - -#ifdef PICO_SUPPORT_MUTEX -#define LOCK(x) {\ - if (x == NULL) \ - x = pico_mutex_init(); \ - pico_mutex_lock(x); \ -} -#define UNLOCK(x) pico_mutex_unlock(x); - -#else -#define LOCK(x) do{}while(0) -#define UNLOCK(x) do{}while(0) -#endif - -#ifdef PICO_SUPPORT_DEBUG_TOOLS -static void debug_q(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - dbg("%d: ", q->frames); - while(p) { - dbg("(%p)-->", p); - p = p->next; - } - dbg("X\n"); -} - -#else - -#define debug_q(x) do{}while(0) -#endif - -static inline int pico_enqueue(struct pico_queue *q, struct pico_frame *p) -{ - if ((q->max_frames) && (q->max_frames <= q->frames)) - return -1; - - if ((Q_LIMIT) && (Q_LIMIT < p->buffer_len + q->size)) - return -1; - - if ((q->max_size) && (q->max_size < (p->buffer_len + q->size))) - return -1; - - if (q->shared) - LOCK(q->mutex); - - p->next = NULL; - if (!q->head) { - q->head = p; - q->tail = p; - q->size = 0; - q->frames = 0; - } else { - q->tail->next = p; - q->tail = p; - } - q->size += p->buffer_len; - q->frames++; - debug_q(q); - - if (q->shared) - UNLOCK(q->mutex); - return q->size; -} - -static inline struct pico_frame *pico_dequeue(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - if (q->frames < 1) - return NULL; - if (q->shared) - LOCK(q->mutex); - - q->head = p->next; - q->frames--; - q->size -= p->buffer_len; - if (q->head == NULL) - q->tail = NULL; - debug_q(q); - p->next = NULL; - if (q->shared) - UNLOCK(q->mutex); - return p; -} - -static inline struct pico_frame *pico_queue_peek(struct pico_queue *q) -{ - struct pico_frame *p = q->head; - if (q->frames < 1) - return NULL; - debug_q(q); - return p; -} - -static inline void pico_queue_empty(struct pico_queue *q) -{ - struct pico_frame *p = pico_dequeue(q); - while(p) { - pico_free(p); - p = pico_dequeue(q); - } -} - -static inline void pico_queue_protect(struct pico_queue *q) -{ - q->shared = 1; -} - -#endif
--- a/include/pico_socket.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,205 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_SOCKET -#define _INCLUDE_PICO_SOCKET -#include "pico_queue.h" -#include "pico_addressing.h" -#include "pico_config.h" -#include "pico_protocol.h" - -//#define PICO_DEFAULT_SOCKETQ (128 * 1024) -#define PICO_DEFAULT_SOCKETQ (4 * 1024) - -#define PICO_SHUT_RD 1 -#define PICO_SHUT_WR 2 -#define PICO_SHUT_RDWR 3 - - -struct pico_socket { - struct pico_protocol *proto; - struct pico_protocol *net; - - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } local_addr; - - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } remote_addr; - - uint16_t local_port; - uint16_t remote_port; - - struct pico_queue q_in; - struct pico_queue q_out; - - void (*wakeup)(uint16_t ev, struct pico_socket *s); - - -#ifdef PICO_SUPPORT_TCP - /* For the TCP backlog queue */ - struct pico_socket *backlog; - struct pico_socket *next; - struct pico_socket *parent; - int max_backlog; -#endif -#ifdef PICO_SUPPORT_MCAST - struct pico_tree *MCASTListen; -#endif - uint16_t ev_pending; - - struct pico_device *dev; - - /* Private field. */ - int id; - uint16_t state; - uint16_t opt_flags; - void *priv; -}; - -struct pico_remote_duple { - union { - struct pico_ip4 ip4; - struct pico_ip6 ip6; - } remote_addr; - - uint16_t remote_port; -}; - - -/* request struct for multicast socket opt */ -struct pico_ip_mreq { - struct pico_ip4 mcast_group_addr; - struct pico_ip4 mcast_link_addr; -}; - -struct pico_ip_mreq_source { - struct pico_ip4 mcast_group_addr; - struct pico_ip4 mcast_source_addr; - struct pico_ip4 mcast_link_addr; -}; - -#define PICO_SOCKET_STATE_UNDEFINED 0x0000 -#define PICO_SOCKET_STATE_SHUT_LOCAL 0x0001 -#define PICO_SOCKET_STATE_SHUT_REMOTE 0x0002 -#define PICO_SOCKET_STATE_BOUND 0x0004 -#define PICO_SOCKET_STATE_CONNECTED 0x0008 -#define PICO_SOCKET_STATE_CLOSING 0x0010 -#define PICO_SOCKET_STATE_CLOSED 0x0020 - -# define PICO_SOCKET_STATE_TCP 0xFF00 -# define PICO_SOCKET_STATE_TCP_UNDEF 0x00FF -# define PICO_SOCKET_STATE_TCP_CLOSED 0x0100 -# define PICO_SOCKET_STATE_TCP_LISTEN 0x0200 -# define PICO_SOCKET_STATE_TCP_SYN_SENT 0x0300 -# define PICO_SOCKET_STATE_TCP_SYN_RECV 0x0400 -# define PICO_SOCKET_STATE_TCP_ESTABLISHED 0x0500 -# define PICO_SOCKET_STATE_TCP_CLOSE_WAIT 0x0600 -# define PICO_SOCKET_STATE_TCP_LAST_ACK 0x0700 -# define PICO_SOCKET_STATE_TCP_FIN_WAIT1 0x0800 -# define PICO_SOCKET_STATE_TCP_FIN_WAIT2 0x0900 -# define PICO_SOCKET_STATE_TCP_CLOSING 0x0a00 -# define PICO_SOCKET_STATE_TCP_TIME_WAIT 0x0b00 -# define PICO_SOCKET_STATE_TCP_ARRAYSIZ 0x0c - -# define PICO_TCP_NODELAY 1 - -# define PICO_SOCKET_OPT_TCPNODELAY 0x0000 - -# define PICO_IP_MULTICAST_EXCLUDE 0 -# define PICO_IP_MULTICAST_INCLUDE 1 -# define PICO_IP_MULTICAST_IF 32 -# define PICO_IP_MULTICAST_TTL 33 -# define PICO_IP_MULTICAST_LOOP 34 -# define PICO_IP_ADD_MEMBERSHIP 35 -# define PICO_IP_DROP_MEMBERSHIP 36 -# define PICO_IP_UNBLOCK_SOURCE 37 -# define PICO_IP_BLOCK_SOURCE 38 -# define PICO_IP_ADD_SOURCE_MEMBERSHIP 39 -# define PICO_IP_DROP_SOURCE_MEMBERSHIP 40 - -# define PICO_SOCKET_OPT_MULTICAST_LOOP 1 - -# define PICO_IP_DEFAULT_MULTICAST_TTL 1 -# define PICO_IP_DEFAULT_MULTICAST_LOOP 1 - -#define PICO_SOCKET_SHUTDOWN_WRITE 0x01 -#define PICO_SOCKET_SHUTDOWN_READ 0x02 -#define TCPSTATE(s) ((s)->state & PICO_SOCKET_STATE_TCP) - -#define PICO_SOCK_EV_RD 1 -#define PICO_SOCK_EV_WR 2 -#define PICO_SOCK_EV_CONN 4 -#define PICO_SOCK_EV_CLOSE 8 -#define PICO_SOCK_EV_FIN 0x10 -#define PICO_SOCK_EV_ERR 0x80 - - -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *s)); - -int pico_socket_read(struct pico_socket *s, void *buf, int len); -int pico_socket_write(struct pico_socket *s, void *buf, int len); - -int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port); -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *local_port); - -int pico_socket_send(struct pico_socket *s, void *buf, int len); -int pico_socket_recv(struct pico_socket *s, void *buf, int len); - -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port); -int pico_socket_connect(struct pico_socket *s, void *srv_addr, uint16_t remote_port); -int pico_socket_listen(struct pico_socket *s, int backlog); -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port); -int pico_socket_del(struct pico_socket *s); - -int pico_socket_setoption(struct pico_socket *s, int option, void *value); -int pico_socket_getoption(struct pico_socket *s, int option, void *value); - -int pico_socket_shutdown(struct pico_socket *s, int mode); -int pico_socket_close(struct pico_socket *s); - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len); - -#ifdef PICO_SUPPORT_IPV4 -# define is_sock_ipv4(x) (x->net == &pico_proto_ipv4) -#else -# define is_sock_ipv4(x) (0) -#endif - -#ifdef PICO_SUPPORT_IPV6 -# define is_sock_ipv6(x) (x->net == &pico_proto_ipv6) -#else -# define is_sock_ipv6(x) (0) -#endif - -#ifdef PICO_SUPPORT_UDP -# define is_sock_udp(x) (x->net == &pico_proto_udp) -#else -# define is_sock_udp(x) (0) -#endif - -#ifdef PICO_SUPPORT_TCP -# define is_sock_tcp(x) (x->net == &pico_proto_tcp) -#else -# define is_sock_tcp(x) (0) -#endif - -/* Interface towards transport protocol */ -int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f); -struct pico_socket *pico_socket_clone(struct pico_socket *facsimile); -int pico_socket_add(struct pico_socket *s); -int pico_transport_error(struct pico_frame *f, uint8_t proto, int code); - -/* Socket loop */ -int pico_sockets_loop(int loop_score); - -/* Port check */ -int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net); - - -#endif
--- a/include/pico_stack.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,65 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_STACK -#define _INCLUDE_PICO_STACK -#include "pico_config.h" -#include "pico_frame.h" - -#define PICO_MAX_TIMERS 20 - -/* ===== RECEIVING FUNCTIONS (from dev up to socket) ===== */ - -/* TRANSPORT LEVEL */ -/* interface towards network */ -int pico_transport_receive(struct pico_frame *f, uint8_t proto); - -/* NETWORK LEVEL */ -/* interface towards ethernet */ -int pico_network_receive(struct pico_frame *f); - -/* The pico_ethernet_receive() function is used by - * those devices supporting ETH in order to push packets up - * into the stack. - */ -/* DATALINK LEVEL */ -int pico_ethernet_receive(struct pico_frame *f); - -/* LOWEST LEVEL: interface towards devices. */ -/* Device driver will call this function which returns immediately. - * Incoming packet will be processed later on in the dev loop. - */ -int pico_stack_recv(struct pico_device *dev, uint8_t *buffer, int len); - - -/* ===== SENDIING FUNCTIONS (from socket down to dev) ===== */ - -int pico_transport_send(struct pico_frame *f); -int pico_network_send(struct pico_frame *f); -int pico_ethernet_send(struct pico_frame *f); -int pico_sendto_dev(struct pico_frame *f); - -/* ----- Initialization ----- */ -void pico_stack_init(void); - -/* ----- Loop Function. ----- */ -void pico_stack_tick(void); -void pico_stack_loop(void); - -/* ---- Notifications for stack errors */ -int pico_notify_socket_unreachable(struct pico_frame *f); -int pico_notify_proto_unreachable(struct pico_frame *f); -int pico_notify_dest_unreachable(struct pico_frame *f); -int pico_notify_ttl_expired(struct pico_frame *f); - -/* Various. */ -int pico_source_is_local(struct pico_frame *f); -int pico_destination_is_local(struct pico_frame *f); -void pico_store_network_origin(void *src, struct pico_frame *f); -void pico_timer_add(unsigned long expire, void (*timer)(unsigned long, void *), void *arg); -uint32_t pico_rand(void); -void pico_rand_feed(uint32_t feed); - -#endif
--- a/include/pico_tree.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,84 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#ifndef __PICO_RBTREE_H__ -#define __PICO_RBTREE_H__ - -#include <stdint.h> -#include "pico_config.h" - -// This is used to declare a new tree, leaf root by default -#define PICO_TREE_DECLARE(name,compareFunction) \ - struct pico_tree name =\ - { \ - &LEAF, \ - compareFunction \ - } - -struct pico_tree_node -{ - void* keyValue; // generic key - struct pico_tree_node* parent; - struct pico_tree_node* leftChild; - struct pico_tree_node* rightChild; - uint8_t color; -}; - -struct pico_tree -{ - struct pico_tree_node * root; // root of the tree - - // this function directly provides the keys as parameters not the nodes. - int (*compare)(void* keyA, void* keyB); -}; - -extern struct pico_tree_node LEAF; // generic leaf node -/* - * Manipulation functions - */ -void * pico_tree_insert(struct pico_tree * tree, void * key); -void * pico_tree_delete(struct pico_tree * tree, void * key); -void * pico_tree_findKey(struct pico_tree * tree, void * key); -void pico_tree_drop(struct pico_tree * tree); -int pico_tree_empty(struct pico_tree * tree); -struct pico_tree_node * pico_tree_findNode(struct pico_tree * tree, void * key); - -void * pico_tree_first(struct pico_tree * tree); -void * pico_tree_last(struct pico_tree * tree); -/* - * Traverse functions - */ -struct pico_tree_node * pico_tree_lastNode(struct pico_tree_node * node); -struct pico_tree_node * pico_tree_firstNode(struct pico_tree_node * node); -struct pico_tree_node * pico_tree_next(struct pico_tree_node * node); -struct pico_tree_node * pico_tree_prev(struct pico_tree_node * node); - -/* - * For each macros - */ - -#define pico_tree_foreach(idx,tree) \ - for ((idx) = pico_tree_firstNode((tree)->root); \ - (idx) != &LEAF; \ - (idx) = pico_tree_next(idx)) - -#define pico_tree_foreach_reverse(idx,tree) \ - for ((idx) = pico_tree_lastNode((tree)->root); \ - (idx) != &LEAF; \ - (idx) = pico_tree_prev(idx)) - -#define pico_tree_foreach_safe(idx,tree,idx2) \ - for ((idx) = pico_tree_firstNode((tree)->root); \ - ((idx) != &LEAF) && ((idx2) = pico_tree_next(idx), 1); \ - (idx) = (idx2)) - -#define pico_tree_foreach_reverse_safe(idx,tree,idx2) \ - for ((idx) = pico_tree_lastNode((tree)->root); \ - ((idx) != &LEAF) && ((idx2) = pico_tree_prev(idx), 1); \ - (idx) = (idx2)) - -#endif
--- a/modules/pico_dev_loop.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,68 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_device.h" -#include "pico_dev_loop.h" -#include "pico_stack.h" - - -#define LOOP_MTU 1500 -static uint8_t l_buf[LOOP_MTU]; -static int l_bufsize = 0; - - -static int pico_loop_send(struct pico_device *dev, void *buf, int len) -{ - if (len > LOOP_MTU) - return 0; - - if (l_bufsize == 0) { - memcpy(l_buf, buf, len); - l_bufsize+=len; - return len; - } - return 0; -} - -static int pico_loop_poll(struct pico_device *dev, int loop_score) -{ - if (loop_score <= 0) - return 0; - - if (l_bufsize > 0) { - pico_stack_recv(dev, l_buf, l_bufsize); - l_bufsize = 0; - loop_score--; - } - return loop_score; -} - -/* Public interface: create/destroy. */ - -void pico_loop_destroy(struct pico_device *dev) -{ -} - -struct pico_device *pico_loop_create(void) -{ - struct pico_device *loop = pico_zalloc(sizeof(struct pico_device)); - if (!loop) - return NULL; - - if( 0 != pico_device_init((struct pico_device *)loop, "loop", NULL)) { - dbg ("Loop init failed.\n"); - pico_loop_destroy((struct pico_device *)loop); - return NULL; - } - loop->send = pico_loop_send; - loop->poll = pico_loop_poll; - loop->destroy = pico_loop_destroy; - dbg("Device %s created.\n", loop->name); - return (struct pico_device *)loop; -} -
--- a/modules/pico_dev_loop.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,15 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_LOOP -#define _INCLUDE_PICO_LOOP -#include "pico_config.h" -#include "pico_device.h" - -void pico_loop_destroy(struct pico_device *loop); -struct pico_device *pico_loop_create(void); - -#endif -
--- a/modules/pico_dev_mbed.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,118 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. -Do not redistribute without a written permission by the Copyright -holders. - -Authors: Toon Peters, Maxime Vincent -*********************************************************************/ -#include "mbed.h" -extern "C" { -#include "pico_device.h" -#include "pico_dev_mbed.h" -#include "pico_stack.h" -#include "ethernet_api.h" -} - -struct pico_device_mbed { - struct pico_device dev; - int bytes_left_in_frame; -}; - -#define ETH_MTU 1514 -uint8_t buf[ETH_MTU]; - -Serial pc(p9, p10, "Serial port"); // tx, rx - -extern "C" { - -static int pico_mbed_send(struct pico_device *dev, void *buf, int len) -{ - int ret, sent; - struct pico_device_mbed *mb = (struct pico_device_mbed *) dev; - - if (len > ETH_MTU) - return -1; - - /* Write buf content to dev and return amount written */ - ret = ethernet_write((const char *)buf, len); - sent = ethernet_send(); - - pc.printf("ETH> sent %d bytes\r\n",ret); - if (len != ret || sent != ret) - return -1; - else - return ret; -} - -static int pico_mbed_poll(struct pico_device *dev, int loop_score) -{ - int len; - struct pico_device_mbed *mb = (struct pico_device_mbed *) dev; - - while(loop_score > 0) - { - /* check for new frame(s) */ - len = (int) ethernet_receive(); - - /* return if no frame has arrived */ - if (!len) - return loop_score; - - /* read and process frame */ - len = ethernet_read((char*)buf, ETH_MTU); - pc.printf("ETH> recv %d bytes: %x:%x\r\n", len, buf[0],buf[1]); - pico_stack_recv(dev, buf, len); - loop_score--; - } - return loop_score; -} - -/* Public interface: create/destroy. */ -void pico_mbed_destroy(struct pico_device *dev) -{ - ethernet_free(); - pico_device_destroy(dev); -} - -struct pico_device *pico_mbed_create(char *name) -{ - std::uint8_t mac[PICO_SIZE_ETH]; - struct pico_device_mbed *mb = (struct pico_device_mbed*) pico_zalloc(sizeof(struct pico_device_mbed)); - - if (!mb) - return NULL; - - ethernet_address((char *)mac); - pc.printf("ETH> Set MAC address to: %x:%x:%x:%x:%x:%x\r\n", mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]); - - if(0 != pico_device_init((struct pico_device *)mb, name, mac)) { - pc.printf ("ETH> Loop init failed.\n"); - //pico_loop_destroy(mb); - return NULL; - } - - mb->dev.send = pico_mbed_send; - mb->dev.poll = pico_mbed_poll; - mb->dev.destroy = pico_mbed_destroy; - mb->bytes_left_in_frame = 0; - - if(0 != ethernet_init()) { - pc.printf("ETH> Failed to initialize hardware.\r\n"); - pico_device_destroy((struct pico_device *)mb); - return NULL; - } - - // future work: make the mac address configurable - - pc.printf("ETH> Device %s created.\r\n", mb->dev.name); - - return (struct pico_device *)mb; -} - -void pico_mbed_get_address(char *mac) -{ - ethernet_address(mac); -} - -} \ No newline at end of file
--- a/modules/pico_dev_mbed.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. -Do not redistribute without a written permission by the Copyright -holders. - -File: pico_dev_mbed.h -Author: Toon Peters -*********************************************************************/ - -#ifndef PICO_DEV_MBED_H -#define PICO_DEV_MBED_H - -#include "pico_config.h" -#include "pico_device.h" - -void pico_mbed_destroy(struct pico_device *vde); -struct pico_device *pico_mbed_create(char *name); - -#endif /* PICO_DEV_MBED_H */ -
--- a/modules/pico_dhcp_client.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,732 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Frederik Van Slycken, Kristof Roelants -*********************************************************************/ - -#include "pico_dhcp_client.h" -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_device.h" -#include "pico_ipv4.h" -#include "pico_socket.h" - -#ifdef PICO_SUPPORT_DHCPC - -/*********** - * structs * - ***********/ - -static uint8_t dhcp_client_mutex = 1; /* to serialize client negotations if multiple devices */ - -struct dhcp_timer_param{ - uint16_t type; - struct pico_dhcp_client_cookie* cli; - int valid; -}; - -struct pico_dhcp_client_cookie -{ - uint32_t xid; - uint32_t *xid_user; - struct pico_ip4 address; - struct pico_ip4 netmask; - struct pico_ip4 gateway; - struct pico_ip4 nameserver; - struct pico_ip4 server_id; - uint32_t lease_time; - uint32_t T1; - uint32_t T2; - struct pico_socket* socket; - int connected; - struct pico_device* device; - unsigned long start_time; - int attempt; - enum dhcp_negotiation_state state; - void (*cb)(void* cli, int code); - struct dhcp_timer_param* timer_param_1; - struct dhcp_timer_param* timer_param_2; - struct dhcp_timer_param* timer_param_lease; - struct dhcp_timer_param* timer_param_retransmit; - int link_added; -}; - -static int dhcp_cookies_cmp(void *ka, void *kb) -{ - struct pico_dhcp_client_cookie *a = ka, *b = kb; - if (a->xid < b->xid) - return -1; - else if (a->xid > b->xid) - return 1; - else - return 0; -} -PICO_TREE_DECLARE(DHCPCookies, dhcp_cookies_cmp); - -/************************* - * function declarations * - *************************/ -static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len); -static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg); - -//cb -static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s); -static void dhcp_timer_cb(unsigned long tick, void* param); - -//util -static void pico_dhcp_retry(struct pico_dhcp_client_cookie *client); -static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type); -static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli); -static int init_cookie(struct pico_dhcp_client_cookie* cli); -static struct pico_dhcp_client_cookie* get_cookie_by_xid(uint32_t xid); -static uint32_t get_xid(uint8_t* data); - -//fsm functions -static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); -static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); -static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); -static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); -static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - -//fsm implementation -static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len); - -/*************** - * entry point * - ***************/ - -static uint32_t pico_dhcp_execute_init(struct pico_dhcp_client_cookie *cli) -{ - if (!dhcp_client_mutex) { - pico_timer_add(3000, pico_dhcp_reinitiate_negotiation, cli); - return 0; - } - dhcp_client_mutex--; - - if (init_cookie(cli) < 0) - return -1; - - dbg("DHCPC: cookie with xid %u\n", cli->xid); - - if (pico_tree_insert(&DHCPCookies, cli)) { - pico_err = PICO_ERR_EAGAIN; - if(cli->cb != NULL) { - cli->cb(cli, PICO_DHCP_ERROR); - } - pico_free(cli); - return -1; /* Element key already exists */ - } - - if (dhclient_send(cli, PICO_DHCP_MSG_DISCOVER) < 0) - return -1; - - return 0; -} - -/* returns a pointer to the client cookie. The user should pass this pointer every time he calls a dhcp-function. This is so that we can (one day) support dhcp on multiple interfaces */ -int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void *cli, int code), uint32_t *xid) -{ - struct pico_dhcp_client_cookie *cli; - - if(!device || !callback || !xid){ - pico_err = PICO_ERR_EINVAL; - return -1; - } - cli = pico_zalloc(sizeof(struct pico_dhcp_client_cookie)); - if(!cli){ - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - cli->device = device; - cli->cb = callback; - cli->xid_user = xid; - *(cli->xid_user) = 0; - - return pico_dhcp_execute_init(cli); -} - -static void pico_dhcp_reinitiate_negotiation(unsigned long now, void *arg) -{ - struct pico_dhcp_client_cookie *cli = (struct pico_dhcp_client_cookie *) arg; - - pico_dhcp_execute_init(cli); - - return; -} - -/******************** - * access functions * - ********************/ - -struct pico_ip4 pico_dhcp_get_address(void* cli) -{ - return ((struct pico_dhcp_client_cookie*)cli)->address; -} - -struct pico_ip4 pico_dhcp_get_gateway(void* cli) -{ - return ((struct pico_dhcp_client_cookie*)cli)->gateway; -} - -struct pico_ip4 pico_dhcp_get_nameserver(void* cli) -{ - return ((struct pico_dhcp_client_cookie*)cli)->nameserver; -} - -/************* - * callbacks * - *************/ - -static void pico_dhcp_wakeup(uint16_t ev, struct pico_socket *s) -{ - uint8_t buf[DHCPC_DATAGRAM_SIZE]; - int r=0; - uint32_t peer; - uint16_t port; - int type; - - struct pico_dhcp_client_cookie *cli; - dbg("DHCPC: called dhcp_wakeup\n"); - if (ev == PICO_SOCK_EV_RD) { - do { - r = pico_socket_recvfrom(s, buf, DHCPC_DATAGRAM_SIZE, &peer, &port); - cli = get_cookie_by_xid(get_xid(buf)); - if(cli == NULL) - return; - if (r > 0 && port == PICO_DHCPD_PORT) { - type = pico_dhcp_verify_and_identify_type(buf, r, cli); - pico_dhcp_state_machine(type, cli, buf, r); - } - } while(r>0); - } -} - -static void dhcp_timer_cb(unsigned long tick, void* param) -{ - struct dhcp_timer_param* param2 = (struct dhcp_timer_param*) param; - if(param2->valid == 1){ - //dbg("called timer cb on active timer type %d\n",param2->type); - pico_dhcp_state_machine(param2->type, param2->cli, NULL, 0); - } - if(param2->cli->timer_param_1 == param){ - param2->cli->timer_param_1 = NULL; - } - if(param2->cli->timer_param_2 == param){ - param2->cli->timer_param_2 = NULL; - } - if(param2->cli->timer_param_lease == param){ - param2->cli->timer_param_lease = NULL; - } - if(param2->cli->timer_param_retransmit == param){ - param2->cli->timer_param_retransmit = NULL; - } - - pico_free(param); - -} -/***************** - * fsm functions * - *****************/ - -static int recv_offer(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) -{ - struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; - uint8_t *nextopt, opt_data[20], opt_type; - int opt_len = 20; - uint8_t msg_type = 0xFF; - int T1_set = 0; - int T2_set = 0; - - cli->address.addr = dhdr->yiaddr; - - opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt); - while (opt_type != PICO_DHCPOPT_END) { - if (opt_type == PICO_DHCPOPT_MSGTYPE) - msg_type = opt_data[0]; - if ((opt_type == PICO_DHCPOPT_LEASETIME) && (opt_len == 4)){ - memcpy(&cli->lease_time, opt_data, 4); - cli->lease_time = long_be(cli->lease_time); - } - if ((opt_type == PICO_DHCPOPT_RENEWALTIME) && (opt_len == 4)){ - memcpy(&cli->T1, opt_data, 4); - cli->T1 = long_be(cli->T1); - T1_set =1; - } - if ((opt_type == PICO_DHCPOPT_REBINDINGTIME) && (opt_len == 4)){ - memcpy(&cli->T2, opt_data, 4); - cli->T2 = long_be(cli->T2); - T2_set =1; - } - if ((opt_type == PICO_DHCPOPT_ROUTER) && (opt_len == 4)) //XXX assuming only one router will be advertised... - memcpy(&cli->gateway.addr, opt_data, 4); - if ((opt_type == PICO_DHCPOPT_DNS) && (opt_len == 4)) - memcpy(&cli->nameserver.addr, opt_data, 4); - if ((opt_type == PICO_DHCPOPT_NETMASK) && (opt_len == 4)) - memcpy(&cli->netmask.addr, opt_data, 4); - if ((opt_type == PICO_DHCPOPT_SERVERID) && (opt_len == 4)) - memcpy(&cli->server_id.addr, opt_data, 4); - if (opt_type == PICO_DHCPOPT_OPTIONOVERLOAD) - dbg("DHCPC: WARNING: option overload present (not processed)"); - - opt_len = 20; - opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt); - } - - /* default values for T1 and T2 if necessary */ - if(T1_set != 1) - cli->T1 = cli->lease_time >> 1; - if(T2_set != 1) - cli->T2 = (cli->lease_time * 875) / 1000; - - - - if ((msg_type != PICO_DHCP_MSG_OFFER) || !cli->lease_time || !cli->netmask.addr || !cli->server_id.addr ) - return 0; - - - dhclient_send(cli, PICO_DHCP_MSG_REQUEST); - cli->state = DHCPSTATE_REQUEST; - return 1; -} - -static int recv_ack(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) -{ - struct pico_ip4 address = {0}; - - if(cli->link_added == 0){ - /* close the socket bound on address 0.0.0.0 */ - pico_socket_close(cli->socket); - cli->socket = NULL; - pico_ipv4_link_del(cli->device, address); - pico_ipv4_link_add(cli->device, cli->address, cli->netmask); - cli->link_added = 1; - } - cli->state = DHCPSTATE_BOUND; - - dbg("DHCPC: T1: %d\n",cli->T1); - dbg("DHCPC: T2: %d\n",cli->T2); - dbg("DHCPC: lease time: %d\n",cli->lease_time); - - if(cli->timer_param_1) - cli->timer_param_1->valid = 0; - if(cli->timer_param_2) - cli->timer_param_2->valid = 0; - if(cli->timer_param_lease) - cli->timer_param_lease->valid = 0; - if(cli->timer_param_retransmit) - cli->timer_param_retransmit->valid = 0; - - - cli->timer_param_1 = pico_zalloc(sizeof(struct dhcp_timer_param)); - if(!cli->timer_param_1){ - if(cli->cb != NULL){ - pico_err = PICO_ERR_ENOMEM; - cli->cb(cli, PICO_DHCP_ERROR); - } - return 0; - } - cli->timer_param_2 = pico_zalloc(sizeof(struct dhcp_timer_param)); - if(!cli->timer_param_2){ - if(cli->cb != NULL){ - pico_err = PICO_ERR_ENOMEM; - cli->cb(cli, PICO_DHCP_ERROR); - } - return 0; - } - cli->timer_param_lease = pico_zalloc(sizeof(struct dhcp_timer_param)); - if(!cli->timer_param_lease){ - if(cli->cb != NULL){ - pico_err = PICO_ERR_ENOMEM; - cli->cb(cli, PICO_DHCP_ERROR); - } - return 0; - } - cli->timer_param_1->valid = 1; - cli->timer_param_2->valid = 1; - cli->timer_param_lease->valid = 1; - - cli->timer_param_1->cli = cli; - cli->timer_param_2->cli = cli; - cli->timer_param_lease->cli = cli; - - cli->timer_param_1->type = PICO_DHCP_EVENT_T1; - cli->timer_param_2->type = PICO_DHCP_EVENT_T2; - cli->timer_param_lease->type = PICO_DHCP_EVENT_LEASE; - //add timer - pico_timer_add(cli->T1*1000, dhcp_timer_cb, cli->timer_param_1); - pico_timer_add(cli->T2*1000, dhcp_timer_cb, cli->timer_param_2); - pico_timer_add(cli->lease_time*1000, dhcp_timer_cb, cli->timer_param_lease); - - *(cli->xid_user) = cli->xid; - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_SUCCESS); - else - dbg("DHCPC: no callback\n"); - - dhcp_client_mutex++; - cli->state = DHCPSTATE_BOUND; - return 0; -} - -static int renew(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) -{ - uint16_t port = PICO_DHCP_CLIENT_PORT; - - /* open and bind to currently acquired address */ - if (cli->socket) - return -1; - - cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup); - if (!cli->socket) { - dbg("DHCPC: error opening socket on renew: %s\n", strerror(pico_err)); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - if (pico_socket_bind(cli->socket, &cli->address, &port) != 0){ - dbg("DHCPC: error binding socket on renew: %s\n", strerror(pico_err)); - pico_socket_close(cli->socket); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - cli->state = DHCPSTATE_RENEWING; - dhclient_send(cli, PICO_DHCP_MSG_REQUEST); - - return 0; -} - -static int reset(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) -{ - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_RESET); - //reset pretty much everything - - if(cli->timer_param_1) - cli->timer_param_1->valid = 0; - if(cli->timer_param_2) - cli->timer_param_2->valid = 0; - if(cli->timer_param_lease) - cli->timer_param_lease->valid = 0; - if(cli->timer_param_retransmit) - cli->timer_param_retransmit->valid = 0; - - pico_socket_close(cli->socket); - pico_ipv4_link_del(cli->device, cli->address); - - //initiate negotiations again - init_cookie(cli); - pico_dhcp_retry(cli); - dhclient_send(cli, PICO_DHCP_MSG_DISCOVER); - - return 0; - -} - -static int retransmit(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len) -{ - pico_dhcp_retry(cli); - - if(cli->state == DHCPSTATE_DISCOVER) - dhclient_send(cli, PICO_DHCP_MSG_DISCOVER); - else if(cli->state == DHCPSTATE_RENEWING) - dhclient_send(cli, PICO_DHCP_MSG_REQUEST); - else - dbg("DHCPC: WARNING: should not get here in state %d!\n", cli->state); - - return 0; - -} - -/********************** - * fsm implementation * - **********************/ - -struct dhcp_action_entry { - uint16_t tcpstate; - int (*offer)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - int (*ack)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - int (*nak)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - int (*timer1)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - int (*timer_lease)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); - int (*timer_retransmit)(struct pico_dhcp_client_cookie *cli, uint8_t *data, int len); -}; - -static struct dhcp_action_entry dhcp_fsm[] = { - /* State offer ack nak timer1 timer_lease timer_retransmit*/ - { DHCPSTATE_DISCOVER, recv_offer, NULL, NULL, NULL, reset, retransmit}, - { DHCPSTATE_OFFER, NULL, NULL, NULL, NULL, reset, NULL}, - { DHCPSTATE_REQUEST, NULL, recv_ack, reset, NULL, reset, retransmit}, - { DHCPSTATE_BOUND, NULL, NULL, reset, renew, reset, NULL}, - { DHCPSTATE_RENEWING, NULL, recv_ack, reset, NULL, reset, retransmit}, -}; - - -static void pico_dhcp_state_machine(int type, struct pico_dhcp_client_cookie* cli, uint8_t* data, int len) -{ - dbg("DHCPC: received incoming event of type %d\n", type); - switch(type){ - case PICO_DHCP_MSG_OFFER: - if(dhcp_fsm[cli->state].offer != NULL) - dhcp_fsm[cli->state].offer(cli, data, len); - break; - case PICO_DHCP_MSG_ACK: - if(dhcp_fsm[cli->state].ack != NULL){ - dhcp_fsm[cli->state].ack(cli, data, len); - } - break; - case PICO_DHCP_MSG_NAK: - if(dhcp_fsm[cli->state].nak!= NULL){ - dhcp_fsm[cli->state].nak(cli, data, len); - } - break; - case PICO_DHCP_EVENT_T1: - if(dhcp_fsm[cli->state].timer1!= NULL){ - dhcp_fsm[cli->state].timer1(cli, NULL, 0); - } - break; - case PICO_DHCP_EVENT_LEASE: - if(dhcp_fsm[cli->state].timer_lease!= NULL){ - dhcp_fsm[cli->state].timer_lease(cli, NULL, 0); - } - break; - case PICO_DHCP_EVENT_RETRANSMIT: - if(dhcp_fsm[cli->state].timer_retransmit!= NULL){ - dhcp_fsm[cli->state].timer_retransmit(cli, NULL, 0); - } - break; - default: - dbg("DHCPC: event not supported yet!!\n"); - break; - } -} - - -/********************* - * utility functions * - *********************/ - -static void pico_dhcp_retry(struct pico_dhcp_client_cookie *cli) -{ - const int MAX_RETRY = 3; - uint32_t new_xid; - if (++cli->attempt > MAX_RETRY) { - cli->start_time = pico_tick; - cli->attempt = 0; - new_xid = pico_rand(); - while(get_cookie_by_xid(new_xid) != NULL){ - new_xid = pico_rand(); - } - cli->xid = new_xid; - cli->state = DHCPSTATE_DISCOVER; - } -} - -static int dhclient_send(struct pico_dhcp_client_cookie *cli, uint8_t msg_type) -{ - uint8_t buf_out[DHCPC_DATAGRAM_SIZE] = {0}; - struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out; - int sent = 0; - int i = 0; - struct pico_ip4 destination; - uint16_t port = PICO_DHCPD_PORT; - if(cli->state == DHCPSTATE_BOUND || cli->state == DHCPSTATE_RENEWING){ - destination.addr = cli->server_id.addr; - }else{ - destination.addr = long_be(0xFFFFFFFF); - } - - if(cli->device->eth == NULL){ - pico_err = PICO_ERR_EOPNOTSUPP; - if(cli->cb != NULL){ - cli->cb(cli, PICO_DHCP_ERROR); - } - return -1; - } - memcpy(dh_out->hwaddr, &cli->device->eth->mac, PICO_HLEN_ETHER); - dh_out->op = PICO_DHCP_OP_REQUEST; - dh_out->htype = PICO_HTYPE_ETHER; - dh_out->hlen = PICO_HLEN_ETHER; - dh_out->xid = cli->xid; - dh_out->secs = (msg_type == PICO_DHCP_MSG_REQUEST)?0:short_be((pico_tick - cli->start_time)/1000); - dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE; - if (cli->state == DHCPSTATE_RENEWING) - dh_out->ciaddr = cli->address.addr; - - /* Option: msg type, len 1 */ - dh_out->options[i++] = PICO_DHCPOPT_MSGTYPE; - dh_out->options[i++] = 1; - dh_out->options[i++] = msg_type; - - if (msg_type == PICO_DHCP_MSG_REQUEST) { - dh_out->options[i++] = PICO_DHCPOPT_REQIP; - dh_out->options[i++] = 4; - dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF000000) >> 24; - dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF0000) >> 16; - dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF00) >> 8; - dh_out->options[i++] = (long_be(cli->address.addr) & 0xFF); - dh_out->options[i++] = PICO_DHCPOPT_SERVERID; - dh_out->options[i++] = 4; - dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF000000) >> 24; - dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF0000) >> 16; - dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF00) >> 8; - dh_out->options[i++] = (long_be(cli->server_id.addr) & 0xFF); - } - - /* Option: req list, len 4 */ - dh_out->options[i++] = PICO_DHCPOPT_PARMLIST; - dh_out->options[i++] = 7; - dh_out->options[i++] = PICO_DHCPOPT_NETMASK; - dh_out->options[i++] = PICO_DHCPOPT_BCAST; - dh_out->options[i++] = PICO_DHCPOPT_TIME; - dh_out->options[i++] = PICO_DHCPOPT_ROUTER; - dh_out->options[i++] = PICO_DHCPOPT_HOSTNAME; - dh_out->options[i++] = PICO_DHCPOPT_RENEWALTIME; - dh_out->options[i++] = PICO_DHCPOPT_REBINDINGTIME; - - /* Option : max message size */ - if( msg_type == PICO_DHCP_MSG_REQUEST || msg_type == PICO_DHCP_MSG_DISCOVER){ - uint16_t dds = DHCPC_DATAGRAM_SIZE; - dh_out->options[i++] = PICO_DHCPOPT_MAXMSGSIZE; - dh_out->options[i++] = 2; - dh_out->options[i++] = (dds & 0xFF00) >> 8; - dh_out->options[i++] = (dds & 0xFF); - } - - - - dh_out->options[i] = PICO_DHCPOPT_END; - sent = pico_socket_sendto(cli->socket, buf_out, DHCPC_DATAGRAM_SIZE, &destination, port); - if (sent < 0) { - dbg("DHCPC: sendto failed: %s\n", strerror(pico_err)); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - } - - - //resend-timer : - if(cli->timer_param_retransmit != NULL) - cli->timer_param_retransmit->valid=0; - - cli->timer_param_retransmit = pico_zalloc(sizeof(struct dhcp_timer_param)); - if(!cli->timer_param_retransmit){ - if(cli->cb != NULL) - pico_err = PICO_ERR_ENOMEM; - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - cli->timer_param_retransmit->valid = 1; - cli->timer_param_retransmit->cli = cli; - cli->timer_param_retransmit->type = PICO_DHCP_EVENT_RETRANSMIT; - pico_timer_add(4000, dhcp_timer_cb, cli->timer_param_retransmit); - - return 0; -} - -//identifies type & does some preprocessing : checking if everything is valid -static int pico_dhcp_verify_and_identify_type(uint8_t* data, int len, struct pico_dhcp_client_cookie *cli) -{ - struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; - uint8_t *nextopt, opt_data[20], opt_type; - int opt_len = 20; - - if (dhdr->xid != cli->xid) - return 0; - - if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr))) - return 0; - - if( dhdr->dhcp_magic != PICO_DHCPD_MAGIC_COOKIE) - return 0; - - opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt); - while (opt_type != PICO_DHCPOPT_END) { - /* parse interesting options here */ - if (opt_type == PICO_DHCPOPT_MSGTYPE) { - return *opt_data; - } - opt_len = 20; - opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt); - } - return 0; - -} - -static int init_cookie(struct pico_dhcp_client_cookie* cli) -{ - uint8_t n = 3; - uint16_t port = PICO_DHCP_CLIENT_PORT; - struct pico_ip4 address, netmask; - - address.addr = long_be(0x00000000); - netmask.addr = long_be(0x00000000); - - cli->state = DHCPSTATE_DISCOVER; - cli->start_time = pico_tick; - cli->attempt = 0; - - cli->socket = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcp_wakeup); - if (!cli->socket) { - dbg("DHCPC: error opening socket: %s\n", strerror(pico_err)); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - if (pico_socket_bind(cli->socket, &address, &port) != 0){ - dbg("DHCPC: error binding socket: %s\n", strerror(pico_err)); - pico_socket_close(cli->socket); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - cli->socket->dev = cli->device; - - if(pico_ipv4_link_add(cli->device, address, netmask) != 0){ - dbg("DHCPC: error adding link: %s\n", strerror(pico_err)); - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - - /* attempt to generate a correct xid 3 times, then fail */ - do { - cli->xid = pico_rand(); - } while (!cli->xid && --n); - if (!cli->xid) { - if(cli->cb != NULL) - cli->cb(cli, PICO_DHCP_ERROR); - return -1; - } - - return 0; -} - -static struct pico_dhcp_client_cookie *get_cookie_by_xid(uint32_t xid) -{ - struct pico_dhcp_client_cookie test = { }, *cookie = NULL; - - if (!xid) - return NULL; - - test.xid = xid; - cookie = pico_tree_findKey(&DHCPCookies, &test); - if (!cookie) - return NULL; - else - return cookie; -} - -void *pico_dhcp_get_identifier(uint32_t xid) -{ - return (void *) get_cookie_by_xid(xid); -} - -static uint32_t get_xid(uint8_t* data) -{ - struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) data; - return dhdr->xid; -} - -#endif
--- a/modules/pico_dhcp_client.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,36 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_DHCP_CLIENT -#define _INCLUDE_PICO_DHCP_CLIENT - - -#include "pico_dhcp_common.h" -#include "pico_addressing.h" -#include "pico_protocol.h" - - -int pico_dhcp_initiate_negotiation(struct pico_device *device, void (*callback)(void* cli, int code), uint32_t *xid); -void pico_dhcp_process_incoming_message(uint8_t *data, int len); -void *pico_dhcp_get_identifier(uint32_t xid); -struct pico_ip4 pico_dhcp_get_address(void *cli); -struct pico_ip4 pico_dhcp_get_gateway(void *cli); -struct pico_ip4 pico_dhcp_get_nameserver(void* cli); - -/* possible codes for the callback */ -#define PICO_DHCP_SUCCESS 0 -#define PICO_DHCP_ERROR 1 -#define PICO_DHCP_RESET 2 - -/* DHCP EVENT TYPE - * these come after the message types, used for the state machine*/ -#define PICO_DHCP_EVENT_T1 9 -#define PICO_DHCP_EVENT_T2 10 -#define PICO_DHCP_EVENT_LEASE 11 -#define PICO_DHCP_EVENT_RETRANSMIT 12 - -#endif
--- a/modules/pico_dhcp_common.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Frederik Van Slycken -*********************************************************************/ - -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_dhcp_common.h" - -#if defined (PICO_SUPPORT_DHCPC) || defined (PICO_SUPPORT_DHCPD) -//this function should only be used after you checked if the options are valid! otherwise it could read from bad memory! -uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt) -{ - uint8_t *p; - uint8_t type; - uint8_t opt_len; - - if (!begin) - p = *nextopt; - else - p = begin; - - type = *p; - *nextopt = ++p; - if ((type == PICO_DHCPOPT_END) || (type == PICO_DHCPOPT_PAD)) { - memset(data, 0, *len); - len = 0; - return type; - } - opt_len = *p; - p++; - if (*len > opt_len) - *len = opt_len; - memcpy(data, p, *len); - *nextopt = p + opt_len; - return type; -} - -int is_options_valid(uint8_t *opt_buffer, int len) -{ - uint8_t *p = opt_buffer; - while (len > 0) { - if (*p == PICO_DHCPOPT_END) - return 1; - else if (*p == PICO_DHCPOPT_PAD) { - p++; - len--; - } else { - uint8_t opt_len; - p++; - len--; - if(len > 0) { - opt_len = *p; - p += opt_len + 1; - len -= opt_len; - }else - return 0; - } - } - return 0; -} - -#endif
--- a/modules/pico_dhcp_common.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_DHCP_COMMON -#define _INCLUDE_PICO_DHCP_COMMON - - -#include <stdint.h> - -//minimum size is 576, cfr RFC -#define DHCPC_DATAGRAM_SIZE 576 -#define DHCPD_DATAGRAM_SIZE 576 - - -#define PICO_DHCPD_PORT (short_be(67)) -#define PICO_DHCP_CLIENT_PORT (short_be(68)) - -#define PICO_DHCP_OP_REQUEST 1 -#define PICO_DHCP_OP_REPLY 2 - -#define PICO_HTYPE_ETHER 1 -#define PICO_HLEN_ETHER 6 - -#define PICO_DHCPD_MAGIC_COOKIE (long_be(0x63825363)) - -/* DHCP OPTIONS, RFC2132 */ -#define PICO_DHCPOPT_PAD 0x00 -#define PICO_DHCPOPT_NETMASK 0x01 -#define PICO_DHCPOPT_TIME 0x02 -#define PICO_DHCPOPT_ROUTER 0x03 -#define PICO_DHCPOPT_DNS 0x06 -#define PICO_DHCPOPT_HOSTNAME 0x0c -#define PICO_DHCPOPT_DOMAINNAME 0x0f -#define PICO_DHCPOPT_MTU 0x1a -#define PICO_DHCPOPT_BCAST 0x1c -#define PICO_DHCPOPT_NETBIOSNS 0x2c -#define PICO_DHCPOPT_NETBIOSSCOPE 0x2f - -#define PICO_DHCPOPT_REQIP 0x32 -#define PICO_DHCPOPT_LEASETIME 0x33 -#define PICO_DHCPOPT_OPTIONOVERLOAD 0x34 -#define PICO_DHCPOPT_MSGTYPE 0x35 -#define PICO_DHCPOPT_SERVERID 0x36 -#define PICO_DHCPOPT_PARMLIST 0x37 -#define PICO_DHCPOPT_MAXMSGSIZE 0x39 -#define PICO_DHCPOPT_RENEWALTIME 0x3a -#define PICO_DHCPOPT_REBINDINGTIME 0x3b -#define PICO_DHCPOPT_DOMAINSEARCH 0x77 -#define PICO_DHCPOPT_STATICROUTE 0x79 -#define PICO_DHCPOPT_END 0xFF - -/* DHCP MESSAGE TYPE */ -#define PICO_DHCP_MSG_DISCOVER 1 -#define PICO_DHCP_MSG_OFFER 2 -#define PICO_DHCP_MSG_REQUEST 3 -#define PICO_DHCP_MSG_DECLINE 4 -#define PICO_DHCP_MSG_ACK 5 -#define PICO_DHCP_MSG_NAK 6 -#define PICO_DHCP_MSG_RELEASE 7 -#define PICO_DHCP_MSG_INFORM 8 - - -enum dhcp_negotiation_state { - DHCPSTATE_DISCOVER = 0, - DHCPSTATE_OFFER, - DHCPSTATE_REQUEST, - DHCPSTATE_BOUND, - DHCPSTATE_RENEWING -}; - - -struct __attribute__((packed)) pico_dhcphdr -{ - uint8_t op; - uint8_t htype; - uint8_t hlen; - uint8_t hops; //zero - uint32_t xid; //store this in the request - uint16_t secs; // ignore - uint16_t flags; - uint32_t ciaddr; // client address - if asking for renewal - uint32_t yiaddr; // your address (client) - uint32_t siaddr; // dhcp offered address - uint32_t giaddr; // relay agent, bootp. - uint8_t hwaddr[6]; - uint8_t hwaddr_padding[10]; - char hostname[64]; - char bootp_filename[128]; - uint32_t dhcp_magic; - uint8_t options[0]; -}; - - -//common functions for client and server - -uint8_t dhcp_get_next_option(uint8_t *begin, uint8_t *data, int *len, uint8_t **nextopt); -int is_options_valid(uint8_t *opt_buffer, int len); -#endif
--- a/modules/pico_dhcp_server.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,290 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - - -Authors: Frederik Van Slycken, Kristof Roelants -*********************************************************************/ - -#ifdef PICO_SUPPORT_DHCPD - -#include "pico_dhcp_server.h" -#include "pico_stack.h" -#include "pico_config.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_arp.h" -#include <stdlib.h> - -# define dhcpd_dbg(...) do{}while(0) -//# define dhcpd_dbg dbg - -#define dhcpd_make_offer(x) dhcpd_make_reply(x, PICO_DHCP_MSG_OFFER) -#define dhcpd_make_ack(x) dhcpd_make_reply(x, PICO_DHCP_MSG_ACK) -#define ip_inrange(x) ((long_be(x) >= long_be(dn->settings->pool_start)) && (long_be(x) <= long_be(dn->settings->pool_end))) - -static int dhcp_settings_cmp(void *ka, void *kb) -{ - struct pico_dhcpd_settings *a = ka, *b = kb; - if (a->dev < b->dev) - return -1; - else if (a->dev > b->dev) - return 1; - else - return 0; -} -PICO_TREE_DECLARE(DHCPSettings, dhcp_settings_cmp); - -static int dhcp_negotiations_cmp(void *ka, void *kb) -{ - struct pico_dhcp_negotiation *a = ka, *b = kb; - if (a->xid < b->xid) - return -1; - else if (a->xid > b->xid) - return 1; - else - return 0; -} -PICO_TREE_DECLARE(DHCPNegotiations, dhcp_negotiations_cmp); - -static struct pico_dhcp_negotiation *get_negotiation_by_xid(uint32_t xid) -{ - struct pico_dhcp_negotiation test = { }, *neg = NULL; - - test.xid = xid; - neg = pico_tree_findKey(&DHCPNegotiations, &test); - if (!neg) - return NULL; - else - return neg; -} - -static void dhcpd_make_reply(struct pico_dhcp_negotiation *dn, uint8_t reply_type) -{ - uint8_t buf_out[DHCPD_DATAGRAM_SIZE] = {0}; - struct pico_dhcphdr *dh_out = (struct pico_dhcphdr *) buf_out; - struct pico_ip4 destination = { }; - uint32_t bcast = dn->settings->my_ip.addr | ~(dn->settings->netmask.addr); - uint32_t dns_server = OPENDNS; - uint16_t port = PICO_DHCP_CLIENT_PORT; - int sent = 0; - - memcpy(dh_out->hwaddr, dn->eth.addr, PICO_HLEN_ETHER); - dh_out->op = PICO_DHCP_OP_REPLY; - dh_out->htype = PICO_HTYPE_ETHER; - dh_out->hlen = PICO_HLEN_ETHER; - dh_out->xid = dn->xid; - dh_out->yiaddr = dn->ipv4.addr; - dh_out->siaddr = dn->settings->my_ip.addr; - dh_out->dhcp_magic = PICO_DHCPD_MAGIC_COOKIE; - - /* Option: msg type, len 1 */ - dh_out->options[0] = PICO_DHCPOPT_MSGTYPE; - dh_out->options[1] = 1; - dh_out->options[2] = reply_type; - - /* Option: server id, len 4 */ - dh_out->options[3] = PICO_DHCPOPT_SERVERID; - dh_out->options[4] = 4; - memcpy(dh_out->options + 5, &dn->settings->my_ip.addr, 4); - - /* Option: Lease time, len 4 */ - dh_out->options[9] = PICO_DHCPOPT_LEASETIME; - dh_out->options[10] = 4; - memcpy(dh_out->options + 11, &dn->settings->lease_time, 4); - - /* Option: Netmask, len 4 */ - dh_out->options[15] = PICO_DHCPOPT_NETMASK; - dh_out->options[16] = 4; - memcpy(dh_out->options + 17, &dn->settings->netmask.addr, 4); - - /* Option: Router, len 4 */ - dh_out->options[21] = PICO_DHCPOPT_ROUTER; - dh_out->options[22] = 4; - memcpy(dh_out->options + 23, &dn->settings->my_ip.addr, 4); - - /* Option: Broadcast, len 4 */ - dh_out->options[27] = PICO_DHCPOPT_BCAST; - dh_out->options[28] = 4; - memcpy(dh_out->options + 29, &bcast, 4); - - /* Option: DNS, len 4 */ - dh_out->options[33] = PICO_DHCPOPT_DNS; - dh_out->options[34] = 4; - memcpy(dh_out->options + 35, &dns_server, 4); - - dh_out->options[40] = PICO_DHCPOPT_END; - - destination.addr = dh_out->yiaddr; - - sent = pico_socket_sendto(dn->settings->s, buf_out, DHCPD_DATAGRAM_SIZE, &destination, port); - if (sent < 0) { - dhcpd_dbg("DHCPD: sendto failed with code %d!\n", pico_err); - } -} - -static void dhcp_recv(struct pico_socket *s, uint8_t *buffer, int len) -{ - struct pico_dhcphdr *dhdr = (struct pico_dhcphdr *) buffer; - struct pico_dhcp_negotiation *dn = get_negotiation_by_xid(dhdr->xid); - struct pico_ip4* ipv4 = NULL; - struct pico_dhcpd_settings test, *settings = NULL; - uint8_t *nextopt, opt_data[20], opt_type; - int opt_len = 20; - - if (!is_options_valid(dhdr->options, len - sizeof(struct pico_dhcphdr))) { - dhcpd_dbg("DHCPD WARNING: invalid options in dhcp message\n"); - return; - } - - if (!dn) { - dn = pico_zalloc(sizeof(struct pico_dhcp_negotiation)); - if (!dn) { - pico_err = PICO_ERR_ENOMEM; - return; - } - dn->xid = dhdr->xid; - dn->state = DHCPSTATE_DISCOVER; - memcpy(dn->eth.addr, dhdr->hwaddr, PICO_HLEN_ETHER); - - test.dev = pico_ipv4_link_find(&s->local_addr.ip4); - settings = pico_tree_findKey(&DHCPSettings, &test); - if (settings) { - dn->settings = settings; - } else { - dhcpd_dbg("DHCPD WARNING: received DHCP message on unconfigured link %s\n", test.dev->name); - pico_free(dn); - return; - } - - ipv4 = pico_arp_reverse_lookup(&dn->eth); - if (!ipv4) { - dn->ipv4.addr = settings->pool_next; - pico_arp_create_entry(dn->eth.addr, dn->ipv4, settings->dev); - settings->pool_next = long_be(long_be(settings->pool_next) + 1); - } else { - dn->ipv4.addr = ipv4->addr; - } - - if (pico_tree_insert(&DHCPNegotiations, dn)) { - dhcpd_dbg("DHCPD WARNING: tried creating new negotation for existing xid %u\n", dn->xid); - pico_free(dn); - return; /* Element key already exists */ - } - } - - if (!ip_inrange(dn->ipv4.addr)) - return; - - opt_type = dhcp_get_next_option(dhdr->options, opt_data, &opt_len, &nextopt); - while (opt_type != PICO_DHCPOPT_END) { - /* parse interesting options here */ - if (opt_type == PICO_DHCPOPT_MSGTYPE) { - /* server simple state machine */ - uint8_t msg_type = opt_data[0]; - if (msg_type == PICO_DHCP_MSG_DISCOVER) { - dhcpd_make_offer(dn); - dn->state = DHCPSTATE_OFFER; - return; - } else if ((msg_type == PICO_DHCP_MSG_REQUEST)&&( dn->state == DHCPSTATE_OFFER)) { - dhcpd_make_ack(dn); - dn->state = DHCPSTATE_BOUND; - return; - } - } - opt_len = 20; - opt_type = dhcp_get_next_option(NULL, opt_data, &opt_len, &nextopt); - } -} - -static void pico_dhcpd_wakeup(uint16_t ev, struct pico_socket *s) -{ - uint8_t buf[DHCPD_DATAGRAM_SIZE] = { }; - int r = 0; - uint32_t peer = 0; - uint16_t port = 0; - - dhcpd_dbg("DHCPD: called dhcpd_wakeup\n"); - if (ev == PICO_SOCK_EV_RD) { - do { - r = pico_socket_recvfrom(s, buf, DHCPD_DATAGRAM_SIZE, &peer, &port); - if (r > 0 && port == PICO_DHCP_CLIENT_PORT) { - dhcp_recv(s, buf, r); - } - } while(r>0); - } -} - -int pico_dhcp_server_initiate(struct pico_dhcpd_settings *setting) -{ - struct pico_dhcpd_settings *settings = NULL; - struct pico_ipv4_link *link = NULL; - uint16_t port = PICO_DHCPD_PORT; - - if (!setting) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!setting->my_ip.addr) { - pico_err = PICO_ERR_EINVAL; - dhcpd_dbg("DHCPD: IP address of interface was not supplied\n"); - return -1; - } - - link = pico_ipv4_link_get(&setting->my_ip); - if (!link) { - pico_err = PICO_ERR_EINVAL; - dhcpd_dbg("DHCPD: no link with IP %X found\n", setting->my_ip.addr); - return -1; - } - - settings = pico_zalloc(sizeof(struct pico_dhcpd_settings)); - if (!settings) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - memcpy(settings, setting, sizeof(struct pico_dhcpd_settings)); - - settings->dev = link->dev; - dhcpd_dbg("DHCPD: configuring DHCP server for link %s\n", link->dev->name); - settings->my_ip.addr = link->address.addr; - dhcpd_dbg("DHCPD: using server addr %X\n", long_be(settings->my_ip.addr)); - settings->netmask.addr = link->netmask.addr; - dhcpd_dbg("DHCPD: using netmask %X\n", long_be(settings->netmask.addr)); - - /* default values if not provided */ - if (settings->pool_start == 0) - settings->pool_start = (settings->my_ip.addr & settings->netmask.addr) | POOL_START; - dhcpd_dbg("DHCPD: using pool_start %X\n", long_be(settings->pool_start)); - if (settings->pool_end == 0) - settings->pool_end = (settings->my_ip.addr & settings->netmask.addr) | POOL_END; - dhcpd_dbg("DHCPD: using pool_end %x\n", long_be(settings->pool_end)); - if (settings->lease_time == 0) - settings->lease_time = LEASE_TIME; - dhcpd_dbg("DHCPD: using lease time %x\n", long_be(settings->lease_time)); - settings->pool_next = settings->pool_start; - - settings->s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dhcpd_wakeup); - if (!settings->s) { - dhcpd_dbg("DHCP: could not open client socket\n"); - pico_free(settings); - return -1; - } - if (pico_socket_bind(settings->s, &settings->my_ip, &port) != 0) { - dhcpd_dbg("DHCP: could not bind server socket (%s)\n", strerror(pico_err)); - pico_free(settings); - return -1; - } - - if (pico_tree_insert(&DHCPSettings, settings)) { - dhcpd_dbg("DHCPD ERROR: link %s already configured\n", link->dev->name); - pico_err = PICO_ERR_EINVAL; - pico_free(settings); - return -1; /* Element key already exists */ - } - dhcpd_dbg("DHCPD: configured DHCP server for link %s\n", link->dev->name); - - return 0; -} -#endif /* PICO_SUPPORT_DHCP */
--- a/modules/pico_dhcp_server.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_DHCP_SERVER -#define _INCLUDE_PICO_DHCP_SERVER - -#include "pico_dhcp_common.h" -#include "pico_addressing.h" - -/* default configuration */ -#define OPENDNS (long_be(0xd043dede)) /* OpenDNS DNS server 208.67.222.222 */ -#define POOL_START long_be(0x00000064) -#define POOL_END long_be(0x000000fe) -#define LEASE_TIME long_be(0x00000078) - -struct pico_dhcpd_settings -{ - struct pico_device *dev; - struct pico_socket *s; - struct pico_ip4 my_ip; - struct pico_ip4 netmask; - uint32_t pool_start; - uint32_t pool_next; - uint32_t pool_end; - uint32_t lease_time; - uint8_t flags; /* unused atm */ -}; - -struct pico_dhcp_negotiation { - struct pico_dhcpd_settings *settings; - struct pico_ip4 ipv4; - struct pico_eth eth; - enum dhcp_negotiation_state state; - uint32_t xid; - uint32_t assigned_address; -}; - -/* required settings field: IP address of the interface to serve, only IPs of this network will be served. */ -int pico_dhcp_server_initiate(struct pico_dhcpd_settings *setting); - -#endif /* _INCLUDE_PICO_DHCP_SERVER */
--- a/modules/pico_dns_client.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,767 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Kristof Roelants -*********************************************************************/ -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_dns_client.h" -#include "pico_tree.h" - -#ifdef PICO_SUPPORT_DNS_CLIENT - -#define dns_dbg(...) do{}while(0) -//#define dns_dbg dbg - -/* DNS response length */ -#define PICO_DNS_MAX_RESPONSE_LEN 256 - -/* DNS client retransmission time (msec) + frequency */ -#define PICO_DNS_CLIENT_RETRANS 4000 -#define PICO_DNS_CLIENT_MAX_RETRANS 3 - -/* Default nameservers */ -#define PICO_DNS_NS_GOOGLE "8.8.8.8" - -/* Nameserver port */ -#define PICO_DNS_NS_PORT 53 - -/* FLAG values */ -#define PICO_DNS_QR_QUERY 0 -#define PICO_DNS_QR_RESPONSE 1 -#define PICO_DNS_OPCODE_QUERY 0 -#define PICO_DNS_OPCODE_IQUERY 1 -#define PICO_DNS_OPCODE_STATUS 2 -#define PICO_DNS_AA_NO_AUTHORITY 0 -#define PICO_DNS_AA_IS_AUTHORITY 1 -#define PICO_DNS_TC_NO_TRUNCATION 0 -#define PICO_DNS_TC_IS_TRUNCATED 1 -#define PICO_DNS_RD_NO_DESIRE 0 -#define PICO_DNS_RD_IS_DESIRED 1 -#define PICO_DNS_RA_NO_SUPPORT 0 -#define PICO_DNS_RA_IS_SUPPORTED 1 -#define PICO_DNS_RCODE_NO_ERROR 0 -#define PICO_DNS_RCODE_EFORMAT 1 -#define PICO_DNS_RCODE_ESERVER 2 -#define PICO_DNS_RCODE_ENAME 3 -#define PICO_DNS_RCODE_ENOIMP 4 -#define PICO_DNS_RCODE_EREFUSED 5 - -/* QTYPE values */ -#define PICO_DNS_TYPE_A 1 -#define PICO_DNS_TYPE_PTR 12 - -/* QCLASS values */ -#define PICO_DNS_CLASS_IN 1 - -/* Compression values */ -#define PICO_DNS_LABEL 0 -#define PICO_DNS_POINTER 3 - -/* TTL values */ -#define PICO_DNS_MAX_TTL 604800 /* one week */ - -/* Header flags */ -#define FLAG_QR(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 15)) | (x << 15)) -#define FLAG_OPCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF << 11)) | (x << 11)) -#define FLAG_AA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 10)) | (x << 10)) -#define FLAG_TC(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 9)) | (x << 9)) -#define FLAG_RD(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 8)) | (x << 8)) -#define FLAG_RA(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x1 << 7)) | (x << 7)) -#define FLAG_Z(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0x7 << 4)) | (x << 4)) -#define FLAG_RCODE(hdr, x) ((hdr)->flags = ((hdr)->flags & ~(0xF)) | x) - -#define GET_FLAG_QR(hdr) ((((hdr)->flags) & (1 << 15)) != 0) -#define GET_FLAG_OPCODE(hdr) ((((hdr)->flags) & (0xF << 11)) >> 11) -#define GET_FLAG_AA(hdr) ((((hdr)->flags) & (1 << 10)) != 0) -#define GET_FLAG_TC(hdr) ((((hdr)->flags) & (1 << 9)) != 0) -#define GET_FLAG_RD(hdr) ((((hdr)->flags) & (1 << 8)) != 0) -#define GET_FLAG_RA(hdr) ((((hdr)->flags) & (1 << 7)) != 0) -#define GET_FLAG_Z(hdr) ((((hdr)->flags) & (0x7 << 4)) >> 4) -#define GET_FLAG_RCODE(hdr) (((hdr)->flags) & (0x0F)) - -/* RFC 1025 section 4. MESSAGES */ -struct __attribute__((packed)) dns_message_hdr -{ - uint16_t id; - uint16_t flags; - uint16_t qdcount; - uint16_t ancount; - uint16_t nscount; - uint16_t arcount; -}; - -struct __attribute__((packed)) dns_query_suffix -{ - /* NAME - domain name to which this resource record pertains */ - uint16_t qtype; - uint16_t qclass; -}; - -struct __attribute__((packed)) dns_answer_suffix -{ - /* NAME - domain name to which this resource record pertains */ - uint16_t qtype; - uint16_t qclass; - uint32_t ttl; - uint16_t rdlength; - /* RDATA - variable length string of octets that describes the resource */ -}; - -struct pico_dns_ns -{ - struct pico_ip4 ns; /* Nameserver */ -}; - -static int dns_ns_cmp(void *ka, void *kb) -{ - struct pico_dns_ns *a = ka, *b = kb; - if (a->ns.addr < b->ns.addr) - return -1; - else if (a->ns.addr > b->ns.addr) - return 1; - else - return 0; -} - -PICO_TREE_DECLARE(NSTable,dns_ns_cmp); - -int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag) -{ - struct pico_dns_ns test, *key = NULL; - - if (!ns) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (flag) - { - case PICO_DNS_NS_ADD: - key = pico_zalloc(sizeof(struct pico_dns_ns)); - if (!key) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - key->ns = *ns; - - if(pico_tree_insert(&NSTable,key)){ - dns_dbg("DNS WARNING: nameserver %08X already added\n",ns->addr); - pico_err = PICO_ERR_EINVAL; - pico_free(key); - return -1; /* Element key already exists */ - } - dns_dbg("DNS: nameserver %08X added\n", ns->addr); - /* If default NS found, remove it */ - pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &test.ns.addr); - if (ns->addr != test.ns.addr) { - - key = pico_tree_findKey(&NSTable,&test); - if (key) { - if(pico_tree_delete(&NSTable,key)) { - dns_dbg("DNS: default nameserver %08X removed\n", test.ns.addr); - pico_free(key); - } else { - pico_err = PICO_ERR_EAGAIN; - return -1; - } - } - } - break; - - case PICO_DNS_NS_DEL: - test.ns = *ns; - - key = pico_tree_findKey(&NSTable,&test); - if (!key) { - dns_dbg("DNS WARNING: nameserver %08X not found\n", ns->addr); - pico_err = PICO_ERR_EINVAL; - return -1; - } - /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ - - if(pico_tree_delete(&NSTable,key)) { - dns_dbg("DNS: nameserver %08X removed\n",key->ns.addr); - pico_free(key); - } else { - pico_err = PICO_ERR_EAGAIN; - return -1; - } - /* If no NS left, add default NS */ - if(pico_tree_first(&NSTable) == NULL){ - dns_dbg("DNS: add default nameserver\n"); - return pico_dns_client_init(); - } - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - return 0; -} - -int pico_dns_client_init() -{ - struct pico_ip4 default_ns; - if (pico_string_to_ipv4(PICO_DNS_NS_GOOGLE, &default_ns.addr) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - return pico_dns_client_nameserver(&default_ns, PICO_DNS_NS_ADD); -} - -struct pico_dns_key -{ - char *q_hdr; - uint16_t len; - uint16_t id; - uint16_t qtype; - uint16_t qclass; - uint8_t retrans; - struct pico_dns_ns q_ns; - struct pico_socket *s; - void (*callback)(char *, void *); - void *arg; -}; - -static int dns_cmp(void *ka, void *kb) -{ - struct pico_dns_key *a = ka,*b = kb; - if (a->id < b->id) - return -1; - else if (a->id > b->id) - return 1; - else - return 0; -} - -PICO_TREE_DECLARE(DNSTable,dns_cmp); - -static int pico_dns_client_strlen(const char *url) -{ - uint16_t len = 0; - int p; - - if (!url) - return -1; - - while ((p = *url++) != 0) { - len++; - } - return len; -} - -/* Replace '.' by the label length */ -static int pico_dns_client_label(char *ptr) -{ - char *l; - uint8_t lbl_len = 0; - int p; - - if (!ptr) - return -1; - - l = ptr++; - while ((p = *ptr++) != 0){ - if (p == '.') { - *l = lbl_len; - l = ptr - 1; - lbl_len = 0; - } else { - lbl_len++; - } - } - *l = lbl_len; - return 0; -} - -/* Replace the label length by '.' */ -static int pico_dns_client_reverse_label(char *ptr) -{ - char *l; - int p; - - if(!ptr) - return -1; - - l = ptr; - while ((p = *ptr++) != 0){ - ptr += p; - *l = '.'; - l = ptr; - } - return 0; -} - -/* Seek the end of a string */ -static char *pico_dns_client_seek(char *ptr) -{ - int p; - - if (!ptr) - return NULL; - - while ((p = *ptr++) != 0); - - return ptr++; -} - -static inline void pico_dns_client_construct_hdr(struct dns_message_hdr *hdr, uint16_t id) -{ - hdr->id = short_be(id); - FLAG_QR(hdr, PICO_DNS_QR_QUERY); - FLAG_OPCODE(hdr, PICO_DNS_OPCODE_QUERY); - FLAG_AA(hdr, PICO_DNS_AA_NO_AUTHORITY); - FLAG_TC(hdr, PICO_DNS_TC_NO_TRUNCATION); - FLAG_RD(hdr, PICO_DNS_RD_IS_DESIRED); - FLAG_RA(hdr, PICO_DNS_RA_NO_SUPPORT); - FLAG_Z(hdr, 0); - FLAG_RCODE(hdr, PICO_DNS_RCODE_NO_ERROR); - hdr->flags = short_be(hdr->flags); - hdr->qdcount = short_be(1); - hdr->ancount = short_be(0); - hdr->nscount = short_be(0); - hdr->arcount = short_be(0); -} - -static inline void pico_dns_client_hdr_ntoh(struct dns_message_hdr *hdr) -{ - hdr->id = short_be(hdr->id); - hdr->flags = short_be(hdr->flags); - hdr->qdcount = short_be(hdr->qdcount); - hdr->ancount = short_be(hdr->ancount); - hdr->nscount = short_be(hdr->nscount); - hdr->arcount = short_be(hdr->arcount); -} - - -static int pico_dns_client_mirror(char *ptr) -{ - unsigned char buf[4] = {0}; - char *m; - int cnt = 0; - int p, i; - - if (!ptr) - return -1; - - m = ptr; - while ((p = *ptr++) != 0) - { - if (pico_is_digit(p)) { - buf[cnt] = (10 * buf[cnt]) + (p - '0'); - } else if (p == '.') { - cnt++; - } else { - return -1; - } - } - - /* Handle short notation */ - if(cnt == 1){ - buf[3] = buf[1]; - buf[1] = 0; - buf[2] = 0; - }else if (cnt == 2){ - buf[3] = buf[2]; - buf[2] = 0; - }else if(cnt != 3){ - /* String could not be parsed, return error */ - return -1; - } - - ptr = m; - for(i = 3; i >= 0; i--) - { - if(buf[i] > 99){ - *ptr++ = '0' + (buf[i] / 100); - *ptr++ = '0' + ((buf[i] % 100) / 10); - *ptr++ = '0' + ((buf[i] % 100) % 10); - }else if(buf[i] > 9){ - *ptr++ = '0' + (buf[i] / 10); - *ptr++ = '0' + (buf[i] % 10); - }else{ - *ptr++ = '0' + buf[i]; - } - if(i > 0) - *ptr++ = '.'; - } - - return 0; -} - -static struct pico_dns_key *pico_dns_client_idcheck(uint16_t id) -{ - struct pico_dns_key test; - - test.id = id; - return pico_tree_findKey(&DNSTable,&test); -} - -static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s); - -static int pico_dns_client_send(struct pico_dns_key *key) -{ - struct pico_socket *s; - int w = 0; - - dns_dbg("DNS: sending query to %08X\n", key->q_ns.ns.addr); - s = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_UDP, &pico_dns_client_callback); - if (!s) - return -1; - key->s = s; - if (pico_socket_connect(s, &key->q_ns.ns, short_be(PICO_DNS_NS_PORT)) != 0) - return -1; - w = pico_socket_send(s, key->q_hdr, key->len); - if (w <= 0) - return -1; - - return 0; -} - -static void pico_dns_client_retransmission(unsigned long now, void *arg) -{ - struct pico_dns_key *key = (struct pico_dns_key *)arg; - struct pico_dns_ns *q_ns = NULL; - - if (!key->retrans) { - dns_dbg("DNS: no retransmission!\n"); - pico_free(key->q_hdr); - - if(pico_tree_delete(&DNSTable,key)) - pico_free(key); - } - else if (key->retrans <= PICO_DNS_CLIENT_MAX_RETRANS) { - key->retrans++; - dns_dbg("DNS: retransmission! (%u attempts)\n", key->retrans); - // ugly hack - q_ns = pico_tree_next(pico_tree_findNode(&NSTable,&key->q_ns))->keyValue; - if (q_ns) - key->q_ns = *q_ns; - else - key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); - pico_dns_client_send(key); - pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); - } else { - dns_dbg("DNS ERROR: no reply from nameservers! (%u attempts)\n", key->retrans); - pico_socket_close(key->s); - pico_err = PICO_ERR_EIO; - key->callback(NULL, key->arg); - pico_free(key->q_hdr); - /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ - - if(pico_tree_delete(&DNSTable,key)) - pico_free(key); - } -} - -static void pico_dns_client_callback(uint16_t ev, struct pico_socket *s) -{ - char *q_qname, *q_suf, *a_hdr, *a_qname, *a_suf, *a_rdata; - struct dns_message_hdr *hdr; - struct dns_query_suffix query_suf; - struct dns_answer_suffix answer_suf; - struct pico_dns_key test, *key; - char *answer; - char dns_answer[PICO_DNS_MAX_RESPONSE_LEN] = {0}; - uint8_t valid_suffix = 0; - uint16_t compression = 0; - int i = 0, r = 0; - - if (ev & PICO_SOCK_EV_RD) { - r = pico_socket_read(s, dns_answer, PICO_DNS_MAX_RESPONSE_LEN); - pico_socket_close(s); - if (r == PICO_DNS_MAX_RESPONSE_LEN || r < (int)sizeof(struct dns_message_hdr)) { - dns_dbg("DNS ERROR: received incorrect number(%d) of bytes\n", r); - return; - } - - /* Check header validity */ - a_hdr = dns_answer; - hdr = (struct dns_message_hdr *) a_hdr; - pico_dns_client_hdr_ntoh(hdr); - if (GET_FLAG_QR(hdr) != PICO_DNS_QR_RESPONSE || GET_FLAG_OPCODE(hdr) != PICO_DNS_OPCODE_QUERY - || GET_FLAG_TC(hdr) == PICO_DNS_TC_IS_TRUNCATED || GET_FLAG_RCODE(hdr) != PICO_DNS_RCODE_NO_ERROR) { - dns_dbg("DNS ERROR: OPCODE %d | TC %d | RCODE %d\n", GET_FLAG_OPCODE(hdr), GET_FLAG_TC(hdr), GET_FLAG_RCODE(hdr)); - return; - } - - if (hdr->ancount < 1 || r < (int)(sizeof(struct dns_message_hdr) + hdr->qdcount * sizeof(struct dns_query_suffix) - + hdr->ancount * sizeof(struct dns_answer_suffix))) { - dns_dbg("DNS ERROR: ancount < 1 OR received number(%d) of bytes too low\n", r); - return; - } - - /* Find DNS key */ - test.id = hdr->id; - - key = pico_tree_findKey(&DNSTable,&test); - if (!key) { - dns_dbg("DNS WARNING: key with id %u not found\n", hdr->id); - return; - } - key->retrans = 0; - - /* Check query suffix validity */ - q_qname = a_hdr + sizeof(struct dns_message_hdr); - q_suf = pico_dns_client_seek(q_qname); - query_suf = *(struct dns_query_suffix *) q_suf; - if (short_be(query_suf.qtype) != key->qtype || short_be(query_suf.qclass) != key->qclass) { - dns_dbg("DNS ERROR: received qtype (%u) or qclass (%u) incorrect\n", short_be(query_suf.qtype), short_be(query_suf.qclass)); - return; - } - - /* Seek answer suffix */ - a_qname = q_suf + sizeof(struct dns_query_suffix); - a_suf = a_qname; - while(i++ < hdr->ancount) { - uint16_t comp_h = short_from(a_suf); - compression = short_be(comp_h); - switch (compression >> 14) - { - case PICO_DNS_POINTER: - while (compression >> 14 == PICO_DNS_POINTER) { - dns_dbg("DNS: pointer\n"); - a_suf += sizeof(uint16_t); - comp_h = short_from(a_suf); - compression = short_be(comp_h); - } - break; - - case PICO_DNS_LABEL: - dns_dbg("DNS: label\n"); - a_suf = pico_dns_client_seek(a_qname); - break; - - default: - dns_dbg("DNS ERROR: incorrect compression (%u) value\n", compression); - return; - } - - /* Check answer suffix validity */ - answer_suf = *(struct dns_answer_suffix *)a_suf; - if (short_be(answer_suf.qtype) != key->qtype || short_be(answer_suf.qclass) != key->qclass) { - dns_dbg("DNS WARNING: received qtype (%u) or qclass (%u) incorrect\n", short_be(answer_suf.qtype), short_be(answer_suf.qclass)); - a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); - continue; - } - - if (short_be(answer_suf.ttl) > PICO_DNS_MAX_TTL) { - dns_dbg("DNS WARNING: received TTL (%u) > MAX (%u)\n", short_be(answer_suf.ttl), PICO_DNS_MAX_TTL); - a_suf = a_suf + sizeof(struct dns_answer_suffix) + short_be(answer_suf.rdlength); - continue; - } - - valid_suffix = 1; - break; - } - - if (!valid_suffix) { - dns_dbg("DNS ERROR: invalid dns answer suffix\n"); - return; - } - - a_rdata = a_suf + sizeof(struct dns_answer_suffix); - if (key->qtype == PICO_DNS_TYPE_A) { - uint32_t ip_h = long_from(a_rdata); - dns_dbg("DNS: length %u | ip %08X\n", short_be(answer_suf.rdlength), long_be(ip_h)); - answer = pico_zalloc(16); - pico_ipv4_to_string(answer, ip_h); - key->callback(answer, key->arg); - } else if (key->qtype == PICO_DNS_TYPE_PTR) { - pico_dns_client_reverse_label((char *) a_rdata); - dns_dbg("DNS: length %u | name %s\n", short_be(answer_suf.rdlength), (char *)a_rdata + 1); - answer = pico_zalloc(answer_suf.rdlength - 1); - memcpy(answer, (char *)a_rdata + 1, short_be(answer_suf.rdlength) - 1); - key->callback(answer, key->arg); - } else { - dns_dbg("DNS ERROR: incorrect qtype (%u)\n", key->qtype); - return; - } - } - - if (ev == PICO_SOCK_EV_ERR) { - dns_dbg("DNS: socket error received\n"); - } -} - -int pico_dns_client_getaddr(const char *url, void (*callback)(char *, void *), void *arg) -{ - char *q_hdr, *q_qname, *q_suf; - struct dns_message_hdr *hdr; - struct dns_query_suffix query_suf; - struct pico_dns_key *key; - uint16_t url_len = 0; - uint16_t id = 0; - - if (!url || !callback) { - dns_dbg("DNS ERROR: NULL parameters\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - url_len = pico_dns_client_strlen(url); - /* 2 extra bytes for url_len to account for 2 extra label length octets */ - q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix)); - if (!q_hdr) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - q_qname = q_hdr + sizeof(struct dns_message_hdr); - q_suf = q_qname + (1 + url_len + 1); - - /* Construct query header */ - hdr = (struct dns_message_hdr *) q_hdr; - do { - id = (uint16_t) (pico_rand() & 0xFFFFU); - dns_dbg("DNS: generated id %u\n", id); - } while (pico_dns_client_idcheck(id)); - pico_dns_client_construct_hdr(hdr, id); - /* Add and manipulate domain name */ - memcpy(q_qname + 1, url, url_len + 1); - pico_dns_client_label(q_qname); - /* Add type and class of query */ - query_suf.qtype = short_be(PICO_DNS_TYPE_A); - query_suf.qclass = short_be(PICO_DNS_CLASS_IN); - memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix)); - /* Create RB entry */ - key = pico_zalloc(sizeof(struct pico_dns_key)); - if (!key) { - pico_free(q_hdr); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - key->q_hdr = q_hdr; - key->len = sizeof(struct dns_message_hdr) + (1 + url_len + 1) + sizeof(struct dns_query_suffix); - key->id = id; - key->qtype = PICO_DNS_TYPE_A; - key->qclass = PICO_DNS_CLASS_IN; - key->retrans = 1; - - key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); - key->s = NULL; - key->callback = callback; - key->arg = arg; - /* Send query */ - if (pico_dns_client_send(key) < 0) { - pico_free(q_hdr); - if (key->s) - pico_socket_close(key->s); - pico_free(key); - pico_err = PICO_ERR_EAGAIN; - return -1; - } - /* Insert RB entry */ - - if(pico_tree_insert(&DNSTable,key)) { - pico_free(q_hdr); - pico_free(key); - pico_err = PICO_ERR_EAGAIN; - return -1; /* Element key already exists */ - } - - pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); - return 0; -} - -int pico_dns_client_getname(const char *ip, void (*callback)(char *, void *), void *arg) -{ - char *q_hdr, *q_qname, *q_suf; - struct dns_message_hdr *hdr; - struct dns_query_suffix query_suf; - struct pico_dns_key *key; - uint16_t ip_len = 0; - uint16_t arpa_len = 0; - uint16_t id = 0; - - if (!ip || !callback) { - dns_dbg("DNS ERROR: NULL parameters\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - - ip_len = pico_dns_client_strlen(ip); - arpa_len = pico_dns_client_strlen(".in-addr.arpa"); - /* 2 extra bytes for ip_len and arpa_len to account for 2 extra length octets */ - q_hdr = pico_zalloc(sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix)); - if (!q_hdr) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - q_qname = q_hdr + sizeof(struct dns_message_hdr); - q_suf = q_qname + (1 + ip_len + arpa_len + 1); - - /* Construct query header */ - hdr = (struct dns_message_hdr *)q_hdr; - do { - id = (uint16_t) (pico_rand() & 0xFFFFU); - dns_dbg("DNS: generated id %u\n", id); - } while (pico_dns_client_idcheck(id)); - pico_dns_client_construct_hdr(hdr, id); - /* Add and manipulate domain name */ - memcpy(q_qname + 1, ip, ip_len + 1); - pico_dns_client_mirror(q_qname + 1); - memcpy(q_qname + 1 + ip_len, ".in-addr.arpa", arpa_len); - pico_dns_client_label(q_qname); - /* Add type and class of query */ - query_suf.qtype = short_be(PICO_DNS_TYPE_PTR); - query_suf.qclass = short_be(PICO_DNS_CLASS_IN); - memcpy(q_suf, &query_suf, sizeof(struct dns_query_suffix)); - /* Create RB entry */ - key = pico_zalloc(sizeof(struct pico_dns_key)); - if (!key) { - pico_free(q_hdr); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - key->q_hdr = q_hdr; - key->len = sizeof(struct dns_message_hdr) + (1 + ip_len + arpa_len + 1) + sizeof(struct dns_query_suffix); - key->id = id; - key->qtype = PICO_DNS_TYPE_PTR; - key->qclass = PICO_DNS_CLASS_IN; - key->retrans = 1; - key->q_ns = *((struct pico_dns_ns *)pico_tree_first(&NSTable)); - key->s = NULL; - key->callback = callback; - key->arg = arg; - /* Send query */ - if (pico_dns_client_send(key) < 0) { - pico_free(q_hdr); - if (key->s) - pico_socket_close(key->s); - pico_free(key); - pico_err = PICO_ERR_EAGAIN; - return -1; - } - /* Insert RB entry */ - - if(pico_tree_insert(&DNSTable,key)) { - pico_free(q_hdr); - pico_free(key); - pico_err = PICO_ERR_EAGAIN; - return -1; /* Element key already exists */ - } - - pico_timer_add(PICO_DNS_CLIENT_RETRANS, pico_dns_client_retransmission, key); - return 0; -} - -#ifdef PICO_DNS_CLIENT_MAIN -int main(int argc, char *argv[]) -{ - dns_dbg(">>>>> DNS GET ADDR\n"); - pico_dns_client_getaddr("www.google.be"); - dns_dbg(">>>>> DNS GET NAME\n"); - pico_dns_client_getname("173.194.67.94"); - - return 0; -} -#endif /* PICO_DNS_CLIENT_MAIN */ -#endif /* PICO_SUPPORT_DNS_CLIENT */
--- a/modules/pico_dns_client.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,22 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Kristof Roelants -*********************************************************************/ -#include <stdint.h> -#ifndef _INCLUDE_PICO_DNS_CLIENT -#define _INCLUDE_PICO_DNS_CLIENT - -#define PICO_DNS_NS_DEL 0 -#define PICO_DNS_NS_ADD 1 - -int pico_dns_client_init(); -/* flag is PICO_DNS_NS_DEL or PICO_DNS_NS_ADD */ -int pico_dns_client_nameserver(struct pico_ip4 *ns, uint8_t flag); -int pico_dns_client_getaddr(const char *url, void (*callback)(char *ip, void *arg), void *arg); -int pico_dns_client_getname(const char *ip, void (*callback)(char *url, void *arg), void *arg); - -#endif /* _INCLUDE_PICO_DNS_CLIENT */
--- a/modules/pico_http_client.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,701 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ -#include <string.h> -#include <stdint.h> -#include "pico_tree.h" -#include "pico_config.h" -#include "pico_socket.h" -#include "pico_tcp.h" -#include "pico_dns_client.h" -#include "pico_http_client.h" -#include "pico_ipv4.h" -#include "pico_stack.h" - -/* - * This is the size of the following header - * - * GET <resource> HTTP/1.1<CRLF> - * Host: <host>:<port><CRLF> - * User-Agent: picoTCP<CRLF> - * Connection: close<CRLF> - * <CRLF> - * - * where <resource>,<host> and <port> will be added later. - */ - -#ifdef PICO_SUPPORT_HTTP_CLIENT - -#define HTTP_GET_BASIC_SIZE 63u -#define HTTP_HEADER_LINE_SIZE 50u -#define RESPONSE_INDEX 9u - -#define HTTP_CHUNK_ERROR 0xFFFFFFFFu - -#ifdef dbg - #undef dbg - #define dbg(...) do{}while(0); -#endif - -#define consumeChar(c) (pico_socket_read(client->sck,&c,1u)) -#define isLocation(line) (memcmp(line,"Location",8u) == 0) -#define isContentLength(line) (memcmp(line,"Content-Length",14u) == 0u) -#define isTransferEncoding(line) (memcmp(line,"Transfer-Encoding",17u) == 0u) -#define isChunked(line) (memcmp(line," chunked",8u) == 0u) -#define isNotHTTPv1(line) (memcmp(line,"HTTP/1.",7u)) -#define is_hex_digit(x) ( ('0' <= x && x <= '9') || ('a' <= x && x <= 'f') ) -#define hex_digit_to_dec(x) ( ('0' <= x && x <= '9') ? x-'0' : ( ('a' <= x && x <= 'f') ? x-'a' + 10 : -1) ) - -struct pico_http_client -{ - uint16_t connectionID; - uint8_t state; - struct pico_socket * sck; - void (*wakeup)(uint16_t ev, uint16_t conn); - struct pico_ip4 ip; - struct pico_http_uri * uriKey; - struct pico_http_header * header; -}; - -// HTTP Client internal states -#define HTTP_READING_HEADER 0 -#define HTTP_READING_BODY 1 -#define HTTP_READING_CHUNK_VALUE 2 -#define HTTP_READING_CHUNK_TRAIL 3 - - -static int compareClients(void * ka, void * kb) -{ - return ((struct pico_http_client *)ka)->connectionID - ((struct pico_http_client *)kb)->connectionID; -} - -PICO_TREE_DECLARE(pico_client_list,compareClients); - -// Local functions -int parseHeaderFromServer(struct pico_http_client * client, struct pico_http_header * header); -int readChunkLine(struct pico_http_client * client); - -void tcpCallback(uint16_t ev, struct pico_socket *s) -{ - - struct pico_http_client * client = NULL; - struct pico_tree_node * index; - - // find httpClient - pico_tree_foreach(index,&pico_client_list) - { - if( ((struct pico_http_client *)index->keyValue)->sck == s ) - { - client = (struct pico_http_client *)index->keyValue; - break; - } - } - - if(!client) - { - dbg("Client not found...Something went wrong !\n"); - return; - } - - if(ev & PICO_SOCK_EV_CONN) - client->wakeup(EV_HTTP_CON,client->connectionID); - - if(ev & PICO_SOCK_EV_RD) - { - - // read the header, if not read - if(client->state == HTTP_READING_HEADER) - { - // wait for header - client->header = pico_zalloc(sizeof(struct pico_http_header)); - if(!client->header) - { - pico_err = PICO_ERR_ENOMEM; - return; - } - - // wait for header - if(parseHeaderFromServer(client,client->header) < 0) - { - client->wakeup(EV_HTTP_ERROR,client->connectionID); - } - else - { - // call wakeup - if(client->header->responseCode != HTTP_CONTINUE) - { - client->wakeup( - client->header->responseCode == HTTP_OK ? - EV_HTTP_REQ | EV_HTTP_BODY : // data comes for sure only when 200 is received - EV_HTTP_REQ - ,client->connectionID); - } - } - } - else - { - // just let the user know that data has arrived, if chunked data comes, will be treated in the - // read api. - client->wakeup(EV_HTTP_BODY,client->connectionID); - } - } - - if(ev & PICO_SOCK_EV_ERR) - { - client->wakeup(EV_HTTP_ERROR,client->connectionID); - } - - if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) ) - { - client->wakeup(EV_HTTP_CLOSE,client->connectionID); - } - -} - -// used for getting a response from DNS servers -static void dnsCallback(char *ip, void * ptr) -{ - struct pico_http_client * client = (struct pico_http_client *)ptr; - - if(!client) - { - dbg("Who made the request ?!\n"); - return; - } - - if(ip) - { - client->wakeup(EV_HTTP_DNS,client->connectionID); - - // add the ip address to the client, and start a tcp connection socket - pico_string_to_ipv4(ip,&client->ip.addr); - pico_free(ip); - client->sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &tcpCallback); - if(!client->sck) - { - client->wakeup(EV_HTTP_ERROR,client->connectionID); - return; - } - - if(pico_socket_connect(client->sck,&client->ip,short_be(client->uriKey->port)) < 0) - { - client->wakeup(EV_HTTP_ERROR,client->connectionID); - return; - } - - } - else - { - // wakeup client and let know error occured - client->wakeup(EV_HTTP_ERROR,client->connectionID); - - // close the client (free used heap) - pico_http_client_close(client->connectionID); - } -} - -/* - * API used for opening a new HTTP Client. - * - * The accepted uri's are [http://]hostname[:port]/resource - * no relative uri's are accepted. - * - * The function returns a connection ID >= 0 if successful - * -1 if an error occured. - */ -int pico_http_client_open(char * uri, void (*wakeup)(uint16_t ev, uint16_t conn)) -{ - struct pico_http_client * client; - - if(!wakeup) - { - pico_err = PICO_ERR_EINVAL; - return HTTP_RETURN_ERROR; - } - - client = pico_zalloc(sizeof(struct pico_http_client)); - if(!client) - { - // memory error - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - - client->wakeup = wakeup; - client->connectionID = (uint16_t)pico_rand() & 0x7FFFu; // negative values mean error, still not good generation - - client->uriKey = pico_zalloc(sizeof(struct pico_http_uri)); - - if(!client->uriKey) - { - pico_err = PICO_ERR_ENOMEM; - pico_free(client); - return HTTP_RETURN_ERROR; - } - - pico_processURI(uri,client->uriKey); - - if(pico_tree_insert(&pico_client_list,client)) - { - // already in - pico_err = PICO_ERR_EEXIST; - pico_free(client->uriKey); - pico_free(client); - return HTTP_RETURN_ERROR; - } - - // dns query - dbg("Querying : %s \n",client->uriKey->host); - pico_dns_client_getaddr(client->uriKey->host, dnsCallback,client); - - // return the connection ID - return client->connectionID; -} - -/* - * API for sending a header to the client. - * - * if hdr == HTTP_HEADER_RAW , then the parameter header - * is sent as it is to client. - * - * if hdr == HTTP_HEADER_DEFAULT, then the parameter header - * is ignored and the library will build the response header - * based on the uri passed when opening the client. - * - */ -int pico_http_client_sendHeader(uint16_t conn, char * header, int hdr) -{ - struct pico_http_client search = {.connectionID = conn}; - struct pico_http_client * http = pico_tree_findKey(&pico_client_list,&search); - int length ; - if(!http) - { - dbg("Client not found !\n"); - return HTTP_RETURN_ERROR; - } - - // the api gives the possibility to the user to build the GET header - // based on the uri passed when opening the client, less headache for the user - if(hdr == HTTP_HEADER_DEFAULT) - { - header = pico_http_client_buildHeader(http->uriKey); - - if(!header) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - } - - length = pico_socket_write(http->sck,(void *)header,strlen(header)+1); - - if(hdr == HTTP_HEADER_DEFAULT) - pico_free(header); - - return length; -} - -/* - * API for reading received data. - * - * This api hides from the user if the transfer-encoding - * was chunked or a full length was provided, in case of - * a chunked transfer encoding will "de-chunk" the data - * and pass it to the user. - */ -int pico_http_client_readData(uint16_t conn, char * data, uint16_t size) -{ - struct pico_http_client dummy = {.connectionID = conn}; - struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy); - - if(!client) - { - dbg("Wrong connection id !\n"); - pico_err = PICO_ERR_EINVAL; - return HTTP_RETURN_ERROR; - } - - // for the moment just read the data, do not care if it's chunked or not - if(client->header->transferCoding == HTTP_TRANSFER_FULL) - return pico_socket_read(client->sck,(void *)data,size); - else - { - int lenRead = 0; - - // read the chunk line - if(readChunkLine(client) == HTTP_RETURN_ERROR) - { - dbg("Probably the chunk is malformed or parsed wrong...\n"); - client->wakeup(EV_HTTP_ERROR,client->connectionID); - return HTTP_RETURN_ERROR; - } - - // nothing to read, no use to try - if(client->state != HTTP_READING_BODY) - { - pico_err = PICO_ERR_EAGAIN; - return HTTP_RETURN_OK; - } - - // check if we need more than one chunk - if(size >= client->header->contentLengthOrChunk) - { - // read the rest of the chunk, if chunk is done, proceed to the next chunk - while(lenRead <= size) - { - int tmpLenRead = 0; - - if(client->state == HTTP_READING_BODY) - { - - // if needed truncate the data - tmpLenRead = pico_socket_read(client->sck,data + lenRead, - client->header->contentLengthOrChunk < size-lenRead ? client->header->contentLengthOrChunk : size-lenRead); - - if(tmpLenRead > 0) - { - client->header->contentLengthOrChunk -= tmpLenRead; - } - else if(tmpLenRead < 0) - { - // error on reading - dbg(">>> Error returned pico_socket_read\n"); - pico_err = PICO_ERR_EBUSY; - // return how much data was read until now - return lenRead; - } - } - - lenRead += tmpLenRead; - if(readChunkLine(client) == HTTP_RETURN_ERROR) - { - dbg("Probably the chunk is malformed or parsed wrong...\n"); - client->wakeup(EV_HTTP_ERROR,client->connectionID); - return HTTP_RETURN_ERROR; - } - - if(client->state != HTTP_READING_BODY || !tmpLenRead) break; - - } - } - else - { - // read the data from the chunk - lenRead = pico_socket_read(client->sck,(void *)data,size); - - if(lenRead) - client->header->contentLengthOrChunk -= lenRead; - } - - return lenRead; - } -} - -/* - * API for reading received data. - * - * Reads out the header struct received from server. - */ -struct pico_http_header * pico_http_client_readHeader(uint16_t conn) -{ - struct pico_http_client dummy = {.connectionID = conn}; - struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy); - - if(client) - { - return client->header; - } - else - { - // not found - dbg("Wrong connection id !\n"); - pico_err = PICO_ERR_EINVAL; - return NULL; - } -} - -/* - * API for reading received data. - * - * Reads out the uri struct after was processed. - */ -struct pico_http_uri * pico_http_client_readUriData(uint16_t conn) -{ - struct pico_http_client dummy = {.connectionID = conn}; - struct pico_http_client * client = pico_tree_findKey(&pico_client_list,&dummy); - // - if(client) - return client->uriKey; - else - { - // not found - dbg("Wrong connection id !\n"); - pico_err = PICO_ERR_EINVAL; - return NULL; - } -} - -/* - * API for reading received data. - * - * Close the client. - */ -int pico_http_client_close(uint16_t conn) -{ - struct pico_http_client * toBeRemoved = NULL; - struct pico_http_client dummy = {}; - dummy.connectionID = conn; - - dbg("Closing the client...\n"); - toBeRemoved = pico_tree_delete(&pico_client_list,&dummy); - if(!toBeRemoved) - { - dbg("Warning ! Element not found ..."); - return HTTP_RETURN_ERROR; - } - - // close socket - if(toBeRemoved->sck) - pico_socket_close(toBeRemoved->sck); - - - if(toBeRemoved->header) - { - // free space used - if(toBeRemoved->header->location) - pico_free(toBeRemoved->header->location); - - pico_free(toBeRemoved->header); - } - - if(toBeRemoved->uriKey) - { - if(toBeRemoved->uriKey->host) - pico_free(toBeRemoved->uriKey->host); - - if(toBeRemoved->uriKey->resource) - pico_free(toBeRemoved->uriKey->resource); - pico_free(toBeRemoved->uriKey); - } - pico_free(toBeRemoved); - - return 0; -} - -/* - * API for reading received data. - * - * Builds a GET header based on the fields on the uri. - */ -char * pico_http_client_buildHeader(const struct pico_http_uri * uriData) -{ - char * header; - char port[6u]; // 6 = max length of a uint16 + \0 - - uint16_t headerSize = HTTP_GET_BASIC_SIZE; - - if(!uriData->host || !uriData->resource || !uriData->port) - { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - // - headerSize += strlen(uriData->host) + strlen(uriData->resource) + pico_itoa(uriData->port,port) + 4u; // 3 = size(CRLF + \0) - header = pico_zalloc(headerSize); - - if(!header) - { - // not enought memory - pico_err = PICO_ERR_ENOMEM; - return NULL; - } - - // build the actual header - strcpy(header,"GET "); - strcat(header,uriData->resource); - strcat(header," HTTP/1.1\r\n"); - strcat(header,"Host: "); - strcat(header,uriData->host); - strcat(header,":"); - strcat(header,port); - strcat(header,"\r\n"); - strcat(header,"User-Agent: picoTCP\r\nConnection: close\r\n\r\n"); //? - - return header; -} - -int parseHeaderFromServer(struct pico_http_client * client, struct pico_http_header * header) -{ - char line[HTTP_HEADER_LINE_SIZE]; - char c; - int index = 0; - - // read the first line of the header - while(consumeChar(c)>0 && c!='\r') - { - if(index < HTTP_HEADER_LINE_SIZE) // truncate if too long - line[index++] = c; - } - - consumeChar(c); // consume \n - - // check the integrity of the response - // make sure we have enough characters to include the response code - // make sure the server response starts with HTTP/1. - if(index < RESPONSE_INDEX+2 || isNotHTTPv1(line)) - { - // wrong format of the the response - pico_err = PICO_ERR_EINVAL; - return HTTP_RETURN_ERROR; - } - - // extract response code - header->responseCode = (line[RESPONSE_INDEX] - '0') * 100u + - (line[RESPONSE_INDEX+1] - '0') * 10u + - (line[RESPONSE_INDEX+2] - '0'); - - - if(header->responseCode/100u > 5u) - { - // invalid response type - header->responseCode = 0; - return HTTP_RETURN_ERROR; - } - - dbg("Server response : %d \n",header->responseCode); - - // parse the rest of the header - while(consumeChar(c)>0) - { - if(c==':') - { - // check for interesting fields - - // Location: - if(isLocation(line)) - { - index = 0; - while(consumeChar(c)>0 && c!='\r') - { - line[index++] = c; - } - - // allocate space for the field - header->location = pico_zalloc(index+1u); - if(!header->location) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - - memcpy(header->location,line,index); - - }// Content-Length: - else if(isContentLength(line)) - { - header->contentLengthOrChunk = 0u; - header->transferCoding = HTTP_TRANSFER_FULL; - // consume the first space - consumeChar(c); - while(consumeChar(c)>0 && c!='\r') - { - header->contentLengthOrChunk = header->contentLengthOrChunk*10u + (c-'0'); - } - - }// Transfer-Encoding: chunked - else if(isTransferEncoding(line)) - { - index = 0; - while(consumeChar(c)>0 && c!='\r') - { - line[index++] = c; - } - - if(isChunked(line)) - { - header->contentLengthOrChunk = 0u; - header->transferCoding = HTTP_TRANSFER_CHUNKED; - } - - }// just ignore the line - else - { - while(consumeChar(c)>0 && c!='\r'); - } - - // consume the next one - consumeChar(c); - // reset the index - index = 0u; - } - else if(c=='\r' && !index) - { - // consume the \n - consumeChar(c); - break; - } - else - { - line[index++] = c; - } - } - - if(header->transferCoding == HTTP_TRANSFER_CHUNKED) - { - // read the first chunk - header->contentLengthOrChunk = 0; - - client->state = HTTP_READING_CHUNK_VALUE; - readChunkLine(client); - - } - else - client->state = HTTP_READING_BODY; - - dbg("End of header\n"); - return HTTP_RETURN_OK; - -} - -// an async read of the chunk part, since in theory a chunk can be split in 2 packets -int readChunkLine(struct pico_http_client * client) -{ - char c = 0; - - if(client->header->contentLengthOrChunk==0 && client->state == HTTP_READING_BODY) - { - client->state = HTTP_READING_CHUNK_VALUE; - } - - if(client->state == HTTP_READING_CHUNK_VALUE) - { - while(consumeChar(c)>0 && c!='\r' && c!=';') - { - if(is_hex_digit(c)) - client->header->contentLengthOrChunk = (client->header->contentLengthOrChunk << 4u) + hex_digit_to_dec(c); - else - { - pico_err = PICO_ERR_EINVAL; - // something went wrong - return HTTP_RETURN_ERROR; - } - } - - if(c=='\r' || c==';') client->state = HTTP_READING_CHUNK_TRAIL; - } - - if(client->state == HTTP_READING_CHUNK_TRAIL) - { - - while(consumeChar(c)>0 && c!='\n'); - - if(c=='\n') client->state = HTTP_READING_BODY; - } - - return HTTP_RETURN_OK; -} -#endif
--- a/modules/pico_http_client.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,49 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - - -#ifndef PICO_HTTP_CLIENT_H_ -#define PICO_HTTP_CLIENT_H_ - -#include "pico_http_util.h" - -/* - * Transfer encodings - */ -#define HTTP_TRANSFER_CHUNKED 1u -#define HTTP_TRANSFER_FULL 0u - -/* - * Parameters for the send header function - */ -#define HTTP_HEADER_RAW 0u -#define HTTP_HEADER_DEFAULT 1u - -/* - * Data types - */ - -struct pico_http_header -{ - uint16_t responseCode; // http response - char * location; // if redirect is reported - uint32_t contentLengthOrChunk; // size of the message - uint8_t transferCoding; // chunked or full - -}; - -int pico_http_client_open(char * uri, void (*wakeup)(uint16_t ev, uint16_t conn)); -int pico_http_client_sendHeader(uint16_t conn, char * header, int hdr); - -struct pico_http_header * pico_http_client_readHeader(uint16_t conn); -struct pico_http_uri * pico_http_client_readUriData(uint16_t conn); -char * pico_http_client_buildHeader(const struct pico_http_uri * uriData); - -int pico_http_client_readData(uint16_t conn, char * data, uint16_t size); -int pico_http_client_close(uint16_t conn); - -#endif /* PICO_HTTP_CLIENT_H_ */
--- a/modules/pico_http_server.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,636 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#include "pico_stack.h" -#include "pico_http_server.h" -#include "pico_tcp.h" -#include "pico_tree.h" -#include "pico_socket.h" - -#ifdef PICO_SUPPORT_HTTP_SERVER - -#define BACKLOG 10 - -#define HTTP_SERVER_CLOSED 0 -#define HTTP_SERVER_LISTEN 1 - -#define HTTP_HEADER_MAX_LINE 256u - -#define consumeChar(c) (pico_socket_read(client->sck,&c,1u)) - -static char returnOkHeader[] = -"HTTP/1.1 200 OK\r\n\ -Host: localhost\r\n\ -Transfer-Encoding: chunked\r\n\ -Connection: close\r\n\ -\r\n"; - -static char returnFailHeader[] = -"HTTP/1.1 404 Not Found\r\n\ -Host: localhost\r\n\ -Connection: close\r\n\ -\r\n\ -<html><body>The resource you requested cannot be found !</body></html>"; - -static char errorHeader[] = -"HTTP/1.1 400 Bad Request\r\n\ -Host: localhost\r\n\ -Connection: close\r\n\ -\r\n\ -<html><body>There was a problem with your request !</body></html>"; - -struct httpServer -{ - uint16_t state; - struct pico_socket * sck; - uint16_t port; - void (*wakeup)(uint16_t ev, uint16_t param); - uint8_t accepted; -}; - -struct httpClient -{ - uint16_t connectionID; - struct pico_socket * sck; - void * buffer; - uint16_t bufferSize; - uint16_t bufferSent; - char * resource; - uint16_t state; -}; - -/* Local states for clients */ -#define HTTP_WAIT_HDR 0 -#define HTTP_WAIT_EOF_HDR 1 -#define HTTP_EOF_HDR 2 -#define HTTP_WAIT_RESPONSE 3 -#define HTTP_WAIT_DATA 4 -#define HTTP_SENDING_DATA 5 -#define HTTP_ERROR 6 -#define HTTP_CLOSED 7 - -static struct httpServer server = {}; - -/* - * Private functions - */ -static int parseRequest(struct httpClient * client); -static int readRemainingHeader(struct httpClient * client); -static void sendData(struct httpClient * client); -static inline int readData(struct httpClient * client); // used only in a place -static inline struct httpClient * findClient(uint16_t conn); - -static int compareClients(void * ka, void * kb) -{ - return ((struct httpClient *)ka)->connectionID - ((struct httpClient *)kb)->connectionID; -} - -PICO_TREE_DECLARE(pico_http_clients,compareClients); - -void httpServerCbk(uint16_t ev, struct pico_socket *s) -{ - struct pico_tree_node * index; - struct httpClient * client = NULL; - uint8_t serverEvent = FALSE; - - // determine the client for the socket - if( s == server.sck) - { - serverEvent = TRUE; - } - else - { - pico_tree_foreach(index,&pico_http_clients) - { - client = index->keyValue; - if(client->sck == s) break; - client = NULL; - } - } - - if(!client && !serverEvent) - { - return; - } - - if (ev & PICO_SOCK_EV_RD) - { - - if(readData(client) == HTTP_RETURN_ERROR) - { - // send out error - client->state = HTTP_ERROR; - pico_socket_write(client->sck,errorHeader,sizeof(errorHeader)-1); - server.wakeup(EV_HTTP_ERROR,client->connectionID); - } - } - - if(ev & PICO_SOCK_EV_WR) - { - if(client->state == HTTP_SENDING_DATA) - { - sendData(client); - } - } - - if(ev & PICO_SOCK_EV_CONN) - { - server.accepted = FALSE; - server.wakeup(EV_HTTP_CON,HTTP_SERVER_ID); - if(!server.accepted) - { - pico_socket_close(s); // reject socket - } - } - - if( (ev & PICO_SOCK_EV_CLOSE) || (ev & PICO_SOCK_EV_FIN) ) - { - server.wakeup(EV_HTTP_CLOSE,(serverEvent ? HTTP_SERVER_ID : client->connectionID)); - } - - if(ev & PICO_SOCK_EV_ERR) - { - server.wakeup(EV_HTTP_ERROR,(serverEvent ? HTTP_SERVER_ID : client->connectionID)); - } -} - -/* - * API for starting the server. If 0 is passed as a port, the port 80 - * will be used. - */ -int pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn)) -{ - struct pico_ip4 anything = {}; - - server.port = port ? short_be(port) : short_be(80u); - - if(!wakeup) - { - pico_err = PICO_ERR_EINVAL; - return HTTP_RETURN_ERROR; - } - - server.sck = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, &httpServerCbk); - - if(!server.sck) - { - pico_err = PICO_ERR_EFAULT; - return HTTP_RETURN_ERROR; - } - - if(pico_socket_bind(server.sck , &anything, &server.port)!=0) - { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return HTTP_RETURN_ERROR; - } - - if (pico_socket_listen(server.sck, BACKLOG) != 0) - { - pico_err = PICO_ERR_EADDRINUSE; - return HTTP_RETURN_ERROR; - } - server.wakeup = wakeup; - server.state = HTTP_SERVER_LISTEN; - return HTTP_RETURN_OK; -} - -/* - * API for accepting new connections. This function should be - * called when the event EV_HTTP_CON is triggered, if not called - * when noticed the connection will be considered rejected and the - * socket will be dropped. - * - * Returns the ID of the new connection or a negative value if error. - */ -int pico_http_server_accept(void) -{ - struct pico_ip4 orig; - struct httpClient * client; - uint16_t port; - - client = pico_zalloc(sizeof(struct httpClient)); - if(!client) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - - client->sck = pico_socket_accept(server.sck,&orig,&port); - - if(!client->sck) - { - pico_err = PICO_ERR_ENOMEM; - pico_free(client); - return HTTP_RETURN_ERROR; - } - - server.accepted = TRUE; - // buffer used for async sending - client->state = HTTP_WAIT_HDR; - client->buffer = NULL; - client->bufferSize = 0; - client->connectionID = pico_rand() & 0x7FFF; - - //add element to the tree, if duplicate because the rand - //regenerate - while(pico_tree_insert(&pico_http_clients,client)!=NULL) - client->connectionID = pico_rand() & 0x7FFF; - - return client->connectionID; -} - -/* - * Function used for getting the resource asked by the - * client. It is useful after the request header (EV_HTTP_REQ) - * from client was received, otherwise NULL is returned. - */ -char * pico_http_getResource(uint16_t conn) -{ - struct httpClient * client = findClient(conn); - - if(!client) - return NULL; - else - return client->resource; -} - -/* - * After the resource was asked by the client (EV_HTTP_REQ) - * before doing anything else, the server has to let know - * the client if the resource can be provided or not. - * - * This is controlled via the code parameter which can - * have two values : - * - * HTTP_RESOURCE_FOUND or HTTP_RESOURCE_NOT_FOUND - * - * If a resource is reported not found the 404 header will be sent and the connection - * will be closed , otherwise the 200 header is sent and the user should - * immediately submit data. - * - */ -int pico_http_respond(uint16_t conn, uint16_t code) -{ - struct httpClient * client = findClient(conn); - - if(!client) - { - dbg("Client not found !\n"); - return HTTP_RETURN_ERROR; - } - - if(client->state == HTTP_WAIT_RESPONSE) - { - if(code == HTTP_RESOURCE_FOUND) - { - client->state = HTTP_WAIT_DATA; - return pico_socket_write(client->sck,returnOkHeader,sizeof(returnOkHeader)-1);//remove \0 - } - else - { - int length; - - length = pico_socket_write(client->sck,returnFailHeader,sizeof(returnFailHeader)-1);//remove \0 - pico_socket_close(client->sck); - client->state = HTTP_CLOSED; - return length; - - } - } - else - { - dbg("Bad state for the client \n"); - return HTTP_RETURN_ERROR; - } - -} - -/* - * API used to submit data to the client. - * Server sends data only using Transfer-Encoding: chunked. - * - * With this function the user will submit a data chunk to - * be sent. - * The function will send the chunk size in hex and the rest will - * be sent using WR event from sockets. - * After each transmision EV_HTTP_PROGRESS is called and at the - * end of the chunk EV_HTTP_SENT is called. - * - * To let the client know this is the last chunk, the user - * should pass a NULL buffer. - */ -int pico_http_submitData(uint16_t conn, void * buffer, int len) -{ - - struct httpClient * client = findClient(conn); - char chunkStr[10]; - int chunkCount; - - if(client->state != HTTP_WAIT_DATA) - { - dbg("Client is in a different state than accepted\n"); - return HTTP_RETURN_ERROR; - } - - if(client->buffer) - { - dbg("Already a buffer submited\n"); - return HTTP_RETURN_ERROR; - } - - if(!client) - { - dbg("Wrong connection ID\n"); - return HTTP_RETURN_ERROR; - } - - if(!buffer) - { - len = 0; - } - - if(len > 0) - { - client->buffer = pico_zalloc(len); - if(!client->buffer) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - // taking over the buffer - memcpy(client->buffer,buffer,len); - } - else - client->buffer = NULL; - - - client->bufferSize = len; - client->bufferSent = 0; - - // create the chunk size and send it - if(len > 0) - { - client->state = HTTP_SENDING_DATA; - chunkCount = pico_itoaHex(client->bufferSize,chunkStr); - chunkStr[chunkCount++] = '\r'; - chunkStr[chunkCount++] = '\n'; - pico_socket_write(client->sck,chunkStr,chunkCount); - } - else if(len == 0) - { - dbg("->\n"); - // end of transmision - pico_socket_write(client->sck,"0\r\n\r\n",5u); - // nothing left, close the client - pico_socket_close(client->sck); - client->state = HTTP_CLOSED; - } - - return HTTP_RETURN_OK; -} - -/* - * When EV_HTTP_PROGRESS is triggered you can use this - * function to check the state of the chunk. - */ - -int pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total) -{ - struct httpClient * client = findClient(conn); - - if(!client) - { - dbg("Wrong connection id !\n"); - return HTTP_RETURN_ERROR; - } - - *sent = client->bufferSent; - *total = client->bufferSize; - - return HTTP_RETURN_OK; -} - -/* - * This API can be used to close either a client - * or the server ( if you pass HTTP_SERVER_ID as a connection ID). - */ -int pico_http_close(uint16_t conn) -{ - // close the server - if(conn == HTTP_SERVER_ID) - { - if(server.state == HTTP_SERVER_LISTEN) - { - struct pico_tree_node * index, * tmp; - // close the server - pico_socket_close(server.sck); - server.sck = NULL; - - // destroy the tree - pico_tree_foreach_safe(index,&pico_http_clients,tmp) - { - struct httpClient * client = index->keyValue; - - if(client->resource) - pico_free(client->resource); - - pico_socket_close(client->sck); - pico_tree_delete(&pico_http_clients,client); - } - - server.state = HTTP_SERVER_CLOSED; - return HTTP_RETURN_OK; - } - else // nothing to close - return HTTP_RETURN_ERROR; - } // close a connection in this case - else - { - - struct httpClient * client = findClient(conn); - - if(!client) - { - dbg("Client not found..\n"); - return HTTP_RETURN_ERROR; - } - - pico_tree_delete(&pico_http_clients,client); - - if(client->resource) - pico_free(client->resource); - - if(client->buffer) - pico_free(client->buffer); - - if(client->state != HTTP_CLOSED || !client->sck) - pico_socket_close(client->sck); - - pico_free(client); - return HTTP_RETURN_OK; - } -} - -// check the integrity of the request -int parseRequest(struct httpClient * client) -{ - char c; - //read first line - consumeChar(c); - if(c == 'G') - { // possible GET - - char line[HTTP_HEADER_MAX_LINE]; - int index = 0; - - line[index] = c; - - // consume the full line - while(consumeChar(c)>0) // read char by char only the first line - { - line[++index] = c; - if(c == '\n') - break; - - if(index >= HTTP_HEADER_MAX_LINE) - { - dbg("Size exceeded \n"); - return HTTP_RETURN_ERROR; - } - } - - // extract the function and the resource - if(memcmp(line,"GET",3u) || line[3u]!=' ' || index < 10u || line[index] !='\n') - { - dbg("Wrong command or wrong ending\n"); - return HTTP_RETURN_ERROR; - } - - // start reading the resource - index = 4u; // go after ' ' - while(line[index]!=' ') - { - if(line[index]=='\n') // no terminator ' ' - { - dbg("No terminator...\n"); - return HTTP_RETURN_ERROR; - } - - index++; - } - - client->resource = pico_zalloc(index - 3u);// allocate without the GET in front + 1 which is \0 - - if(!client) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_RETURN_ERROR; - } - - // copy the resource - memcpy(client->resource,line+4u,index-4u);// copy without the \0 which was already set by pico_zalloc - - client->state = HTTP_WAIT_EOF_HDR; - return HTTP_RETURN_OK; - - } - - return HTTP_RETURN_ERROR; -} - - - -int readRemainingHeader(struct httpClient * client) -{ - char line[100]; - int count = 0; - int len; - - while( (len = pico_socket_read(client->sck,line,100u)) > 0) - { - char c; - int index = 0; - // parse the response - while(index < len) - { - c = line[index++]; - if(c!='\r' && c!='\n') - count++; - if(c=='\n') - { - if(!count) - { - client->state = HTTP_EOF_HDR; - dbg("End of header !\n"); - break; - } - count = 0; - - } - } - } - - return HTTP_RETURN_OK; -} - -void sendData(struct httpClient * client) -{ - int length; - while( client->bufferSent < client->bufferSize && - (length = pico_socket_write(client->sck,client->buffer+client->bufferSent,client->bufferSize-client->bufferSent)) > 0 ) - { - client->bufferSent += length; - server.wakeup(EV_HTTP_PROGRESS,client->connectionID); - } - - if(client->bufferSent == client->bufferSize && client->bufferSize) - { - //send chunk trail - if(pico_socket_write(client->sck,"\r\n",2) > 0) - { - client->state = HTTP_WAIT_DATA; - //free the buffer - pico_free(client->buffer); - client->buffer = NULL; - server.wakeup(EV_HTTP_SENT,client->connectionID); - } - } - -} - -int readData(struct httpClient * client) -{ - if(client->state == HTTP_WAIT_HDR) - { - if(parseRequest(client)<0 || readRemainingHeader(client)<0) - { - return HTTP_RETURN_ERROR; - } - } // continue with this in case the header comes line by line not a big chunk - else if(client->state == HTTP_WAIT_EOF_HDR) - { - if(readRemainingHeader(client)<0 ) - return HTTP_RETURN_ERROR; - } - - if(client->state == HTTP_EOF_HDR) - { - client->state = HTTP_WAIT_RESPONSE; - pico_socket_shutdown(client->sck,PICO_SHUT_RD); - server.wakeup(EV_HTTP_REQ,client->connectionID); - } - - return HTTP_RETURN_OK; -} - -struct httpClient * findClient(uint16_t conn) -{ - struct httpClient dummy = {.connectionID = conn}; - - return pico_tree_findKey(&pico_http_clients,&dummy); -} -#endif
--- a/modules/pico_http_server.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,40 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#ifndef PICO_HTTP_SERVER_H_ -#define PICO_HTTP_SERVER_H_ - -#include <stdint.h> -#include "pico_http_util.h" - -// Response codes -#define HTTP_RESOURCE_FOUND 0 -#define HTTP_RESOURCE_NOT_FOUND 1 - -// Generic id for the server -#define HTTP_SERVER_ID 0 - -/* - * Server functions - */ -int pico_http_server_start(uint16_t port, void (*wakeup)(uint16_t ev, uint16_t conn)); -int pico_http_server_accept(void); - -/* - * Client functions - */ -char * pico_http_getResource(uint16_t conn); -int pico_http_getProgress(uint16_t conn, uint16_t * sent, uint16_t *total); - -/* - * Handshake and data functions - */ -int pico_http_respond(uint16_t conn, uint16_t code); -int pico_http_submitData(uint16_t conn, void * buffer, int len); -int pico_http_close(uint16_t conn); - -#endif /* PICO_HTTP_SERVER_H_ */
--- a/modules/pico_http_util.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,186 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#include <stdint.h> -#include "pico_config.h" -#include "pico_stack.h" -#include "pico_protocol.h" -#include "pico_http_util.h" - -#define TRUE 1 -#define FALSE 0 - -#define HTTP_PROTO_TOK "http://" -#define HTTP_PROTO_LEN 7u - -#if defined PICO_SUPPORT_HTTP_CLIENT || defined PICO_SUPPORT_HTTP_SERVER - -int pico_itoaHex(uint16_t port, char * ptr) -{ - int size = 0; - int index; - - // transform to from number to string [ in backwards ] - while(port) - { - ptr[size] = ((port & 0xF) < 10) ? ((port & 0xF) + '0') : ((port & 0xF) - 10 + 'a'); - port = port>>4u; //divide by 16 - size++; - } - - // invert positions - for(index=0 ;index < size>>1u ;index++) - { - char c = ptr[index]; - ptr[index] = ptr[size-index-1]; - ptr[size-index-1] = c; - } - ptr[size] = '\0'; - return size; -} - -int pico_itoa(uint16_t port, char * ptr) -{ - int size = 0; - int index; - - // transform to from number to string [ in backwards ] - while(port) - { - ptr[size] = port%10 + '0'; - port = port/10; - size++; - } - - // invert positions - for(index=0 ;index < size>>1u ;index++) - { - char c = ptr[index]; - ptr[index] = ptr[size-index-1]; - ptr[size-index-1] = c; - } - ptr[size] = '\0'; - return size; -} - - -int pico_processURI(const char * uri, struct pico_http_uri * urikey) -{ - - uint16_t lastIndex = 0, index; - - if(!uri || !urikey || uri[0] == '/') - { - pico_err = PICO_ERR_EINVAL; - goto error; - } - - // detect protocol => search for "://" - if(memcmp(uri,HTTP_PROTO_TOK,HTTP_PROTO_LEN) == 0) // could be optimized - { // protocol identified, it is http - urikey->protoHttp = TRUE; - lastIndex = HTTP_PROTO_LEN; - } - else - { - if(strstr(uri,"://")) // different protocol specified - { - urikey->protoHttp = FALSE; - goto error; - } - // no protocol specified, assuming by default it's http - urikey->protoHttp = TRUE; - } - - // detect hostname - index = lastIndex; - while(uri[index] && uri[index]!='/' && uri[index]!=':') index++; - - if(index == lastIndex) - { - // wrong format - urikey->host = urikey->resource = NULL; - urikey->port = urikey->protoHttp = 0u; - - goto error; - } - else - { - // extract host - urikey->host = (char *)pico_zalloc(index-lastIndex+1); - - if(!urikey->host) - { - // no memory - goto error; - } - memcpy(urikey->host,uri+lastIndex,index-lastIndex); - } - - if(!uri[index]) - { - // nothing specified - urikey->port = 80u; - urikey->resource = pico_zalloc(2u); - urikey->resource[0] = '/'; - return HTTP_RETURN_OK; - } - else if(uri[index] == '/') - { - urikey->port = 80u; - } - else if(uri[index] == ':') - { - urikey->port = 0u; - index++; - while(uri[index] && uri[index]!='/') - { - // should check if every component is a digit - urikey->port = urikey->port*10 + (uri[index] - '0'); - index++; - } - } - - // extract resource - if(!uri[index]) - { - urikey->resource = pico_zalloc(2u); - urikey->resource[0] = '/'; - } - else - { - lastIndex = index; - while(uri[index] && uri[index]!='?' && uri[index]!='&' && uri[index]!='#') index++; - urikey->resource = (char *)pico_zalloc(index-lastIndex+1); - - if(!urikey->resource) - { - // no memory - pico_err = PICO_ERR_ENOMEM; - goto error; - } - - memcpy(urikey->resource,uri+lastIndex,index-lastIndex); - } - - return HTTP_RETURN_OK; - - error : - if(urikey->resource) - { - pico_free(urikey->resource); - urikey->resource = NULL; - } - if(urikey->host) - { - pico_free(urikey->host); - urikey->host = NULL; - } - - return HTTP_RETURN_ERROR; -} -#endif
--- a/modules/pico_http_util.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,117 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#ifndef PICO_HTTP_UTIL_H_ -#define PICO_HTTP_UTIL_H_ - -/* Informational reponses */ -#define HTTP_CONTINUE 100u -#define HTTP_SWITCHING_PROTOCOLS 101u -#define HTTP_PROCESSING 102u - -/* Success */ -#define HTTP_OK 200u -#define HTTP_CREATED 201u -#define HTTP_ACCEPTED 202u -#define HTTP_NON_AUTH_INFO 203u -#define HTTP_NO_CONTENT 204u -#define HTTP_RESET_CONTENT 205u -#define HTTP_PARTIAL_CONTENT 206u -#define HTTP_MULTI_STATUS 207u -#define HTTP_ALREADY_REPORTED 208u -#define HTTP_LOW_SPACE 250u -#define HTTP_IM_SPACE 226u - -/* Redirection */ -#define HTTP_MULTI_CHOICE 300u -#define HTTP_MOVED_PERMANENT 301u -#define HTTP_FOUND 302u -#define HTTP_SEE_OTHER 303u -#define HTTP_NOT_MODIFIED 304u -#define HTTP_USE_PROXY 305u -#define HTTP_SWITCH_PROXY 306u -#define HTTP_TEMP_REDIRECT 307u -#define HTTP_PERM_REDIRECT 308u - -/* Client error */ -#define HTTP_BAD_REQUEST 400u -#define HTTP_UNAUTH 401u -#define HTTP_PAYMENT_REQ 402u -#define HTTP_FORBIDDEN 403u -#define HTTP_NOT_FOUND 404u -#define HTTP_METH_NOT_ALLOWED 405u -#define HTTP_NOT_ACCEPTABLE 406u -#define HTTP_PROXY_AUTH_REQ 407u -#define HTTP_REQ_TIMEOUT 408u -#define HTTP_CONFLICT 409u -#define HTTP_GONE 410u -#define HTTP_LEN_REQ 411u -#define HTTP_PRECONDITION_FAIL 412u -#define HTTP_REQ_ENT_LARGE 413u -#define HTTP_URI_TOO_LONG 414u -#define HTTP_UNSUPORTED_MEDIA 415u -#define HTTP_REQ_RANGE_NOK 416u -#define HTTP_EXPECT_FAILED 417u -#define HTTP_TEAPOT 418u -#define HTTP_UNPROC_ENTITY 422u -#define HTTP_LOCKED 423u -#define HTTP_METHOD_FAIL 424u -#define HTTP_UNORDERED 425u -#define HTTP_UPGRADE_REQ 426u -#define HTTP_PRECOND_REQ 428u -#define HTTP_TOO_MANY_REQ 429u -#define HTTP_HEDER_FIELD_LARGE 431u - -/* Server error */ -#define HTTP_INTERNAL_SERVER_ERR 500u -#define HTTP_NOT_IMPLEMENTED 501u -#define HTTP_BAD_GATEWAY 502u -#define HTTP_SERVICE_UNAVAILABLE 503u -#define HTTP_GATEWAY_TIMEOUT 504u -#define HTTP_NOT_SUPPORTED 505u -#define HTTP_SERV_LOW_STORAGE 507u -#define HTTP_LOOP_DETECTED 508u -#define HTTP_NOT_EXTENDED 510u -#define HTTP_NETWORK_AUTH 511u -#define HTTP_PERMISSION_DENIED 550u - -/* Returns used */ -#define HTTP_RETURN_ERROR -1 -#define HTTP_RETURN_OK 0 - -/* List of events - shared between client and server */ -#define EV_HTTP_CON 1u -#define EV_HTTP_REQ 2u -#define EV_HTTP_PROGRESS 4u -#define EV_HTTP_SENT 8u -#define EV_HTTP_CLOSE 16u -#define EV_HTTP_ERROR 32u -#define EV_HTTP_BODY 64u -#define EV_HTTP_DNS 128u - -#ifndef TRUE - #define TRUE 1 -#endif - -#ifndef FALSE - #define FALSE 0 -#endif - -struct pico_http_uri -{ - uint8_t protoHttp; // is the protocol Http ? - char * host; // hostname - uint16_t port; // port if specified - char * resource; // resource , ignoring the other possible parameters -}; - -// used for chunks -int pico_itoaHex(uint16_t port, char * ptr); -int pico_itoa(uint16_t port, char * ptr); -int pico_processURI(const char * uri, struct pico_http_uri * urikey); - -#endif /* PICO_HTTP_UTIL_H_ */
--- a/modules/pico_icmp4.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,315 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_icmp4.h" -#include "pico_config.h" -#include "pico_ipv4.h" -#include "pico_eth.h" -#include "pico_device.h" -#include "pico_stack.h" -#include "pico_tree.h" - -/* Queues */ -static struct pico_queue icmp_in = {}; -static struct pico_queue icmp_out = {}; - - -/* Functions */ - -static int pico_icmp4_checksum(struct pico_frame *f) -{ - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - if (!hdr) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, f->transport_len)); - return 0; -} - -#ifdef PICO_SUPPORT_PING -static void ping_recv_reply(struct pico_frame *f); -#endif - -static int pico_icmp4_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - if (hdr->type == PICO_ICMP_ECHO) { - hdr->type = PICO_ICMP_ECHOREPLY; - /* Ugly, but the best way to get ICMP data size here. */ - f->transport_len = f->buffer_len - PICO_SIZE_IP4HDR; - if (f->dev->eth) - f->transport_len -= PICO_SIZE_ETHHDR; - pico_icmp4_checksum(f); - f->net_hdr = f->transport_hdr - PICO_SIZE_IP4HDR; - f->start = f->net_hdr; - f->len = f->buffer_len; - if (f->dev->eth) - f->len -= PICO_SIZE_ETHHDR; - pico_ipv4_rebound(f); - } else if (hdr->type == PICO_ICMP_UNREACH) { - f->net_hdr = f->transport_hdr + PICO_ICMPHDR_UN_SIZE; - pico_ipv4_unreachable(f, hdr->code); - } else if (hdr->type == PICO_ICMP_ECHOREPLY) { -#ifdef PICO_SUPPORT_PING - ping_recv_reply(f); -#endif - pico_frame_discard(f); - } else { - pico_frame_discard(f); - } - return 0; -} - -static int pico_icmp4_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - dbg("Called %s\n", __FUNCTION__); - return 0; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_icmp4 = { - .name = "icmp4", - .proto_number = PICO_PROTO_ICMP4, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_icmp4_process_in, - .process_out = pico_icmp4_process_out, - .q_in = &icmp_in, - .q_out = &icmp_out, -}; - -static int pico_icmp4_notify(struct pico_frame *f, uint8_t type, uint8_t code) -{ - struct pico_frame *reply; - struct pico_icmp4_hdr *hdr; - struct pico_ipv4_hdr *info; - if (f == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - reply = pico_proto_ipv4.alloc(&pico_proto_ipv4, 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE); - info = (struct pico_ipv4_hdr*)(f->net_hdr); - hdr = (struct pico_icmp4_hdr *) reply->transport_hdr; - hdr->type = type; - hdr->code = code; - hdr->hun.ih_pmtu.ipm_nmtu = short_be(1500); - hdr->hun.ih_pmtu.ipm_void = 0; - reply->transport_len = 8 + sizeof(struct pico_ipv4_hdr) + PICO_ICMPHDR_UN_SIZE; - reply->payload = reply->transport_hdr + PICO_ICMPHDR_UN_SIZE; - memcpy(reply->payload, f->net_hdr, 8 + sizeof(struct pico_ipv4_hdr)); - pico_icmp4_checksum(reply); - pico_ipv4_frame_push(reply, &info->src, PICO_PROTO_ICMP4); - return 0; -} - -int pico_icmp4_port_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PORT); -} - -int pico_icmp4_proto_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_PROTOCOL); -} - -int pico_icmp4_dest_unreachable(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_HOST); -} - -int pico_icmp4_ttl_expired(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - return pico_icmp4_notify(f, PICO_ICMP_TIME_EXCEEDED, PICO_ICMP_TIMXCEED_INTRANS); -} - - -int pico_icmp4_packet_filtered(struct pico_frame *f) -{ - /*Parameter check executed in pico_icmp4_notify*/ - /*Packet Filtered: type 3, code 13 (Communication Administratively Prohibited)*/ - return pico_icmp4_notify(f, PICO_ICMP_UNREACH, PICO_ICMP_UNREACH_FILTER_PROHIB); -} - - -/***********************/ -/* Ping implementation */ -/***********************/ -/***********************/ -/***********************/ -/***********************/ - - -#ifdef PICO_SUPPORT_PING - - -struct pico_icmp4_ping_cookie -{ - struct pico_ip4 dst; - uint16_t err; - uint16_t id; - uint16_t seq; - uint16_t size; - int count; - unsigned long timestamp; - int interval; - int timeout; - void (*cb)(struct pico_icmp4_stats*); - -}; - -static int cookie_compare(void *ka, void *kb) -{ - struct pico_icmp4_ping_cookie *a = ka, *b = kb; - if (a->id < b->id) - return -1; - if (a->id > b->id) - return 1; - return (a->seq - b->seq); -} - -PICO_TREE_DECLARE(Pings,cookie_compare); - -static int pico_icmp4_send_echo(struct pico_icmp4_ping_cookie *cookie) -{ - struct pico_frame *echo = pico_proto_ipv4.alloc(&pico_proto_ipv4, PICO_ICMPHDR_UN_SIZE + cookie->size); - struct pico_icmp4_hdr *hdr; - - hdr = (struct pico_icmp4_hdr *) echo->transport_hdr; - - hdr->type = PICO_ICMP_ECHO; - hdr->code = 0; - hdr->hun.ih_idseq.idseq_id = short_be(cookie->id); - hdr->hun.ih_idseq.idseq_seq = short_be(cookie->seq); - echo->transport_len = PICO_ICMPHDR_UN_SIZE + cookie->size; - echo->payload = echo->transport_hdr + PICO_ICMPHDR_UN_SIZE; - echo->payload_len = cookie->size; - /* XXX: Fill payload */ - pico_icmp4_checksum(echo); - pico_ipv4_frame_push(echo, &cookie->dst, PICO_PROTO_ICMP4); - return 0; -} - - -static void ping_timeout(unsigned long now, void *arg) -{ - struct pico_icmp4_ping_cookie *cookie = (struct pico_icmp4_ping_cookie *)arg; - if(pico_tree_findKey(&Pings,cookie)){ - if (cookie->err == PICO_PING_ERR_PENDING) { - struct pico_icmp4_stats stats; - stats.dst = cookie->dst; - stats.seq = cookie->seq; - stats.time = 0; - stats.size = cookie->size; - stats.err = PICO_PING_ERR_TIMEOUT; - dbg(" ---- Ping timeout!!!\n"); - cookie->cb(&stats); - } - - pico_tree_delete(&Pings,cookie); - pico_free(cookie); - } -} - -static void next_ping(unsigned long now, void *arg); -static inline void send_ping(struct pico_icmp4_ping_cookie *cookie) -{ - pico_icmp4_send_echo(cookie); - cookie->timestamp = pico_tick; - pico_timer_add(cookie->timeout, ping_timeout, cookie); - if (cookie->seq < cookie->count) - pico_timer_add(cookie->interval, next_ping, cookie); -} - -static void next_ping(unsigned long now, void *arg) -{ - struct pico_icmp4_ping_cookie *newcookie, *cookie = (struct pico_icmp4_ping_cookie *)arg; - - if(pico_tree_findKey(&Pings,cookie)){ - if (cookie->seq < cookie->count) { - newcookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie)); - if (!newcookie) - return; - memcpy(newcookie, cookie, sizeof(struct pico_icmp4_ping_cookie)); - newcookie->seq++; - - pico_tree_insert(&Pings,newcookie); - send_ping(newcookie); - } - } -} - - -static void ping_recv_reply(struct pico_frame *f) -{ - struct pico_icmp4_ping_cookie test, *cookie; - struct pico_icmp4_hdr *hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - test.id = short_be(hdr->hun.ih_idseq.idseq_id ); - test.seq = short_be(hdr->hun.ih_idseq.idseq_seq); - - cookie = pico_tree_findKey(&Pings, &test); - if (cookie) { - struct pico_icmp4_stats stats; - cookie->err = PICO_PING_ERR_REPLIED; - stats.dst = cookie->dst; - stats.seq = cookie->seq; - stats.size = cookie->size; - stats.time = pico_tick - cookie->timestamp; - stats.err = cookie->err; - stats.ttl = ((struct pico_ipv4_hdr *)f->net_hdr)->ttl; - if(cookie->cb != NULL) - cookie->cb(&stats); - } else { - dbg("Reply for seq=%d, not found.\n", test.seq); - } -} - -int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)) -{ - static uint16_t next_id = 0x91c0; - struct pico_icmp4_ping_cookie *cookie; - - if((dst == NULL) || (interval == 0) || (timeout == 0) || (count == 0)){ - pico_err = PICO_ERR_EINVAL; - return -1; - } - - cookie = pico_zalloc(sizeof(struct pico_icmp4_ping_cookie)); - if (!cookie) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - if (pico_string_to_ipv4(dst, &cookie->dst.addr) < 0) { - pico_err = PICO_ERR_EINVAL; - pico_free(cookie); - return -1; - } - cookie->seq = 1; - cookie->id = next_id++; - cookie->err = PICO_PING_ERR_PENDING; - cookie->size = size; - cookie->interval = interval; - cookie->timeout = timeout; - cookie->cb = cb; - cookie->count = count; - - pico_tree_insert(&Pings,cookie); - send_ping(cookie); - - return 0; - -} - -#endif
--- a/modules/pico_icmp4.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_ICMP4 -#define _INCLUDE_PICO_ICMP4 -#include "pico_addressing.h" -#include "pico_protocol.h" - -extern struct pico_protocol pico_proto_icmp4; - -struct __attribute__((packed)) pico_icmp4_hdr { - uint8_t type; - uint8_t code; - uint16_t crc; - - /* hun */ - union { - uint8_t ih_pptr; - struct pico_ip4 ih_gwaddr; - struct { - uint16_t idseq_id; - uint16_t idseq_seq; - } ih_idseq; - uint32_t ih_void; - struct { - uint16_t ipm_void; - uint16_t ipm_nmtu; - } ih_pmtu; - struct { - uint8_t rta_numgw; - uint8_t rta_wpa; - uint16_t rta_lifetime; - } ih_rta; - } hun; - - /* dun */ - union { - struct { - uint32_t ts_otime; - uint32_t ts_rtime; - uint32_t ts_ttime; - } id_ts; - struct { - uint32_t ip_options; - uint32_t ip_data_hi; - uint32_t ip_data_lo; - } id_ip; - struct { - uint32_t ira_addr; - uint32_t ira_pref; - } id_ra; - uint32_t id_mask; - uint8_t id_data[1]; - } dun; -}; - -#define PICO_ICMPHDR_DRY_SIZE 4 -#define PICO_ICMPHDR_UN_SIZE 8 - -#define PICO_ICMP_ECHOREPLY 0 -#define PICO_ICMP_DEST_UNREACH 3 -#define PICO_ICMP_SOURCE_QUENCH 4 -#define PICO_ICMP_REDIRECT 5 -#define PICO_ICMP_ECHO 8 -#define PICO_ICMP_TIME_EXCEEDED 11 -#define PICO_ICMP_PARAMETERPROB 12 -#define PICO_ICMP_TIMESTAMP 13 -#define PICO_ICMP_TIMESTAMPREPLY 14 -#define PICO_ICMP_INFO_REQUEST 15 -#define PICO_ICMP_INFO_REPLY 16 -#define PICO_ICMP_ADDRESS 17 -#define PICO_ICMP_ADDRESSREPLY 18 - - -#define PICO_ICMP_UNREACH 3 -#define PICO_ICMP_SOURCEQUENCH 4 -#define PICO_ICMP_ROUTERADVERT 9 -#define PICO_ICMP_ROUTERSOLICIT 10 -#define PICO_ICMP_TIMXCEED 11 -#define PICO_ICMP_PARAMPROB 12 -#define PICO_ICMP_TSTAMP 13 -#define PICO_ICMP_TSTAMPREPLY 14 -#define PICO_ICMP_IREQ 15 -#define PICO_ICMP_IREQREPLY 16 -#define PICO_ICMP_MASKREQ 17 -#define PICO_ICMP_MASKREPLY 18 - -#define PICO_ICMP_MAXTYPE 18 - - -#define PICO_ICMP_UNREACH_NET 0 -#define PICO_ICMP_UNREACH_HOST 1 -#define PICO_ICMP_UNREACH_PROTOCOL 2 -#define PICO_ICMP_UNREACH_PORT 3 -#define PICO_ICMP_UNREACH_NEEDFRAG 4 -#define PICO_ICMP_UNREACH_SRCFAIL 5 -#define PICO_ICMP_UNREACH_NET_UNKNOWN 6 -#define PICO_ICMP_UNREACH_HOST_UNKNOWN 7 -#define PICO_ICMP_UNREACH_ISOLATED 8 -#define PICO_ICMP_UNREACH_NET_PROHIB 9 -#define PICO_ICMP_UNREACH_HOST_PROHIB 10 -#define PICO_ICMP_UNREACH_TOSNET 11 -#define PICO_ICMP_UNREACH_TOSHOST 12 -#define PICO_ICMP_UNREACH_FILTER_PROHIB 13 -#define PICO_ICMP_UNREACH_HOST_PRECEDENCE 14 -#define PICO_ICMP_UNREACH_PRECEDENCE_CUTOFF 15 - - -#define PICO_ICMP_REDIRECT_NET 0 -#define PICO_ICMP_REDIRECT_HOST 1 -#define PICO_ICMP_REDIRECT_TOSNET 2 -#define PICO_ICMP_REDIRECT_TOSHOST 3 - - -#define PICO_ICMP_TIMXCEED_INTRANS 0 -#define PICO_ICMP_TIMXCEED_REASS 1 - - -#define PICO_ICMP_PARAMPROB_OPTABSENT 1 - -#define PICO_SIZE_ICMP4HDR ((sizeof(struct pico_icmp4_hdr))) - -struct pico_icmp4_stats -{ - struct pico_ip4 dst; - unsigned long size; - unsigned long seq; - unsigned long time; - unsigned long ttl; - int err; -}; - -int pico_icmp4_port_unreachable(struct pico_frame *f); -int pico_icmp4_proto_unreachable(struct pico_frame *f); -int pico_icmp4_dest_unreachable(struct pico_frame *f); -int pico_icmp4_ttl_expired(struct pico_frame *f); -int pico_icmp4_packet_filtered(struct pico_frame *f); - -int pico_icmp4_ping(char *dst, int count, int interval, int timeout, int size, void (*cb)(struct pico_icmp4_stats *)); -#define PICO_PING_ERR_REPLIED 0 -#define PICO_PING_ERR_TIMEOUT 1 -#define PICO_PING_ERR_UNREACH 2 -#define PICO_PING_ERR_PENDING 0xFFFF - -#endif
--- a/modules/pico_igmp.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1120 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -RFC 1112, 2236, 3376, 3569, 3678, 4607 - -Authors: Kristof Roelants (IGMPv3), Simon Maes, Brecht Van Cauwenberghe -*********************************************************************/ - -#include "pico_stack.h" -#include "pico_ipv4.h" -#include "pico_igmp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_addressing.h" -#include "pico_frame.h" -#include "pico_tree.h" -#include "pico_device.h" -#include "pico_socket.h" - -#define igmp_dbg(...) do{}while(0) -//#define igmp_dbg dbg - -/* membership states */ -#define IGMP_STATE_NON_MEMBER (0x0) -#define IGMP_STATE_DELAYING_MEMBER (0x1) -#define IGMP_STATE_IDLE_MEMBER (0x2) - -/* events */ -#define IGMP_EVENT_DELETE_GROUP (0x0) -#define IGMP_EVENT_CREATE_GROUP (0x1) -#define IGMP_EVENT_UPDATE_GROUP (0x2) -#define IGMP_EVENT_QUERY_RECV (0x3) -#define IGMP_EVENT_REPORT_RECV (0x4) -#define IGMP_EVENT_TIMER_EXPIRED (0x5) - -/* message types */ -#define IGMP_TYPE_MEM_QUERY (0x11) -#define IGMP_TYPE_MEM_REPORT_V1 (0x12) -#define IGMP_TYPE_MEM_REPORT_V2 (0x16) -#define IGMP_TYPE_LEAVE_GROUP (0x17) -#define IGMP_TYPE_MEM_REPORT_V3 (0x22) - -/* group record types */ -#define IGMP_MODE_IS_INCLUDE (1) -#define IGMP_MODE_IS_EXCLUDE (2) -#define IGMP_CHANGE_TO_INCLUDE_MODE (3) -#define IGMP_CHANGE_TO_EXCLUDE_MODE (4) -#define IGMP_ALLOW_NEW_SOURCES (5) -#define IGMP_BLOCK_OLD_SOURCES (6) - -/* host flag */ -#define IGMP_HOST_LAST (0x1) -#define IGMP_HOST_NOT_LAST (0x0) - -/* list of timers, counters and their default values */ -#define IGMP_ROBUSTNESS (2) -#define IGMP_QUERY_INTERVAL (125) /* secs */ -#define IGMP_QUERY_RESPONSE_INTERVAL (10) /* secs */ -#define IGMP_STARTUP_QUERY_INTERVAL (IGMPV3_QUERY_INTERVAL / 4) -#define IGMP_STARTUP_QUERY_COUNT (IGMPV3_ROBUSTNESS) -#define IGMP_LAST_MEMBER_QUERY_INTERVAL (1) /* secs */ -#define IGMP_LAST_MEMBER_QUERY_COUNT (IGMPV3_ROBUSTNESS) -#define IGMP_UNSOLICITED_REPORT_INTERVAL (1) /* secs */ -#define IGMP_DEFAULT_MAX_RESPONSE_TIME (100) - -/* custom timers types */ -#define IGMP_TIMER_GROUP_REPORT (1) -#define IGMP_TIMER_V1_QUERIER (2) -#define IGMP_TIMER_V2_QUERIER (3) - -/* IGMP groups */ -#define IGMP_ALL_HOST_GROUP long_be(0xE0000001) /* 224.0.0.1 */ -#define IGMP_ALL_ROUTER_GROUP long_be(0xE0000002) /* 224.0.0.2 */ -#define IGMPV3_ALL_ROUTER_GROUP long_be(0xE0000016) /* 224.0.0.22 */ - -/* misc */ -#define IGMP_TIMER_STOPPED (1) -#define IP_OPTION_ROUTER_ALERT_LEN (4) -#define IGMP_MAX_GROUPS (32) /* max 255 */ - -struct __attribute__((packed)) igmp_message { - uint8_t type; - uint8_t max_resp_time; - uint16_t crc; - uint32_t mcast_group; -}; - -struct __attribute__((packed)) igmpv3_query { - uint8_t type; - uint8_t max_resp_time; - uint16_t crc; - uint32_t mcast_group; - uint8_t rsq; - uint8_t qqic; - uint16_t sources; - uint32_t source_addr[0]; -}; - -struct __attribute__((packed)) igmpv3_group_record { - uint8_t type; - uint8_t aux; - uint16_t sources; - uint32_t mcast_group; - uint32_t source_addr[0]; -}; - -struct __attribute__((packed)) igmpv3_report { - uint8_t type; - uint8_t res0; - uint16_t crc; - uint16_t res1; - uint16_t groups; - struct igmpv3_group_record record[0]; -}; - -struct igmp_parameters { - uint8_t event; - uint8_t state; - uint8_t last_host; - uint8_t filter_mode; - uint8_t max_resp_time; - struct pico_ip4 mcast_link; - struct pico_ip4 mcast_group; - struct pico_tree *MCASTFilter; - struct pico_frame *f; -}; - -struct igmp_timer { - uint8_t type; - uint8_t stopped; - unsigned long start; - unsigned long delay; - struct pico_ip4 mcast_link; - struct pico_ip4 mcast_group; - struct pico_frame *f; - void (*callback)(struct igmp_timer *t); -}; - -/* queues */ -static struct pico_queue igmp_in = {}; -static struct pico_queue igmp_out = {}; - -/* finite state machine caller */ -static int pico_igmp_process_event(struct igmp_parameters *p); - -/* state callback prototype */ -typedef int (*callback)(struct igmp_parameters *); - -/* redblack trees */ -static int igmp_timer_cmp(void *ka, void *kb) -{ - struct igmp_timer *a = ka, *b =kb; - if (a->type < b->type) - return -1; - if (a->type > b->type) - return 1; - if (a->mcast_group.addr < b->mcast_group.addr) - return -1; - if (a->mcast_group.addr > b->mcast_group.addr) - return 1; - if (a->mcast_link.addr < b->mcast_link.addr) - return -1; - if (a->mcast_link.addr > b->mcast_link.addr) - return 1; - return 0; -} -PICO_TREE_DECLARE(IGMPTimers, igmp_timer_cmp); - -static int igmp_parameters_cmp(void *ka, void *kb) -{ - struct igmp_parameters *a = ka, *b = kb; - if (a->mcast_group.addr < b->mcast_group.addr) - return -1; - if (a->mcast_group.addr > b->mcast_group.addr) - return 1; - if (a->mcast_link.addr < b->mcast_link.addr) - return -1; - if (a->mcast_link.addr > b->mcast_link.addr) - return 1; - return 0; -} -PICO_TREE_DECLARE(IGMPParameters, igmp_parameters_cmp); - -static int igmp_sources_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - if (a->addr < b->addr) - return -1; - if (a->addr > b->addr) - return 1; - return 0; -} -PICO_TREE_DECLARE(IGMPAllow, igmp_sources_cmp); -PICO_TREE_DECLARE(IGMPBlock, igmp_sources_cmp); - -static struct igmp_parameters *pico_igmp_find_parameter(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - struct igmp_parameters test = {0}; - test.mcast_link.addr = mcast_link->addr; - test.mcast_group.addr = mcast_group->addr; - return pico_tree_findKey(&IGMPParameters, &test); -} - -static int pico_igmp_delete_parameter(struct igmp_parameters *p) -{ - if (pico_tree_delete(&IGMPParameters, p)) - pico_free(p); - else - return -1; - - return 0; -} - -static void pico_igmp_timer_expired(unsigned long now, void *arg) -{ - struct igmp_timer *t = NULL, *timer = NULL, test = {0}; - - t = (struct igmp_timer *)arg; - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - igmp_dbg("IGMP: timer expired for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) { - return; - } - if (timer->stopped == IGMP_TIMER_STOPPED) { - pico_free(t); - return; - } - if (timer->start + timer->delay < PICO_TIME_MS()) { - pico_tree_delete(&IGMPTimers, timer); - if (timer->callback) - timer->callback(timer); - pico_free(timer); - } else { - igmp_dbg("IGMP: restart timer for %08X, delay %lu, new delay %lu\n", t->mcast_group.addr, t->delay, (timer->start + timer->delay) - PICO_TIME_MS()); - pico_timer_add((timer->start + timer->delay) - PICO_TIME_MS(), &pico_igmp_timer_expired, timer); - } - return; -} - -static int pico_igmp_timer_reset(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = {0}; - - igmp_dbg("IGMP: reset timer for %08X, delay %lu\n", t->mcast_group.addr, t->delay); - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) - return -1; - - *timer = *t; - timer->start = PICO_TIME_MS(); - return 0; -} - -static int pico_igmp_timer_start(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = {0}; - - igmp_dbg("IGMP: start timer for %08X link %08X type %u, delay %lu\n", t->mcast_group.addr, t->mcast_link.addr, t->type, t->delay); - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (timer) - return pico_igmp_timer_reset(t); - - timer = pico_zalloc(sizeof(struct igmp_timer)); - if (!timer) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - *timer = *t; - timer->start = PICO_TIME_MS(); - - pico_tree_insert(&IGMPTimers, timer); - pico_timer_add(timer->delay, &pico_igmp_timer_expired, timer); - return 0; -} - -static int pico_igmp_timer_stop(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = {0}; - - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (!timer) - return 0; - - igmp_dbg("IGMP: stop timer for %08X, delay %lu\n", timer->mcast_group.addr, timer->delay); - timer->stopped = IGMP_TIMER_STOPPED; - return 0; -} - -static int pico_igmp_timer_is_running(struct igmp_timer *t) -{ - struct igmp_timer *timer = NULL, test = {0}; - - test.type = t->type; - test.mcast_link = t->mcast_link; - test.mcast_group = t->mcast_group; - timer = pico_tree_findKey(&IGMPTimers, &test); - if (timer) - return 1; - return 0; -} - -static struct igmp_timer *pico_igmp_find_timer(uint8_t type, struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - struct igmp_timer test = {0}; - - test.type = type; - test.mcast_link = *mcast_link; - test.mcast_group = *mcast_group; - return pico_tree_findKey(&IGMPTimers, &test); -} - -static void pico_igmp_report_expired(struct igmp_timer *t) -{ - struct igmp_parameters *p = NULL; - - p = pico_igmp_find_parameter(&t->mcast_link, &t->mcast_group); - if (!p) - return; - - p->event = IGMP_EVENT_TIMER_EXPIRED; - pico_igmp_process_event(p); -} - -static void pico_igmp_v2querier_expired(struct igmp_timer *t) -{ - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - - link = pico_ipv4_link_by_dev(t->f->dev); - if (!link) - return; - - /* When changing compatibility mode, cancel all pending response - * and retransmission timers. - */ - pico_tree_foreach_safe(index, &IGMPTimers, _tmp) - { - ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; - pico_tree_delete(&IGMPTimers, index->keyValue); - } - igmp_dbg("IGMP: switch to compatibility mode IGMPv3\n"); - link->mcast_compatibility = PICO_IGMPV3; - return; -} - -static int pico_igmp_is_checksum_valid(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = NULL; - uint8_t ihl = 24, datalen = 0; - - hdr = (struct pico_ipv4_hdr *)f->net_hdr; - ihl = (hdr->vhl & 0x0F) * 4; /* IHL is in 32bit words */ - datalen = short_be(hdr->len) - ihl; - - if (short_be(pico_checksum(f->transport_hdr, datalen)) == 0) - return 1; - igmp_dbg("IGMP: invalid checksum\n"); - return 0; -} - -/* RFC 3376 $7.1 */ -static int pico_igmp_compatibility_mode(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = NULL; - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct igmp_timer t = {0}; - uint8_t ihl = 24, datalen = 0; - - link = pico_ipv4_link_by_dev(f->dev); - if (!link) - return -1; - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ihl = (hdr->vhl & 0x0F) * 4; /* IHL is in 32bit words */ - datalen = short_be(hdr->len) - ihl; - igmp_dbg("IGMP: IHL = %u, LEN = %u, OCTETS = %u\n", ihl, short_be(hdr->len), datalen); - - if (datalen > 12) { - /* IGMPv3 query */ - t.type = IGMP_TIMER_V2_QUERIER; - if (pico_igmp_timer_is_running(&t)) { /* IGMPv2 querier present timer still running */ - return -1; - } else { - link->mcast_compatibility = PICO_IGMPV3; - return 0; - } - } else if (datalen == 8) { - struct igmp_message *query = (struct igmp_message *)f->transport_hdr; - if (query->max_resp_time != 0) { - /* IGMPv2 query */ - /* When changing compatibility mode, cancel all pending response - * and retransmission timers. - */ - pico_tree_foreach_safe(index, &IGMPTimers, _tmp) - { - ((struct igmp_timer *)index->keyValue)->stopped = IGMP_TIMER_STOPPED; - pico_tree_delete(&IGMPTimers, index->keyValue); - } - igmp_dbg("IGMP: switch to compatibility mode IGMPv2\n"); - link->mcast_compatibility = PICO_IGMPV2; - t.type = IGMP_TIMER_V2_QUERIER; - t.delay = ((IGMP_ROBUSTNESS * link->mcast_last_query_interval) + IGMP_QUERY_RESPONSE_INTERVAL) * 1000; - t.f = f; - t.callback = pico_igmp_v2querier_expired; - /* only one of this type of timer may exist! */ - pico_igmp_timer_start(&t); - } else { - /* IGMPv1 query, not supported */ - return -1; - } - } else { - /* invalid query, silently ignored */ - return -1; - } - return 0; -} - -static struct igmp_parameters *pico_igmp_analyse_packet(struct pico_frame *f) -{ - struct igmp_message *message = NULL; - struct igmp_parameters *p = NULL; - struct pico_ipv4_link *link = NULL; - struct pico_ip4 mcast_group = {0}; - - link = pico_ipv4_link_by_dev(f->dev); - if (!link) - return NULL; - - /* IGMPv2 and IGMPv3 have a similar structure for the first 8 bytes */ - message = (struct igmp_message *)f->transport_hdr; - mcast_group.addr = message->mcast_group; - p = pico_igmp_find_parameter(&link->address, &mcast_group); - if (!p && mcast_group.addr == 0) { /* general query */ - p = pico_zalloc(sizeof(struct igmp_parameters)); - if (!p) - return NULL; - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link.addr = link->address.addr; - p->mcast_group.addr = mcast_group.addr; - pico_tree_insert(&IGMPParameters, p); - } else if (!p) { - return NULL; - } - - switch (message->type) { - case IGMP_TYPE_MEM_QUERY: - p->event = IGMP_EVENT_QUERY_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V1: - p->event = IGMP_EVENT_REPORT_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V2: - p->event = IGMP_EVENT_REPORT_RECV; - break; - case IGMP_TYPE_MEM_REPORT_V3: - p->event = IGMP_EVENT_REPORT_RECV; - break; - default: - return NULL; - } - p->max_resp_time = message->max_resp_time; /* if IGMPv3 report this will be 0 (res0 field) */ - p->f = f; - - return p; -} - -static int pico_igmp_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct igmp_parameters *p = NULL; - - if (!pico_igmp_is_checksum_valid(f)) - goto out; - if (pico_igmp_compatibility_mode(f) < 0) - goto out; - p = pico_igmp_analyse_packet(f); - if (!p) - goto out; - - return pico_igmp_process_event(p); - - out: - pico_frame_discard(f); - return 0; -} - -static int pico_igmp_process_out(struct pico_protocol *self, struct pico_frame *f) { - /* packets are directly transferred to the IP layer by calling pico_ipv4_frame_push */ - return 0; -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_igmp = { - .name = "igmp", - .proto_number = PICO_PROTO_IGMP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_igmp_process_in, - .process_out = pico_igmp_process_out, - .q_in = &igmp_in, - .q_out = &igmp_out, -}; - -int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *MCASTFilter, uint8_t state) -{ - struct igmp_parameters *p = NULL; - - if (mcast_group->addr == IGMP_ALL_HOST_GROUP) - return 0; - - p = pico_igmp_find_parameter(mcast_link, mcast_group); - if (!p && state == PICO_IGMP_STATE_CREATE) { - p = pico_zalloc(sizeof(struct igmp_parameters)); - if (!p) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - p->state = IGMP_STATE_NON_MEMBER; - p->mcast_link = *mcast_link; - p->mcast_group = *mcast_group; - pico_tree_insert(&IGMPParameters, p); - } else if (!p) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (state) { - case PICO_IGMP_STATE_CREATE: - p->event = IGMP_EVENT_CREATE_GROUP; - break; - - case PICO_IGMP_STATE_UPDATE: - p->event = IGMP_EVENT_UPDATE_GROUP; - break; - - case PICO_IGMP_STATE_DELETE: - p->event = IGMP_EVENT_DELETE_GROUP; - break; - - default: - return -1; - } - p->filter_mode = filter_mode; - p->MCASTFilter = MCASTFilter; - - return pico_igmp_process_event(p); -} - -static int pico_igmp_send_report(struct igmp_parameters *p, struct pico_frame *f) -{ - struct pico_ip4 dst = {0}; - struct pico_ip4 mcast_group = {0}; - struct pico_ipv4_link *link = NULL; - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - mcast_group.addr = p->mcast_group.addr; - switch (link->mcast_compatibility) { - case PICO_IGMPV2: - if (p->event == IGMP_EVENT_DELETE_GROUP) - dst.addr = IGMP_ALL_ROUTER_GROUP; - else - dst.addr = mcast_group.addr; - break; - - case PICO_IGMPV3: - dst.addr = IGMPV3_ALL_ROUTER_GROUP; - break; - - default: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - } - - igmp_dbg("IGMP: send membership report on group %08X to %08X\n", mcast_group.addr, dst.addr); - pico_ipv4_frame_push(f, &dst, PICO_PROTO_IGMP); - return 0; -} - -static int pico_igmp_generate_report(struct igmp_parameters *p) -{ - struct pico_ipv4_link *link = NULL; - int i = 0; - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (link->mcast_compatibility) { - case PICO_IGMPV1: - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; - - case PICO_IGMPV2: - { - struct igmp_message *report = NULL; - uint8_t report_type = IGMP_TYPE_MEM_REPORT_V2; - if (p->event == IGMP_EVENT_DELETE_GROUP) - report_type = IGMP_TYPE_LEAVE_GROUP; - - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + sizeof(struct igmp_message)); - p->f->net_len += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_len -= IP_OPTION_ROUTER_ALERT_LEN; - p->f->dev = pico_ipv4_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - report = (struct igmp_message *)p->f->transport_hdr; - report->type = report_type; - report->max_resp_time = IGMP_DEFAULT_MAX_RESPONSE_TIME; - report->mcast_group = p->mcast_group.addr; - - report->crc = 0; - report->crc = short_be(pico_checksum(report, sizeof(struct igmp_message))); - break; - } - case PICO_IGMPV3: - { - struct igmpv3_report *report = NULL; - struct igmpv3_group_record *record = NULL; - struct pico_mcast_group *g = NULL, test = {0}; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_tree *IGMPFilter = NULL; - struct pico_ip4 *source = NULL; - uint8_t record_type = 0; - uint8_t sources = 0; - int len = 0; - - test.mcast_addr = p->mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (p->event == IGMP_EVENT_DELETE_GROUP) { /* "non-existent" state of filter mode INCLUDE and empty source list */ - p->filter_mode = PICO_IP_MULTICAST_INCLUDE; - p->MCASTFilter = NULL; - } - - /* cleanup filters */ - pico_tree_foreach_safe(index, &IGMPAllow, _tmp) - { - pico_tree_delete(&IGMPAllow, index->keyValue); - } - pico_tree_foreach_safe(index, &IGMPBlock, _tmp) - { - pico_tree_delete(&IGMPBlock, index->keyValue); - } - - switch (g->filter_mode) { - - case PICO_IP_MULTICAST_INCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - if (p->event == IGMP_EVENT_DELETE_GROUP) { /* all ADD_SOURCE_MEMBERSHIP had an equivalent DROP_SOURCE_MEMBERSHIP */ - /* TO_IN (B) */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - IGMPFilter = &IGMPAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - } /* else { IGMPAllow stays empty } */ - break; - } - - /* ALLOW (B-A) */ - /* if event is CREATE A will be empty, thus only ALLOW (B-A) has sense */ - if (p->event == IGMP_EVENT_CREATE_GROUP) /* first ADD_SOURCE_MEMBERSHIP */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - else - record_type = IGMP_ALLOW_NEW_SOURCES; - IGMPFilter = &IGMPAllow; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&IGMPAllow, index->keyValue); - if (source) { - pico_tree_delete(&IGMPAllow, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ - break; - - /* BLOCK (A-B) */ - record_type = IGMP_BLOCK_OLD_SOURCES; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&IGMPBlock, index->keyValue); - if (source) { - pico_tree_delete(&IGMPBlock, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ - break; - - /* ALLOW (B-A) and BLOCK (A-B) are empty: do not send report (RFC 3376 $5.1) */ - p->f = NULL; - return 0; - - case PICO_IP_MULTICAST_EXCLUDE: - /* TO_EX (B) */ - record_type = IGMP_CHANGE_TO_EXCLUDE_MODE; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - - case PICO_IP_MULTICAST_EXCLUDE: - switch (p->filter_mode) { - case PICO_IP_MULTICAST_INCLUDE: - /* TO_IN (B) */ - record_type = IGMP_CHANGE_TO_INCLUDE_MODE; - IGMPFilter = &IGMPAllow; - if (p->MCASTFilter) { - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - } /* else { IGMPAllow stays empty } */ - break; - - case PICO_IP_MULTICAST_EXCLUDE: - /* BLOCK (B-A) */ - record_type = IGMP_BLOCK_OLD_SOURCES; - IGMPFilter = &IGMPBlock; - pico_tree_foreach(index, p->MCASTFilter) - { - pico_tree_insert(&IGMPBlock, index->keyValue); - sources++; - } - pico_tree_foreach(index, &g->MCASTSources) /* A */ - { - source = pico_tree_findKey(&IGMPBlock, index->keyValue); /* B */ - if (source) { - pico_tree_delete(&IGMPBlock, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPBlock)) /* record type is BLOCK */ - break; - - /* ALLOW (A-B) */ - record_type = IGMP_ALLOW_NEW_SOURCES; - IGMPFilter = &IGMPAllow; - pico_tree_foreach(index, &g->MCASTSources) - { - pico_tree_insert(&IGMPAllow, index->keyValue); - sources++; - } - pico_tree_foreach(index, p->MCASTFilter) /* B */ - { - source = pico_tree_findKey(&IGMPAllow, index->keyValue); /* A */ - if (source) { - pico_tree_delete(&IGMPAllow, source); - sources--; - } - } - if (!pico_tree_empty(&IGMPAllow)) /* record type is ALLOW */ - break; - - /* BLOCK (B-A) and ALLOW (A-B) are empty: do not send report (RFC 3376 $5.1) */ - p->f = NULL; - return 0; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - len = sizeof(struct igmpv3_report) + sizeof(struct igmpv3_group_record) + (sources * sizeof(struct pico_ip4)); - p->f = pico_proto_ipv4.alloc(&pico_proto_ipv4, IP_OPTION_ROUTER_ALERT_LEN + len); - p->f->net_len += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_hdr += IP_OPTION_ROUTER_ALERT_LEN; - p->f->transport_len -= IP_OPTION_ROUTER_ALERT_LEN; - p->f->dev = pico_ipv4_link_find(&p->mcast_link); - /* p->f->len is correctly set by alloc */ - - report = (struct igmpv3_report *)p->f->transport_hdr; - report->type = IGMP_TYPE_MEM_REPORT_V3; - report->res0 = 0; - report->crc = 0; - report->res1 = 0; - report->groups = short_be(1); - - record = &report->record[0]; - record->type = record_type; - record->aux = 0; - record->sources = short_be(sources); - record->mcast_group = p->mcast_group.addr; - if (!pico_tree_empty(IGMPFilter)) { - i = 0; - pico_tree_foreach(index, IGMPFilter) - { - record->source_addr[i] = ((struct pico_ip4 *)index->keyValue)->addr; - i++; - } - } - report->crc = short_be(pico_checksum(report, len)); - break; - } - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - return 0; -} - -/* stop timer, send leave if flag set */ -static int stslifs(struct igmp_parameters *p) -{ - struct igmp_timer t = {0}; - - igmp_dbg("IGMP: event = leave group | action = stop timer, send leave if flag set\n"); - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_igmp_timer_stop(&t) < 0) - return -1; - - /* always send leave, even if not last host */ - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - pico_igmp_delete_parameter(p); - igmp_dbg("IGMP: new state = non-member\n"); - return 0; -} - -/* send report, set flag, start timer */ -static int srsfst(struct igmp_parameters *p) -{ - struct igmp_timer t = {0}; - struct pico_frame *copy_frame = NULL; - - igmp_dbg("IGMP: event = join group | action = send report, set flag, start timer\n"); - - p->last_host = IGMP_HOST_LAST; - - if (pico_igmp_generate_report(p) < 0) - return -1; - if (!p->f) - return 0; - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* merge report, send report, reset timer (IGMPv3 only) */ -static int mrsrrt(struct igmp_parameters *p) -{ - struct igmp_timer *t = NULL; - struct pico_frame *copy_frame = NULL; - struct pico_ipv4_link *link = NULL; - - igmp_dbg("IGMP: event = update group | action = merge report, send report, reset timer (IGMPv3 only)\n"); - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_IGMPV3) { - igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); - return -1; - } - - /* XXX: merge with pending report rfc 3376 $5.1 */ - - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - t->delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - pico_igmp_timer_reset(t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* send report, start timer (IGMPv3 only) */ -static int srst(struct igmp_parameters *p) -{ - struct igmp_timer t = {0}; - struct pico_frame *copy_frame = NULL; - struct pico_ipv4_link *link = NULL; - - igmp_dbg("IGMP: event = update group | action = send report, start timer (IGMPv3 only)\n"); - - link = pico_ipv4_link_get(&p->mcast_link); - if (!link) - return -1; - - if (link->mcast_compatibility != PICO_IGMPV3) { - igmp_dbg("IGMP: no IGMPv3 compatible router on network\n"); - return -1; - } - - if (pico_igmp_generate_report(p) < 0) - return -1; - if (!p->f) - return 0; - copy_frame = pico_frame_copy(p->f); - if (!copy_frame) - return -1; - if (pico_igmp_send_report(p, copy_frame) < 0) - return -1; - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (IGMP_UNSOLICITED_REPORT_INTERVAL * 10000)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* send leave if flag set */ -static int slifs(struct igmp_parameters *p) -{ - igmp_dbg("IGMP: event = leave group | action = send leave if flag set\n"); - - /* always send leave, even if not last host */ - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - pico_igmp_delete_parameter(p); - igmp_dbg("IGMP: new state = non-member\n"); - return 0; -} - -/* start timer */ -static int st(struct igmp_parameters *p) -{ - struct igmp_timer t = {0}; - - igmp_dbg("IGMP: event = query received | action = start timer\n"); - - if (pico_igmp_generate_report(p) < 0) - return -1; - if (!p->f) - return -1; - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - t.delay = (pico_rand() % (p->max_resp_time * 100)); - t.f = p->f; - t.callback = pico_igmp_report_expired; - pico_igmp_timer_start(&t); - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -/* stop timer, clear flag */ -static int stcl(struct igmp_parameters *p) -{ - struct igmp_timer t = {0}; - - igmp_dbg("IGMP: event = report received | action = stop timer, clear flag\n"); - - t.type = IGMP_TIMER_GROUP_REPORT; - t.mcast_link = p->mcast_link; - t.mcast_group = p->mcast_group; - if (pico_igmp_timer_stop(&t) < 0) - return -1; - - p->last_host = IGMP_HOST_NOT_LAST; - p->state = IGMP_STATE_IDLE_MEMBER; - igmp_dbg("IGMP: new state = idle member\n"); - return 0; -} - -/* send report, set flag */ -static int srsf(struct igmp_parameters *p) -{ - igmp_dbg("IGMP: event = timer expired | action = send report, set flag\n"); - - if (pico_igmp_send_report(p, p->f) < 0) - return -1; - - p->state = IGMP_STATE_IDLE_MEMBER; - igmp_dbg("IGMP: new state = idle member\n"); - return 0; -} - -/* reset timer if max response time < current timer */ -static int rtimrtct(struct igmp_parameters *p) -{ - struct igmp_timer *t = NULL; - unsigned long time_to_run = 0; - - igmp_dbg("IGMP: event = query received | action = reset timer if max response time < current timer\n"); - - t = pico_igmp_find_timer(IGMP_TIMER_GROUP_REPORT, &p->mcast_link, &p->mcast_group); - if (!t) - return -1; - - time_to_run = t->start + t->delay - PICO_TIME_MS(); - if ((p->max_resp_time * 100) < time_to_run) { /* max_resp_time in units of 1/10 seconds */ - t->delay = pico_rand() % (p->max_resp_time * 100); - pico_igmp_timer_reset(t); - } - - p->state = IGMP_STATE_DELAYING_MEMBER; - igmp_dbg("IGMP: new state = delaying member\n"); - return 0; -} - -static int discard(struct igmp_parameters *p){ - igmp_dbg("IGMP: ignore and discard frame\n"); - pico_frame_discard(p->f); - return 0; -} - -/* finite state machine table */ -const callback host_membership_diagram_table[3][6] = -{ /* event |Delete Group |Create Group |Update Group |Query Received |Report Received |Timer Expired */ -/* state Non-Member */ { discard, srsfst, srsfst, discard, discard, discard }, -/* state Delaying Member */ { stslifs, mrsrrt, mrsrrt, rtimrtct, stcl, srsf }, -/* state Idle Member */ { slifs, srst, srst, st, discard, discard } -}; - -static int pico_igmp_process_event(struct igmp_parameters *p) -{ - struct pico_tree_node *index = NULL; - struct igmp_parameters *_p = NULL; - - igmp_dbg("IGMP: process event on group address %08X\n", p->mcast_group.addr); - if (p->event == IGMP_EVENT_QUERY_RECV && p->mcast_group.addr == 0) { /* general query */ - pico_tree_foreach(index, &IGMPParameters) { - _p = index->keyValue; - _p->max_resp_time = p->max_resp_time; - _p->event = IGMP_EVENT_QUERY_RECV; - igmp_dbg("IGMP: for each mcast_group = %08X | state = %u\n", _p->mcast_group.addr, _p->state); - host_membership_diagram_table[_p->state][_p->event](_p); - } - } else { - igmp_dbg("IGMP: state = %u (0: non-member - 1: delaying member - 2: idle member)\n", p->state); - host_membership_diagram_table[p->state][p->event](p); - } - return 0; -} -
--- a/modules/pico_igmp.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe -*********************************************************************/ - -#ifndef _INCLUDE_PICO_IGMP -#define _INCLUDE_PICO_IGMP - -#define PICO_IGMPV1 1 -#define PICO_IGMPV2 2 -#define PICO_IGMPV3 3 - -#define PICO_IGMP_STATE_CREATE 1 -#define PICO_IGMP_STATE_UPDATE 2 -#define PICO_IGMP_STATE_DELETE 3 - -#define PICO_IGMP_QUERY_INTERVAL 125 - -extern struct pico_protocol pico_proto_igmp; - -int pico_igmp_state_change(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t filter_mode, struct pico_tree *MCASTFilter, uint8_t state); -#endif /* _INCLUDE_PICO_IGMP */
--- a/modules/pico_ipfilter.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Simon Maes -*********************************************************************/ - -#include "pico_ipv4.h" -#include "pico_config.h" -#include "pico_icmp4.h" -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_ipfilter.h" -#include "pico_tcp.h" -#include "pico_udp.h" - - -//#define ipf_dbg dbg -#define ipf_dbg(...) do{}while(0) - -struct filter_node; -typedef int (*func_pntr)(struct filter_node *filter, struct pico_frame *f); - -struct filter_node { - struct pico_device *fdev; - struct filter_node *next_filter; - uint32_t out_addr; - uint32_t out_addr_netmask; - uint32_t in_addr; - uint32_t in_addr_netmask; - uint16_t out_port; - uint16_t in_port; - uint8_t proto; - int8_t priority; - uint8_t tos; - uint8_t filter_id; - func_pntr function_ptr; -}; - -static struct filter_node *head = NULL; -static struct filter_node *tail = NULL; - -/*======================== FUNCTION PNTRS ==========================*/ - -static int fp_accept(struct filter_node *filter, struct pico_frame *f) {return 0;} - -static int fp_priority(struct filter_node *filter, struct pico_frame *f) { - - //TODO do priority-stuff - return 0; -} - -static int fp_reject(struct filter_node *filter, struct pico_frame *f) { -// TODO check first if sender is pico itself or not - ipf_dbg("ipfilter> #reject\n"); - pico_icmp4_packet_filtered(f); - pico_frame_discard(f); - return 1; -} - -static int fp_drop(struct filter_node *filter, struct pico_frame *f) { - - ipf_dbg("ipfilter> # drop\n"); - pico_frame_discard(f); - return 1; -} - -/*============================ API CALLS ============================*/ -int pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr, struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port, int8_t priority, uint8_t tos, enum filter_action action) -{ - static uint8_t filter_id = 0; - struct filter_node *new_filter; - - if ( !(dev != NULL || proto != 0 || (out_addr != NULL && out_addr->addr != 0U) || (out_addr_netmask != NULL && out_addr_netmask->addr != 0U)|| (in_addr != NULL && in_addr->addr != 0U) || (in_addr_netmask != NULL && in_addr_netmask->addr != 0U)|| out_port != 0 || in_port !=0 || tos != 0 )) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if ( priority > 10 || priority < -10) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (action > 3 || action < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - ipf_dbg("ipfilter> # adding filter\n"); - - new_filter = pico_zalloc(sizeof(struct filter_node)); - if (!head) { - head = tail = new_filter; - } else { - tail->next_filter = new_filter; - tail = new_filter; - } - - new_filter->fdev = dev; - new_filter->proto = proto; - if (out_addr != NULL) - new_filter->out_addr = out_addr->addr; - else - new_filter->out_addr = 0U; - - if (out_addr_netmask != NULL) - new_filter->out_addr_netmask = out_addr_netmask->addr; - else - new_filter->out_addr_netmask = 0U; - - if (in_addr != NULL) - new_filter->in_addr = in_addr->addr; - else - new_filter->in_addr = 0U; - - if (in_addr_netmask != NULL) - new_filter->in_addr_netmask = in_addr_netmask->addr; - else - new_filter->in_addr_netmask = 0U; - - new_filter->out_port = out_port; - new_filter->in_port = in_port; - new_filter->priority = priority; - new_filter->tos = tos; - new_filter->filter_id = filter_id++; - - /*Define filterType_functionPointer here instead of in ipfilter-function, to prevent running multiple times through switch*/ - switch (action) { - case FILTER_ACCEPT: - new_filter->function_ptr = fp_accept; - break; - case FILTER_PRIORITY: - new_filter->function_ptr = fp_priority; - break; - case FILTER_REJECT: - new_filter->function_ptr = fp_reject; - break; - case FILTER_DROP: - new_filter->function_ptr = fp_drop; - break; - default: - ipf_dbg("ipfilter> #unknown filter action\n"); - break; - } - return new_filter->filter_id; -} - -int pico_ipv4_filter_del(uint8_t filter_id) -{ - struct filter_node *work; - struct filter_node *prev; - - if (!tail || !head) { - pico_err = PICO_ERR_EPERM; - return -1; - } - - work = head; - if (work->filter_id == filter_id) { - /*delete filter_node from linked list*/ - head = work->next_filter; - pico_free(work); - return 0; - } - prev = work; - work = work->next_filter; - - while (1) { - if (work->filter_id == filter_id) { - if (work != tail) { - /*delete filter_node from linked list*/ - prev->next_filter = work->next_filter; - pico_free(work); - return 0; - } else { - prev->next_filter = NULL; - pico_free(work); - return 0; - } - } else { - /*check next filter_node*/ - prev = work; - work = work->next_filter; - if (work == tail) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - } -} - -/*================================== CORE FILTER FUNCTIONS ==================================*/ -int match_filter(struct filter_node *filter, struct pico_frame *f) -{ - struct filter_node temp; - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_tcp_hdr *tcp_hdr; - struct pico_udp_hdr *udp_hdr; - - if (!filter|| !f) { - ipf_dbg("ipfilter> ## nullpointer in match filter \n"); - return -1; - } - - temp.fdev = f->dev; - temp.out_addr = ipv4_hdr->dst.addr; - temp.in_addr = ipv4_hdr->src.addr; - if (ipv4_hdr->proto == PICO_PROTO_TCP ) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - temp.out_port = short_be(tcp_hdr->trans.dport); - temp.in_port = short_be(tcp_hdr->trans.sport); - }else if (ipv4_hdr->proto == PICO_PROTO_UDP ) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - temp.out_port = short_be(udp_hdr->trans.dport); - temp.in_port = short_be(udp_hdr->trans.sport); - } else { - temp.out_port = temp.in_port = 0; - } - temp.proto = ipv4_hdr->proto; - temp.priority = f->priority; - temp.tos = ipv4_hdr->tos; - - - - if ( ((filter->fdev == NULL || filter->fdev == temp.fdev) && \ - (filter->in_addr == 0 || ((filter->in_addr_netmask == 0) ? (filter->in_addr == temp.in_addr) : 1)) &&\ - (filter->in_port == 0 || filter->in_port == temp.in_port) &&\ - (filter->out_addr == 0 || ((filter->out_addr_netmask == 0) ? (filter->out_addr == temp.out_addr) : 1)) && \ - (filter->out_port == 0 || filter->out_port == temp.out_port) && \ - (filter->proto == 0 || filter->proto == temp.proto ) &&\ - (filter->priority == 0 || filter->priority == temp.priority ) &&\ - (filter->tos == 0 || filter->tos == temp.tos ) &&\ - (filter->out_addr_netmask == 0 || ((filter->out_addr & filter->out_addr_netmask) == (temp.out_addr & filter->out_addr_netmask)) ) &&\ - (filter->in_addr_netmask == 0 || ((filter->in_addr & filter->in_addr_netmask) == (temp.in_addr & filter->in_addr_netmask)) )\ - ) ) - return 0; - - //No filter match! - ipf_dbg("ipfilter> #no match\n"); - return 1; -} - -int ipfilter(struct pico_frame *f) -{ - struct filter_node *work = head; - - /*return 1 if pico_frame is discarded as result of the filtering, 0 for an incomming packet, -1 for faults*/ - if (!tail || !head) { - return 0; - } - - if ( match_filter(work, f) == 0 ) { - ipf_dbg("ipfilter> # ipfilter match\n"); - /*filter match, execute filter!*/ - return work->function_ptr(work, f); - } - while (tail != work) { - ipf_dbg("ipfilter> next filter..\n"); - work = work->next_filter; - if ( match_filter(work, f) == 0 ) { - ipf_dbg("ipfilter> # ipfilter match\n"); - /*filter match, execute filter!*/ - return work->function_ptr(work, f); - } - } - return 0; -} -
--- a/modules/pico_ipfilter.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,31 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Simon Maes -*********************************************************************/ -#ifndef _INCLUDE_PICO_IPFILTER -#define _INCLUDE_PICO_IPFILTER - -#include "pico_device.h" - -enum filter_action { - FILTER_ACCEPT = 0, - FILTER_PRIORITY, - FILTER_REJECT, - FILTER_DROP, -}; - - - -int pico_ipv4_filter_add(struct pico_device *dev, uint8_t proto, - struct pico_ip4 *out_addr, struct pico_ip4 *out_addr_netmask, struct pico_ip4 *in_addr, - struct pico_ip4 *in_addr_netmask, uint16_t out_port, uint16_t in_port, - int8_t priority, uint8_t tos, enum filter_action action); - -int pico_ipv4_filter_del(uint8_t filter_id); - -int ipfilter(struct pico_frame *f); - -#endif /* _INCLUDE_PICO_IPFILTER */ -
--- a/modules/pico_ipv4.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1418 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Authors: Daniele Lacamera, Markian Yskout -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_ipfilter.h" -#include "pico_ipv4.h" -#include "pico_icmp4.h" -#include "pico_stack.h" -#include "pico_eth.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "pico_device.h" -#include "pico_nat.h" -#include "pico_igmp.h" -#include "pico_tree.h" - -#ifdef PICO_SUPPORT_IPV4 - -#ifdef PICO_SUPPORT_MCAST -# define ip_mcast_dbg(...) do{}while(0) /* so_mcast_dbg in pico_socket.c */ -# define PICO_MCAST_ALL_HOSTS long_be(0xE0000001) /* 224.0.0.1 */ -/* Default network interface for multicast transmission */ -static struct pico_ipv4_link *mcast_default_link = NULL; -#endif -#ifdef PICO_SUPPORT_IPFRAG -# define reassembly_dbg(...) do{}while(0) -#endif - -/* Queues */ -static struct pico_queue in = {}; -static struct pico_queue out = {}; - -/* Functions */ -static int ipv4_route_compare(void *ka, void * kb); - -int pico_ipv4_to_string(char *ipbuf, const uint32_t ip) -{ - const unsigned char *addr = (unsigned char *) &ip; - int i; - - if (!ipbuf) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - for(i = 0; i < 4; i++) - { - if(addr[i] > 99){ - *ipbuf++ = '0' + (addr[i] / 100); - *ipbuf++ = '0' + ((addr[i] % 100) / 10); - *ipbuf++ = '0' + ((addr[i] % 100) % 10); - }else if(addr[i] > 9){ - *ipbuf++ = '0' + (addr[i] / 10); - *ipbuf++ = '0' + (addr[i] % 10); - }else{ - *ipbuf++ = '0' + addr[i]; - } - if(i < 3) - *ipbuf++ = '.'; - } - *ipbuf = '\0'; - - return 0; -} - -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip) -{ - unsigned char buf[4] = {0}; - int cnt = 0; - int p; - - if(!ipstr || !ip) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - while((p = *ipstr++) != 0) - { - if(pico_is_digit(p)){ - buf[cnt] = (10 * buf[cnt]) + (p - '0'); - }else if(p == '.'){ - cnt++; - }else{ - return -1; - } - } - - /* Handle short notation */ - if(cnt == 1){ - buf[3] = buf[1]; - buf[1] = 0; - buf[2] = 0; - }else if (cnt == 2){ - buf[3] = buf[2]; - buf[2] = 0; - }else if(cnt != 3){ - /* String could not be parsed, return error */ - return -1; - } - - *ip = long_from(buf); - - return 0; - -} - -int pico_ipv4_valid_netmask(uint32_t mask) -{ - int cnt = 0; - int end = 0; - int i; - uint32_t mask_swap = long_be(mask); - - /* - * Swap bytes for convenient parsing - * e.g. 0x..f8ff will become 0xfff8.. - * Then, we count the consecutive bits - * - * */ - - for(i = 0; i < 32; i++){ - if((mask_swap << i) & (1 << 31)){ - if(end) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - cnt++; - }else{ - end = 1; - } - } - return cnt; -} - -int pico_ipv4_is_unicast(uint32_t address) -{ - const unsigned char *addr = (unsigned char *) &address; - if((addr[0] & 0xe0) == 0xe0) - return 0; /* multicast */ - - return 1; -} - -int pico_ipv4_is_multicast(uint32_t address) -{ - const unsigned char *addr = (unsigned char *) &address; - if((addr[0] != 0xff) && ((addr[0] & 0xe0) == 0xe0)) - return 1; /* multicast */ - - return 0; -} - -static int pico_ipv4_checksum(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) - return -1; - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, f->net_len)); - return 0; -} - -#ifdef PICO_SUPPORT_IPFRAG -struct pico_ipv4_fragmented_packet { - uint16_t id; - uint8_t proto; - struct pico_ip4 src; - struct pico_ip4 dst; - uint16_t total_len; - struct pico_tree *t; -}; - -static int pico_ipv4_fragmented_packet_cmp(void *ka, void *kb) -{ - struct pico_ipv4_fragmented_packet *a = ka, *b = kb; - - if (a->id < b->id) - return -1; - else if (a->id > b->id) - return 1; - else { - if (a->proto < b->proto) - return -1; - else if (a->proto > b->proto) - return 1; - else { - if (a->src.addr < b->src.addr) - return -1; - else if (a->src.addr > b->src.addr) - return 1; - else { - if (a->dst.addr < b->dst.addr) - return -1; - else if (a->dst.addr > b->dst.addr) - return 1; - else - return 0; - } - } - } -} - -static int pico_ipv4_fragmented_element_cmp(void *ka, void *kb) -{ - struct pico_frame *frame_a = ka, *frame_b = kb; - struct pico_ipv4_hdr *a, *b; - a = (struct pico_ipv4_hdr *) frame_a->net_hdr; - b = (struct pico_ipv4_hdr *) frame_b->net_hdr; - - if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) < short_be((b->frag & PICO_IPV4_FRAG_MASK))) - return -1; - else if (short_be((a->frag & PICO_IPV4_FRAG_MASK)) > short_be((b->frag & PICO_IPV4_FRAG_MASK))) - return 1; - else - return 0; -} - -PICO_TREE_DECLARE(pico_ipv4_fragmented_tree, pico_ipv4_fragmented_packet_cmp); - -static inline void pico_ipv4_fragmented_cleanup(struct pico_ipv4_fragmented_packet *pfrag) -{ - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_frame *f_frag = NULL; - - pico_tree_foreach_safe(index, pfrag->t, _tmp) { - f_frag = index->keyValue; - reassembly_dbg("REASSEMBLY: remove packet with offset %u\n", short_be(((struct pico_ipv4_hdr *)f_frag->net_hdr)->frag) & PICO_IPV4_FRAG_MASK); - pico_tree_delete(pfrag->t, f_frag); - pico_frame_discard(f_frag); - } - pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag); - pico_free(pfrag->t); - pico_free(pfrag); -} -#endif /* PICO_SUPPORT_IPFRAG */ - -#ifdef PICO_SUPPORT_IPFRAG -static inline int pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f) -{ - uint8_t *running_pointer = NULL; - uint16_t running_offset = 0; - uint16_t offset = 0; - uint16_t data_len = 0; - struct pico_ipv4_hdr *f_frag_hdr = NULL, *hdr = (struct pico_ipv4_hdr *) (*f)->net_hdr; - struct pico_udp_hdr *udp_hdr = NULL; - struct pico_tcp_hdr *tcp_hdr = NULL; - struct pico_ipv4_fragmented_packet *pfrag = NULL, frag; - struct pico_frame *f_new = NULL, *f_frag = NULL; - struct pico_tree_node *index, *_tmp; - - data_len = short_be(hdr->len) - (*f)->net_len; - offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK; - if (short_be(hdr->frag) & PICO_IPV4_MOREFRAG) { - if (!offset) { - reassembly_dbg("REASSEMBLY: first element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); - if (!pico_tree_empty(&pico_ipv4_fragmented_tree)) { - reassembly_dbg("REASSEMBLY: cleanup tree\n"); - // only one entry allowed in this tree - pfrag = pico_tree_first(&pico_ipv4_fragmented_tree); - pico_ipv4_fragmented_cleanup(pfrag); - } - // add entry in tree for this ID and create secondary tree to contain fragmented elements - pfrag = pico_zalloc(sizeof(struct pico_ipv4_fragmented_packet)); - if (!pfrag) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - pfrag->id = short_be(hdr->id); - pfrag->proto = hdr->proto; - pfrag->src.addr = long_be(hdr->src.addr); - pfrag->dst.addr = long_be(hdr->dst.addr); - pfrag->total_len = short_be(hdr->len) - (*f)->net_len; - pfrag->t = pico_zalloc(sizeof(struct pico_tree)); - if (!pfrag->t) { - pico_free(pfrag); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - pfrag->t->root = &LEAF; - pfrag->t->compare = pico_ipv4_fragmented_element_cmp; - - pico_tree_insert(pfrag->t, *f); - pico_tree_insert(&pico_ipv4_fragmented_tree, pfrag); - return 0; - } - else { - reassembly_dbg("REASSEMBLY: intermediate element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); - frag.id = short_be(hdr->id); - frag.proto = hdr->proto; - frag.src.addr = long_be(hdr->src.addr); - frag.dst.addr = long_be(hdr->dst.addr); - pfrag = pico_tree_findKey(&pico_ipv4_fragmented_tree, &frag); - if (pfrag) { - pfrag->total_len += (short_be(hdr->len) - (*f)->net_len); - pico_tree_insert(pfrag->t, *f); - return 0; - } else { - reassembly_dbg("REASSEMBLY: silently discard intermediate frame, first packet was lost or disallowed (one fragmented packet at a time)\n"); - pico_frame_discard(*f); - return 0; - } - } - } else if (offset) { - reassembly_dbg("REASSEMBLY: last element of a fragmented packet with id %X and offset %u\n", short_be(hdr->id), offset); - frag.id = short_be(hdr->id); - frag.proto = hdr->proto; - frag.src.addr = long_be(hdr->src.addr); - frag.dst.addr = long_be(hdr->dst.addr); - pfrag = pico_tree_findKey(&pico_ipv4_fragmented_tree, &frag); - if (pfrag) { - pfrag->total_len += (short_be(hdr->len) - (*f)->net_len); - reassembly_dbg("REASSEMBLY: fragmented packet in tree, reassemble packet of %u data bytes\n", pfrag->total_len); - f_new = self->alloc(self, pfrag->total_len); - - f_frag = pico_tree_first(pfrag->t); - reassembly_dbg("REASSEMBLY: copy IP header information len = %lu\n", f_frag->net_len); - f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr; - data_len = short_be(f_frag_hdr->len) - f_frag->net_len; - memcpy(f_new->net_hdr, f_frag->net_hdr, f_frag->net_len); - memcpy(f_new->transport_hdr, f_frag->transport_hdr, data_len); - running_pointer = f_new->transport_hdr + data_len; - offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK; - running_offset = data_len / 8; - pico_tree_delete(pfrag->t, f_frag); - pico_frame_discard(f_frag); - reassembly_dbg("REASSEMBLY: reassembled first packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); - - pico_tree_foreach_safe(index, pfrag->t, _tmp) - { - f_frag = index->keyValue; - f_frag_hdr = (struct pico_ipv4_hdr *)f_frag->net_hdr; - data_len = short_be(f_frag_hdr->len) - f_frag->net_len; - memcpy(running_pointer, f_frag->transport_hdr, data_len); - running_pointer += data_len; - offset = short_be(f_frag_hdr->frag) & PICO_IPV4_FRAG_MASK; - if (offset != running_offset) { - reassembly_dbg("REASSEMBLY: error reassembling intermediate packet: offset %u != expected offset %u (missing fragment)\n", offset, running_offset); - pico_ipv4_fragmented_cleanup(pfrag); - return -1; - } - running_offset += (data_len / 8); - pico_tree_delete(pfrag->t, f_frag); - pico_frame_discard(f_frag); - reassembly_dbg("REASSEMBLY: reassembled intermediate packet of %u data bytes, offset = %u next expected offset = %u\n", data_len, offset, running_offset); - } - pico_tree_delete(&pico_ipv4_fragmented_tree, pfrag); - pico_free(pfrag); - - data_len = short_be(hdr->len) - (*f)->net_len; - memcpy(running_pointer, (*f)->transport_hdr, data_len); - offset = short_be(hdr->frag) & PICO_IPV4_FRAG_MASK; - pico_frame_discard(*f); - reassembly_dbg("REASSEMBLY: reassembled last packet of %u data bytes, offset = %u\n", data_len, offset); - - hdr = (struct pico_ipv4_hdr *)f_new->net_hdr; - hdr->len = pfrag->total_len; - hdr->frag = 0; /* flags cleared and no offset */ - hdr->crc = 0; - hdr->crc = short_be(pico_checksum(hdr, f_new->net_len)); - /* Optional, the UDP/TCP CRC should already be correct */ - if (0) { - #ifdef PICO_SUPPORT_TCP - } else if (hdr->proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; - tcp_hdr->crc = 0; - tcp_hdr->crc = short_be(pico_tcp_checksum_ipv4(f_new)); - #endif - #ifdef PICO_SUPPORT_UDP - } else if (hdr->proto == PICO_PROTO_UDP){ - udp_hdr = (struct pico_udp_hdr *) f_new->transport_hdr; - udp_hdr->crc = 0; - udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f_new)); - #endif - } - reassembly_dbg("REASSEMBLY: packet with id %X reassembled correctly\n", short_be(hdr->id)); - *f = f_new; - return 1; - } else { - reassembly_dbg("REASSEMBLY: silently discard last frame, first packet was lost or disallowed (one fragmented packet at a time)\n"); - pico_frame_discard(*f); - return 0; - } - } else { - return 1; - } -} -#else -static inline int pico_ipv4_fragmented_check(struct pico_protocol *self, struct pico_frame **f) -{ - return 1; -} -#endif /* PICO_SUPPORT_IPFRAG */ - -#ifdef PICO_SUPPORT_CRC -static inline int pico_ipv4_crc_check(struct pico_frame *f) -{ - uint16_t checksum_invalid = 1; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - checksum_invalid = short_be(pico_checksum(hdr, f->net_len)); - if (checksum_invalid) { - dbg("IP: checksum failed!\n"); - pico_frame_discard(f); - return 0; - } - return 1; -} -#else -static inline int pico_ipv4_crc_check(struct pico_frame *f) -{ - return 1; -} -#endif /* PICO_SUPPORT_CRC */ - -static int pico_ipv4_forward(struct pico_frame *f); -#ifdef PICO_SUPPORT_MCAST -static int pico_ipv4_mcast_filter(struct pico_frame *f); -#endif - -static int ipv4_link_compare(void *ka, void *kb) -{ - struct pico_ipv4_link *a = ka, *b =kb; - if (a->address.addr < b->address.addr) - return -1; - if (a->address.addr > b->address.addr) - return 1; - - //zero can be assigned multiple times (e.g. for DHCP) - if (a->dev != NULL && b->dev != NULL && a->address.addr == PICO_IP4_ANY && b->address.addr == PICO_IP4_ANY){ - if (a->dev < b->dev) - return -1; - if (a->dev > b->dev) - return 1; - } - return 0; -} - -PICO_TREE_DECLARE(Tree_dev_link, ipv4_link_compare); - -static int pico_ipv4_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - uint8_t option_len = 0; - int ret = 0; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_ipv4_link test = {.address = {.addr = PICO_IP4_ANY}, .dev = NULL}; - - /* NAT needs transport header information */ - if(((hdr->vhl) & 0x0F )> 5){ - option_len = 4*(((hdr->vhl) & 0x0F)-5); - } - f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR + option_len; - f->transport_len = short_be(hdr->len) - PICO_SIZE_IP4HDR - option_len; - f->net_len = PICO_SIZE_IP4HDR + option_len; - -#ifdef PICO_SUPPORT_IPFILTER - if (ipfilter(f)) { - /*pico_frame is discarded as result of the filtering*/ - return 0; - } -#endif - - /* ret == 1 indicates to continue the function */ - ret = pico_ipv4_crc_check(f); - if (ret < 1) - return ret; - ret = pico_ipv4_fragmented_check(self, &f); - if (ret < 1) - return ret; - -#ifdef PICO_SUPPORT_MCAST - /* Multicast address in source, discard quietly */ - if (pico_ipv4_is_multicast(hdr->src.addr)) { - ip_mcast_dbg("MCAST: ERROR multicast address %08X in source address\n", hdr->src.addr); - pico_frame_discard(f); - return 0; - } -#endif - if (hdr->frag & 0x80) { - pico_frame_discard(f); //RFC 3514 - return 0; - } - if (0) { -#ifdef PICO_SUPPORT_UDP - } else if (pico_ipv4_is_broadcast(hdr->dst.addr) && (hdr->proto == PICO_PROTO_UDP)) { - /* Receiving UDP broadcast datagram */ - f->flags |= PICO_FRAME_FLAG_BCAST; - pico_enqueue(pico_proto_udp.q_in, f); -#endif - } else if (pico_ipv4_is_multicast(hdr->dst.addr)) { -#ifdef PICO_SUPPORT_MCAST - /* Receiving UDP multicast datagram TODO set f->flags? */ - if (hdr->proto == PICO_PROTO_IGMP) { - ip_mcast_dbg("MCAST: received IGMP message\n"); - pico_transport_receive(f, PICO_PROTO_IGMP); - } else if ((pico_ipv4_mcast_filter(f) == 0) && (hdr->proto == PICO_PROTO_UDP)) { - pico_enqueue(pico_proto_udp.q_in, f); - } else { - pico_frame_discard(f); - } -#endif - } else if (pico_ipv4_link_find(&hdr->dst)) { - if (pico_ipv4_nat_isenabled_in(f) == 0) { /* if NAT enabled (dst port registerd), do NAT */ - if(pico_ipv4_nat(f, hdr->dst) != 0) { - return -1; - } - pico_ipv4_forward(f); /* Local packet became forward packet after NAT */ - } else { /* no NAT so enqueue to next layer */ - pico_transport_receive(f, hdr->proto); - } - } else if (pico_tree_findKey(&Tree_dev_link, &test)){ -#ifdef PICO_SUPPORT_UDP - //address of this device is apparently 0.0.0.0; might be a DHCP packet - pico_enqueue(pico_proto_udp.q_in, f); -#endif - } else { - /* Packet is not local. Try to forward. */ - if (pico_ipv4_forward(f) != 0) { - pico_frame_discard(f); - } - } - return 0; -} - -PICO_TREE_DECLARE(Routes, ipv4_route_compare); - - -static int pico_ipv4_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - f->start = (uint8_t*) f->net_hdr; - #ifdef PICO_SUPPORT_IPFILTER - if (ipfilter(f)) { - /*pico_frame is discarded as result of the filtering*/ - return 0; - } - #endif - return pico_sendto_dev(f); -} - - -static struct pico_frame *pico_ipv4_alloc(struct pico_protocol *self, int size) -{ - struct pico_frame *f = pico_frame_alloc(size + PICO_SIZE_IP4HDR + PICO_SIZE_ETHHDR); - if (!f) - return NULL; - f->datalink_hdr = f->buffer; - f->net_hdr = f->buffer + PICO_SIZE_ETHHDR; - f->net_len = PICO_SIZE_IP4HDR; - f->transport_hdr = f->net_hdr + PICO_SIZE_IP4HDR; - f->transport_len = size; - f->len = size + PICO_SIZE_IP4HDR; - return f; -} - -static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f); - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_ipv4 = { - .name = "ipv4", - .proto_number = PICO_PROTO_IPV4, - .layer = PICO_LAYER_NETWORK, - .alloc = pico_ipv4_alloc, - .process_in = pico_ipv4_process_in, - .process_out = pico_ipv4_process_out, - .push = pico_ipv4_frame_sock_push, - .q_in = &in, - .q_out = &out, -}; - -struct pico_ipv4_route -{ - struct pico_ip4 dest; - struct pico_ip4 netmask; - struct pico_ip4 gateway; - struct pico_ipv4_link *link; - uint32_t metric; -}; - - -static int ipv4_route_compare(void *ka, void * kb) -{ - struct pico_ipv4_route *a = ka, *b = kb; - - /* Routes are sorted by (host side) netmask len, then by addr, then by metric. */ - if (long_be(a->netmask.addr) < long_be(b->netmask.addr)) - return -1; - - if (long_be(a->netmask.addr) > long_be(b->netmask.addr)) - return 1; - - if (a->dest.addr < b->dest.addr) - return -1; - - if (a->dest.addr > b->dest.addr) - return 1; - - if (a->metric < b->metric) - return -1; - - if (a->metric > b->metric) - return 1; - - return 0; -} - -static struct pico_ipv4_route *route_find(struct pico_ip4 *addr) -{ - struct pico_ipv4_route *r; - struct pico_tree_node * index; - - if(addr->addr != PICO_IP4_BCAST) - { - pico_tree_foreach_reverse(index, &Routes) { - r = index->keyValue; - if ((addr->addr & (r->netmask.addr)) == (r->dest.addr)) { - return r; - } - } - } - else - { - r = pico_tree_first(&Routes); - if(!r->netmask.addr) - { - return r; - } - else - { - dbg("WARNING: no default route for a global broadcast found\n"); - } - } - - return NULL; -} - -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr) -{ - struct pico_ip4 nullip; - struct pico_ipv4_route *route; - nullip.addr = 0U; - - if(!addr) { - pico_err = PICO_ERR_EINVAL; - return nullip; - } - - route = route_find(addr); - if (!route) { - pico_err = PICO_ERR_EHOSTUNREACH; - return nullip; - } - else - return route->gateway; -} - -struct pico_ip4 *pico_ipv4_source_find(struct pico_ip4 *dst) -{ - struct pico_ip4 *myself = NULL; - struct pico_ipv4_route *rt; - - if(!dst) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - rt = route_find(dst); - if (rt) { - myself = &rt->link->address; - } else - pico_err = PICO_ERR_EHOSTUNREACH; - return myself; -} - - -#ifdef PICO_SUPPORT_MCAST -/* link - * | - * MCASTGroups - * | | | - * ------------ | ------------ - * | | | - * MCASTSources MCASTSources MCASTSources - * | | | | | | | | | | | | - * S S S S S S S S S S S S - * - * MCASTGroups: RBTree(mcast_group) - * MCASTSources: RBTree(source) - */ -static int ipv4_mcast_groups_cmp(void * ka, void * kb) -{ - struct pico_mcast_group *a = ka, *b = kb; - if (a->mcast_addr.addr < b->mcast_addr.addr) { - return -1; - } else if (a->mcast_addr.addr > b->mcast_addr.addr) { - return 1; - } else { - return 0; - } -} - -static int ipv4_mcast_sources_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - if (a->addr < b->addr) - return -1; - if (a->addr > b->addr) - return 1; - return 0; -} - -static void pico_ipv4_mcast_print_groups(struct pico_ipv4_link *mcast_link) -{ - uint16_t i = 0; - struct pico_mcast_group __attribute__ ((unused)) *g = NULL; - struct pico_ip4 __attribute__ ((unused)) *source = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - - ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - ip_mcast_dbg("+ MULTICAST list interface %-16s +\n", mcast_link->dev->name); - ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); - ip_mcast_dbg("+ nr | interface | host group | reference count | filter mode | source +\n"); - ip_mcast_dbg("+---------------------------------------------------------------------------------+\n"); - - pico_tree_foreach(index, mcast_link->MCASTGroups) - { - g = index->keyValue; - ip_mcast_dbg("+ %04d | %16s | %08X | %05u | %u | %8s +\n", i, mcast_link->dev->name, g->mcast_addr.addr, g->reference_count, g->filter_mode, ""); - pico_tree_foreach(index2, &g->MCASTSources) - { - source = index2->keyValue; - ip_mcast_dbg("+ %4s | %16s | %8s | %5s | %s | %08X +\n", "", "", "", "", "", source->addr); - } - i++; - } - ip_mcast_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -} - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - struct pico_mcast_group *g = NULL, test = {0}; - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip4 *source = NULL; - - if (mcast_link) - link = pico_ipv4_link_get(mcast_link); - else - link = mcast_default_link; - - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (reference_count) - g->reference_count++; - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); - } else { - g = pico_zalloc(sizeof(struct pico_mcast_group)); - if (!g) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - /* "non-existent" state of filter mode INCLUDE and empty source list */ - g->filter_mode = PICO_IP_MULTICAST_INCLUDE; - g->reference_count = 1; - g->mcast_addr = *mcast_group; - g->MCASTSources.root = &LEAF; - g->MCASTSources.compare = ipv4_mcast_sources_cmp; - pico_tree_insert(link->MCASTGroups, g); - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_CREATE); - } - - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) - { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - pico_free(source); - } - /* insert new filter */ - if (MCASTFilter) { - pico_tree_foreach(index, MCASTFilter) - { - source = pico_zalloc(sizeof(struct pico_ip4)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source->addr = ((struct pico_ip4 *)index->keyValue)->addr; - pico_tree_insert(&g->MCASTSources, source); - } - } - g->filter_mode = filter_mode; - - pico_ipv4_mcast_print_groups(link); - return 0; -} - -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - - struct pico_mcast_group *g = NULL, test = {0}; - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL; - struct pico_ip4 *source = NULL; - - if (mcast_link) - link = pico_ipv4_link_get(mcast_link); - else - link = mcast_default_link; - - test.mcast_addr = *mcast_group; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (!g) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - if (reference_count && (--(g->reference_count) < 1)) { - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_DELETE); - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) - { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - pico_free(source); - } - pico_tree_delete(link->MCASTGroups, g); - pico_free(g); - } else { - pico_igmp_state_change(mcast_link, mcast_group, filter_mode, MCASTFilter, PICO_IGMP_STATE_UPDATE); - /* cleanup filter */ - pico_tree_foreach_safe(index, &g->MCASTSources, _tmp) - { - source = index->keyValue; - pico_tree_delete(&g->MCASTSources, source); - pico_free(source); - } - /* insert new filter */ - if (MCASTFilter) { - pico_tree_foreach(index, MCASTFilter) - { - source = pico_zalloc(sizeof(struct pico_ip4)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source->addr = ((struct pico_ip4 *)index->keyValue)->addr; - pico_tree_insert(&g->MCASTSources, source); - } - } - g->filter_mode = filter_mode; - } - } - - pico_ipv4_mcast_print_groups(link); - return 0; -} - -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) -{ - return mcast_default_link; -} - -static int pico_ipv4_mcast_filter(struct pico_frame *f) -{ - struct pico_ipv4_link *link = NULL; - struct pico_tree_node *index = NULL, *index2 = NULL; - struct pico_mcast_group *g = NULL, test = {0}; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - test.mcast_addr = hdr->dst; - - pico_tree_foreach(index, &Tree_dev_link) - { - link = index->keyValue; - g = pico_tree_findKey(link->MCASTGroups, &test); - if (g) { - if (f->dev == link->dev) { - ip_mcast_dbg("MCAST: IP %08X is group member of current link %s\n", hdr->dst.addr, f->dev->name); - /* perform source filtering */ - switch (g->filter_mode) - { - case PICO_IP_MULTICAST_INCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) - { - if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { - ip_mcast_dbg("MCAST: IP %08X in included interface source list\n", hdr->src.addr); - return 0; - } - } - ip_mcast_dbg("MCAST: IP %08X NOT in included interface source list\n", hdr->src.addr); - return -1; - break; - - case PICO_IP_MULTICAST_EXCLUDE: - pico_tree_foreach(index2, &g->MCASTSources) - { - if (hdr->src.addr == ((struct pico_ip4 *)index2->keyValue)->addr) { - ip_mcast_dbg("MCAST: IP %08X in excluded interface source list\n", hdr->src.addr); - return -1; - } - } - ip_mcast_dbg("MCAST: IP %08X NOT in excluded interface source list\n", hdr->src.addr); - return 0; - break; - - default: - return -1; - break; - } - } else { - ip_mcast_dbg("MCAST: IP %08X is group member of different link %s\n", hdr->dst.addr, link->dev->name); - } - } else { - ip_mcast_dbg("MCAST: IP %08X is not a group member of link %s\n", hdr->dst.addr, f->dev->name); - } - } - return -1; -} - -#else - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; -} -#endif /* PICO_SUPPORT_MCAST */ - -int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto) -{ - - struct pico_ipv4_route *route; - struct pico_ipv4_link *link; - struct pico_ipv4_hdr *hdr; - uint8_t ttl = PICO_IPV4_DEFAULT_TTL; - uint8_t vhl = 0x45; /* version 4, header length 20 */ - static uint16_t ipv4_progressive_id = 0x91c0; -#ifdef PICO_SUPPORT_MCAST - struct pico_tree_node *index; -#endif - - if(!f || !dst) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) { - dbg("IP header error\n"); - pico_err = PICO_ERR_EINVAL; - goto drop; - } - - if (dst->addr == 0) { - dbg("IP destination addr error\n"); - pico_err = PICO_ERR_EINVAL; - goto drop; - } - - route = route_find(dst); - if (!route) { - dbg("Route to %08x not found.\n", long_be(dst->addr)); - pico_err = PICO_ERR_EHOSTUNREACH; - goto drop; - } else { - link = route->link; -#ifdef PICO_SUPPORT_MCAST - if (pico_ipv4_is_multicast(dst->addr)) { /* if multicast */ - switch (proto) { - case PICO_PROTO_UDP: - if(pico_udp_get_mc_ttl(f->sock, &ttl) < 0) - ttl = PICO_IP_DEFAULT_MULTICAST_TTL; - break; - case PICO_PROTO_IGMP: - vhl = 0x46; /* header length 24 */ - ttl = 1; - /* router alert (RFC 2113) */ - hdr->options[0] = 0x94; - hdr->options[1] = 0x04; - hdr->options[2] = 0x00; - hdr->options[3] = 0x00; - if (f->dev && link->dev != f->dev) { /* default link is not requested link */ - pico_tree_foreach(index, &Tree_dev_link) { - link = index->keyValue; - if (link->dev == f->dev) - break; - } - } - break; - default: - ttl = PICO_IPV4_DEFAULT_TTL; - } - } -#endif - } - - hdr->vhl = vhl; - hdr->len = short_be(f->transport_len + f->net_len); - if (f->transport_hdr != f->payload) - ipv4_progressive_id++; - hdr->id = short_be(ipv4_progressive_id); - hdr->dst.addr = dst->addr; - hdr->src.addr = link->address.addr; - hdr->ttl = ttl; - hdr->proto = proto; - hdr->frag = short_be(PICO_IPV4_DONTFRAG); -#ifdef PICO_SUPPORT_IPFRAG -# ifdef PICO_SUPPORT_UDP - if (proto == PICO_PROTO_UDP) { - /* first fragment, can not use transport_len to calculate IP length */ - if (f->transport_hdr != f->payload) - hdr->len = short_be(f->payload_len + sizeof(struct pico_udp_hdr) + f->net_len); - /* set fragmentation flags and offset calculated in socket layer */ - hdr->frag = f->frag; - } -# endif /* PICO_SUPPORT_UDP */ -#endif /* PICO_SUPPORT_IPFRAG */ - pico_ipv4_checksum(f); - - if (f->sock && f->sock->dev){ - //if the socket has its device set, use that (currently used for DHCP) - f->dev = f->sock->dev; - } else { - f->dev = link->dev; - } - -#ifdef PICO_SUPPORT_MCAST - if (pico_ipv4_is_multicast(hdr->dst.addr)) { - struct pico_frame *cpy; - /* Sending UDP multicast datagram, am I member? If so, loopback copy */ - if ((proto != PICO_PROTO_IGMP) && (pico_ipv4_mcast_filter(f) == 0)) { - ip_mcast_dbg("MCAST: sender is member of group, loopback copy\n"); - cpy = pico_frame_copy(f); - pico_enqueue(&in, cpy); - } - } -#endif - - if(pico_ipv4_link_get(&hdr->dst)){ - //it's our own IP - return pico_enqueue(&in, f); - }else{ - /* TODO: Check if there are members subscribed here */ - return pico_enqueue(&out, f); - } - -drop: - pico_frame_discard(f); - return -1; -} - - -static int pico_ipv4_frame_sock_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_ip4 *dst; - struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info; - if (!f->sock) { - pico_frame_discard(f); - return -1; - } - - if (remote_duple) { - dst = &remote_duple->remote_addr.ip4; - } else { - dst = &f->sock->remote_addr.ip4; - } - - return pico_ipv4_frame_push(f, dst, f->sock->proto->proto_number); -} - - -#ifdef DEBUG_ROUTE -static void dbg_route(void) -{ - struct pico_ipv4_route *r; - struct pico_tree_node * index; - pico_tree_foreach(index,&Routes){ - r = index->keyValue; - dbg("Route to %08x/%08x, gw %08x, dev: %s, metric: %d\n", r->dest.addr, r->netmask.addr, r->gateway.addr, r->link->dev->name, r->metric); - } -} -#else -#define dbg_route() do{ }while(0) -#endif - -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) -{ - struct pico_ipv4_route test, *new; - test.dest.addr = address.addr; - test.netmask.addr = netmask.addr; - test.metric = metric; - - if(pico_tree_findKey(&Routes,&test)){ - pico_err = PICO_ERR_EINVAL; - return -1; - } - - new = pico_zalloc(sizeof(struct pico_ipv4_route)); - if (!new) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - new->dest.addr = address.addr; - new->netmask.addr = netmask.addr; - new->gateway.addr = gateway.addr; - new->metric = metric; - if (gateway.addr == 0) { - /* No gateway provided, use the link */ - new->link = link; - } else { - struct pico_ipv4_route *r = route_find(&gateway); - if (!r ) { /* Specified Gateway is unreachable */ - pico_err = PICO_ERR_EHOSTUNREACH; - pico_free(new); - return -1; - } - if (r->gateway.addr) { /* Specified Gateway is not a neighbor */ - pico_err = PICO_ERR_ENETUNREACH; - pico_free(new); - return -1; - } - new->link = r->link; - } - if (!new->link) { - pico_err = PICO_ERR_EINVAL; - pico_free(new); - return -1; - } - - pico_tree_insert(&Routes,new); - dbg_route(); - return 0; -} - -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link) -{ - struct pico_ipv4_route test, *found; - if (!link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - test.dest.addr = address.addr; - test.netmask.addr = netmask.addr; - test.metric = metric; - - found = pico_tree_findKey(&Routes,&test); - if (found) { - - pico_tree_delete(&Routes,found); - pico_free(found); - - dbg_route(); - return 0; - } - pico_err = PICO_ERR_EINVAL; - return -1; -} - - -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask) -{ - struct pico_ipv4_link test, *new; - struct pico_ip4 network, gateway; - char ipstr[30]; - - if(!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - test.address.addr = address.addr; - test.netmask.addr = netmask.addr; - test.dev = dev; - /** XXX: Valid netmask / unicast address test **/ - - if(pico_tree_findKey(&Tree_dev_link, &test)) { - dbg("IPv4: Trying to assign an invalid address (in use)\n"); - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - - /** XXX: Check for network already in use (e.g. trying to assign 10.0.0.1/24 where 10.1.0.1/8 is in use) **/ - new = pico_zalloc(sizeof(struct pico_ipv4_link)); - if (!new) { - dbg("IPv4: Out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - new->address.addr = address.addr; - new->netmask.addr = netmask.addr; - new->dev = dev; -#ifdef PICO_SUPPORT_MCAST - new->MCASTGroups = pico_zalloc(sizeof(struct pico_tree)); - if (!new->MCASTGroups) { - pico_free(new); - dbg("IPv4: Out of memory!\n"); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - new->MCASTGroups->root = &LEAF; - new->MCASTGroups->compare = ipv4_mcast_groups_cmp; - new->mcast_compatibility = PICO_IGMPV3; /* default RFC 3376 $7.2.1 */ - new->mcast_last_query_interval = PICO_IGMP_QUERY_INTERVAL; -#endif - - pico_tree_insert(&Tree_dev_link, new); -#ifdef PICO_SUPPORT_MCAST - do { - struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw; - if (!mcast_default_link) { - mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ - mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ - mcast_gw.addr = long_be(0x00000000); - mcast_default_link = new; - pico_ipv4_route_add(mcast_addr, mcast_nm, mcast_gw, 1, new); - } - mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; - pico_ipv4_mcast_join(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - } while(0); -#endif - - network.addr = address.addr & netmask.addr; - gateway.addr = 0U; - pico_ipv4_route_add(network, netmask, gateway, 1, new); - pico_ipv4_to_string(ipstr, new->address.addr); - dbg("Assigned ipv4 %s to device %s\n", ipstr, new->dev->name); - return 0; -} - - -int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address) -{ - struct pico_ipv4_link test, *found; - struct pico_ip4 network; - - if(!dev) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - test.address.addr = address.addr; - test.dev = dev; - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - network.addr = found->address.addr & found->netmask.addr; - pico_ipv4_route_del(network, found->netmask,pico_ipv4_route_get_gateway(&found->address), 1, found); -#ifdef PICO_SUPPORT_MCAST - do { - struct pico_ip4 mcast_all_hosts, mcast_addr, mcast_nm, mcast_gw; - struct pico_mcast_group *g = NULL; - struct pico_tree_node * index, * _tmp; - if (found == mcast_default_link) { - mcast_addr.addr = long_be(0xE0000000); /* 224.0.0.0 */ - mcast_nm.addr = long_be(0xF0000000); /* 15.0.0.0 */ - mcast_gw.addr = long_be(0x00000000); - mcast_default_link = NULL; - pico_ipv4_route_del(mcast_addr, mcast_nm, mcast_gw, 1, found); - } - mcast_all_hosts.addr = PICO_MCAST_ALL_HOSTS; - pico_ipv4_mcast_leave(&address, &mcast_all_hosts, 1, PICO_IP_MULTICAST_EXCLUDE, NULL); - pico_tree_foreach_safe(index,found->MCASTGroups, _tmp) - { - g = index->keyValue; - pico_tree_delete(found->MCASTGroups, g); - pico_free(g); - } - } while(0); -#endif - - pico_tree_delete(&Tree_dev_link, found); - /* XXX: pico_free(found); */ - /* XXX: cleanup all routes containing the removed link */ - return 0; -} - - -struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address) -{ - struct pico_ipv4_link test = {0}, *found = NULL; - test.address.addr = address->addr; - - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) - return NULL; - else - return found; -} - -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev) -{ - struct pico_tree_node *index = NULL; - struct pico_ipv4_link *link = NULL; - - pico_tree_foreach(index, &Tree_dev_link) - { - link = index->keyValue; - if (link->dev == dev) - return link; - } - return NULL; -} - - -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address) -{ - struct pico_ipv4_link test, *found; - if(!address) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - test.dev = NULL; - test.address.addr = address->addr; - found = pico_tree_findKey(&Tree_dev_link, &test); - if (!found) { - pico_err = PICO_ERR_ENXIO; - return NULL; - } - return found->dev; -} - -int pico_ipv4_rebound(struct pico_frame *f) -{ - struct pico_ip4 dst; - struct pico_ipv4_hdr *hdr; - if(!f) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!hdr) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - dst.addr = hdr->src.addr; - return pico_ipv4_frame_push(f, &dst, hdr->proto); -} - -static int pico_ipv4_forward(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_ipv4_route *rt; - if (!hdr) { - return -1; - } - - //dbg("IP> FORWARDING.\n"); - rt = route_find(&hdr->dst); - if (!rt) { - pico_notify_dest_unreachable(f); - return -1; - } - //dbg("ROUTE: valid..\n"); - f->dev = rt->link->dev; - hdr->ttl-=1; - if (hdr->ttl < 1) { - pico_notify_ttl_expired(f); - return -1; - } - hdr->crc++; - - /* check if NAT enbled on link and do NAT if so */ - if (pico_ipv4_nat_isenabled_out(rt->link) == 0) - pico_ipv4_nat(f, rt->link->address); - - //dbg("Routing towards %s\n", f->dev->name); - f->start = f->net_hdr; - if(f->dev->eth != NULL) - f->len -= PICO_SIZE_ETHHDR; - pico_sendto_dev(f); - return 0; - -} - -int pico_ipv4_is_broadcast(uint32_t addr) -{ - struct pico_ipv4_link *link; - struct pico_tree_node * index; - if (addr == PICO_IP4_ANY) - return 1; - if (addr == PICO_IP4_BCAST) - return 1; - - pico_tree_foreach(index,&Tree_dev_link) { - link = index->keyValue; - if ((link->address.addr | (~link->netmask.addr)) == addr) - return 1; - } - return 0; -} - -void pico_ipv4_unreachable(struct pico_frame *f, int err) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; -#if defined PICO_SUPPORT_TCP || defined PICO_SUPPORT_UDP - f->transport_hdr = ((uint8_t *)f->net_hdr) + PICO_SIZE_IP4HDR; - pico_transport_error(f, hdr->proto, err); -#endif -} - -#endif
--- a/modules/pico_ipv4.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,96 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_IPV4 -#define _INCLUDE_PICO_IPV4 -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_tree.h" - -#define PICO_IPV4_INADDR_ANY 0x00000000U - -#define PICO_SIZE_IP4HDR ((sizeof(struct pico_ipv4_hdr))) -#define PICO_IPV4_DONTFRAG 0x4000 -#define PICO_IPV4_MOREFRAG 0x2000 -#define PICO_IPV4_FRAG_MASK 0x1FFF -#define PICO_IPV4_DEFAULT_TTL 64 - -extern struct pico_protocol pico_proto_ipv4; - -struct __attribute__((packed)) pico_ipv4_hdr { - uint8_t vhl; - uint8_t tos; - uint16_t len; - uint16_t id; - uint16_t frag; - uint8_t ttl; - uint8_t proto; - uint16_t crc; - struct pico_ip4 src; - struct pico_ip4 dst; - uint8_t options[0]; -}; - -struct __attribute__((packed)) pico_ipv4_pseudo_hdr -{ - struct pico_ip4 src; - struct pico_ip4 dst; - uint8_t zeros; - uint8_t proto; - uint16_t len; -}; - -/* Interface: link to device */ -struct pico_mcast_list; - -struct pico_ipv4_link -{ - struct pico_device *dev; - struct pico_ip4 address; - struct pico_ip4 netmask; -#ifdef PICO_SUPPORT_MCAST - struct pico_tree *MCASTGroups; - uint8_t mcast_compatibility; - uint8_t mcast_last_query_interval; -#endif -}; - -#ifdef PICO_SUPPORT_MCAST -struct pico_mcast_group { - uint8_t filter_mode; - uint16_t reference_count; - struct pico_ip4 mcast_addr; - struct pico_tree MCASTSources; -}; -#endif - -int pico_ipv4_to_string(char *ipbuf, const uint32_t ip); -int pico_string_to_ipv4(const char *ipstr, uint32_t *ip); -int pico_ipv4_valid_netmask(uint32_t mask); -int pico_ipv4_is_unicast(uint32_t address); -int pico_ipv4_is_multicast(uint32_t address); -int pico_ipv4_is_broadcast(uint32_t addr); - -int pico_ipv4_link_add(struct pico_device *dev, struct pico_ip4 address, struct pico_ip4 netmask); -int pico_ipv4_link_del(struct pico_device *dev, struct pico_ip4 address); -int pico_ipv4_rebound(struct pico_frame *f); - -int pico_ipv4_frame_push(struct pico_frame *f, struct pico_ip4 *dst, uint8_t proto); -struct pico_ipv4_link *pico_ipv4_link_get(struct pico_ip4 *address); -struct pico_ipv4_link *pico_ipv4_link_by_dev(struct pico_device *dev); -struct pico_device *pico_ipv4_link_find(struct pico_ip4 *address); -struct pico_ip4 *pico_ipv4_source_find(struct pico_ip4 *dst); -int pico_ipv4_route_add(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -int pico_ipv4_route_del(struct pico_ip4 address, struct pico_ip4 netmask, struct pico_ip4 gateway, int metric, struct pico_ipv4_link *link); -struct pico_ip4 pico_ipv4_route_get_gateway(struct pico_ip4 *addr); -void pico_ipv4_unreachable(struct pico_frame *f, int err); - -int pico_ipv4_mcast_join(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter); -int pico_ipv4_mcast_leave(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group, uint8_t reference_count, uint8_t filter_mode, struct pico_tree *MCASTFilter); -struct pico_ipv4_link *pico_ipv4_get_default_mcastlink(void); - -#endif /* _INCLUDE_PICO_IPV4 */
--- a/modules/pico_ipv6.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,30 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_IPV6 -#define _INCLUDE_PICO_IPV6 -#include "pico_addressing.h" -#include "pico_protocol.h" - -extern struct pico_protocol pico_proto_ipv6; -extern const uint8_t PICO_IPV6_ANY[PICO_SIZE_IP6]; - - -/* This module is responsible for routing outgoing packets and - * delivering incoming packets to other layers - */ - -/* Interface for processing incoming ipv6 packets (decap/deliver) */ -int pico_ipv6_process_in(struct pico_frame *f); - -/* Interface for processing outgoing ipv6 frames (encap/push) */ -int pico_ipv6_process_out(struct pico_frame *f); - -/* Return estimated overhead for ipv6 frames to define allocation */ -int pico_ipv6_overhead(struct pico_frame *f); - -#endif
--- a/modules/pico_mbed.cpp Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,21 +0,0 @@ -#include <mbed.h> -#include <rtos.h> - -extern "C" { - void *pico_mutex_init(void) - { - return new Mutex(); - } - - void pico_mutex_lock(void *_m) - { - Mutex *m = (Mutex *)_m; - m->lock(); - } - - void pico_mutex_unlock(void *_m) - { - Mutex *m = (Mutex *)_m; - m->unlock(); - } -}
--- a/modules/pico_nat.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,683 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Kristof Roelants, Brecht Van Cauwenberghe, - Simon Maes, Philippe Mariman -*********************************************************************/ - -#include "pico_stack.h" -#include "pico_frame.h" -#include "pico_tcp.h" -#include "pico_udp.h" -#include "pico_ipv4.h" -#include "pico_addressing.h" -#include "pico_nat.h" - - -#ifdef PICO_SUPPORT_IPV4 -#ifdef PICO_SUPPORT_NAT - -#define nat_dbg(...) do{}while(0) -//#define nat_dbg dbg -#define NAT_TCP_TIMEWAIT 240000 /* 4mins (in msec) */ -//#define NAT_TCP_TIMEWAIT 10000 /* 10 sec (in msec) - for testing purposes only*/ - - -struct pico_nat_key { - struct pico_ip4 pub_addr; - uint16_t pub_port; - struct pico_ip4 priv_addr; - uint16_t priv_port; - uint8_t proto; - /* - del_flags: - 1 0 - 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - |F|B|S|R|P|~| CONNECTION ACTIVE | - +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ - - F: FIN from Forwarding packet - B: FIN from Backwarding packet - S: SYN - R: RST - P: Persistant - - */ - uint16_t del_flags; - /* Connector for trees */ -}; - -static struct pico_ipv4_link pub_link; -static uint8_t enable_nat_flag = 0; - -static int nat_cmp_backward(void * ka, void * kb) -{ - struct pico_nat_key *a = ka, *b = kb; - if (a->pub_port < b->pub_port) { - return -1; - } - else if (a->pub_port > b->pub_port) { - return 1; - } - else { - if (a->proto < b->proto) { - return -1; - } - else if (a->proto > b->proto) { - return 1; - } - else { - /* a and b are identical */ - return 0; - } - } -} - -static int nat_cmp_forward(void * ka, void * kb) -{ - struct pico_nat_key *a =ka, *b = kb; - if (a->priv_addr.addr < b->priv_addr.addr) { - return -1; - } - else if (a->priv_addr.addr > b->priv_addr.addr) { - return 1; - } - else { - if (a->priv_port < b->priv_port) { - return -1; - } - else if (a->priv_port > b->priv_port) { - return 1; - } - else { - if (a->proto < b->proto) { - return -1; - } - else if (a->proto > b->proto) { - return 1; - } - else { - /* a and b are identical */ - return 0; - } - } - } -} - -PICO_TREE_DECLARE(KEYTable_forward,nat_cmp_forward); -PICO_TREE_DECLARE(KEYTable_backward,nat_cmp_backward); - -/* - 2 options: - find on proto and pub_port - find on priv_addr, priv_port and proto - zero the unused parameters -*/ -static struct pico_nat_key *pico_ipv4_nat_find_key(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto) -{ - struct pico_nat_key test; - test.pub_port = pub_port; - test.priv_port = priv_port; - test.proto = proto; - if (priv_addr) - test.priv_addr = *priv_addr; - else - test.priv_addr.addr = 0; - - /* returns NULL if test can not be found */ - if (!pub_port) - return pico_tree_findKey(&KEYTable_forward,&test); - else - return pico_tree_findKey(&KEYTable_backward, &test); -} - -int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto) -{ - struct pico_nat_key *k = NULL; - - k = pico_ipv4_nat_find_key(pub_port, priv_addr, priv_port, proto); - if (k) - return 0; - else - return -1; -} - -int pico_ipv4_nat_snif_forward(struct pico_nat_key *nk, struct pico_frame *f) -{ - uint8_t proto; - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_tcp_hdr *tcp_hdr; - - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - if (tcp_hdr->flags & PICO_TCP_FIN) { - nk->del_flags |= PICO_DEL_FLAGS_FIN_FORWARD; //FIN from forwarding packet - } - if (tcp_hdr->flags & PICO_TCP_SYN) { - nk->del_flags |= PICO_DEL_FLAGS_SYN; - } - if (tcp_hdr->flags & PICO_TCP_RST) { - nk->del_flags |= PICO_DEL_FLAGS_RST; - } - } else if (proto == PICO_PROTO_UDP) { - /* set conn active to 1 */ - nk->del_flags &= 0xFE00; - nk->del_flags++; - } - return 0; -} - - -int pico_ipv4_nat_snif_backward(struct pico_nat_key *nk, struct pico_frame *f) -{ - uint8_t proto; - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr; - struct pico_tcp_hdr *tcp_hdr; - - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - if (tcp_hdr->flags & PICO_TCP_FIN) { - nk->del_flags |= PICO_DEL_FLAGS_FIN_BACKWARD; //FIN from backwarding packet - } - if (tcp_hdr->flags & PICO_TCP_SYN) { - nk->del_flags |= PICO_DEL_FLAGS_SYN; - } - if (tcp_hdr->flags & PICO_TCP_RST) { - nk->del_flags |= PICO_DEL_FLAGS_RST; - } - } else if (proto == PICO_PROTO_UDP) { - /* set conn active to 1 */ - nk->del_flags &= 0xFE00; - nk->del_flags++; - } - return 0; -} - -void pico_ipv4_nat_table_cleanup(unsigned long now, void *_unused) -{ - struct pico_tree_node * idx, * safe; - struct pico_nat_key *k = NULL; - nat_dbg("NAT: before table cleanup:\n"); - pico_ipv4_nat_print_table(); - - //struct pico_nat_key *tmp; - pico_tree_foreach_reverse_safe(idx,&KEYTable_forward,safe){ - k = idx->keyValue; - switch (k->proto) - { - case PICO_PROTO_TCP: - if ((k->del_flags & 0x0800) >> 11) { - /* entry is persistant */ - break; - } - else if ((k->del_flags & 0x01FF) == 0) { - /* conn active is zero, delete entry */ - pico_ipv4_nat_del(k->pub_port, k->proto); - } - else if ((k->del_flags & 0x1000) >> 12) { - /* RST flag set, set conn active to zero */ - k->del_flags &= 0xFE00; - } - else if (((k->del_flags & 0x8000) >> 15) && ((k->del_flags & 0x4000) >> 14)) { - /* FIN1 and FIN2 set, set conn active to zero */ - k->del_flags &= 0xFE00; - } - else if ((k->del_flags & 0x01FF) > 360) { - /* conn is active for 24 hours, delete entry */ - pico_ipv4_nat_del(k->pub_port, k->proto); - } - else { - k->del_flags++; - } - break; - - case PICO_PROTO_UDP: - if ((k->del_flags & 0x0800) >> 11) { - /* entry is persistant */ - break; - } - else if ((k->del_flags & 0x01FF) > 1) { - /* Delete entry when it has existed NAT_TCP_TIMEWAIT */ - pico_ipv4_nat_del(k->pub_port, k->proto); - } - else { - k->del_flags++; - } - break; - - default: - /* Unknown protocol in NAT table, delete when it has existed NAT_TCP_TIMEWAIT */ - if ((k->del_flags & 0x01FF) > 1) { - pico_ipv4_nat_del(k->pub_port, k->proto); - } - else { - k->del_flags++; - } - } - } - - nat_dbg("NAT: after table cleanup:\n"); - pico_ipv4_nat_print_table(); - pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL); -} - -int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto) -{ - struct pico_nat_key *key = pico_zalloc(sizeof(struct pico_nat_key)); - if (!key) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - - key->pub_addr = pub_addr; - key->pub_port = pub_port; - key->priv_addr = priv_addr; - key->priv_port = priv_port; - key->proto = proto; - key->del_flags = 0x0001; /* set conn active to 1, other flags to 0 */ - - /* RB_INSERT returns NULL when element added, pointer to the element if already in tree */ - if(!pico_tree_insert(&KEYTable_forward, key) && !pico_tree_insert(&KEYTable_backward, key)){ - return 0; /* New element added */ - } - else { - pico_free(key); - pico_err = PICO_ERR_EINVAL; - return -1; /* Element key already exists */ - } -} - - -int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto) -{ - struct pico_nat_key *key = NULL; - key = pico_ipv4_nat_find_key(pub_port, NULL, 0, proto); - if (!key) { - nat_dbg("NAT: key to delete not found: proto %u | pub_port %u\n", proto, pub_port); - return -1; - } - else { - nat_dbg("NAT: key to delete found: proto %u | pub_port %u\n", proto, pub_port); - /* RB_REMOVE returns pointer to removed element, NULL to indicate error */ - if(pico_tree_delete(&KEYTable_forward, key) && pico_tree_delete(&KEYTable_backward, key)) - pico_free(key); - else - return -1; /* Error on removing element, do not free! */ - } - return 0; -} - -int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant) -{ - struct pico_nat_key *key = NULL; - - switch (persistant) - { - case PICO_IPV4_FORWARD_ADD: - if (pico_ipv4_nat_add(pub_addr, pub_port, priv_addr, priv_port, proto) != 0) - return -1; /* pico_err set in nat_add */ - key = pico_ipv4_nat_find_key(pub_port, &priv_addr, priv_port, proto); - if (!key) { - pico_err = PICO_ERR_EAGAIN; - return -1; - } - key->del_flags = (key->del_flags & ~(0x1 << 11)) | (persistant << 11); - break; - - case PICO_IPV4_FORWARD_DEL: - return pico_ipv4_nat_del(pub_port, proto); - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - pico_ipv4_nat_print_table(); - return 0; -} - - -void pico_ipv4_nat_print_table(void) -{ - struct pico_nat_key __attribute__((unused)) *k = NULL ; - struct pico_tree_node * index; - uint16_t i = 0; - - nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); - nat_dbg("+ NAT table +\n"); - nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n"); - nat_dbg("+ pointer | private_addr | private_port | proto | pub_addr | pub_port | conn active | FIN1 | FIN2 | SYN | RST | PERS +\n"); - nat_dbg("+-----------------------------------------------------------------------------------------------------------------------+\n"); - - pico_tree_foreach(index,&KEYTable_forward){ - k = index->keyValue; - nat_dbg("+ %10p | %08X | %05u | %04u | %08X | %05u | %03u | %u | %u | %u | %u | %u +\n", - k, k->priv_addr.addr, k->priv_port, k->proto, k->pub_addr.addr, k->pub_port, (k->del_flags)&0x01FF, ((k->del_flags)&0x8000)>>15, - ((k->del_flags)&0x4000)>>14, ((k->del_flags)&0x2000)>>13, ((k->del_flags)&0x1000)>>12, ((k->del_flags)&0x0800)>>11); - i++; - } - nat_dbg("+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n"); -} - -int pico_ipv4_nat_generate_key(struct pico_nat_key* nk, struct pico_frame* f, struct pico_ip4 pub_addr) -{ - uint16_t pub_port = 0; - uint8_t proto; - struct pico_tcp_hdr *tcp_hdr = NULL; /* forced to use pico_trans */ - struct pico_udp_hdr *udp_hdr = NULL; /* forced to use pico_trans */ - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - do { - /* 1. generate valid new NAT port entry */ - uint32_t rand = pico_rand(); - pub_port = (uint16_t) (rand & 0xFFFFU); - pub_port = (uint16_t)(pub_port % (65535 - 1024)) + 1024U; - pub_port = short_be(pub_port); - - /* 2. check if already in table, if no exit */ - nat_dbg("NAT: check if generated port %u is free\n", short_be(pub_port)); - if (pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4)) - break; - - } while (1); - nat_dbg("NAT: port %u is free\n", short_be(pub_port)); - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - nk->priv_port = tcp_hdr->trans.sport; - } else if (proto == PICO_PROTO_UDP) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (!udp_hdr) - return -1; - nk->priv_port = udp_hdr->trans.sport; - } else if (proto == PICO_PROTO_ICMP4) { - nk->priv_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF); - pub_port = (uint16_t)(ipv4_hdr->dst.addr & 0x00FF); - if (!pico_is_port_free(proto, pub_port, NULL, &pico_proto_ipv4)) - return -1; - } - - nk->pub_addr = pub_addr; /* get public ip address from device */ - nk->pub_port = pub_port; - nk->priv_addr = ipv4_hdr->src; - nk->proto = ipv4_hdr->proto; - nk->del_flags = 0x0001; /* set conn active to 1 */ - if (pico_ipv4_nat_add(nk->pub_addr, nk->pub_port, nk->priv_addr, nk->priv_port, nk->proto) < 0) { - return -1; - } else { - return 0; - } -} - - -static int pico_nat_tcp_checksum(struct pico_frame *f) -{ - struct pico_tcp_hdr *trans_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - struct tcp_pseudo_hdr_ipv4 pseudo; - if (!trans_hdr || !net_hdr) - return -1; - - pseudo.src.addr = net_hdr->src.addr; - pseudo.dst.addr = net_hdr->dst.addr; - pseudo.res = 0; - pseudo.proto = PICO_PROTO_TCP; - pseudo.tcp_len = short_be(f->transport_len); - - trans_hdr->crc = 0; - trans_hdr->crc = pico_dualbuffer_checksum(&pseudo, sizeof(struct tcp_pseudo_hdr_ipv4), trans_hdr, f->transport_len); - trans_hdr->crc = short_be(trans_hdr->crc); - return 0; -} - - -int pico_ipv4_nat_translate(struct pico_nat_key* nk, struct pico_frame* f) -{ - uint8_t proto; - struct pico_tcp_hdr *tcp_hdr = NULL; /* forced to use pico_trans */ - struct pico_udp_hdr *udp_hdr = NULL; /* forced to use pico_trans */ - - struct pico_ipv4_hdr* ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - tcp_hdr->trans.sport = nk->pub_port; - } else if (proto == PICO_PROTO_UDP) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (!udp_hdr) - return -1; - udp_hdr->trans.sport = nk->pub_port; - } - - //if(f->proto == PICO_PROTO_ICMP){ - //} XXX no action - - ipv4_hdr->src = nk->pub_addr; - - if (proto == PICO_PROTO_TCP) { - pico_nat_tcp_checksum(f); - } else if (proto == PICO_PROTO_UDP){ - udp_hdr->crc = 0; - udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f)); - } - - // pico_ipv4_checksum(f); - ipv4_hdr->crc = 0; - ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len)); - - return 0; -} - - -int pico_ipv4_nat_port_forward(struct pico_frame* f) -{ - struct pico_nat_key *nk = NULL; - struct pico_tcp_hdr *tcp_hdr = NULL; - struct pico_udp_hdr *udp_hdr = NULL; - struct pico_icmp4_hdr *icmp_hdr = NULL; - struct pico_ipv4_hdr* ipv4_hdr; - uint16_t pub_port = 0; - uint8_t proto; - - ipv4_hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - pub_port = tcp_hdr->trans.dport; - } else if (proto == PICO_PROTO_UDP) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (!udp_hdr) - return -1; - pub_port = udp_hdr->trans.dport; - } else if (proto == PICO_PROTO_ICMP4) { - icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - if (!icmp_hdr) - return -1; - /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */ - pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF); - } - - nk = pico_ipv4_nat_find_key(pub_port, 0, 0, proto); - - if (!nk) { - nat_dbg("\nNAT: ERROR key not found in table\n"); - return -1; - } else { - pico_ipv4_nat_snif_forward(nk,f); - ipv4_hdr->dst.addr = nk->priv_addr.addr; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr->trans.dport = nk->priv_port; - pico_nat_tcp_checksum(f); - } else if (proto == PICO_PROTO_UDP) { - udp_hdr->trans.dport = nk->priv_port; - udp_hdr->crc = 0; - udp_hdr->crc = short_be(pico_udp_checksum_ipv4(f)); - } - } - - ipv4_hdr->crc = 0; - ipv4_hdr->crc = short_be(pico_checksum(ipv4_hdr, f->net_len)); - - return 0; -} - - - -int pico_ipv4_nat(struct pico_frame *f, struct pico_ip4 pub_addr) -{ - /*do nat---------*/ - struct pico_nat_key *nk = NULL; - struct pico_nat_key key; - struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_tcp_hdr *tcp_hdr = NULL; - struct pico_udp_hdr *udp_hdr = NULL; - int ret; - uint8_t proto = net_hdr->proto; - uint16_t priv_port = 0; - struct pico_ip4 priv_addr= net_hdr->src; - - nk= &key; - - /* TODO DELME check if IN */ - if (pub_addr.addr == net_hdr->dst.addr) { - nat_dbg("NAT: backward translation {dst.addr, dport}: {%08X,%u} ->", net_hdr->dst.addr, ((struct pico_trans *)f->transport_hdr)->dport); - ret = pico_ipv4_nat_port_forward(f); /* our IN definition */ - nat_dbg(" {%08X,%u}\n", net_hdr->dst.addr, short_be(((struct pico_trans *)f->transport_hdr)->dport)); - } else { - if (net_hdr->proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - priv_port = tcp_hdr->trans.sport; - } else if (net_hdr->proto == PICO_PROTO_UDP) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - priv_port = udp_hdr->trans.sport; - } else if (net_hdr->proto == PICO_PROTO_ICMP4) { - //udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - priv_port = (uint16_t)(net_hdr->src.addr & 0x00FF); - } - - ret = pico_ipv4_nat_find(0, &priv_addr, priv_port, proto); - if (ret >= 0) { - // Key is available in table - nk = pico_ipv4_nat_find_key(0, &priv_addr, priv_port, proto); - } else { - nat_dbg("NAT: key not found in NAT table -> generate key\n"); - pico_ipv4_nat_generate_key(nk, f, pub_addr); - } - pico_ipv4_nat_snif_backward(nk,f); - nat_dbg("NAT: forward translation {src.addr, sport}: {%08X,%u} ->", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport)); - pico_ipv4_nat_translate(nk, f); /* our OUT definition */ - nat_dbg(" {%08X,%u}\n", net_hdr->src.addr, short_be(((struct pico_trans *)f->transport_hdr)->sport)); - } - return 0; -} - - -int pico_ipv4_nat_enable(struct pico_ipv4_link *link) -{ - if (link == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pub_link = *link; - pico_timer_add(NAT_TCP_TIMEWAIT, pico_ipv4_nat_table_cleanup, NULL); - enable_nat_flag = 1; - return 0; -} - -int pico_ipv4_nat_disable(void) -{ - pub_link.address.addr = 0; - enable_nat_flag = 0; - return 0; -} - - -int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link) -{ - if (enable_nat_flag) { - // is pub_link = *link - if (pub_link.address.addr == link->address.addr) - return 0; - else - return -1; - } else { - return -1; - } -} - - -int pico_ipv4_nat_isenabled_in(struct pico_frame *f) -{ - if (enable_nat_flag) { - struct pico_tcp_hdr *tcp_hdr = NULL; - struct pico_udp_hdr *udp_hdr = NULL; - uint16_t pub_port = 0; - int ret; - uint8_t proto; - - struct pico_ipv4_hdr *ipv4_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - if (!ipv4_hdr) - return -1; - proto = ipv4_hdr->proto; - - if (proto == PICO_PROTO_TCP) { - tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - if (!tcp_hdr) - return -1; - pub_port= tcp_hdr->trans.dport; - } else if (proto == PICO_PROTO_UDP) { - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (!udp_hdr) - return -1; - pub_port= udp_hdr->trans.dport; - } else if (proto == PICO_PROTO_ICMP4) { - //icmp_hdr = (struct pico_icmp4_hdr *) f->transport_hdr; - //if (!icmp_hdr) - // return -1; - /* XXX PRELIMINARY ONLY LAST 16 BITS OF IP */ - pub_port = (uint16_t)(ipv4_hdr->src.addr & 0x00FF); - } - ret = pico_ipv4_nat_find(pub_port, NULL, 0, proto); - if (ret == 0) - return 0; - else - return -1; - } else { - return -1; - } -} -#endif -#endif -
--- a/modules/pico_nat.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Kristof Roelants, Simon Maes, Brecht Van Cauwenberghe -*********************************************************************/ - -#ifndef _INCLUDE_PICO_NAT -#define _INCLUDE_PICO_NAT -#include "pico_frame.h" - -#define PICO_DEL_FLAGS_FIN_FORWARD (0x8000) -#define PICO_DEL_FLAGS_FIN_BACKWARD (0x4000) -#define PICO_DEL_FLAGS_SYN (0x2000) -#define PICO_DEL_FLAGS_RST (0x1000) - -#define PICO_IPV4_FORWARD_DEL 0 -#define PICO_IPV4_FORWARD_ADD 1 - -#ifdef PICO_SUPPORT_NAT -void pico_ipv4_nat_print_table(void); -int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto); -int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto); -int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 *priv_addr, uint16_t priv_port, uint8_t proto); -int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant); - -int pico_ipv4_nat(struct pico_frame* f, struct pico_ip4 pub_addr); -int pico_ipv4_nat_enable(struct pico_ipv4_link *link); -int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link); -int pico_ipv4_nat_isenabled_in(struct pico_frame *f); - -#else - -static inline int pico_ipv4_nat_isenabled_out(struct pico_ipv4_link *link) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -static inline int pico_ipv4_nat_isenabled_in(struct pico_frame *f) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat(struct pico_frame* f, struct pico_ip4 pub_addr) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_enable(struct pico_ipv4_link *link) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -#define pico_ipv4_nat_print_table() do{}while(0) - -static inline int pico_ipv4_nat_add(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_nat_del(uint16_t pub_port, uint8_t proto) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - - -static inline int pico_ipv4_nat_find(uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} - -static inline int pico_ipv4_port_forward(struct pico_ip4 pub_addr, uint16_t pub_port, struct pico_ip4 priv_addr, uint16_t priv_port, uint8_t proto, uint8_t persistant) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -#endif - -#endif /* _INCLUDE_PICO_NAT */ -
--- a/modules/pico_simple_http.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,128 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#include "pico_config.h" -#include "pico_socket.h" -#include "pico_tcp.h" -#include "pico_ipv4.h" -#include "pico_simple_http.h" - -/* The HTTP Server cannot be available without TCP support */ -#if (defined PICO_SUPPORT_HTTP) && (defined PICO_SUPPORT_IPV4) && (defined PICO_SUPPORT_TCP) - -#define HTTP_LISTEN_PORT 80u -#define HTTP_BACKLOG 5u -#define HTTP_HEADER_SIZE 256u - -#define HTTP_SUCCESS 0 -#define HTTP_ERROR -1 - -static struct pico_socket * httpServer = NULL; -static char httpResponse[] = -"HTTP/1.0 200 OK\r\n\ -Content-Type: text/html\r\n\ -\r\n\ -<html><head>\r\n\ -<title>picoTCP Simple Http server</title>\r\n\ -</head>\r\n\ -<body>\r\n\ -<h1>Hello world from picoTCP !!</h1>\r\n\ -</body>\r\n"; - -static void httpEventCbk(uint16_t ev, struct pico_socket *self) -{ - static struct pico_socket * client = NULL; - uint32_t peer; - uint16_t port; - int r; - char buffer[HTTP_HEADER_SIZE]; - - switch(ev) - { - case PICO_SOCK_EV_CONN : - if(!client) - client = pico_socket_accept(self, &peer, &port); - break; - - case PICO_SOCK_EV_RD: - // do not check http integrity, just mark that the http header has arrived - // prepare to send the response - r = pico_socket_recvfrom(self, buffer, HTTP_HEADER_SIZE, &peer, &port); - if(r>0 && memcmp(buffer,"GET",3u) == 0u) - { // it is an http header asking for data, return data and close - pico_socket_write(self,httpResponse,sizeof(httpResponse)); - pico_socket_close(self); - } - else - { - // kill the connection, invalid header - pico_socket_close(self); - } - break; - - case PICO_SOCK_EV_ERR: - case PICO_SOCK_EV_CLOSE: - // free the used socket - client = NULL; - break; - - default : - break; - } -} - -int pico_startHttpServer(struct pico_ip4 * address) -{ - - uint16_t localHttpPort = short_be(HTTP_LISTEN_PORT); - - if(!pico_is_port_free(localHttpPort,PICO_PROTO_TCP, address, &pico_proto_ipv4)) - { - pico_err = PICO_ERR_EADDRINUSE; - return HTTP_ERROR; - } - - httpServer = pico_socket_open(PICO_PROTO_IPV4, PICO_PROTO_TCP, httpEventCbk); - - if(!httpServer) - { - pico_err = PICO_ERR_ENOMEM; - return HTTP_ERROR; - } - - // both functions set the pico_err themselves. - if(pico_socket_bind(httpServer,address,&localHttpPort)) - return HTTP_ERROR; - - if(pico_socket_listen(httpServer,HTTP_BACKLOG)) - return HTTP_ERROR; - - return HTTP_SUCCESS; -} - -int pico_stopHttpServer(void) -{ - if(!httpServer) - { - pico_err = PICO_ERR_EINVAL; - return HTTP_ERROR; - } - - if(pico_socket_close(httpServer)) - { - // no need to set the error here, function already set it - httpServer = NULL; - return HTTP_ERROR; - } - - httpServer = NULL; - return HTTP_SUCCESS; -} - -#endif - -
--- a/modules/pico_simple_http.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,14 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#ifndef PICO_SIMPLE_HTTP -#define PICO_SIMPLE_HTTP - -extern int pico_startHttpServer(struct pico_ip4 * address); -extern int pico_stopHttpServer(void); - -#endif
--- a/modules/pico_tcp.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2190 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera, Philippe Mariman -*********************************************************************/ - -#include "pico_tcp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_stack.h" -#include "pico_socket.h" -#include "pico_queue.h" -#include "pico_tree.h" - -#define TCP_SOCK(s) ((struct pico_socket_tcp *)s) -#define SEQN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->seq)):0) -#define ACKN(f) (f?(long_be(((struct pico_tcp_hdr *)(f->transport_hdr))->ack)):0) - -#define PICO_TCP_RTO_MIN 1000 -#define PICO_TCP_RTO_MAX 120000 -#define PICO_TCP_IW 2 - -#define PICO_TCP_MAX_CONNECT_RETRIES 7 - -#define PICO_TCP_LOOKAHEAD 0x00 -#define PICO_TCP_FIRST_DUPACK 0x01 -#define PICO_TCP_SECOND_DUPACK 0x02 -#define PICO_TCP_RECOVER 0x03 -#define PICO_TCP_BLACKOUT 0x04 -#define PICO_TCP_UNREACHABLE 0x05 -#define PICO_TCP_WINDOW_FULL 0x06 - -/* check if the Nagle algorithm is enabled on the socket */ -#define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))))) -/* check if tcp connection is "idle" according to Nagle (RFC 896) */ -#define IS_TCP_IDLE(t) ((t->in_flight == 0) && (t->tcpq_out.size == 0)) -/* check if the hold queue contains data (again Nagle) */ -#define IS_TCP_HOLDQ_EMPTY(t) (t->tcpq_hold.size == 0) - -#ifdef PICO_SUPPORT_TCP -#define tcp_dbg(...) do{}while(0) -//#define tcp_dbg dbg - - -#ifdef PICO_SUPPORT_MUTEX -static void * Mutex = NULL; -#define LOCK(x) {\ - if (x == NULL) \ - x = pico_mutex_init(); \ - pico_mutex_lock(x); \ -} -#define UNLOCK(x) pico_mutex_unlock(x); - -#else -#define LOCK(x) do{}while(0) -#define UNLOCK(x) do{}while(0) -#endif - - -static inline int seq_compare(uint32_t a, uint32_t b) -{ - uint32_t thresh = ((uint32_t)(-1))>>1; - if (((a > thresh) && (b > thresh)) || ((a <= thresh) && (b <= thresh))) { - if (a > b) - return 1; - if (b > a) - return -1; - } else { - if (a > b) - return -2; - if (b > a) - return 2; - } - return 0; -} - -static int segment_compare(void * ka, void * kb) -{ - struct pico_frame *a = ka, *b = kb; - return seq_compare(SEQN(a), SEQN(b)); -} - -struct pico_tcp_queue -{ - struct pico_tree pool; - uint32_t max_size; - uint32_t size; - uint32_t frames; -}; - -static struct pico_frame *peek_segment(struct pico_tcp_queue *tq, uint32_t seq) -{ - struct pico_tcp_hdr H; - struct pico_frame f = {}; - f.transport_hdr = (uint8_t *) (&H); - H.seq = long_be(seq); - - return pico_tree_findKey(&tq->pool,&f); -} - -static struct pico_frame *first_segment(struct pico_tcp_queue *tq) -{ - return pico_tree_first(&tq->pool); -} - -static struct pico_frame *next_segment(struct pico_tcp_queue *tq, struct pico_frame *cur) -{ - if (!cur) - return NULL; - return peek_segment(tq, SEQN(cur) + cur->payload_len); -} - -static int pico_enqueue_segment(struct pico_tcp_queue *tq, struct pico_frame *f) -{ - int ret = -1; - if (f->payload_len <= 0) { - tcp_dbg("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! TRIED TO ENQUEUE INVALID SEGMENT!\n"); - //abort(); - return -1; - } - LOCK(Mutex); - if ((tq->size + f->payload_len) > tq->max_size) - { - ret = 0; - goto out; - } - if (pico_tree_insert(&tq->pool,f) != 0) - { - ret = 0; - goto out; - } - tq->size += f->payload_len; - if (f->payload_len > 0) - tq->frames++; - ret = f->payload_len; - -out : - UNLOCK(Mutex); - return ret; -} - -static void pico_discard_segment(struct pico_tcp_queue *tq, struct pico_frame *f) -{ - struct pico_frame *f1; - LOCK(Mutex); - f1 = pico_tree_delete(&tq->pool,f); - if (f1) { - tq->size -= f->payload_len; - if (f->payload_len > 0) - tq->frames--; - } - pico_frame_discard(f); - UNLOCK(Mutex); -} - -/* Structure for TCP socket */ -struct tcp_sack_block { - uint32_t left; - uint32_t right; - struct tcp_sack_block *next; -}; - -struct pico_socket_tcp { - struct pico_socket sock; - - /* Tree/queues */ - struct pico_tcp_queue tcpq_in; - struct pico_tcp_queue tcpq_out; - struct pico_tcp_queue tcpq_hold; /* buffer to hold delayed frames according to Nagle */ - - /* tcp_output */ - uint32_t snd_nxt; - uint32_t snd_last; - uint32_t snd_old_ack; - uint32_t snd_retry; - uint32_t snd_last_out; - - /* congestion control */ - uint32_t avg_rtt; - uint32_t rttvar; - uint32_t rto; - uint32_t in_flight; - uint8_t timer_running; - uint8_t keepalive_timer_running; - uint16_t cwnd_counter; - uint16_t cwnd; - uint16_t ssthresh; - uint16_t recv_wnd; - uint16_t recv_wnd_scale; - - /* tcp_input */ - uint32_t rcv_nxt; - uint32_t rcv_ackd; - uint32_t rcv_processed; - uint16_t wnd; - uint16_t wnd_scale; - - /* options */ - uint32_t ts_nxt; - uint16_t mss; - uint8_t sack_ok; - uint8_t ts_ok; - uint8_t mss_ok; - uint8_t scale_ok; - struct tcp_sack_block *sacks; - uint8_t jumbo; - - /* Transmission */ - uint8_t x_mode; - uint8_t dupacks; - uint8_t backoff; - -}; - -/* Queues */ -static struct pico_queue tcp_in = {}; -static struct pico_queue tcp_out = {}; - -/* If Nagle enabled, this function can make 1 new segment from smaller segments in hold queue */ -static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t); - -/* checks if tcpq_in is empty */ -int pico_tcp_queue_in_is_empty(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - - if (t->tcpq_in.frames == 0) - return 1; - else - return 0; -} - -/* Useful for getting rid of the beginning of the buffer (read() op) */ -static int release_until(struct pico_tcp_queue *q, uint32_t seq) -{ - struct pico_frame *head = first_segment(q); - int ret = 0; - while (head && (seq_compare(SEQN(head) + head->payload_len, seq) <= 0)) { - struct pico_frame *cur = head; - head = next_segment(q, cur); - tcp_dbg("Releasing %p\n", q); - pico_discard_segment(q, cur); - ret++; - } - return ret; -} - -static int release_all_until(struct pico_tcp_queue *q, uint32_t seq) -{ - struct pico_frame *f = NULL, *tmp __attribute__((unused)); - struct pico_tree_node * idx, * temp; - int ret = 0; - - pico_tree_foreach_safe(idx,&q->pool,temp){ - f = idx->keyValue; - if (seq_compare(SEQN(f) + f->payload_len, seq) <= 0) { - tcp_dbg("Releasing %p\n", f); - pico_discard_segment(q, f); - ret++; - } else - return ret; - } - return ret; -} - -/* API calls */ - -uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_tcp_hdr *tcp_hdr = (struct pico_tcp_hdr *) f->transport_hdr; - struct pico_socket *s = f->sock; - struct pico_ipv4_pseudo_hdr pseudo; - - if (s) { - /* Case of outgoing frame */ - //dbg("TCP CRC: on outgoing frame\n"); - pseudo.src.addr = s->local_addr.ip4.addr; - pseudo.dst.addr = s->remote_addr.ip4.addr; - } else { - /* Case of incomming frame */ - //dbg("TCP CRC: on incomming frame\n"); - pseudo.src.addr = hdr->src.addr; - pseudo.dst.addr = hdr->dst.addr; - } - pseudo.zeros = 0; - pseudo.proto = PICO_PROTO_TCP; - pseudo.len = short_be(f->transport_len); - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), tcp_hdr, f->transport_len); -} - -static int pico_tcp_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr; - struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - - if (f->payload_len > 0) { - tcp_dbg("Process out: sending %p (%d bytes)\n",f, f->payload_len); - } else { - tcp_dbg("Sending empty packet\n"); - } - - if (f->payload_len > 0) { - if (seq_compare(SEQN(f) + f->payload_len, t->snd_nxt) > 0) { - t->snd_nxt = SEQN(f) + f->payload_len; - tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); - } - } else if (hdr->flags == PICO_TCP_ACK) { /* pure ack */ - hdr->seq = long_be(t->snd_nxt); - } else { - tcp_dbg("%s: non-pure ACK with len=0, fl:%04x\n", __FUNCTION__, hdr->flags); - } - pico_network_send(f); - return 0; -} - -int pico_tcp_push(struct pico_protocol *self, struct pico_frame *data); - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_tcp = { - .name = "tcp", - .proto_number = PICO_PROTO_TCP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_transport_process_in, - .process_out = pico_tcp_process_out, - .push = pico_tcp_push, - .q_in = &tcp_in, - .q_out = &tcp_out, -}; - -static uint32_t pico_paws(void) -{ - static unsigned long _paws = 0; - _paws = pico_rand(); - return long_be(_paws); /*XXX: implement paws */ -} - -static void tcp_add_options(struct pico_socket_tcp *ts, struct pico_frame *f, uint16_t flags, int optsiz) -{ - uint32_t tsval = long_be(pico_tick); - uint32_t tsecr = long_be(ts->ts_nxt); - int i = 0; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - - memset(f->start, PICO_TCP_OPTION_NOOP, optsiz); /* fill blanks with noop */ - - if (flags & PICO_TCP_SYN) { - f->start[i++] = PICO_TCP_OPTION_MSS; - f->start[i++] = PICO_TCPOPTLEN_MSS; - f->start[i++] = (ts->mss >> 8) & 0xFF; - f->start[i++] = ts->mss & 0xFF; - f->start[i++] = PICO_TCP_OPTION_SACK_OK; - f->start[i++] = PICO_TCPOPTLEN_SACK_OK; - } - - f->start[i++] = PICO_TCP_OPTION_WS; - f->start[i++] = PICO_TCPOPTLEN_WS; - f->start[i++] = ts->wnd_scale; - - if (optsiz >= 12) { - f->start[i++] = PICO_TCP_OPTION_TIMESTAMP; - f->start[i++] = PICO_TCPOPTLEN_TIMESTAMP; - memcpy(f->start + i, &tsval, 4); - i += 4; - memcpy(f->start + i, &tsecr, 4); - i += 4; - } - - if (flags & PICO_TCP_ACK) { - struct tcp_sack_block *sb; - int len_off; - - if (ts->sack_ok && ts->sacks) { - f->start[i++] = PICO_TCP_OPTION_SACK; - len_off = i; - f->start[i++] = PICO_TCPOPTLEN_SACK; - while(ts->sacks) { - sb = ts->sacks; - ts->sacks = sb->next; - memcpy(f->start + i, sb, 2 * sizeof(uint32_t)); - i += (2 * sizeof(uint32_t)); - f->start[len_off] += (2 * sizeof(uint32_t)); - pico_free(sb); - } - } - } - if (i < optsiz) - f->start[ optsiz - 1 ] = PICO_TCP_OPTION_END; -} - -static void tcp_send_ack(struct pico_socket_tcp *t); - -static void tcp_set_space(struct pico_socket_tcp *t) -{ - int mtu, space; - int shift = 0; - - mtu = t->mss + PICO_SIZE_TCPHDR + PICO_SIZE_TCPOPT_SYN ; - if (t->tcpq_in.max_size == 0) { - space = 1024 * 1024 * 1024; /* One Gigabyte, for unlimited sockets. */ - } else { - space = ((t->tcpq_in.max_size - t->tcpq_in.size) / mtu) * t->mss; - } - if (space < 0) - space = 0; - while(space > 0xFFFF) { - space >>= 1; - shift++; - } - if ((space != t->wnd) || (shift != t->wnd_scale) || ((space - t->wnd) > (space>>2))) { - t->wnd = space; - t->wnd_scale = shift; - } -} - -/* Return 32-bit aligned option size */ -static int tcp_options_size(struct pico_socket_tcp *t, uint16_t flags) -{ - int size = 0; - struct tcp_sack_block *sb = t->sacks; - - if (flags & PICO_TCP_SYN) { /* Full options */ - size = PICO_TCPOPTLEN_MSS + PICO_TCP_OPTION_SACK_OK + PICO_TCPOPTLEN_WS + PICO_TCPOPTLEN_TIMESTAMP; - } else { - - /* Always update window scale. */ - size += PICO_TCPOPTLEN_WS; - - if (t->ts_ok) - size += PICO_TCPOPTLEN_TIMESTAMP; - - size+= PICO_TCPOPTLEN_END; - } - if ((flags & PICO_TCP_ACK) && (t->sack_ok && sb)) { - size += 2; - while(sb) { - size += (2 * sizeof(uint32_t)); - sb = sb->next; - } - } - size = (((size + 3) >> 2) << 2); - return size; -} - -int pico_tcp_overhead(struct pico_socket *s) -{ - if (!s) - return 0; - - return PICO_SIZE_TCPHDR + tcp_options_size((struct pico_socket_tcp *)s, 0); /* hdr + Options size for data pkt */ - -} - -static void tcp_process_sack(struct pico_socket_tcp *t, uint32_t start, uint32_t end) -{ - struct pico_frame *f; - struct pico_tree_node * index, * temp; - int cmp; - int count = 0; - - pico_tree_foreach_safe(index,&t->tcpq_out.pool,temp){ - f = index->keyValue; - cmp = seq_compare(SEQN(f), start); - if (cmp > 0) - goto done; - - if (cmp == 0) { - cmp = seq_compare(SEQN(f) + f->payload_len, end); - if (cmp > 0) { - tcp_dbg("Invalid SACK: ignoring.\n"); - } - - tcp_dbg("Marking (by SACK) segment %08x BLK:[%08x::%08x]\n", SEQN(f), start, end); - f->flags |= PICO_FRAME_FLAG_SACKED; - count++; - - if (cmp == 0) { - /* that was last segment sacked. Job done */ - goto done; - } - } - } - -done: - if (t->x_mode > PICO_TCP_LOOKAHEAD) { - if (t->in_flight > (count)) - t->in_flight -= (count); - else - t->in_flight = 0; - } -} - -static void tcp_rcv_sack(struct pico_socket_tcp *t, uint8_t *opt, int len) -{ - uint32_t start, end; - int i = 0; - if (len % 8) { - tcp_dbg("SACK: Invalid len.\n"); - return; - } - while (i < len) { - start = long_from(opt + i); - i += 4; - end = long_from(opt + i); - i += 4; - tcp_process_sack(t, long_be(start), long_be(end)); - } -} - -static void tcp_parse_options(struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)f->sock; - uint8_t *opt = f->transport_hdr + PICO_SIZE_TCPHDR; - int i = 0; - while (i < (f->transport_len - PICO_SIZE_TCPHDR)) { - uint8_t type = opt[i++]; - uint8_t len; - if(i < (f->transport_len - PICO_SIZE_TCPHDR) && (type > 1)) - len = opt[i++]; - else - len = 1; - if (f->payload && ((opt + i) > f->payload)) - break; - tcp_dbg("Received option '%d', len = %d \n", type, len); - switch (type) { - case PICO_TCP_OPTION_NOOP: - case PICO_TCP_OPTION_END: - break; - case PICO_TCP_OPTION_WS: - if (len != PICO_TCPOPTLEN_WS) { - tcp_dbg("TCP Window scale: bad len received (%d).\n", len); - i += len - 2; - break; - } - t->recv_wnd_scale = opt[i++]; - tcp_dbg("TCP Window scale: received %d\n", t->recv_wnd_scale); - break; - case PICO_TCP_OPTION_SACK_OK: - if (len != PICO_TCPOPTLEN_SACK_OK) { - tcp_dbg("TCP option sack: bad len received.\n"); - i += len - 2; - break; - } - t->sack_ok = 1; - break; - case PICO_TCP_OPTION_MSS: { - uint16_t mss; - if (len != PICO_TCPOPTLEN_MSS) { - tcp_dbg("TCP option mss: bad len received.\n"); - i += len - 2; - break; - } - t->mss_ok = 1; - mss = short_from(opt + i); - i += sizeof(uint16_t); - if (t->mss > short_be(mss)) - t->mss = short_be(mss); - break; - } - case PICO_TCP_OPTION_TIMESTAMP: { - uint32_t tsval, tsecr; - if (len != PICO_TCPOPTLEN_TIMESTAMP) { - tcp_dbg("TCP option timestamp: bad len received.\n"); - i += len - 2; - break; - } - t->ts_ok = 1; - tsval = long_from(opt + i); - i += sizeof(uint32_t); - tsecr = long_from(opt + i); - f->timestamp = long_be(tsecr); - i += sizeof(uint32_t); - - t->ts_nxt = long_be(tsval); - break; - } - case PICO_TCP_OPTION_SACK: - { - tcp_rcv_sack(t, opt + i, len - 2); - i += len - 2; - break; - } - default: - tcp_dbg("TCP: received unsupported option %u\n", type); - i += len - 2; - } - } -} - -static int tcp_send(struct pico_socket_tcp *ts, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr= (struct pico_tcp_hdr *) f->transport_hdr; - struct pico_frame *cpy; - hdr->trans.sport = ts->sock.local_port; - hdr->trans.dport = ts->sock.remote_port; - if (!hdr->seq) - hdr->seq = long_be(ts->snd_nxt); - - if (ts->rcv_nxt != 0) { - if ( (ts->rcv_ackd == 0) || (seq_compare(ts->rcv_ackd, ts->rcv_nxt) != 0) || (hdr->flags & PICO_TCP_ACK)) { - hdr->flags |= PICO_TCP_ACK; - hdr->ack = long_be(ts->rcv_nxt); - ts->rcv_ackd = ts->rcv_nxt; - } - } - - if (hdr->flags & PICO_TCP_SYN) { - ts->snd_nxt++; - } - if (f->payload_len > 0) { - hdr->flags |= PICO_TCP_PSH | PICO_TCP_ACK; - hdr->ack = long_be(ts->rcv_nxt); - ts->rcv_ackd = ts->rcv_nxt; - } - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(ts->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - - /* TCP: ENQUEUE to PROTO ( Transmit ) */ - cpy = pico_frame_copy(f); - if (pico_enqueue(&tcp_out, cpy) > 0) { - if (f->payload_len > 0) - ts->in_flight++; - tcp_dbg("DBG> [tcp output] state: %02x --> local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", - TCPSTATE(&ts->sock) >> 8, short_be(hdr->trans.sport), short_be(hdr->trans.dport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2 , f->payload_len ); - } else { - pico_frame_discard(cpy); - } - return 0; -} - -//#define PICO_TCP_SUPPORT_SOCKET_STATS - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS -static void sock_stats(unsigned long when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - tcp_dbg("STATISTIC> [%lu] socket state: %02x --> local port:%d remote port: %d queue size: %d snd_una: %08x snd_nxt: %08x timer: %d cwnd: %d\n", - when, t->sock.state, short_be(t->sock.local_port), short_be(t->sock.remote_port), t->tcpq_out.size, SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, t->timer_running, t->cwnd); - pico_timer_add(2000, sock_stats, t); -} -#endif - -struct pico_socket *pico_tcp_open(void) -{ - struct pico_socket_tcp *t = pico_zalloc(sizeof(struct pico_socket_tcp)); - if (!t) - return NULL; - t->mss = PICO_TCP_DEFAULT_MSS; - - t->tcpq_in.pool.root = t->tcpq_hold.pool.root = t->tcpq_out.pool.root = &LEAF; - t->tcpq_hold.pool.compare = t->tcpq_in.pool.compare = t->tcpq_out.pool.compare = segment_compare; - - t->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; - t->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; - t->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS; - - /* enable Nagle by default */ - t->sock.opt_flags &= (~(1 << PICO_SOCKET_OPT_TCPNODELAY)); - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS - pico_timer_add(2000, sock_stats, t); -#endif - tcp_set_space(t); - - return &t->sock; -} - -int pico_tcp_read(struct pico_socket *s, void *buf, int len) -{ - struct pico_socket_tcp *t = TCP_SOCK(s); - struct pico_frame *f; - uint32_t in_frame_off, in_frame_len; - int tot_rd_len = 0; - - while (tot_rd_len < len) { - /* To be sure we don't have garbage at the beginning */ - release_until(&t->tcpq_in, t->rcv_processed); - f = first_segment(&t->tcpq_in); - if (!f) { - tcp_set_space(t); - goto out; - } - - /* Hole at the beginning of data, awaiting retransmissions. */ - if (seq_compare(t->rcv_processed, SEQN(f)) < 0) { - tcp_dbg("TCP> read hole beginning of data, %08x - %08x. rcv_nxt is %08x\n",t->rcv_processed, SEQN(f), t->rcv_nxt); - goto out; - } - - if(seq_compare(t->rcv_processed, SEQN(f)) > 0) { - in_frame_off = t->rcv_processed - SEQN(f); - in_frame_len = f->payload_len - in_frame_off; - } else { - in_frame_off = 0; - in_frame_len = f->payload_len; - } - if ((in_frame_len + tot_rd_len) > len) { - in_frame_len = len - tot_rd_len; - } - - if (in_frame_len > f->payload_len - in_frame_off) - in_frame_len = f->payload_len - in_frame_off; - - memcpy(buf + tot_rd_len, f->payload + in_frame_off, in_frame_len); - tot_rd_len += in_frame_len; - t->rcv_processed += in_frame_len; - - if ((in_frame_len == 0) || (in_frame_len == f->payload_len)) { - pico_discard_segment(&t->tcpq_in, f); - } - } - -out: - tcp_set_space(t); - if (t->tcpq_in.size == 0) { - s->ev_pending &= (~PICO_SOCK_EV_RD); - } - return tot_rd_len; -} - -int pico_tcp_initconn(struct pico_socket *s); -static void initconn_retry(unsigned long when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_SYN_SENT) { - if (t->backoff > PICO_TCP_MAX_CONNECT_RETRIES) { - tcp_dbg("TCP> Connection timeout. \n"); - if (t->sock.wakeup) - t->sock.wakeup(PICO_SOCK_EV_ERR, &t->sock); - return; - } - tcp_dbg("TCP> SYN retry %d...\n", t->backoff); - t->backoff++; - pico_tcp_initconn(&t->sock); - } else { - tcp_dbg("TCP> Connection is already established: no retry needed. good.\n"); - } -} - -int pico_tcp_initconn(struct pico_socket *s) -{ - struct pico_socket_tcp *ts = TCP_SOCK(s); - struct pico_frame *syn; - struct pico_tcp_hdr *hdr; - int opt_len = tcp_options_size(ts, PICO_TCP_SYN); - - syn = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len); - if (!syn) - return -1; - hdr = (struct pico_tcp_hdr *) syn->transport_hdr; - - if (!ts->snd_nxt) - ts->snd_nxt = long_be(pico_paws()); - ts->snd_last = ts->snd_nxt; - ts->cwnd = PICO_TCP_IW; - ts->ssthresh = 40; - syn->sock = s; - hdr->seq = long_be(ts->snd_nxt); - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo; - hdr->flags = PICO_TCP_SYN; - tcp_set_space(ts); - hdr->rwnd = short_be(ts->wnd); - tcp_add_options(ts,syn, PICO_TCP_SYN, opt_len); - hdr->trans.sport = ts->sock.local_port; - hdr->trans.dport = ts->sock.remote_port; - - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(syn)); - - /* TCP: ENQUEUE to PROTO ( SYN ) */ - tcp_dbg("Sending SYN... (ports: %d - %d) size: %d\n", short_be(ts->sock.local_port), short_be(ts->sock.remote_port), syn->buffer_len); - pico_enqueue(&tcp_out, syn); - pico_timer_add(PICO_TCP_RTO_MIN << ts->backoff, initconn_retry, ts); - return 0; -} - -static int tcp_send_synack(struct pico_socket *s) -{ - struct pico_socket_tcp *ts = TCP_SOCK(s); - struct pico_frame *synack; - struct pico_tcp_hdr *hdr; - int opt_len = tcp_options_size(ts, PICO_TCP_SYN | PICO_TCP_ACK); - - synack = s->net->alloc(s->net, PICO_SIZE_TCPHDR + opt_len); - if (!synack) - return -1; - hdr = (struct pico_tcp_hdr *) synack->transport_hdr; - - synack->sock = s; - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | ts->jumbo; - hdr->flags = PICO_TCP_SYN | PICO_TCP_ACK; - hdr->rwnd = short_be(ts->wnd); - hdr->seq = long_be(ts->snd_nxt); - ts->rcv_processed = long_be(hdr->seq); - ts->snd_last = ts->snd_nxt; - tcp_set_space(ts); - tcp_add_options(ts,synack, hdr->flags, opt_len); - synack->payload_len = 0; - synack->timestamp = pico_tick; - tcp_send(ts, synack); - pico_frame_discard(synack); - return 0; -} - -static void tcp_send_empty(struct pico_socket_tcp *t, uint16_t flags) -{ - struct pico_frame *f; - struct pico_tcp_hdr *hdr; - int opt_len = tcp_options_size(t, flags); - f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); - if (!f) { - return; - } - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; - hdr->flags = flags; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t,f, flags, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_nxt); - if ((flags & PICO_TCP_ACK) != 0) - hdr->ack = long_be(t->rcv_nxt); - t->rcv_ackd = t->rcv_nxt; - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); -} - -static void tcp_send_ack(struct pico_socket_tcp *t) -{ - return tcp_send_empty(t, PICO_TCP_ACK); -} - -static int tcp_send_rst(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_frame *f; - struct pico_tcp_hdr *hdr, *hdr_rcv; - int opt_len = tcp_options_size(t, PICO_TCP_RST); - - tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> START\n"); - /* go to CLOSED here to prevent timer callback to go on after timeout */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - - f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); - - if (!f) { - return -1; - } - - hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; - - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; - hdr->flags = PICO_TCP_RST; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t,f, PICO_TCP_RST, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_nxt); - - /* check if state is synchronized */ - if (((s->state & PICO_SOCKET_STATE_TCP) > PICO_SOCKET_STATE_TCP_SYN_RECV)) { - /* in synchronized state: send RST with seq = ack from previous segment */ - hdr->seq = hdr_rcv->ack; - } else { - /* non-synchronized state */ - } - - hdr->ack = long_be(t->rcv_nxt); - t->rcv_ackd = t->rcv_nxt; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); - - /* goto CLOSED */ - //(t->sock).state &= 0x00FFU; - //(t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - - /* call EV_FIN wakeup before deleting */ - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - - /* delete socket */ - pico_socket_del(&t->sock); - - tcp_dbg("TCP SEND_RST >>>>>>>>>>>>>>> DONE, deleted socket\n"); - - return 0; -} - -int pico_tcp_reply_rst(struct pico_frame *fr) -{ - struct pico_tcp_hdr *hdr; - struct pico_frame *f; - int size = PICO_SIZE_TCPHDR; - - tcp_dbg("TCP>>>>>>>>>>>>>>>> sending RST ... <<<<<<<<<<<<<<<<<<\n"); - - f = fr->sock->net->alloc(fr->sock->net, size); - - /* fill in IP data from original frame */ - // TODO if IPv4 - ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->src.addr; - ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr = ((struct pico_ipv4_hdr *)(fr->net_hdr))->dst.addr; - - /* fill in TCP data from original frame */ - ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.dport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.sport; - ((struct pico_tcp_hdr *)(f->transport_hdr))->trans.sport = ((struct pico_tcp_hdr *)(fr->transport_hdr))->trans.dport; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = size << 2; - hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; - hdr->rwnd = 0; - if (((struct pico_tcp_hdr *)(fr->transport_hdr))->flags & PICO_TCP_ACK) { - hdr->seq = ((struct pico_tcp_hdr *)(fr->transport_hdr))->ack; - } else { - hdr->seq = 0U; - } - - hdr->ack = ((struct pico_tcp_hdr *)(fr->transport_hdr))->seq + short_be(fr->payload_len); - - /* enqueue for transmission */ - pico_ipv4_frame_push(f,&(((struct pico_ipv4_hdr *)(f->net_hdr))->dst),PICO_PROTO_TCP); - - return 0; -} - -static int tcp_nosync_rst(struct pico_socket *s, struct pico_frame *fr) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_frame *f; - struct pico_tcp_hdr *hdr, *hdr_rcv; - int opt_len = tcp_options_size(t, PICO_TCP_RST | PICO_TCP_ACK); - - tcp_dbg("TCP SEND RST (NON-SYNC) >>>>>>>>>>>>>>>>>> state %x\n",(s->state & PICO_SOCKET_STATE_TCP)); - if (((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_LISTEN)) { - /* XXX TODO NOTE: to prevent the parent socket from trying to send, because this socket has no knowledge of dst IP !!! */ - return pico_tcp_reply_rst(fr); - } - - /***************************************************************************/ - /* sending RST */ - f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); - - if (!f) { - return -1; - } - - hdr_rcv = (struct pico_tcp_hdr *) fr->transport_hdr; - - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; - hdr->flags = PICO_TCP_RST | PICO_TCP_ACK; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t,f, PICO_TCP_RST | PICO_TCP_ACK, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - - /* non-synchronized state */ - if (hdr_rcv->flags & PICO_TCP_ACK) { - hdr->seq = hdr_rcv->ack; - } else { - hdr->seq = 0U; - } - - hdr->ack = hdr_rcv->seq + short_be(fr->payload_len); - - t->rcv_ackd = t->rcv_nxt; - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - - /* TCP: ENQUEUE to PROTO */ - pico_enqueue(&tcp_out, f); - - /***************************************************************************/ - - tcp_dbg("TCP SEND_RST (NON_SYNC) >>>>>>>>>>>>>>> DONE, ...\n"); - - return 0; -} - -static void tcp_send_fin(struct pico_socket_tcp *t) -{ - struct pico_frame *f; - struct pico_tcp_hdr *hdr; - int opt_len = tcp_options_size(t, PICO_TCP_FIN); - f = t->sock.net->alloc(t->sock.net, PICO_SIZE_TCPHDR + opt_len); - if (!f) { - return; - } - f->sock = &t->sock; - hdr = (struct pico_tcp_hdr *) f->transport_hdr; - hdr->len = (PICO_SIZE_TCPHDR + opt_len) << 2 | t->jumbo; - hdr->flags = PICO_TCP_FIN | PICO_TCP_ACK; - hdr->ack = long_be(t->rcv_nxt); - t->rcv_ackd = t->rcv_nxt; - hdr->rwnd = short_be(t->wnd); - tcp_set_space(t); - tcp_add_options(t,f, PICO_TCP_FIN, opt_len); - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_nxt); - - f->start = f->transport_hdr + PICO_SIZE_TCPHDR; - hdr->rwnd = short_be(t->wnd); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - //tcp_dbg("SENDING FIN...\n"); - /* TCP: ENQUEUE to PROTO ( Pure ACK ) */ - pico_enqueue(&tcp_out, f); - t->snd_nxt++; -} - -static void tcp_sack_prepare(struct pico_socket_tcp *t) -{ - struct pico_frame *pkt; - uint32_t left=0, right=0; - struct tcp_sack_block *sb; - int n = 0; - if (t->sacks) /* previous sacks are pending */ - return; - - pkt = first_segment(&t->tcpq_in); - while(n < 3) { - if (!pkt) { - if(left) { - sb = pico_zalloc(sizeof(struct tcp_sack_block)); - if (!sb) - break; - sb->left = long_be(left); - sb->right = long_be(right); - n++; - sb->next = t->sacks; - t->sacks = sb; - left = 0; - right = 0; - } - break; - } - if ((SEQN(pkt) < t->rcv_nxt)) { - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } - if (!left) { - left = SEQN(pkt); - right = SEQN(pkt) + pkt->payload_len; - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } - if(SEQN(pkt) == (right + 1)) { - right += pkt->payload_len; - pkt = next_segment(&t->tcpq_in, pkt); - continue; - } else { - sb = pico_zalloc(sizeof(struct tcp_sack_block)); - if (!sb) - break; - sb->left = long_be(left); - sb->right = long_be(right); - n++; - sb->next = t->sacks; - t->sacks = sb; - left = 0; - right = 0; - pkt = next_segment(&t->tcpq_in, pkt); - } - } -} - -static int tcp_data_in(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - - if (((hdr->len & 0xf0) >> 2) <= f->transport_len) { - tcp_parse_options(f); - f->payload = f->transport_hdr + ((hdr->len & 0xf0) >>2); - f->payload_len = f->transport_len - ((hdr->len & 0xf0) >>2); - - if (seq_compare(SEQN(f), t->rcv_nxt) >= 0) { - struct pico_frame *cpy = pico_frame_copy(f); - struct pico_frame *nxt; - /* Enqueue: try to put into RCV buffer */ - if (pico_enqueue_segment(&t->tcpq_in, cpy) <= 0) { - pico_frame_discard(cpy); - return -1; - } - if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { /* Exactly what we expected */ - t->rcv_nxt = SEQN(f) + f->payload_len; - nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); - while(nxt) { - tcp_dbg("scrolling rcv_nxt...%08x\n", t->rcv_nxt); - t->rcv_nxt += f->payload_len; - nxt = peek_segment(&t->tcpq_in, t->rcv_nxt); - } - t->sock.ev_pending |= PICO_SOCK_EV_RD; - t->rcv_nxt = SEQN(f) + f->payload_len; - } else { - tcp_dbg("TCP> lo segment. Possible retransmission. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - } - } else { - tcp_dbg("TCP> hi segment. Possible packet loss. I'll dupack this. (exp: %x got: %x)\n", t->rcv_nxt, SEQN(f)); - if (t->sack_ok) { - tcp_sack_prepare(t); - } - } - /* In either case, ack til recv_nxt. */ - if ( ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_CLOSE_WAIT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_SENT) && ((t->sock.state & PICO_SOCKET_STATE_TCP) != PICO_SOCKET_STATE_TCP_SYN_RECV)) { - //tcp_dbg("SENDACK CALLED FROM OUTSIDE tcp_synack, state %x\n",t->sock.state); - tcp_send_ack(t); - } else { - //tcp_dbg("SENDACK PREVENTED IN SYNSENT STATE\n"); - } - return 0; - } else { - tcp_dbg("TCP: invalid data in pkt len, exp: %d, got %d\n", (hdr->len & 0xf0) >> 2, f->transport_len); - return -1; - } -} - -static int tcp_ack_advance_una(struct pico_socket_tcp *t, struct pico_frame *f) -{ - int ret = release_all_until(&t->tcpq_out, ACKN(f)); - if (ret > 0) - t->sock.ev_pending |= PICO_SOCK_EV_WR; - return ret; -} - -static uint16_t time_diff(unsigned long a, unsigned long b) -{ - if (a >= b) - return (a - b); - else - return (b - a); -} - -static void tcp_rtt(struct pico_socket_tcp *t, uint32_t rtt) -{ - - uint32_t avg = t->avg_rtt; - uint32_t rvar = t->rttvar; - if (!avg) { - /* This follows RFC2988 - * (2.2) When the first RTT measurement R is made, the host MUST set - * - * SRTT <- R - * RTTVAR <- R/2 - * RTO <- SRTT + max (G, K*RTTVAR) - */ - t->avg_rtt = rtt; - t->rttvar = rtt >> 1; - t->rto = t->avg_rtt + (t->rttvar << 4); - } else { - int var = (t->avg_rtt - rtt); - if (var < 0) - var = 0-var; - /* RFC2988, section (2.3). Alpha and beta are the ones suggested. */ - - /* First, evaluate a new value for the rttvar */ - t->rttvar <<= 2; - t->rttvar -= rvar; - t->rttvar += var; - t->rttvar >>= 2; - - /* Then, calculate the new avg_rtt */ - t->avg_rtt <<= 3; - t->avg_rtt -= avg; - t->avg_rtt += rtt; - t->avg_rtt >>= 3; - - /* Finally, assign a new value for the RTO, as specified in the RFC, with K=4 */ - t->rto = t->avg_rtt + (t->rttvar << 2); - } - tcp_dbg(" -----=============== RTT AVG: %u RTTVAR: %u RTO: %u ======================----\n", t->avg_rtt, t->rttvar, t->rto); -} - -static void tcp_congestion_control(struct pico_socket_tcp *t) -{ - if (t->x_mode > PICO_TCP_LOOKAHEAD) - return; - if (t->cwnd > t->tcpq_out.frames) { - tcp_dbg("Limited by app: %d\n", t->cwnd); - return; - } - tcp_dbg("Doing congestion control\n"); - if (t->cwnd < t->ssthresh) { - t->cwnd++; - } else { - t->cwnd_counter++; - if (t->cwnd_counter >= t->cwnd) { - t->cwnd++; - t->cwnd_counter = 0; - } - } - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); -} - -static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts); -static void tcp_retrans_timeout(unsigned long val, void *sock) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) sock; - struct pico_frame *f = NULL; - unsigned long limit = val - t->rto; - struct pico_tcp_hdr *hdr; - if(t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED)) - { - tcp_dbg("\n\nTIMEOUT! backoff = %d\n", t->backoff); - /* was timer cancelled? */ - if (t->timer_running == 0) { - add_retransmission_timer(t, 0); - return; - } - t->timer_running--; - - f = first_segment(&t->tcpq_out); - while (f) { - if ((t->x_mode == PICO_TCP_WINDOW_FULL) || - ((f->timestamp != 0) && (f->timestamp <= limit))) { - struct pico_frame *cpy; - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - tcp_dbg("TCP BLACKOUT> TIMED OUT (output) frame %08x, len= %d rto=%d\n", SEQN(f), f->payload_len, t->rto); - if ((t->x_mode != PICO_TCP_WINDOW_FULL) ) { - t->x_mode = PICO_TCP_BLACKOUT; - tcp_dbg("Mode: Blackout.\n"); - t->cwnd = PICO_TCP_IW; - t->in_flight = 0; - } - f->timestamp = pico_tick; - tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR); - hdr->rwnd = short_be(t->wnd); - hdr->flags |= PICO_TCP_PSH; - hdr->ack = long_be(t->rcv_nxt); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - /* TCP: ENQUEUE to PROTO ( retransmit )*/ - cpy = pico_frame_copy(f); - if (pico_enqueue(&tcp_out, cpy) > 0) { - t->backoff++; - add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); - return; - } else { - add_retransmission_timer(t, (t->rto << t->backoff) + pico_tick); - pico_frame_discard(cpy); - } - } - f = next_segment(&t->tcpq_out, f); - } - t->backoff = 0; - add_retransmission_timer(t, 0); - if (t->tcpq_out.size < t->tcpq_out.max_size) - t->sock.ev_pending |= PICO_SOCK_EV_WR; - return; - } -} - -static void add_retransmission_timer(struct pico_socket_tcp *t, unsigned long next_ts) -{ - struct pico_tree_node * index; - - if (t->timer_running > 0) - return; - - if (next_ts == 0) { - struct pico_frame *f; - - pico_tree_foreach(index,&t->tcpq_out.pool){ - f = index->keyValue; - if (((next_ts == 0) || (f->timestamp < next_ts)) && (f->timestamp > 0)) { - next_ts = f->timestamp; - } - } - } - if (next_ts > 0) { - if ((next_ts + t->rto) > pico_tick) { - pico_timer_add(next_ts + t->rto - pico_tick, tcp_retrans_timeout, t); - } else { - pico_timer_add(1, tcp_retrans_timeout, t); - } - t->timer_running++; - } -} - -static int tcp_retrans(struct pico_socket_tcp *t, struct pico_frame *f) -{ - struct pico_frame *cpy; - struct pico_tcp_hdr *hdr; - if (f) { - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - tcp_dbg("TCP> RETRANS (by dupack) frame %08x, len= %d\n", SEQN(f), f->payload_len); - f->timestamp = pico_tick; - tcp_add_options(t, f, 0, f->transport_len - f->payload_len - PICO_SIZE_TCPHDR); - hdr->rwnd = short_be(t->wnd); - hdr->flags |= PICO_TCP_PSH; - hdr->ack = long_be(t->rcv_nxt); - hdr->crc = 0; - hdr->crc = short_be(pico_tcp_checksum_ipv4(f)); - /* TCP: ENQUEUE to PROTO ( retransmit )*/ - cpy = pico_frame_copy(f); - if (pico_enqueue(&tcp_out, cpy) > 0) { - t->in_flight++; - t->snd_last_out = SEQN(cpy); - add_retransmission_timer(t, pico_tick + t->rto); - } else { - pico_frame_discard(cpy); - } - return(f->payload_len); - } - return 0; -} - -#ifdef TCP_ACK_DBG -static void tcp_ack_dbg(struct pico_socket *s, struct pico_frame *f) -{ - uint32_t una, nxt, ack, cur; - struct pico_frame *una_f = NULL, *cur_f; - struct pico_tree_node *idx; - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - char info[64]; - char tmp[64]; - ack = ACKN(f); - nxt = t->snd_nxt; - tcp_dbg("===================================\n"); - tcp_dbg("Queue out (%d/%d). ACKED=%08x\n", t->tcpq_out.size, t->tcpq_out.max_size, ack); - - pico_tree_foreach(idx, &t->tcpq_out.pool) { - info[0] = 0; - cur_f = idx->keyValue; - cur = SEQN(cur_f); - if (!una_f) { - una_f = cur_f; - una = SEQN(una_f); - } - - if (cur == nxt) { - strncpy(tmp, info, strlen(info)); - snprintf(info,64, "%s SND_NXT", tmp); - } - if (cur == ack) { - strncpy(tmp, info, strlen(info)); - snprintf(info,64, "%s ACK", tmp); - } - if (cur == una) { - strncpy(tmp, info, strlen(info)); - snprintf(info,64, "%s SND_UNA", tmp); - } - if (cur == t->snd_last) { - strncpy(tmp, info, strlen(info)); - snprintf(info,64, "%s SND_LAST", tmp); - } - tcp_dbg("%08x %d%s\n", cur, cur_f->payload_len, info); - - } - tcp_dbg("SND_NXT is %08x, snd_LAST is %08x", nxt, t->snd_last); - tcp_dbg("===================================\n"); - tcp_dbg("\n\n"); -} -#endif - -static int tcp_ack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_frame *f_new; /* use with Nagle to push to out queue */ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) f->transport_hdr; - uint32_t rtt = 0; - int acked = 0; - struct pico_frame *una = NULL; - if ((hdr->flags & PICO_TCP_ACK) == 0) - return -1; - -#ifdef TCP_ACK_DBG - tcp_ack_dbg(s,f); -#endif - - tcp_parse_options(f); - t->recv_wnd = short_be(hdr->rwnd); - - acked = tcp_ack_advance_una(t, f); - una = first_segment(&t->tcpq_out); - - if ((t->x_mode == PICO_TCP_BLACKOUT) || - ((t->x_mode == PICO_TCP_WINDOW_FULL) && ((t->recv_wnd << t->recv_wnd_scale) > t->mss))) { - tcp_dbg("Re-entering look-ahead...\n\n\n"); - t->x_mode = PICO_TCP_LOOKAHEAD; - t->backoff = 0; - } - - /* One should be acked. */ -// if ((acked == 0) && (t->in_flight > 0)) - if ((acked == 0) && (f->payload_len == 0) && (t->in_flight > 0)) - t->in_flight--; - if (!una || acked > 0) { - t->x_mode = PICO_TCP_LOOKAHEAD; - tcp_dbg("Mode: Look-ahead. In flight: %d/%d buf: %d\n", t->in_flight, t->cwnd, t->tcpq_out.frames); - t->backoff = 0; - - /* Do rtt/rttvar/rto calculations */ - if(una && (una->timestamp != 0)) { - rtt = time_diff(pico_tick, una->timestamp); - if (rtt) - tcp_rtt(t, rtt); - } - - tcp_dbg("TCP ACK> FRESH ACK %08x (acked %d) Queue size: %u/%u frames: %u cwnd: %u in_flight: %u snd_una: %u\n", ACKN(f), acked, t->tcpq_out.size, t->tcpq_out.max_size, t->tcpq_out.frames, t->cwnd, t->in_flight, SEQN(una)); - if (acked > t->in_flight) { - tcp_dbg("WARNING: in flight < 0\n"); - t->in_flight = 0; - } else - t->in_flight -= (acked); - - } else if ((t->snd_old_ack == ACKN(f)) && /* We've just seen this ack, and... */ - ((0 == (hdr->flags & (PICO_TCP_PSH | PICO_TCP_SYN))) && - (f->payload_len == 0)) && /* This is a pure ack, and... */ - (ACKN(f) != t->snd_nxt)) /* There is something in flight awaiting to be acked... */ - { - /* Process incoming duplicate ack. */ - if (t->x_mode < PICO_TCP_RECOVER) { - t->x_mode++; - tcp_dbg("Mode: DUPACK %d, due to PURE ACK %0x, len = %d\n", t->x_mode, SEQN(f), f->payload_len); - tcp_dbg("ACK: %x - QUEUE: %x\n",ACKN(f), SEQN(first_segment(&t->tcpq_out))); - if (t->x_mode == PICO_TCP_RECOVER) { /* Switching mode */ - t->snd_retry = SEQN(first_segment(&t->tcpq_out)); - if (t->ssthresh > t->cwnd) - t->ssthresh >>=2; - else - t->ssthresh = (t->cwnd >> 1); - if (t->ssthresh < 2) - t->ssthresh = 2; - } - } else if (t->x_mode == PICO_TCP_RECOVER) { - tcp_dbg("TCP RECOVER> DUPACK! snd_una: %08x, snd_nxt: %08x, acked now: %08x\n", SEQN(first_segment(&t->tcpq_out)), t->snd_nxt, ACKN(f)); - if (t->in_flight <= t->cwnd) { - struct pico_frame *nxt = peek_segment(&t->tcpq_out, t->snd_retry); - if (!nxt) - nxt = first_segment(&t->tcpq_out); - - while (nxt && (nxt->flags & PICO_FRAME_FLAG_SACKED) && (nxt != first_segment(&t->tcpq_out))) { - tcp_dbg("Skipping %08x because it is sacked.\n", SEQN(nxt)); - nxt = next_segment(&t->tcpq_out, nxt); - } - - if (nxt && (seq_compare(SEQN(nxt), t->snd_nxt)) > 0) - nxt = NULL; - if (nxt && (seq_compare(SEQN(nxt), SEQN(first_segment(&t->tcpq_out))) > (t->recv_wnd << t->recv_wnd_scale))) - nxt = NULL; - - if(!nxt) - nxt = first_segment(&t->tcpq_out); - if (nxt) { - tcp_retrans(t, peek_segment(&t->tcpq_out, t->snd_retry)); - t->snd_retry = SEQN(nxt); - } - } - - if (++t->cwnd_counter > 1) { - t->cwnd--; - if (t->cwnd < 2) - t->cwnd = 2; - t->cwnd_counter = 0; - } - } else { - tcp_dbg("DUPACK in mode %d \n", t->x_mode); - - } - } /* End case duplicate ack detection */ - - /* Do congestion control */ - tcp_congestion_control(t); - if ((acked > 0) && t->sock.wakeup) { - if (t->tcpq_out.size < t->tcpq_out.max_size) - t->sock.wakeup(PICO_SOCK_EV_WR, &(t->sock)); - //t->sock.ev_pending |= PICO_SOCK_EV_WR; - } - - /* if Nagle enabled, check if no unack'ed data and fill out queue (till window) */ - if (IS_NAGLE_ENABLED((&(t->sock)))) { - while (!IS_TCP_HOLDQ_EMPTY(t) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) { - tcp_dbg("TCP_ACK - NAGLE add new segment\n"); - f_new = pico_hold_segment_make(t); - if (f_new == NULL) - break; /* XXX corrupt !!! (or no memory) */ - if (pico_enqueue_segment(&t->tcpq_out,f_new) <= 0) - // handle error - tcp_dbg("TCP_ACK - NAGLE FAILED to enqueue in out\n"); - } - } - - /* If some space was created, put a few segments out. */ - tcp_dbg("TCP_CWND, %lu, %u, %u, %u\n", pico_tick, t->cwnd, t->ssthresh, t->in_flight); - if (t->x_mode == PICO_TCP_LOOKAHEAD) { - if ((t->cwnd >= t->in_flight) && (t->snd_nxt > t->snd_last_out)) { - pico_tcp_output(&t->sock, t->cwnd - t->in_flight); - } - } - - t->snd_old_ack = ACKN(f); - return 0; -} - -static int tcp_finwaitack(struct pico_socket *s, struct pico_frame *f) -{ - tcp_dbg("RECEIVED ACK IN FIN_WAIT1\nTCP> IN STATE FIN_WAIT2\n"); - - /* acking part */ - tcp_ack(s,f); - /* update TCP state */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT2; - - return 0; -} - -static void tcp_deltcb(unsigned long when, void *arg) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)arg; - if (TCPSTATE(&t->sock) == PICO_SOCKET_STATE_TCP_TIME_WAIT) { - tcp_dbg("TCP> state: time_wait, final timer expired, going to closed state\n"); - /* update state */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - /* call EV_FIN wakeup before deleting */ - if (t->sock.wakeup) { - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - } - /* delete socket */ - pico_socket_del(&t->sock); - } else { - tcp_dbg("TCP> trying to go to closed, wrong state\n"); - } -} - -static int tcp_finwaitfin(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - tcp_dbg("TCP> received fin in FIN_WAIT2\n"); - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_CLOSE, s); - if (f->payload_len > 0) /* needed?? */ - tcp_data_in(s,f); - /* send ACK */ - tcp_send_ack(t); - /* set timer */ - pico_timer_add(200, tcp_deltcb, t); - return 0; -} - -static int tcp_closewaitack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("TCP> received ack in CLOSING\n"); - /* acking part */ - tcp_ack(s,f); - /* update TCP state */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set timer */ - pico_timer_add(200, tcp_deltcb, t); - return 0; -} - -static int tcp_lastackwait(struct pico_socket *s, struct pico_frame *f) -{ - tcp_dbg("TCP> state: last_ack, received ack, to closed\n"); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSED; - s->state &= 0xFF00U; - s->state |= PICO_SOCKET_STATE_CLOSED; - /* call socket wakeup with EV_FIN */ - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_FIN, s); - /* delete socket */ - pico_socket_del(s); - return 0; -} - -static int tcp_syn(struct pico_socket *s, struct pico_frame *f) -{ - /* TODO: Check against backlog length */ - struct pico_socket_tcp *new = (struct pico_socket_tcp *)pico_socket_clone(s); - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - if (!new) - return -1; - -#ifdef PICO_TCP_SUPPORT_SOCKET_STATS - pico_timer_add(2000, sock_stats, s); -#endif - - new->sock.remote_port = ((struct pico_trans *)f->transport_hdr)->sport; -#ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - new->sock.remote_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->src.addr; - new->sock.local_addr.ip4.addr = ((struct pico_ipv4_hdr *)(f->net_hdr))->dst.addr; - } -#endif -#ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - memcpy(new->sock.remote_addr.ip6.addr, ((struct pico_ipv6_hdr *)(f->net_hdr))->src, PICO_SIZE_IP6); - memcpy(new->sock.remote_addr.ip6.addr, ((struct pico_ipv6_hdr *)(f->net_hdr))->src, PICO_SIZE_IP6); - } -#endif - - /* Set socket limits */ - new->tcpq_in.max_size = PICO_DEFAULT_SOCKETQ; - new->tcpq_out.max_size = PICO_DEFAULT_SOCKETQ; - new->tcpq_hold.max_size = 2*PICO_TCP_DEFAULT_MSS; - - f->sock = &new->sock; - tcp_parse_options(f); - new->mss = PICO_TCP_DEFAULT_MSS; - new->rcv_nxt = long_be(hdr->seq) + 1; - new->snd_nxt = long_be(pico_paws()); - new->snd_last = new->snd_nxt; - new->cwnd = PICO_TCP_IW; - new->ssthresh = 40; - new->recv_wnd = short_be(hdr->rwnd); - new->jumbo = hdr->len & 0x07; - new->sock.parent = s; - new->sock.wakeup = s->wakeup; - /* Initialize timestamp values */ - new->sock.state = PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_RECV; - pico_socket_add(&new->sock); - tcp_send_synack(&new->sock); - tcp_dbg("SYNACK sent, socket added. snd_nxt is %08x\n", new->snd_nxt); - return 0; -} - -static void tcp_set_init_point(struct pico_socket *s) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->rcv_processed = t->rcv_nxt; -} - -static int tcp_synack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - - if (ACKN(f) == (1 + t->snd_nxt)) { - t->rcv_nxt = long_be(hdr->seq); - t->rcv_processed = t->rcv_nxt + 1; - tcp_ack(s, f); - - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; - tcp_dbg("TCP> Established. State: %x\n", s->state); - - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_CONN, s); - s->ev_pending |= PICO_SOCK_EV_WR; - - t->rcv_nxt++; - t->snd_nxt++; - tcp_send_ack(t); /* return ACK */ - - return 0; - - } else { - tcp_dbg("TCP> Not established, RST sent.\n"); - tcp_nosync_rst(s,f); - return 0; - } -} - -static int tcp_first_ack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("ACK in SYN_RECV: expecting %08x got %08x\n", t->snd_nxt, ACKN(f)); - if (t->snd_nxt == ACKN(f)) { - tcp_set_init_point(s); - tcp_ack(s, f); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_ESTABLISHED; - tcp_dbg("TCP: Established. State now: %04x\n", s->state); - if( !s->parent && s->wakeup) { /* If the socket has no parent, -> sending socket that has a sim_open */ - tcp_dbg("FIRST ACK - No parent found -> sending socket\n"); - s->wakeup(PICO_SOCK_EV_CONN, s); - } - if (s->parent && s->parent->wakeup) { - tcp_dbg("FIRST ACK - Parent found -> listening socket\n"); - s->wakeup = s->parent->wakeup; - s->parent->wakeup(PICO_SOCK_EV_CONN, s->parent); - } - s->ev_pending |= PICO_SOCK_EV_WR; - tcp_dbg("%s: snd_nxt is now %08x\n", __FUNCTION__, t->snd_nxt); - return 0; - } else { - tcp_nosync_rst(s,f); - return 0; - } -} - -static int tcp_closewait(struct pico_socket *s, struct pico_frame *f) -{ - - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - - if (f->payload_len > 0) - tcp_data_in(s,f); - if (f->flags & PICO_TCP_ACK) - tcp_ack(s,f); - if (seq_compare(SEQN(f), t->rcv_nxt) == 0) { - /* received FIN, increase ACK nr */ - t->rcv_nxt = long_be(hdr->seq) + 1; - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSE_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - tcp_dbg("TCP> Close-wait\n"); - if (s->wakeup){ - if(f->payload_len>0){ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - t->sock.ev_pending |=PICO_SOCK_EV_CLOSE; - }else - s->wakeup(PICO_SOCK_EV_CLOSE, s); - } - } else { - tcp_send_ack(t); /* return ACK */ - } - return 0; -} - -/*static int tcp_fin(struct pico_socket *s, struct pico_frame *f) -{ - return 0; -}*/ - -static int tcp_rcvfin(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("TCP> Received FIN in FIN_WAIT1\n"); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_CLOSING; - t->rcv_processed = t->rcv_nxt + 1; - t->rcv_nxt++; - /* send ACK */ - tcp_send_ack(t); - return 0; -} - -static int tcp_finack(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - tcp_dbg("TCP> ENTERED finack\n"); - t->rcv_nxt++; - /* send ACK */ - tcp_send_ack(t); - - /* call socket wakeup with EV_FIN */ - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_FIN, s); - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_TIME_WAIT; - /* set SHUT_REMOTE */ - s->state |= PICO_SOCKET_STATE_SHUT_REMOTE; - pico_timer_add(2000, tcp_deltcb, t); - - return 0; -} - -static int tcp_rst(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *) s; - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - - tcp_dbg("TCP >>>>>>>>>>>>>> received RST <<<<<<<<<<<<<<<<<<<<\n"); - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_SENT) { - /* the RST is acceptable if the ACK field acknowledges the SYN */ - if ((t->snd_nxt + 1) == ACKN(f)) { /* valid, got to closed state */ - /* update state */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - - /* call EV_FIN wakeup before deleting */ - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - - /* call EV_ERR wakeup before deleting */ - pico_err = PICO_ERR_ECONNRESET; - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); - - /* delete socket */ - pico_socket_del(&t->sock); - } else { /* not valid, ignore */ - tcp_dbg("TCP RST> IGNORE\n"); - return 0; - } - } else { /* all other states */ - /* all reset (RST) segments are validated by checking their SEQ-fields, - a reset is valid if its sequence number is in the window */ - if ((long_be(hdr->seq) >= t->rcv_ackd) && (long_be(hdr->seq) <= ((short_be(hdr->rwnd)<<(t->wnd_scale)) + t->rcv_ackd))) { - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_SYN_RECV) { - /* go to closed */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - /* call EV_ERR wakeup */ - pico_err = PICO_ERR_ECONNRESET; - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); - tcp_dbg("TCP RST> SOCKET BACK TO LISTEN\n"); - pico_socket_del(s); - } else { - /* go to closed */ - (t->sock).state &= 0x00FFU; - (t->sock).state |= PICO_SOCKET_STATE_TCP_CLOSED; - (t->sock).state &= 0xFF00U; - (t->sock).state |= PICO_SOCKET_STATE_CLOSED; - - /* call EV_FIN wakeup before deleting */ - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_FIN, &(t->sock)); - /* call EV_ERR wakeup before deleting */ - pico_err = PICO_ERR_ECONNRESET; - if ((t->sock).wakeup) - (t->sock).wakeup(PICO_SOCK_EV_ERR, &(t->sock)); - - /* delete socket */ - pico_socket_del(&t->sock); - } - } else { /* not valid, ignore */ - tcp_dbg("TCP RST> IGNORE\n"); - return 0; - } - } - - return 0; -} - -struct tcp_action_entry { - uint16_t tcpstate; - int (*syn)(struct pico_socket *s, struct pico_frame *f); - int (*synack)(struct pico_socket *s, struct pico_frame *f); - int (*ack)(struct pico_socket *s, struct pico_frame *f); - int (*data)(struct pico_socket *s, struct pico_frame *f); - int (*fin)(struct pico_socket *s, struct pico_frame *f); - int (*finack)(struct pico_socket *s, struct pico_frame *f); - int (*rst)(struct pico_socket *s, struct pico_frame *f); -}; - -static struct tcp_action_entry tcp_fsm[] = { - /* State syn synack ack data fin finack rst*/ - { PICO_SOCKET_STATE_TCP_UNDEF, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - { PICO_SOCKET_STATE_TCP_CLOSED, NULL, NULL, NULL, NULL, NULL, NULL, NULL }, - { PICO_SOCKET_STATE_TCP_LISTEN, &tcp_syn, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, NULL }, - { PICO_SOCKET_STATE_TCP_SYN_SENT, &tcp_nosync_rst, &tcp_synack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_SYN_RECV, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_first_ack, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_nosync_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_ESTABLISHED, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_data_in, &tcp_closewait, &tcp_closewait, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_CLOSE_WAIT, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_LAST_ACK, &tcp_send_rst, &tcp_send_rst, &tcp_lastackwait, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_FIN_WAIT1, &tcp_send_rst, &tcp_send_rst, &tcp_finwaitack, &tcp_data_in, &tcp_rcvfin, &tcp_finack, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_FIN_WAIT2, &tcp_send_rst, &tcp_send_rst, &tcp_ack, &tcp_data_in, &tcp_finwaitfin, &tcp_finack, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_CLOSING, &tcp_send_rst, &tcp_send_rst, &tcp_closewaitack, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst }, - { PICO_SOCKET_STATE_TCP_TIME_WAIT, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_send_rst, &tcp_rst } -}; - -/* - NOTE: in SYN-RECV receiving syn when cloned by default (see yellow pos-it), should send reset. -*/ - -int pico_tcp_input(struct pico_socket *s, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *) (f->transport_hdr); - int ret = 0; - uint8_t flags = hdr->flags; - struct tcp_action_entry *action = &tcp_fsm[s->state >> 8]; - - f->payload = (f->transport_hdr + ((hdr->len & 0xf0) >> 2)); - f->payload_len = f->transport_len - ((hdr->len & 0xf0) >> 2); - - tcp_dbg("[%lu] TCP> [tcp input] socket: %p state: %d <-- local port:%d remote port: %d seq: %08x ack: %08x flags: %02x = t_len: %d, hdr: %u payload: %d\n", pico_tick, - s, s->state >> 8, short_be(hdr->trans.dport), short_be(hdr->trans.sport), SEQN(f), ACKN(f), hdr->flags, f->transport_len, (hdr->len & 0xf0) >> 2, f->payload_len ); - - /* This copy of the frame has the current socket as owner */ - f->sock = s; - - /* Those are not supported at this time. */ - flags &= ~(PICO_TCP_CWR | PICO_TCP_URG | PICO_TCP_ECN); - if (flags == PICO_TCP_SYN) { - if (action->syn) - action->syn(s,f); - } else if (flags == (PICO_TCP_SYN | PICO_TCP_ACK)) { - if (action->synack) - action->synack(s,f); - } else { - if ((flags == PICO_TCP_ACK) || (flags == (PICO_TCP_ACK | PICO_TCP_PSH))) { - if (action->ack) { - action->ack(s,f); - } - } - if (f->payload_len > 0) { - ret = f->payload_len; - if (action->data) - action->data(s,f); - } - if (flags == PICO_TCP_FIN) { - if (action->fin) - action->fin(s,f); - } - if ((flags == (PICO_TCP_FIN | PICO_TCP_ACK)) || (flags == (PICO_TCP_FIN | PICO_TCP_ACK | PICO_TCP_PSH))) { - if (action->finack) - action->finack(s,f); - } - if (flags & PICO_TCP_RST) { - if (action->rst) - action->rst(s,f); - } - } - -//discard: - pico_frame_discard(f); - return ret; -} - -static void tcp_send_keepalive(unsigned long when, void *_t) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)_t; - tcp_dbg("\n\nSending keepalive (%d), [State = %d]...\n", t->backoff,t->sock.state ); - if( t->sock.net && ((t->sock.state & 0xFF00) == PICO_SOCKET_STATE_TCP_ESTABLISHED) ) - { - tcp_send_ack(t); - - if (t->keepalive_timer_running > 0) { - t->keepalive_timer_running--; - } - - if (t->keepalive_timer_running == 0) { - t->keepalive_timer_running++; - tcp_dbg("[Self] Adding timer(retransmit keepalive)\n"); - pico_timer_add(t->rto << (++t->backoff), tcp_send_keepalive, t); - } - } -} - -int pico_tcp_output(struct pico_socket *s, int loop_score) -{ - struct pico_socket_tcp *t = (struct pico_socket_tcp *)s; - struct pico_frame *f, *una; - struct pico_tcp_hdr *hdr; - int sent = 0; - - una = first_segment(&t->tcpq_out); - - f = peek_segment(&t->tcpq_out, t->snd_nxt); - while((f) && (t->cwnd >= t->in_flight)) { - hdr = (struct pico_tcp_hdr *)f->transport_hdr; - f->timestamp = pico_tick; - tcp_add_options(t, f, hdr->flags, tcp_options_size(t, hdr->flags)); - if (seq_compare(SEQN(f) + f->payload_len, SEQN(una) + (t->recv_wnd << t->recv_wnd_scale)) > 0) { - t->cwnd = t->in_flight; - if (t->cwnd < 1) - t->cwnd = 1; - if (t->x_mode != PICO_TCP_WINDOW_FULL) { - tcp_dbg("TCP> RIGHT SIZING (rwnd: %d, frame len: %d\n",t->recv_wnd << t->recv_wnd_scale, f->payload_len); - tcp_dbg("In window full...\n"); - t->snd_nxt = SEQN(una); - - /* Alternative to the line above: (better performance, but seems to lock anyway with larger buffers) - if (seq_compare(t->snd_nxt, SEQN(una)) > 0) - t->snd_nxt -= f->payload_len; - */ - - t->x_mode = PICO_TCP_WINDOW_FULL; - if (t->keepalive_timer_running == 0) { - tcp_dbg("[Window full] Adding timer(send keepalive)\n"); - tcp_send_keepalive(0, t); - } - } - break; - } - tcp_dbg("TCP> DEQUEUED (for output) frame %08x, acks %08x len= %d, remaining frames %d\n", SEQN(f), ACKN(f), f->payload_len,t->tcpq_out.frames); - tcp_send(t, f); - sent++; - loop_score--; - t->snd_last_out = SEQN(f); - if (loop_score < 1) - break; - if (f->payload_len > 0) { - f = next_segment(&t->tcpq_out, f); - } else { - f = NULL; - } - } - if (sent > 0) { - if (t->rto < PICO_TCP_RTO_MIN) - t->rto = PICO_TCP_RTO_MIN; - add_retransmission_timer(t, pico_tick + t->rto); - } else { - // no packets in queue ?? - } - - if ((t->tcpq_out.frames == 0) && (s->state & PICO_SOCKET_STATE_SHUT_LOCAL)) { /* if no more packets in queue, XXX replacled !f by tcpq check */ - if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_ESTABLISHED) { - tcp_dbg("TCP> buffer empty, shutdown established ...\n"); - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to FIN_WAIT1 */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_FIN_WAIT1; - } else if ((s->state & PICO_SOCKET_STATE_TCP) == PICO_SOCKET_STATE_TCP_CLOSE_WAIT) { - /* send fin if queue empty and in state shut local (write) */ - tcp_send_fin(t); - /* change tcp state to LAST_ACK */ - s->state &= 0x00FFU; - s->state |= PICO_SOCKET_STATE_TCP_LAST_ACK; - tcp_dbg("TCP> STATE: LAST_ACK.\n"); - } - } - return loop_score; -} - -/* function to make new segment from hold queue with specific size (mss) */ -static struct pico_frame * pico_hold_segment_make(struct pico_socket_tcp *t) -{ - struct pico_frame *f_temp,*f_new; - struct pico_socket *s = (struct pico_socket *) &t->sock; - struct pico_tcp_hdr *hdr; - int total_len = 0, total_payload_len = 0; - int off = 0, test = 0; - - off = pico_tcp_overhead(s); - - /* init with first frame in hold queue */ - f_temp = first_segment(&t->tcpq_hold); - total_len = f_temp->payload_len; - f_temp = next_segment(&t->tcpq_hold, f_temp); - - /* check till total_len <= MSS */ - while ((f_temp != NULL) && ((total_len+f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { - total_len += f_temp->payload_len; - f_temp = next_segment(&t->tcpq_hold, f_temp); - if (f_temp == NULL) - break; - } - /* alloc new frame with payload size = off + total_len */ - f_new = pico_socket_frame_alloc(s, off + total_len); - if (!f_new) { - pico_err = PICO_ERR_ENOMEM; - return f_new; - } - - hdr = (struct pico_tcp_hdr *) f_new->transport_hdr; - /* init new frame */ - f_new->payload += off; - f_new->payload_len -= off; - f_new->sock = s; - - f_temp = first_segment(&t->tcpq_hold); - hdr->seq = ((struct pico_tcp_hdr *)(f_temp->transport_hdr))->seq; /* get sequence number of first frame */ - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - - /* check till total_payload_len <= MSS */ - while ((f_temp != NULL) && ((total_payload_len + f_temp->payload_len) <= PICO_TCP_DEFAULT_MSS)) { - /* cpy data and discard frame */ - test++; - memcpy(f_new->payload + total_payload_len, f_temp->payload, f_temp->payload_len); - total_payload_len += f_temp->payload_len; - pico_discard_segment(&t->tcpq_hold, f_temp); - f_temp = first_segment(&t->tcpq_hold); - } - - hdr->len = (f_new->payload - f_new->transport_hdr) << 2 | t->jumbo; - - tcp_dbg("NAGLE make - joined %d segments, len %d bytes\n",test,total_payload_len); - - return f_new; -} - -/* original behavior kept when Nagle disabled; - Nagle algorithm added here, keeping hold frame queue instead of eg linked list of data */ -int pico_tcp_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_tcp_hdr *hdr = (struct pico_tcp_hdr *)f->transport_hdr; - struct pico_socket_tcp *t = (struct pico_socket_tcp *) f->sock; - struct pico_frame *f_new; - int total_len = 0; - - hdr->trans.sport = t->sock.local_port; - hdr->trans.dport = t->sock.remote_port; - hdr->seq = long_be(t->snd_last + 1); - hdr->len = (f->payload - f->transport_hdr) << 2 | t->jumbo; - - if (f->payload_len > (t->tcpq_out.max_size - t->tcpq_out.size)) - t->sock.ev_pending &= (~PICO_SOCK_EV_WR); - - /***************************************************************************/ - - if (!IS_NAGLE_ENABLED((&(t->sock)))) { - /* TCP_NODELAY enabled, original behavior */ - if (pico_enqueue_segment(&t->tcpq_out,f) > 0) { - tcp_dbg("TCP_PUSH - NO NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); - t->snd_last += f->payload_len; - return f->payload_len; - } else { - tcp_dbg("Enqueue failed.\n"); - return 0; - } - } - /***************************************************************************/ - else { - /* Nagle's algorithm enabled, check if ready to send, or put frame in hold queue */ - if (IS_TCP_IDLE(t) && IS_TCP_HOLDQ_EMPTY(t)) { /* opt 1. send frame */ - if (pico_enqueue_segment(&t->tcpq_out,f) > 0) { - tcp_dbg("TCP_PUSH - NAGLE - Pushing segment %08x, len %08x to socket %p\n", t->snd_last + 1, f->payload_len, t); - t->snd_last += f->payload_len; - return f->payload_len; - } else { - tcp_dbg("Enqueue failed.\n"); - return 0; - } - } else { /* opt 2. hold data back */ - total_len = f->payload_len + t->tcpq_hold.size; - if ((total_len >= PICO_TCP_DEFAULT_MSS) && ((t->tcpq_out.max_size - t->tcpq_out.size) >= PICO_TCP_DEFAULT_MSS)) {/* TODO check mss socket */ - /* IF enough data in hold (>mss) AND space in out queue (>mss) */ - /* add current frame in hold and make new segment */ - if (pico_enqueue_segment(&t->tcpq_hold,f) > 0 ) { - tcp_dbg("TCP_PUSH - NAGLE - Pushed into hold, make new (enqueued frames out %d)\n",t->tcpq_out.frames); - t->snd_last += f->payload_len; /* XXX WATCH OUT */ - f_new = pico_hold_segment_make(t); - } else { - tcp_dbg("TCP_PUSH - NAGLE - enqueue hold failed 1\n"); - return 0; - } - /* and put new frame in out queue */ - if ((f_new != NULL) && (pico_enqueue_segment(&t->tcpq_out,f_new) > 0)) { - return f_new->payload_len; - } else { - tcp_dbg("TCP_PUSH - NAGLE - enqueue out failed, f_new = %p\n",f_new); - return -1; /* XXX something seriously wrong */ - } - } else { - /* ELSE put frame in hold queue */ - if (pico_enqueue_segment(&t->tcpq_hold,f) > 0) { - tcp_dbg("TCP_PUSH - NAGLE - Pushed into hold (enqueued frames out %d)\n",t->tcpq_out.frames); - t->snd_last += f->payload_len; /* XXX WATCH OUT */ - return f->payload_len; - } else { - tcp_dbg("TCP_PUSH - NAGLE - enqueue hold failed 2\n"); - return 0; - } - } - } - } - /***************************************************************************/ -} -#endif //PICO_SUPPORT_TCP
--- a/modules/pico_tcp.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_TCP -#define _INCLUDE_PICO_TCP -#include "pico_addressing.h" -#include "pico_protocol.h" -#include "pico_socket.h" - -extern struct pico_protocol pico_proto_tcp; - -struct __attribute__((packed)) pico_tcp_hdr { - struct pico_trans trans; - uint32_t seq; - uint32_t ack; - uint8_t len; - uint8_t flags; - uint16_t rwnd; - uint16_t crc; - uint16_t urgent; -}; - -struct __attribute__((packed)) tcp_pseudo_hdr_ipv4 -{ - struct pico_ip4 src; - struct pico_ip4 dst; - uint16_t tcp_len; - uint8_t res; - uint8_t proto; -}; - -#define PICO_TCPHDR_SIZE 20 -#define PICO_SIZE_TCPOPT_SYN 20 -#define PICO_SIZE_TCPHDR (sizeof(struct pico_tcp_hdr)) - -#define PICO_TCP_DEFAULT_MSS 1444 - - - -/* TCP options */ -#define PICO_TCP_OPTION_END 0x00 -#define PICO_TCPOPTLEN_END 1 -#define PICO_TCP_OPTION_NOOP 0x01 -#define PICO_TCPOPTLEN_NOOP 1 -#define PICO_TCP_OPTION_MSS 0x02 -#define PICO_TCPOPTLEN_MSS 4 -#define PICO_TCP_OPTION_WS 0x03 -#define PICO_TCPOPTLEN_WS 3 -#define PICO_TCP_OPTION_SACK_OK 0x04 -#define PICO_TCPOPTLEN_SACK_OK 2 -#define PICO_TCP_OPTION_SACK 0x05 -#define PICO_TCPOPTLEN_SACK 2 /* Plus the block */ -#define PICO_TCP_OPTION_TIMESTAMP 0x08 -#define PICO_TCPOPTLEN_TIMESTAMP 10 - -/* TCP flags */ -#define PICO_TCP_FIN 0x01 -#define PICO_TCP_SYN 0x02 -#define PICO_TCP_RST 0x04 -#define PICO_TCP_PSH 0x08 -#define PICO_TCP_ACK 0x10 -#define PICO_TCP_URG 0x20 -#define PICO_TCP_ECN 0x40 -#define PICO_TCP_CWR 0x80 - - - -struct __attribute__((packed)) pico_tcp_option -{ - uint8_t kind; - uint8_t len; -#if 0 - union { - uint16_t mss; - uint8_t wshift; - struct { - uint32_t tsval; - uint32_t tsecr; - } timestamp; - } data; -#endif -}; - -struct pico_socket *pico_tcp_open(void); -int pico_tcp_read(struct pico_socket *s, void *buf, int len); -int pico_tcp_initconn(struct pico_socket *s); -int pico_tcp_input(struct pico_socket *s, struct pico_frame *f); -uint16_t pico_tcp_checksum_ipv4(struct pico_frame *f); -int pico_tcp_overhead(struct pico_socket *s); -int pico_tcp_output(struct pico_socket *s, int loop_score); -int pico_tcp_queue_in_is_empty(struct pico_socket *s); -int pico_tcp_reply_rst(struct pico_frame *f); - -#endif
--- a/modules/pico_udp.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,176 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_udp.h" -#include "pico_config.h" -#include "pico_eth.h" -#include "pico_socket.h" -#include "pico_stack.h" - - -/* Queues */ -static struct pico_queue udp_in = {}; -static struct pico_queue udp_out = {}; - - -/* Functions */ - -uint16_t pico_udp_checksum_ipv4(struct pico_frame *f) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_udp_hdr *udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - struct pico_socket *s = f->sock; - struct pico_ipv4_pseudo_hdr pseudo; - - if (s) { - /* Case of outgoing frame */ - //dbg("UDP CRC: on outgoing frame\n"); - pseudo.src.addr = s->local_addr.ip4.addr; - pseudo.dst.addr = s->remote_addr.ip4.addr; - } else { - /* Case of incomming frame */ - //dbg("UDP CRC: on incomming frame\n"); - pseudo.src.addr = hdr->src.addr; - pseudo.dst.addr = hdr->dst.addr; - } - pseudo.zeros = 0; - pseudo.proto = PICO_PROTO_UDP; - pseudo.len = short_be(f->transport_len); - - return pico_dualbuffer_checksum(&pseudo, sizeof(struct pico_ipv4_pseudo_hdr), udp_hdr, f->transport_len); -} - - -static int pico_udp_process_out(struct pico_protocol *self, struct pico_frame *f) -{ - return pico_network_send(f); -} - -static int pico_udp_push(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_udp_hdr *hdr = (struct pico_udp_hdr *) f->transport_hdr; - struct pico_remote_duple *remote_duple = (struct pico_remote_duple *) f->info; - - /* this (fragmented) frame should contain a transport header */ - if (f->transport_hdr != f->payload) { - hdr->trans.sport = f->sock->local_port; - if (remote_duple) { - hdr->trans.dport = remote_duple->remote_port; - } else { - hdr->trans.dport = f->sock->remote_port; - } - hdr->len = short_be(f->transport_len); - /* do not perform CRC validation. If you want to, a system needs to be - implemented to calculate the CRC over the total payload of a - fragmented payload */ - hdr->crc = 0; - } - - if (pico_enqueue(self->q_out, f) > 0) { - return f->payload_len; - } else { - return 0; - } -} - -/* Interface: protocol definition */ -struct pico_protocol pico_proto_udp = { - .name = "udp", - .proto_number = PICO_PROTO_UDP, - .layer = PICO_LAYER_TRANSPORT, - .process_in = pico_transport_process_in, - .process_out = pico_udp_process_out, - .push = pico_udp_push, - .q_in = &udp_in, - .q_out = &udp_out, -}; - - -#define PICO_UDP_MODE_UNICAST 0x01 -#define PICO_UDP_MODE_MULTICAST 0x02 -#define PICO_UDP_MODE_BROADCAST 0xFF - -struct pico_socket_udp -{ - struct pico_socket sock; - int mode; -#ifdef PICO_SUPPORT_MCAST - uint8_t mc_ttl; /* Multicasting TTL */ -#endif -}; - -#ifdef PICO_SUPPORT_MCAST -int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl) -{ - struct pico_socket_udp *u; - if(!s) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - u = (struct pico_socket_udp *) s; - u->mc_ttl = ttl; - return 0; -} - -int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) -{ - struct pico_socket_udp *u; - if(!s) - return -1; - u = (struct pico_socket_udp *) s; - *ttl = u->mc_ttl; - return 0; -} -#endif /* PICO_SUPPORT_MCAST */ - -struct pico_socket *pico_udp_open(void) -{ - struct pico_socket_udp *u = pico_zalloc(sizeof(struct pico_socket_udp)); - if (!u) - return NULL; - u->mode = PICO_UDP_MODE_UNICAST; - -#ifdef PICO_SUPPORT_MCAST - u->mc_ttl = PICO_IP_DEFAULT_MULTICAST_TTL; - /* enable multicast loopback by default */ - u->sock.opt_flags |= (1 << PICO_SOCKET_OPT_MULTICAST_LOOP); -#endif - - return &u->sock; -} - -int pico_udp_recv(struct pico_socket *s, void *buf, int len, void *src, uint16_t *port) -{ - struct pico_frame *f = pico_queue_peek(&s->q_in); - if (f) { - f->payload = f->transport_hdr + sizeof(struct pico_udp_hdr); - f->payload_len = f->transport_len - sizeof(struct pico_udp_hdr); -// dbg("expected: %d, got: %d\n", len, f->payload_len); - if (src) - pico_store_network_origin(src, f); - if (port) { - struct pico_trans *hdr = (struct pico_trans *)f->transport_hdr; - *port = hdr->sport; - } - if (f->payload_len > len) { - memcpy(buf, f->payload, len); - f->payload += len; - f->payload_len -= len; - return len; - } else { - int ret = f->payload_len; - memcpy(buf, f->payload, f->payload_len); - f = pico_dequeue(&s->q_in); - pico_frame_discard(f); - return ret; - } - } else return 0; -} -
--- a/modules/pico_udp.h Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,42 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -*********************************************************************/ -#ifndef _INCLUDE_PICO_UDP -#define _INCLUDE_PICO_UDP -#include "pico_addressing.h" -#include "pico_protocol.h" - -extern struct pico_protocol pico_proto_udp; - -struct __attribute__((packed)) pico_udp_hdr { - struct pico_trans trans; - uint16_t len; - uint16_t crc; -}; -#define PICO_UDPHDR_SIZE 8 - -struct pico_socket *pico_udp_open(void); -int pico_udp_recv(struct pico_socket *s, void *buf, int len, void *src, uint16_t *port); -uint16_t pico_udp_checksum_ipv4(struct pico_frame *f); - -#ifdef PICO_SUPPORT_MCAST -int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl); -int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl); -#else -static inline int pico_udp_set_mc_ttl(struct pico_socket *s, uint8_t ttl) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -static inline int pico_udp_get_mc_ttl(struct pico_socket *s, uint8_t *ttl) -{ - pico_err = PICO_ERR_EPROTONOSUPPORT; - return -1; -} -#endif /* PICO_SUPPORT_MCAST */ - -#endif
--- a/stack/pico_arp.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,317 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_arp.h" -#include "pico_tree.h" -#include "pico_ipv4.h" -#include "pico_device.h" -#include "pico_stack.h" - -const uint8_t PICO_ETHADDR_ALL[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; -#define PICO_ARP_TIMEOUT 600000 -#define PICO_ARP_RETRY 300 - -#ifdef DEBUG_ARP - #define arp_dbg dbg -#else - #define arp_dbg(...) do{}while(0) -#endif - -static struct pico_queue pending; -static int pending_timer_on = 0; - -void check_pending(unsigned long now, void *_unused) -{ - struct pico_frame *f = pico_dequeue(&pending); - if (!f) { - pending_timer_on = 0; - return; - } - if(pico_ethernet_send(f) > 0) - pico_frame_discard(f); - pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL); -} - - -struct -__attribute__ ((__packed__)) -pico_arp_hdr -{ - uint16_t htype; - uint16_t ptype; - uint8_t hsize; - uint8_t psize; - uint16_t opcode; - uint8_t s_mac[PICO_SIZE_ETH]; - struct pico_ip4 src; - uint8_t d_mac[PICO_SIZE_ETH]; - struct pico_ip4 dst; -}; - - -#define PICO_SIZE_ARPHDR ((sizeof(struct pico_arp_hdr))) - -/* Arp Entries for the tables. */ -struct pico_arp { -/* CAREFUL MAN! ARP entry MUST begin with a pico_eth structure, - * due to in-place casting!!! */ - struct pico_eth eth; - struct pico_ip4 ipv4; - int arp_status; - uint32_t timestamp; - struct pico_device *dev; -}; - - - -/*****************/ -/** ARP TREE **/ -/*****************/ - -/* Routing destination */ - -static int arp_compare(void * ka, void * kb) -{ - struct pico_arp *a = ka, *b = kb; - if (a->ipv4.addr < b->ipv4.addr) - return -1; - else if (a->ipv4.addr > b->ipv4.addr) - return 1; - return 0; -} - -PICO_TREE_DECLARE(arp_tree, arp_compare); - -/*********************/ -/** END ARP TREE **/ -/*********************/ - -struct pico_eth *pico_arp_lookup(struct pico_ip4 *dst) -{ - struct pico_arp search, *found; - search.ipv4.addr = dst->addr; - found = pico_tree_findKey(&arp_tree,&search); - if (found && (found->arp_status != PICO_ARP_STATUS_STALE)) - return &found->eth; - return NULL; -} - -struct pico_ip4 *pico_arp_reverse_lookup(struct pico_eth *dst) -{ - struct pico_arp* search; - struct pico_tree_node * index; - pico_tree_foreach(index,&arp_tree){ - search = index->keyValue; - if(memcmp(&(search->eth.addr), &dst->addr, 6) == 0) - return &search->ipv4; - } - return NULL; -} - -struct pico_eth *pico_arp_get(struct pico_frame *f) { - struct pico_eth *a4; - struct pico_ip4 gateway; - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_ipv4_link *l; - - l = pico_ipv4_link_get(&hdr->dst); - if(l){ - //address belongs to ourself - return &l->dev->eth->mac; - } - - gateway = pico_ipv4_route_get_gateway(&hdr->dst); - /* check if dst is local (gateway = 0), or if to use gateway */ - if (gateway.addr != 0) - a4 = pico_arp_lookup(&gateway); /* check if gateway ip mac in cache */ - else - a4 = pico_arp_lookup(&hdr->dst); /* check if local ip mac in cache */ - if (!a4) { - if (++f->failure_count < 4) { - dbg ("================= ARP REQUIRED: %d =============\n\n", f->failure_count); - /* check if dst is local (gateway = 0), or if to use gateway */ - if (gateway.addr != 0) - pico_arp_query(f->dev, &gateway); /* arp to gateway */ - else - pico_arp_query(f->dev, &hdr->dst); /* arp to dst */ - - pico_enqueue(&pending, f); - if (!pending_timer_on) { - pending_timer_on++; - pico_timer_add(PICO_ARP_RETRY, &check_pending, NULL); - } - } else { - dbg("ARP: Destination Unreachable\n"); - pico_notify_dest_unreachable(f); - pico_frame_discard(f); - } - } - return a4; -} - -#ifdef DEBUG_ARP -void dbg_arp(void) -{ - struct pico_arp *a; - struct pico_tree_node * index; - - pico_tree_foreach(index,&arp_tree) { - a = index->keyValue; - arp_dbg("ARP to %08x, mac: %02x:%02x:%02x:%02x:%02x:%02x\n", a->ipv4.addr,a->eth.addr[0],a->eth.addr[1],a->eth.addr[2],a->eth.addr[3],a->eth.addr[4],a->eth.addr[5] ); - } -} -#endif - -void arp_expire(unsigned long now, void *_stale) -{ - struct pico_arp *stale = (struct pico_arp *) _stale; - stale->arp_status = PICO_ARP_STATUS_STALE; - arp_dbg("ARP: Setting arp_status to STALE\n"); - pico_arp_query(stale->dev, &stale->ipv4); - -} - -void pico_arp_add_entry(struct pico_arp *entry) -{ - entry->arp_status = PICO_ARP_STATUS_REACHABLE; - entry->timestamp = PICO_TIME(); - - pico_tree_insert(&arp_tree,entry); - arp_dbg("ARP ## reachable.\n"); - pico_timer_add(PICO_ARP_TIMEOUT, arp_expire, entry); -} - -int pico_arp_create_entry(uint8_t* hwaddr, struct pico_ip4 ipv4, struct pico_device* dev) -{ - struct pico_arp* arp = pico_zalloc(sizeof(struct pico_arp)); - if(!arp){ - pico_err = PICO_ERR_ENOMEM; - return -1; - } - memcpy(arp->eth.addr, hwaddr, 6); - arp->ipv4.addr = ipv4.addr; - arp->dev = dev; - - pico_arp_add_entry(arp); - - return 0; -} - -int pico_arp_receive(struct pico_frame *f) -{ - struct pico_arp_hdr *hdr; - struct pico_arp search, *found, *new = NULL; - int ret = -1; - hdr = (struct pico_arp_hdr *) f->net_hdr; - - if (!hdr) - goto end; - - - /* Populate a new arp entry */ - search.ipv4.addr = hdr->src.addr; - memcpy(search.eth.addr, hdr->s_mac, PICO_SIZE_ETH); - - /* Search for already existing entry */ - - found = pico_tree_findKey(&arp_tree,&search); - if (!found) { - new = pico_zalloc(sizeof(struct pico_arp)); - if (!new) - goto end; - new->ipv4.addr = hdr->src.addr; - } - else if (found->arp_status == PICO_ARP_STATUS_STALE) { - /* Replace if stale */ - new = found; - - pico_tree_delete(&arp_tree,new); - } - - ret = 0; - - if (new) { - memcpy(new->eth.addr, hdr->s_mac, PICO_SIZE_ETH); - new->dev = f->dev; - pico_arp_add_entry(new); - } - - if (hdr->opcode == PICO_ARP_REQUEST) { - struct pico_ip4 me; - struct pico_eth_hdr *eh = (struct pico_eth_hdr *)f->datalink_hdr; - struct pico_device *link_dev; - me.addr = hdr->dst.addr; - - link_dev = pico_ipv4_link_find(&me); - if (link_dev != f->dev) - goto end; - - hdr->opcode = PICO_ARP_REPLY; - memcpy(hdr->d_mac, hdr->s_mac, PICO_SIZE_ETH); - memcpy(hdr->s_mac, f->dev->eth->mac.addr, PICO_SIZE_ETH); - hdr->dst.addr = hdr->src.addr; - hdr->src.addr = me.addr; - - /* Prepare eth header for arp reply */ - memcpy(eh->daddr, eh->saddr, PICO_SIZE_ETH); - memcpy(eh->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - f->start = f->datalink_hdr; - f->len = PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR; - f->dev->send(f->dev, f->start, f->len); - } - -#ifdef DEBUG_ARG - dbg_arp(); -#endif - -end: - pico_frame_discard(f); - return ret; -} - -int pico_arp_query(struct pico_device *dev, struct pico_ip4 *dst) -{ - struct pico_frame *q = pico_frame_alloc(PICO_SIZE_ETHHDR + PICO_SIZE_ARPHDR); - struct pico_eth_hdr *eh; - struct pico_arp_hdr *ah; - struct pico_ip4 *src; - int ret; - - src = pico_ipv4_source_find(dst); - if (!src) - return -1; - - arp_dbg("QUERY: %08x\n", dst->addr); - - if (!q) - return -1; - eh = (struct pico_eth_hdr *)q->start; - ah = (struct pico_arp_hdr *) (q->start + PICO_SIZE_ETHHDR); - - /* Fill eth header */ - memcpy(eh->saddr, dev->eth->mac.addr, PICO_SIZE_ETH); - memcpy(eh->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH); - eh->proto = PICO_IDETH_ARP; - - /* Fill arp header */ - ah->htype = PICO_ARP_HTYPE_ETH; - ah->ptype = PICO_IDETH_IPV4; - ah->hsize = PICO_SIZE_ETH; - ah->psize = PICO_SIZE_IP4; - ah->opcode = PICO_ARP_REQUEST; - memcpy(ah->s_mac, dev->eth->mac.addr, PICO_SIZE_ETH); - ah->src.addr = src->addr; - ah->dst.addr = dst->addr; - arp_dbg("Sending arp query.\n"); - ret = dev->send(dev, q->start, q->len); - pico_frame_discard(q); - return ret; -}
--- a/stack/pico_device.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,246 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_device.h" -#include "pico_stack.h" -#include "pico_protocol.h" -#include "pico_tree.h" - - -static int pico_dev_cmp(void *ka, void *kb) -{ - struct pico_device *a = ka, *b = kb; - if (a->hash < b->hash) - return -1; - if (a->hash > b->hash) - return 1; - return 0; -} - -PICO_TREE_DECLARE(Device_tree,pico_dev_cmp); - -int pico_device_init(struct pico_device *dev, char *name, uint8_t *mac) -{ - int len = strlen(name); - if(len>MAX_DEVICE_NAME) - len = MAX_DEVICE_NAME; - memcpy(dev->name, name, len); - dev->hash = pico_hash(dev->name); - - pico_tree_insert(&Device_tree,dev); - dev->q_in = pico_zalloc(sizeof(struct pico_queue)); - dev->q_out = pico_zalloc(sizeof(struct pico_queue)); - - if (mac) { - dev->eth = pico_zalloc(sizeof(struct pico_ethdev)); - memcpy(dev->eth->mac.addr, mac, PICO_SIZE_ETH); - } else { - dev->eth = NULL; - } - - if (!dev->q_in || !dev->q_out || (mac && !dev->eth)) - return -1; - return 0; -} - -void pico_device_destroy(struct pico_device *dev) -{ - if (dev->destroy) - dev->destroy(dev); - - if (dev->q_in) { - pico_queue_empty(dev->q_in); - pico_free(dev->q_in); - } - if (dev->q_out) { - pico_queue_empty(dev->q_out); - pico_free(dev->q_out); - } - - if (dev->eth) - pico_free(dev->eth); - - pico_tree_delete(&Device_tree,dev); - pico_free(dev); -} - -static int devloop(struct pico_device *dev, int loop_score, int direction) -{ - struct pico_frame *f; - - /* If device supports interrupts, read the value of the condition and trigger the dsr */ - if ((dev->__serving_interrupt) && (dev->dsr)) { - /* call dsr routine */ - loop_score = dev->dsr(dev, loop_score); - } - - /* If device supports polling, give control. Loop score is managed internally, - * remaining loop points are returned. */ - if (dev->poll) { - loop_score = dev->poll(dev, loop_score); - } - - if (direction == PICO_LOOP_DIR_OUT) { - - while(loop_score > 0) { - if (dev->q_out->frames <= 0) - break; - - /* Device dequeue + send */ - f = pico_dequeue(dev->q_out); - if (f) { - if (dev->eth) { - int ret = pico_ethernet_send(f); - if (0 == ret) { - loop_score--; - continue; - } if (ret < 0) { - if (!pico_source_is_local(f)) { - dbg("Destination unreachable -------> SEND ICMP\n"); - pico_notify_dest_unreachable(f); - } else { - dbg("Destination unreachable -------> LOCAL\n"); - } - pico_frame_discard(f); - continue; - } - } else { - dev->send(dev, f->start, f->len); - } - pico_frame_discard(f); - loop_score--; - } - } - - } else if (direction == PICO_LOOP_DIR_IN) { - - while(loop_score > 0) { - if (dev->q_in->frames <= 0) - break; - - /* Receive */ - f = pico_dequeue(dev->q_in); - if (f) { - if (dev->eth) { - f->datalink_hdr = f->buffer; - pico_ethernet_receive(f); - } else { - f->net_hdr = f->buffer; - pico_network_receive(f); - } - loop_score--; - } - } - } - - return loop_score; -} - - -#define DEV_LOOP_MIN 16 - -int pico_devices_loop(int loop_score, int direction) -{ - struct pico_device *start; - static struct pico_device *next = NULL, *next_in = NULL, *next_out = NULL; - static struct pico_tree_node * next_node, * in_node, * out_node; - - if (next_in == NULL) { - in_node = pico_tree_firstNode(Device_tree.root); - next_in = in_node->keyValue; - } - if (next_out == NULL) { - out_node = pico_tree_firstNode(Device_tree.root); - next_out = out_node->keyValue; - } - - if (direction == PICO_LOOP_DIR_IN) - { - next_node = in_node; - next = next_in; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - next_node = out_node; - next = next_out; - } - - /* init start node */ - start = next; - - /* round-robin all devices, break if traversed all devices */ - while (loop_score > DEV_LOOP_MIN && next != NULL) { - loop_score = devloop(next, loop_score, direction); - - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - - if (next == NULL) - { - next_node = pico_tree_firstNode(Device_tree.root); - next = next_node->keyValue; - } - if (next == start) - break; - } - - if (direction == PICO_LOOP_DIR_IN) - { - in_node = next_node; - next_in = next; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - out_node = next_node; - next_out = next; - } - - return loop_score; -} - -struct pico_device* pico_get_device(char* name) -{ - struct pico_device *dev; - struct pico_tree_node * index; - pico_tree_foreach(index, &Device_tree){ - dev = index->keyValue; - if(strcmp(name, dev->name) == 0) - return dev; - } - return NULL; -} - -int pico_device_broadcast(struct pico_frame * f) -{ - struct pico_tree_node * index; - int ret = -1; - - pico_tree_foreach(index,&Device_tree) - { - struct pico_device * dev = index->keyValue; - if(dev != f->dev) - { - struct pico_frame * copy = pico_frame_copy(f); - - if(!copy) - return -1; - copy->dev = dev; - copy->dev->send(copy->dev, copy->start, copy->len); - pico_frame_discard(copy); - } - else - { - ret = f->dev->send(f->dev, f->start, f->len); - } - } - - return ret; -}
--- a/stack/pico_frame.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,195 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_frame.h" - -#ifdef PICO_SUPPORT_DEBUG_MEMORY -static int n_frames_allocated; -#endif - -/** frame alloc/dealloc/copy **/ -void pico_frame_discard(struct pico_frame *f) -{ - (*f->usage_count)--; - if (*f->usage_count <= 0) { - pico_free(f->usage_count); -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Discarded buffer @%p, caller: %p\n", f->buffer, __builtin_return_address(3)); - dbg("DEBUG MEMORY: %d frames in use.\n", --n_frames_allocated); -#endif - pico_free(f->buffer); - if (f->info) - pico_free(f->info); - } -#ifdef PICO_SUPPORT_DEBUG_MEMORY - else { - dbg("Removed frame @%p(copy), usage count now: %d\n", f, *f->usage_count); - } -#endif - pico_free(f); -} - -struct pico_frame *pico_frame_copy(struct pico_frame *f) -{ - struct pico_frame *new = pico_zalloc(sizeof(struct pico_frame)); - if (!new) - return NULL; - memcpy(new, f, sizeof(struct pico_frame)); - *(new->usage_count) += 1; -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count); -#endif - new->next = NULL; - return new; -} - - -struct pico_frame *pico_frame_alloc(int size) -{ - struct pico_frame *p = pico_zalloc(sizeof(struct pico_frame)); - if (!p) - return NULL; - p->buffer = pico_zalloc(size); - if (!p->buffer) { - pico_free(p); - return NULL; - } - p->usage_count = pico_zalloc(sizeof(uint32_t)); - if (!p->usage_count) { - pico_free(p->buffer); - pico_free(p); - return NULL; - } - p->buffer_len = size; - - - /* By default, frame content is the full buffer. */ - p->start = p->buffer; - p->len = p->buffer_len; - *p->usage_count = 1; -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Allocated buffer @%p, len= %d caller: %p\n", p->buffer, p->buffer_len, __builtin_return_address(2)); - dbg("DEBUG MEMORY: %d frames in use.\n", ++n_frames_allocated); -#endif - return p; -} - -struct pico_frame *pico_frame_deepcopy(struct pico_frame *f) -{ - struct pico_frame *new = pico_frame_alloc(f->buffer_len); - int addr_diff; - unsigned char *buf; - uint32_t *uc; - if (!new) - return NULL; - - /* Save the two key pointers... */ - buf = new->buffer; - uc = new->usage_count; - - /* Overwrite all fields with originals */ - memcpy(new, f, sizeof(struct pico_frame)); - - /* ...restore the two key pointers */ - new->buffer = buf; - new->usage_count = uc; - - /* Update in-buffer pointers with offset */ - addr_diff = (int)new->buffer - (int)f->buffer; - new->net_hdr += addr_diff; - new->transport_hdr += addr_diff; - new->app_hdr += addr_diff; - new->start += addr_diff; - new->payload += addr_diff; - -#ifdef PICO_SUPPORT_DEBUG_MEMORY - dbg("Deep-Copied frame @%p, into %p, usage count now: %d\n", f, new, *new->usage_count); -#endif - new->next = NULL; - return new; -} - -/** - * Calculate checksum of a given string - */ -uint16_t pico_checksum(void *inbuf, int len) -{ - uint8_t *buf = (uint8_t *) inbuf; - uint16_t tmp = 0; - uint32_t sum = 0, carry=0; - int i=0; - for(i=0; i<len; i++){ - if (i%2){ - sum+=buf[i]; - }else{ - tmp = buf[i]; - sum+=( tmp << 8); - } - } - carry = (sum&0xFFFF0000) >>16; - sum = (sum&0x0000FFFF); - return (uint16_t) ~(sum + carry) ; -} - -uint16_t pico_dualbuffer_checksum(void *inbuf1, int len1, void *inbuf2, int len2) -{ - uint8_t *b1 = (uint8_t *) inbuf1; - uint8_t *b2 = (uint8_t *) inbuf2; - uint16_t tmp = 0; - uint32_t sum = 0, carry=0; - int i=0, j=0; - for(i=0; i<len1; i++){ - if (j%2){ - sum+=b1[i]; - }else{ - tmp = b1[i]; - sum+=( tmp << 8); - } - j++; - } - - for(i=0; i<len2; i++){ - if (j%2){ - sum+=b2[i]; - }else{ - tmp = b2[i]; - sum+=( tmp << 8); - } - j++; - } - carry = (sum&0xFFFF0000) >>16; - sum = (sum&0x0000FFFF); - return (uint16_t) (~(sum + carry)) ; -} - -uint16_t pico_dualbuffer_checksum_broken(void *inbuf1, int len1, void *inbuf2, int len2) -{ - uint16_t *b1 = (uint16_t *) inbuf1; - uint16_t *b2 = (uint16_t *) inbuf2; - uint32_t sum = 0; - int i=0, j=0; - for(i=0; i<(len1>>1); i++){ - sum += short_be(b1[i]); - j++; - } - for(i=0; i<(len2>>1); i++){ - sum += short_be(b2[i]); - j++; - } - sum = (sum & 0xFFFF) + (sum >> 16); - sum += (sum >> 16); - - // Take the bitwise complement of sum - sum = ~sum; - return (uint16_t) (sum) ; -} - -
--- a/stack/pico_protocol.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,350 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_protocol.h" -#include "pico_tree.h" - -static int pico_proto_cmp(void *ka, void *kb) -{ - struct pico_protocol *a = ka, *b=kb; - if (a->hash < b->hash) - return -1; - if (a->hash > b->hash) - return 1; - return 0; -} - -PICO_TREE_DECLARE(Datalink_proto_tree,pico_proto_cmp); -PICO_TREE_DECLARE(Network_proto_tree,pico_proto_cmp); -PICO_TREE_DECLARE(Transport_proto_tree,pico_proto_cmp); -PICO_TREE_DECLARE(Socket_proto_tree,pico_proto_cmp); - -static int proto_loop(struct pico_protocol *proto, int loop_score, int direction) -{ - struct pico_frame *f; - - if (direction == PICO_LOOP_DIR_IN) { - - while(loop_score >0) { - if (proto->q_in->frames <= 0) - break; - - f = pico_dequeue(proto->q_in); - if ((f) &&(proto->process_in(proto, f) > 0)) { - loop_score--; - } - } - - } else if (direction == PICO_LOOP_DIR_OUT) { - - while(loop_score >0) { - if (proto->q_out->frames <= 0) - break; - - f = pico_dequeue(proto->q_out); - if ((f) &&(proto->process_out(proto, f) > 0)) { - loop_score--; - } - } - } - - return loop_score; -} - -#define DL_LOOP_MIN 1 - -int pico_protocol_datalink_loop(int loop_score, int direction) -{ - struct pico_protocol *start; - static struct pico_protocol *next = NULL, *next_in = NULL, *next_out = NULL; - static struct pico_tree_node * next_node, * in_node, * out_node; - - if (next_in == NULL) { - in_node = pico_tree_firstNode(Datalink_proto_tree.root); - if (in_node) - next_in = in_node->keyValue; - } - if (next_out == NULL) { - out_node = pico_tree_firstNode(Datalink_proto_tree.root); - if (out_node) - next_out = out_node->keyValue; - } - - if (direction == PICO_LOOP_DIR_IN) - { - next_node = in_node; - next = next_in; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - next_node = out_node; - next = next_out; - } - - /* init start node */ - start = next; - - /* round-robin all datalink protocols, break if traversed all protocols */ - while (loop_score > DL_LOOP_MIN && next != NULL) { - loop_score = proto_loop(next, loop_score, direction); - - //next = RB_NEXT(pico_protocol_tree, &Datalink_proto_tree, next); - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - - if (next == NULL) - { - next_node = pico_tree_firstNode(Datalink_proto_tree.root); - next = next_node->keyValue; - } - if (next == start) - break; - } - - if (direction == PICO_LOOP_DIR_IN) - { - in_node = next_node; - next_in = next; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - out_node = next_node; - next_out = next; - } - - return loop_score; -} - - -#define NW_LOOP_MIN 1 - -int pico_protocol_network_loop(int loop_score, int direction) -{ - struct pico_protocol *start; - static struct pico_protocol *next = NULL, *next_in = NULL, *next_out = NULL; - static struct pico_tree_node * next_node, * in_node, * out_node; - - if (next_in == NULL) { - in_node = pico_tree_firstNode(Network_proto_tree.root); - if (in_node) - next_in = in_node->keyValue; - } - if (next_out == NULL) { - out_node = pico_tree_firstNode(Network_proto_tree.root); - if (out_node) - next_out = out_node->keyValue; - } - if (direction == PICO_LOOP_DIR_IN) - { - next_node = in_node; - next = next_in; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - next_node = out_node; - next = next_out; - } - - /* init start node */ - start = next; - - /* round-robin all network protocols, break if traversed all protocols */ - while (loop_score > NW_LOOP_MIN && next != NULL) { - loop_score = proto_loop(next, loop_score, direction); - - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - - if (next == NULL) - { - next_node = pico_tree_firstNode(Network_proto_tree.root); - next = next_node->keyValue; - } - if (next == start) - break; - } - - if (direction == PICO_LOOP_DIR_IN) - { - in_node = next_node; - next_in = next; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - out_node = next_node; - next_out = next; - } - - return loop_score; -} - -#define TP_LOOP_MIN 1 - -int pico_protocol_transport_loop(int loop_score, int direction) -{ - struct pico_protocol *start; - static struct pico_protocol *next = NULL, *next_in = NULL, *next_out = NULL; - static struct pico_tree_node * next_node, * in_node, * out_node; - - if (next_in == NULL) { - in_node = pico_tree_firstNode(Transport_proto_tree.root); - if (in_node) - next_in = in_node->keyValue; - } - if (next_out == NULL) { - out_node = pico_tree_firstNode(Transport_proto_tree.root); - if (out_node) - next_out = out_node->keyValue; - } - - if (direction == PICO_LOOP_DIR_IN) - { - next_node = in_node; - next = next_in; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - next_node = out_node; - next = next_out; - } - - /* init start node */ - start = next; - - /* round-robin all transport protocols, break if traversed all protocols */ - while (loop_score > DL_LOOP_MIN && next != NULL) { - loop_score = proto_loop(next, loop_score, direction); - - //next = RB_NEXT(pico_protocol_tree, &Transport_proto_tree, next); - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - - if (next == NULL) - { - next_node = pico_tree_firstNode(Transport_proto_tree.root); - next = next_node->keyValue; - } - if (next == start) - break; - } - - if (direction == PICO_LOOP_DIR_IN) - { - in_node = next_node; - next_in = next; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - out_node = next_node; - next_out = next; - } - - return loop_score; -} - - -#define SOCK_LOOP_MIN 1 - -int pico_protocol_socket_loop(int loop_score, int direction) -{ - struct pico_protocol *start; - static struct pico_protocol *next = NULL, *next_in = NULL, *next_out = NULL; - static struct pico_tree_node * next_node, * in_node, * out_node; - - if (next_in == NULL) { - in_node = pico_tree_firstNode(Socket_proto_tree.root); - if(in_node) - next_in = in_node->keyValue; - } - if (next_out == NULL) { - out_node = pico_tree_firstNode(Socket_proto_tree.root); - if(out_node) - next_out = out_node->keyValue; - } - - if (direction == PICO_LOOP_DIR_IN) - { - next_node = in_node; - next = next_in; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - next_node = out_node; - next = next_out; - } - - /* init start node */ - start = next; - - /* round-robin all transport protocols, break if traversed all protocols */ - while (loop_score > SOCK_LOOP_MIN && next != NULL) { - loop_score = proto_loop(next, loop_score,direction); - - next_node = pico_tree_next(next_node); - next = next_node->keyValue; - - if (next == NULL) - { - next_node = pico_tree_firstNode(next_node); - next = next_node->keyValue; - } - if (next == start) - break; - } - - if (direction == PICO_LOOP_DIR_IN) - { - in_node = next_node; - next_in = next; - } - else if (direction == PICO_LOOP_DIR_OUT) - { - out_node = next_node; - next_out = next; - } - - return loop_score; -} - -int pico_protocols_loop(int loop_score) -{ -/* - loop_score = pico_protocol_datalink_loop(loop_score); - loop_score = pico_protocol_network_loop(loop_score); - loop_score = pico_protocol_transport_loop(loop_score); - loop_score = pico_protocol_socket_loop(loop_score); -*/ - return loop_score; -} - -void pico_protocol_init(struct pico_protocol *p) -{ - if (!p) - return; - - p->hash = pico_hash(p->name); - switch (p->layer) { - case PICO_LAYER_DATALINK: - pico_tree_insert(&Datalink_proto_tree, p); - break; - case PICO_LAYER_NETWORK: - pico_tree_insert(&Network_proto_tree,p); - break; - case PICO_LAYER_TRANSPORT: - pico_tree_insert(&Transport_proto_tree,p); - break; - case PICO_LAYER_SOCKET: - pico_tree_insert(&Socket_proto_tree,p); - break; - } - dbg("Protocol %s registered (layer: %d).\n", p->name, p->layer); - -} -
--- a/stack/pico_socket.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2270 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_queue.h" -#include "pico_socket.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_stack.h" -#include "pico_icmp4.h" -#include "pico_nat.h" -#include "pico_tree.h" -#include "pico_device.h" - -#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6) -#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP) - - -#ifdef PICO_SUPPORT_MUTEX -static void * Mutex = NULL; -#define LOCK(x) {\ - if (x == NULL) \ - x = pico_mutex_init(); \ - pico_mutex_lock(x); \ -} -#define UNLOCK(x) pico_mutex_unlock(x); - -#else -#define LOCK(x) do{}while(0) -#define UNLOCK(x) do{}while(0) -#endif - - -#define PROTO(s) ((s)->proto->proto_number) - -#ifdef PICO_SUPPORT_TCP -# define IS_NAGLE_ENABLED(s) (!(!(!(s->opt_flags & (1 << PICO_SOCKET_OPT_TCPNODELAY))))) -#endif - -#define PICO_SOCKET_MTU 1480 /* Ethernet MTU(1500) - IP header size(20) */ - -#ifdef PICO_SUPPORT_IPV4 -# define IS_SOCK_IPV4(s) ((s->net == &pico_proto_ipv4)) -#else -# define IS_SOCK_IPV4(s) (0) -#endif - -#ifdef PICO_SUPPORT_IPV6 -# define IS_SOCK_IPV6(s) ((s->net == &pico_proto_ipv6)) -#else -# define IS_SOCK_IPV6(s) (0) -#endif - -#ifdef PICO_SUPPORT_IPFRAG -# define frag_dbg(...) do{}while(0) -#endif - -#ifdef PICO_SUPPORT_MCAST -# define so_mcast_dbg(...) do{}while(0) /* ip_mcast_dbg in pico_ipv4.c */ -#endif - -static struct pico_sockport *sp_udp = NULL ,*sp_tcp = NULL; - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len); - -static int socket_cmp(void * ka, void * kb) -{ - struct pico_socket *a = ka, *b = kb; - int a_is_ip6 = is_sock_ipv6(a); - int b_is_ip6 = is_sock_ipv6(b); - - int diff; - - /* First, order by network ver */ - if (a_is_ip6 < b_is_ip6) - return -1; - if (a_is_ip6 > b_is_ip6) - return 1; - - /* If either socket is PICO_IPV4_INADDR_ANY mode, skip local address comparison */ - - /* At this point, sort by local host */ - - if (0) { -#ifdef PICO_SUPPORT_IPV6 - } else if (a_is_ip6) { - if ((memcmp(a->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6)==0) || memcmp((b->local_addr.ip6.addr, PICO_IP6_ANY, PICO_SIZE_IP6) == 0)) - diff = 0; - else - diff = memcmp(a->local_addr.ip6.addr, b->local_addr.ip6.addr, PICO_SIZE_IP6); -#endif - } else { - if ((a->local_addr.ip4.addr == PICO_IP4_ANY) || (b->local_addr.ip4.addr == PICO_IP4_ANY)) - diff = 0; - else - diff = a->local_addr.ip4.addr - b->local_addr.ip4.addr; - } - - if (diff) - return diff; - - - /* Sort by remote host */ - if (a_is_ip6) - diff = memcmp(a->remote_addr.ip6.addr, b->remote_addr.ip6.addr, PICO_SIZE_IP6); - else - diff = a->remote_addr.ip4.addr - b->remote_addr.ip4.addr; - - if (diff) - return diff; - - /* And finally by remote port. The two sockets are coincident if the quad is the same. */ - return b->remote_port - a->remote_port; -} - -struct pico_sockport -{ - struct pico_tree socks; // how you make the connection ? - uint16_t number; - uint16_t proto; -}; - -#define INIT_SOCKPORT { {&LEAF , socket_cmp}, 0, 0 } - -int sockport_cmp(void * ka, void * kb) -{ - struct pico_sockport *a = ka, *b = kb; - if (a->number < b->number) - return -1; - if (a->number > b->number) - return 1; - return 0; -} - -PICO_TREE_DECLARE(UDPTable,sockport_cmp); -PICO_TREE_DECLARE(TCPTable,sockport_cmp); - -#ifdef PICO_SUPPORT_MCAST -/* socket - * | - * MCASTListen - * | | | - * ------------ | ------------ - * | | | - * MCASTSources MCASTSources MCASTSources - * | | | | | | | | | | | | - * S S S S S S S S S S S S - * - * MCASTListen: RBTree(mcast_link, mcast_group) - * MCASTSources: RBTree(source) - */ -struct pico_mcast_listen -{ - uint8_t filter_mode; - struct pico_ip4 mcast_link; - struct pico_ip4 mcast_group; - struct pico_tree MCASTSources; -}; - -static int mcast_listen_cmp(void *ka, void *kb) -{ - struct pico_mcast_listen *a = ka, *b = kb; - if (a->mcast_group.addr < b->mcast_group.addr) - return -1; - if (a->mcast_group.addr > b->mcast_group.addr) - return 1; - - if (a->mcast_link.addr < b->mcast_link.addr) - return -1; - if (a->mcast_link.addr > b->mcast_link.addr) - return 1; - - return 0; -} - -static int mcast_sources_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - if (a->addr < b->addr) - return -1; - if (a->addr > b->addr) - return 1; - return 0; -} - -static int mcast_socket_cmp(void *ka, void *kb) -{ - struct pico_socket *a = ka, *b = kb; - if (a < b) - return -1; - if (a > b) - return 1; - return 0; -} -/* gather all multicast sockets to hasten filter aggregation */ -PICO_TREE_DECLARE(MCASTSockets, mcast_socket_cmp); - -static int mcast_filter_cmp(void *ka, void *kb) -{ - struct pico_ip4 *a = ka, *b = kb; - if (a->addr < b->addr) - return -1; - if (a->addr > b->addr) - return 1; - return 0; -} -/* gather sources to be filtered */ -PICO_TREE_DECLARE(MCASTFilter, mcast_filter_cmp); - -/* MCASTFilter will be empty if no socket is listening on mcast_group on mcast_link anymore */ -static int pico_socket_aggregate_mcastfilters(struct pico_ip4 *mcast_link, struct pico_ip4 *mcast_group) -{ - uint8_t filter_mode = PICO_IP_MULTICAST_INCLUDE; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL; - struct pico_socket *mcast_sock = NULL; - struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL; - - ltest.mcast_link = *mcast_link; - ltest.mcast_group = *mcast_group; - - /* cleanup old filter */ - pico_tree_foreach_safe(index, &MCASTFilter, _tmp) - { - pico_tree_delete(&MCASTFilter, index->keyValue); - } - - /* construct new filter */ - pico_tree_foreach(index, &MCASTSockets) - { - mcast_sock = index->keyValue; - listen = pico_tree_findKey(mcast_sock->MCASTListen, <est); - if (listen) { - /* aggregate filter */ - switch(filter_mode) - { - case PICO_IP_MULTICAST_INCLUDE: - switch (listen->filter_mode) - { - case PICO_IP_MULTICAST_INCLUDE: - /* filter = summation of INCLUDEs */ - /* mode stays INCLUDE, add all sources to filter */ - pico_tree_foreach(index2, &listen->MCASTSources) - { - source = index2->keyValue; - pico_tree_insert(&MCASTFilter, source); - } - break; - - case PICO_IP_MULTICAST_EXCLUDE: - /* filter = EXCLUDE - INCLUDE */ - /* delete from the interface INCLUDE filter any source NOT in the socket EXCLUDE filter */ - pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2) - { - source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter, index2->keyValue); - } - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - filter_mode = PICO_IP_MULTICAST_EXCLUDE; - /* add to the interface EXCLUDE filter any socket source NOT in the former interface INCLUDE filter */ - pico_tree_foreach(index2, &listen->MCASTSources) - { - source = pico_tree_insert(&MCASTFilter, index2->keyValue); - if (source) - pico_tree_delete(&MCASTFilter, source); - } - break; - - default: - return -1; - } - break; - - case PICO_IP_MULTICAST_EXCLUDE: - switch (listen->filter_mode) - { - case PICO_IP_MULTICAST_INCLUDE: - /* filter = EXCLUDE - INCLUDE */ - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - /* remove from the interface EXCLUDE filter any source in the socket INCLUDE filter */ - pico_tree_foreach(index2, &listen->MCASTSources) - { - source = pico_tree_findKey(&MCASTFilter, index2->keyValue); - if (source) - pico_tree_delete(&MCASTFilter, source); - } - break; - - case PICO_IP_MULTICAST_EXCLUDE: - /* filter = intersection of EXCLUDEs */ - /* any record with filter mode EXCLUDE, causes the interface mode to be EXCLUDE */ - /* remove from the interface EXCLUDE filter any source not in the socket EXCLUDE filter */ - pico_tree_foreach_safe(index2, &MCASTFilter, _tmp2) - { - source = pico_tree_findKey(&listen->MCASTSources, index2->keyValue); - if (!source) - pico_tree_delete(&MCASTFilter, index2->keyValue); - } - break; - - default: - return -1; - } - break; - - default: - return -1; - } - } - } - return filter_mode; -} - -static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src) -{ - struct pico_ipv4_link *mcast_link = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_tree_node *index = NULL; - - /* no multicast enabled on socket */ - if (!s->MCASTListen) - return 0; - - mcast_link = pico_ipv4_link_get(&s->local_addr.ip4); - if (!mcast_link) - return -1; - - ltest.mcast_link.addr = mcast_link->address.addr; - ltest.mcast_group = *mcast_group; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (!listen) - return -1; - - /* perform source filtering */ - switch (listen->filter_mode) - { - case PICO_IP_MULTICAST_INCLUDE: - pico_tree_foreach(index, &listen->MCASTSources) - { - if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) { - so_mcast_dbg("MCAST: IP %08X in included socket source list\n", src->addr); - return 0; - } - } - so_mcast_dbg("MCAST: IP %08X NOT in included socket source list\n", src->addr); - return -1; - break; - - case PICO_IP_MULTICAST_EXCLUDE: - pico_tree_foreach(index, &listen->MCASTSources) - { - if (src->addr == ((struct pico_ip4 *)index->keyValue)->addr) { - so_mcast_dbg("MCAST: IP %08X in excluded socket source list\n", src->addr); - return -1; - } - } - so_mcast_dbg("MCAST: IP %08X NOT in excluded socket source list\n", src->addr); - return 0; - break; - - default: - return -1; - break; - } - return -1; -} - -static inline struct pico_ipv4_link *pico_socket_setoption_mcastargs_validation(struct pico_ip_mreq *mreq, struct pico_ip_mreq_source *mreq_source) -{ - struct pico_ipv4_link *mcast_link = NULL; - - if (!mreq && !mreq_source) - return NULL; - - if (mreq) { - if (!mreq->mcast_group_addr.addr) - return NULL; - if (pico_ipv4_is_unicast(mreq->mcast_group_addr.addr)) - return NULL; - - if (!mreq->mcast_link_addr.addr) { - mcast_link = pico_ipv4_get_default_mcastlink(); - if (!mcast_link) - return NULL; - } else { - mcast_link = pico_ipv4_link_get(&mreq->mcast_link_addr); - if (!mcast_link) - return NULL; - } - } - if (mreq_source) { - if (!mreq_source->mcast_group_addr.addr) - return NULL; - if (pico_ipv4_is_unicast(mreq_source->mcast_group_addr.addr)) - return NULL; - - if (!mreq_source->mcast_source_addr.addr) - return NULL; - if (!pico_ipv4_is_unicast(mreq_source->mcast_source_addr.addr)) - return NULL; - - if (!mreq_source->mcast_link_addr.addr) { - mcast_link = pico_ipv4_get_default_mcastlink(); - if (!mcast_link) - return NULL; - } else { - mcast_link = pico_ipv4_link_get(&mreq_source->mcast_link_addr); - if (!mcast_link) - return NULL; - } - } - return mcast_link; -} -#else -static int pico_socket_mcast_filter(struct pico_socket *s, struct pico_ip4 *mcast_group, struct pico_ip4 *src) { - return 0; -} -#endif /* PICO_SUPPORT_MCAST */ - -static struct pico_sockport *pico_get_sockport(uint16_t proto, uint16_t port) -{ - struct pico_sockport test = INIT_SOCKPORT; - test.number = port; - - if (proto == PICO_PROTO_UDP) - return pico_tree_findKey(&UDPTable,&test); - - else if (proto == PICO_PROTO_TCP) - return pico_tree_findKey(&TCPTable,&test); - - else return NULL; -} - -int pico_is_port_free(uint16_t proto, uint16_t port, void *addr, void *net) -{ - struct pico_sockport *sp; - struct pico_ip4 ip; - sp = pico_get_sockport(proto, port); - - if (!net) - net = &pico_proto_ipv4; - - /** IPv6 (wip) ***/ - if (net != &pico_proto_ipv4) { - dbg("IPV6!!!!!\n"); - return (!sp); - } - - /* IPv4 */ -#ifdef PICO_SUPPORT_NAT - if (pico_ipv4_nat_find(port,NULL, 0,proto) == 0) { - dbg("In use by nat....\n"); - return 0; - } -#endif - if (addr) - ip.addr = ((struct pico_ip4 *)addr)->addr; - else - ip.addr = PICO_IPV4_INADDR_ANY; - - if (ip.addr == PICO_IPV4_INADDR_ANY) { - if (!sp) return 1; - else { - dbg("In use, and asked for ANY\n"); - return 0; - } - } - if (sp) { - struct pico_ip4 *s_local; - struct pico_tree_node *idx; - struct pico_socket *s; - pico_tree_foreach(idx, &sp->socks) { - s = idx->keyValue; - if (s->net == &pico_proto_ipv4) { - s_local = (struct pico_ip4*) &s->local_addr; - if ((s_local->addr == PICO_IPV4_INADDR_ANY) || (s_local->addr == ip.addr)) - return 0; - } - } - } - return 1; -} - -static int pico_check_socket(struct pico_socket *s) -{ - struct pico_sockport *test; - struct pico_socket *found; - struct pico_tree_node * index; - - test = pico_get_sockport(PROTO(s), s->local_port); - - if (!test) { - return -1; - } - - pico_tree_foreach(index,&test->socks){ - found = index->keyValue; - if (s == found) { - return 0; - } - } - - return -1; -} - - -int pico_socket_add(struct pico_socket *s) -{ - struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port); - LOCK(Mutex); - if (!sp) { - //dbg("Creating sockport..%04x\n", s->local_port); /* In comment due to spam during test */ - sp = pico_zalloc(sizeof(struct pico_sockport)); - - if (!sp) { - pico_err = PICO_ERR_ENOMEM; - UNLOCK(Mutex); - return -1; - } - sp->proto = PROTO(s); - sp->number = s->local_port; - sp->socks.root = &LEAF; - sp->socks.compare = socket_cmp; - - if (PROTO(s) == PICO_PROTO_UDP) - { - pico_tree_insert(&UDPTable,sp); - } - else if (PROTO(s) == PICO_PROTO_TCP) - { - pico_tree_insert(&TCPTable,sp); - } - } - - pico_tree_insert(&sp->socks,s); - s->state |= PICO_SOCKET_STATE_BOUND; - UNLOCK(Mutex); -#if DEBUG_SOCKET_TREE - { - struct pico_tree_node * index; - //RB_FOREACH(s, socket_tree, &sp->socks) { - pico_tree_foreach(index,&sp->socks){ - s = index->keyValue; - dbg(">>>> List Socket lc=%hu rm=%hu\n", short_be(s->local_port), short_be(s->remote_port)); - } - - } -#endif - return 0; -} - -static void socket_garbage_collect(unsigned long now, void *arg) -{ - struct pico_socket *s = (struct pico_socket *) arg; - pico_free(s); -} - -int pico_socket_del(struct pico_socket *s) -{ - struct pico_sockport *sp = pico_get_sockport(PROTO(s), s->local_port); - - if (!sp) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - LOCK(Mutex); - pico_tree_delete(&sp->socks,s); - s->net = NULL; - if(pico_tree_empty(&sp->socks)){ - if (PROTO(s) == PICO_PROTO_UDP) - { - pico_tree_delete(&UDPTable,sp); - } - else if (PROTO(s) == PICO_PROTO_TCP) - { - pico_tree_delete(&TCPTable,sp); - } - - if(sp_tcp == sp) sp_tcp = NULL; - - if(sp_udp == sp) sp_udp = NULL; - - pico_free(sp); - - } - -#ifdef PICO_SUPPORT_MCAST - do { - uint8_t filter_mode = 0; - struct pico_tree_node *index = NULL, *_tmp = NULL, *index2 = NULL, *_tmp2 = NULL; - struct pico_mcast_listen *listen = NULL; - struct pico_ip4 *source = NULL; - if (s->MCASTListen) { - pico_tree_delete(&MCASTSockets, s); - pico_tree_foreach_safe(index, s->MCASTListen, _tmp) - { - listen = index->keyValue; - pico_tree_foreach_safe(index2, &listen->MCASTSources, _tmp2) - { - source = index->keyValue; - pico_tree_delete(&listen->MCASTSources, source); - pico_free(source); - } - filter_mode = pico_socket_aggregate_mcastfilters(&listen->mcast_link, &listen->mcast_group); - pico_ipv4_mcast_leave(&listen->mcast_link, &listen->mcast_group, 1, filter_mode, &MCASTFilter); - pico_tree_delete(s->MCASTListen, listen); - pico_free(listen); - } - pico_free(s->MCASTListen); - } - } while (0); -#endif - - s->state = PICO_SOCKET_STATE_CLOSED; - pico_timer_add(3000, socket_garbage_collect, s); - UNLOCK(Mutex); - return 0; -} - -static int pico_socket_alter_state(struct pico_socket *s, uint16_t more_states, uint16_t less_states, uint16_t tcp_state) -{ - struct pico_sockport *sp; - if (more_states & PICO_SOCKET_STATE_BOUND) - return pico_socket_add(s); - - if (less_states & PICO_SOCKET_STATE_BOUND) - return pico_socket_del(s); - - sp = pico_get_sockport(PROTO(s), s->local_port); - if (!sp) { - pico_err = PICO_ERR_ENXIO; - return -1; - } - - s->state |= more_states; - s->state &= (~less_states); - if (tcp_state) { - s->state &= 0x00FF; - s->state |= tcp_state; - } - - return 0; -} - -static int pico_socket_deliver(struct pico_protocol *p, struct pico_frame *f, uint16_t localport) -{ - struct pico_frame *cpy = NULL; - struct pico_sockport *sp = NULL; - struct pico_socket *s = NULL, *found = NULL; - struct pico_tree_node *index = NULL; - struct pico_tree_node *_tmp; - struct pico_trans *tr = (struct pico_trans *) f->transport_hdr; - #ifdef PICO_SUPPORT_IPV4 - struct pico_ipv4_hdr *ip4hdr; - #endif - #ifdef PICO_SUPPORT_IPV6 - struct pico_ipv6_hdr *ip6hdr; - #endif - - if (!tr) - return -1; - - sp = pico_get_sockport(p->proto_number, localport); - - if (!sp) { - dbg("No such port %d\n",short_be(localport)); - return -1; - } - - #ifdef PICO_SUPPORT_TCP - if (p->proto_number == PICO_PROTO_TCP) { - pico_tree_foreach_safe(index,&sp->socks, _tmp){ - s = index->keyValue; - /* 4-tuple identification of socket (port-IP) */ - #ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - struct pico_ip4 s_local, s_remote, p_src, p_dst; - ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr); - s_local.addr = s->local_addr.ip4.addr; - s_remote.addr = s->remote_addr.ip4.addr; - p_src.addr = ip4hdr->src.addr; - p_dst.addr = ip4hdr->dst.addr; - if ( (s->remote_port == tr->sport) && /* remote port check */ - (s_remote.addr == p_src.addr) && /* remote addr check */ - ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */ - found = s; - break; - } else if ( (s->remote_port == 0) && /* not connected... listening */ - ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr))) { /* Either local socket is ANY, or matches dst */ - /* listen socket */ - found = s; - } - } - #endif - #ifdef PICO_SUPPORT_IPV6 /* XXX TODO make compare for ipv6 addresses */ - if (IS_IPV6(f)) { - ip6hdr = (struct pico_ipv6_hdr*)(f->net_hdr); - if ( (s->remote_port == localport) ) { // && (((struct pico_ip6) s->remote_addr.ip6).addr == ((struct pico_ip6)(ip6hdr->src)).addr) ) { - found = s; - break; - } else if (s->remote_port == 0) { - /* listen socket */ - found = s; - } - } - #endif - } /* FOREACH */ - if (found != NULL) { - pico_tcp_input(found,f); - if ((found->ev_pending) && found->wakeup) { - found->wakeup(found->ev_pending, found); - } - return 0; - } else { - dbg("SOCKET> mmm something wrong (prob sockport)\n"); - return -1; - } - } /* TCP CASE */ -#endif - -#ifdef PICO_SUPPORT_UDP - if (p->proto_number == PICO_PROTO_UDP) { - pico_tree_foreach_safe(index,&sp->socks, _tmp){ - s = index->keyValue; - if (IS_IPV4(f)) { /* IPV4 */ - struct pico_ip4 s_local, p_dst; - ip4hdr = (struct pico_ipv4_hdr*)(f->net_hdr); - s_local.addr = s->local_addr.ip4.addr; - p_dst.addr = ip4hdr->dst.addr; - if ((pico_ipv4_is_broadcast(p_dst.addr)) || pico_ipv4_is_multicast(p_dst.addr)) { - struct pico_device *dev = pico_ipv4_link_find(&s->local_addr.ip4); - if (pico_ipv4_is_multicast(p_dst.addr) && (pico_socket_mcast_filter(s, &ip4hdr->dst, &ip4hdr->src) < 0)) - return -1; - if ((s_local.addr == PICO_IPV4_INADDR_ANY) || /* If our local ip is ANY, or.. */ - (dev == f->dev) ) { /* the source of the bcast packet is a neighbor... */ - cpy = pico_frame_copy(f); - if (!cpy) - return -1; - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } - } - } else if ((s_local.addr == PICO_IPV4_INADDR_ANY) || (s_local.addr == p_dst.addr)) - { /* Either local socket is ANY, or matches dst */ - cpy = pico_frame_copy(f); - if (!cpy) - return -1; - if (pico_enqueue(&s->q_in, cpy) > 0) { - if (s->wakeup) - s->wakeup(PICO_SOCK_EV_RD, s); - } - } - } else { - /*... IPv6 */ - } - } /* FOREACH */ - pico_frame_discard(f); - if (s) - return 0; - else - return -1; - } -#endif - return -1; -} - -struct pico_socket *pico_socket_open(uint16_t net, uint16_t proto, void (*wakeup)(uint16_t ev, struct pico_socket *)) -{ - - struct pico_socket *s = NULL; - -#ifdef PICO_SUPPORT_UDP - if (proto == PICO_PROTO_UDP) { - s = pico_udp_open(); - s->proto = &pico_proto_udp; - } -#endif - -#ifdef PICO_SUPPORT_TCP - if (proto == PICO_PROTO_TCP) { - s = pico_tcp_open(); - s->proto = &pico_proto_tcp; - /*check if Nagle enabled */ - if (!IS_NAGLE_ENABLED(s)) - dbg("ERROR Nagle should be enabled here\n\n"); - } -#endif - - if (!s) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; - } - -#ifdef PICO_SUPPORT_IPV4 - if (net == PICO_PROTO_IPV4) - s->net = &pico_proto_ipv4; -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (net == PICO_PROTO_IPV6) - s->net = &pico_proto_ipv6; -#endif - - s->q_in.max_size = PICO_DEFAULT_SOCKETQ; - s->q_out.max_size = PICO_DEFAULT_SOCKETQ; - s->wakeup = wakeup; - - if (!s->net) { - pico_free(s); - pico_err = PICO_ERR_ENETUNREACH; - return NULL; - } - return s; -} - - -struct pico_socket *pico_socket_clone(struct pico_socket *facsimile) -{ - struct pico_socket *s = NULL; - -#ifdef PICO_SUPPORT_UDP - if (facsimile->proto->proto_number == PICO_PROTO_UDP) { - s = pico_udp_open(); - s->proto = &pico_proto_udp; - } -#endif - -#ifdef PICO_SUPPORT_TCP - if (facsimile->proto->proto_number == PICO_PROTO_TCP) { - s = pico_tcp_open(); - s->proto = &pico_proto_tcp; - } -#endif - - if (!s) { - pico_err = PICO_ERR_EPROTONOSUPPORT; - return NULL; - } - s->local_port = facsimile->local_port; - s->remote_port = facsimile->remote_port; - s->state = facsimile->state; - -#ifdef PICO_SUPPORT_IPV4 - if (facsimile->net == &pico_proto_ipv4) { - s->net = &pico_proto_ipv4; - memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip4)); - memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip4)); - } -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (net == &pico_proto_ipv6) { - s->net = &pico_proto_ipv6; - memcpy(&s->local_addr, &facsimile->local_addr, sizeof(struct pico_ip6)); - memcpy(&s->remote_addr, &facsimile->remote_addr, sizeof(struct pico_ip6)); - } -#endif - s->q_in.max_size = PICO_DEFAULT_SOCKETQ; - s->q_out.max_size = PICO_DEFAULT_SOCKETQ; - s->wakeup = NULL; - if (!s->net) { - pico_free(s); - pico_err = PICO_ERR_ENETUNREACH; - return NULL; - } - return s; -} - -int pico_socket_read(struct pico_socket *s, void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EIO; - return -1; - } -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) - return pico_udp_recv(s, buf, len, NULL, NULL); -#endif - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP){ - /* check if in shutdown state and if no more data in tcpq_in */ - if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s) ) { - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } else { - return pico_tcp_read(s, buf, len); - } - } -#endif - return 0; -} - -int pico_socket_write(struct pico_socket *s, void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EIO; - return -1; - } - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } else if (s->state & PICO_SOCKET_STATE_SHUT_LOCAL) { /* check if in shutdown state */ - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } else { - return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port); - } -} - -uint16_t pico_socket_high_port(uint16_t proto) -{ - uint16_t port; - if (0 || -#ifdef PICO_SUPPORT_TCP - (proto == PICO_PROTO_TCP) || -#endif -#ifdef PICO_SUPPORT_TCP - (proto == PICO_PROTO_UDP) || -#endif - 0) { - do { - uint32_t rand = pico_rand(); - port = (uint16_t) (rand & 0xFFFFU); - port = (uint16_t)(port % (65535 - 1024)) + 1024U; - if (pico_is_port_free(proto, port, NULL, NULL)) { - return short_be(port); - } - } while(1); - } - else return 0U; -} - - -int pico_socket_sendto(struct pico_socket *s, void *buf, int len, void *dst, uint16_t remote_port) -{ - struct pico_frame *f; - struct pico_remote_duple *remote_duple = NULL; - int header_offset = 0; - int total_payload_written = 0; -#ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *src4; -#endif - -#ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *src6; -#endif - if (len == 0) { - return 0; - } else if (len < 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (buf == NULL || s == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!dst || !remote_port) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) != 0) { - if (remote_port != s->remote_port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - -#ifdef PICO_SUPPORT_IPV4 - if (IS_SOCK_IPV4(s)) { - if ((s->state & PICO_SOCKET_STATE_CONNECTED)) { - if (s->remote_addr.ip4.addr != ((struct pico_ip4 *)dst)->addr ) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } - } else { - src4 = pico_ipv4_source_find(dst); - if (!src4) { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; - } - if (src4->addr != PICO_IPV4_INADDR_ANY) - s->local_addr.ip4.addr = src4->addr; -# ifdef PICO_SUPPORT_UDP - /* socket remote info could change in a consecutive call, make persistent */ - if (PROTO(s) == PICO_PROTO_UDP) { - remote_duple = pico_zalloc(sizeof(struct pico_remote_duple)); - remote_duple->remote_addr.ip4.addr = ((struct pico_ip4 *)dst)->addr; - remote_duple->remote_port = remote_port; - } -# endif - } - } -#endif - -#ifdef PICO_SUPPORT_IPV6 - if (IS_SOCK_IPV6(s)) { - if (s->state & PICO_SOCKET_STATE_CONNECTED) { - if (memcmp(&s->remote_addr, dst, PICO_SIZE_IP6)) - return -1; - } else { - src6 = pico_ipv6_source_find(dst); - if (!src6) { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; - } - memcpy(&s->local_addr, src6, PICO_SIZE_IP6); - memcpy(&s->remote_addr, dst, PICO_SIZE_IP6); -# ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - remote_duple = pico_zalloc(sizeof(struct pico_remote_duple)); - remote_duple->remote_addr.ip6.addr = ((struct pico_ip6 *)dst)->addr; - remote_duple->remote_port = remote_port; - } -# endif - } - } -#endif - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - s->local_port = pico_socket_high_port(s->proto->proto_number); - if (s->local_port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - s->remote_port = remote_port; - } - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) - header_offset = pico_tcp_overhead(s); -#endif - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) - header_offset = sizeof(struct pico_udp_hdr); -#endif - - while (total_payload_written < len) { - int transport_len = (len - total_payload_written) + header_offset; - if (transport_len > PICO_SOCKET_MTU) - transport_len = PICO_SOCKET_MTU; -#ifdef PICO_SUPPORT_IPFRAG - else { - if (total_payload_written) - transport_len -= header_offset; /* last fragment, do not allocate memory for transport header */ - } -#endif /* PICO_SUPPORT_IPFRAG */ - - f = pico_socket_frame_alloc(s, transport_len); - if (!f) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - f->payload += header_offset; - f->payload_len -= header_offset; - f->sock = s; - if (remote_duple) { - f->info = pico_zalloc(sizeof(struct pico_remote_duple)); - memcpy(f->info, remote_duple, sizeof(struct pico_remote_duple)); - } - -#ifdef PICO_SUPPORT_IPFRAG -# ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP && ((len + header_offset) > PICO_SOCKET_MTU)) { - /* hacking way to identify fragmentation frames: payload != transport_hdr -> first frame */ - if (!total_payload_written) { - frag_dbg("FRAG: first fragmented frame %p | len = %u offset = 0\n", f, f->payload_len); - /* transport header length field contains total length + header length */ - f->transport_len = len + header_offset; - f->frag = short_be(PICO_IPV4_MOREFRAG); - } else { - /* no transport header in fragmented IP */ - f->payload = f->transport_hdr; - f->payload_len += header_offset; - /* set offset in octets */ - f->frag = short_be((total_payload_written + header_offset) / 8); - if (total_payload_written + f->payload_len < len) { - frag_dbg("FRAG: intermediate fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag)); - f->frag |= short_be(PICO_IPV4_MOREFRAG); - } else { - frag_dbg("FRAG: last fragmented frame %p | len = %u offset = %u\n", f, f->payload_len, short_be(f->frag)); - f->frag &= short_be(PICO_IPV4_FRAG_MASK); - } - } - } else { - f->frag = short_be(PICO_IPV4_DONTFRAG); - } -# endif /* PICO_SUPPORT_UDP */ -#endif /* PICO_SUPPORT_IPFRAG */ - - if (f->payload_len <= 0) { - pico_frame_discard(f); - if (remote_duple) - pico_free(remote_duple); - return total_payload_written; - } - - memcpy(f->payload, buf + total_payload_written, f->payload_len); - //dbg("Pushing segment, hdr len: %d, payload_len: %d\n", header_offset, f->payload_len); - - if (s->proto->push(s->proto, f) > 0) { - total_payload_written += f->payload_len; - } else { - pico_frame_discard(f); - pico_err = PICO_ERR_EAGAIN; - break; - } - } - if (remote_duple) - pico_free(remote_duple); - return total_payload_written; -} - -int pico_socket_send(struct pico_socket *s, void *buf, int len) -{ - if (!s || buf == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_CONNECTED) == 0) { - pico_err = PICO_ERR_ENOTCONN; - return -1; - } - return pico_socket_sendto(s, buf, len, &s->remote_addr, s->remote_port); -} - -int pico_socket_recvfrom(struct pico_socket *s, void *buf, int len, void *orig, uint16_t *remote_port) -{ - if (!s || buf == NULL) { /// || orig == NULL || remote_port == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - /* See task #178 */ - return -1; - } - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - return pico_udp_recv(s, buf, len, orig, remote_port); - } -#endif -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - /* check if in shutdown state and if tcpq_in empty */ - if ((s->state & PICO_SOCKET_STATE_SHUT_REMOTE) && pico_tcp_queue_in_is_empty(s)) { - pico_err = PICO_ERR_ESHUTDOWN; - return -1; - } else { - //dbg("socket tcp recv\n"); - return pico_tcp_read(s, buf, len); - } - } -#endif - //dbg("socket return 0\n"); - return 0; -} - -int pico_socket_recv(struct pico_socket *s, void *buf, int len) -{ - return pico_socket_recvfrom(s, buf, len, NULL, NULL); -} - - -int pico_socket_bind(struct pico_socket *s, void *local_addr, uint16_t *port) -{ - if (!s || !local_addr || !port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (!is_sock_ipv6(s)) { - struct pico_ip4 *ip = (struct pico_ip4 *)local_addr; - if (ip->addr != PICO_IPV4_INADDR_ANY) { - if (!pico_ipv4_link_find(local_addr)) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - } else { - /*... IPv6 */ - } - - - /* When given port = 0, get a random high port to bind to. */ - if (*port == 0) { - *port = pico_socket_high_port(PROTO(s)); - if (*port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (pico_is_port_free(PROTO(s), *port, local_addr, s->net) == 0) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - s->local_port = *port; - - if (is_sock_ipv6(s)) { - struct pico_ip6 *ip = (struct pico_ip6 *) local_addr; - memcpy(s->local_addr.ip6.addr, ip, PICO_SIZE_IP6); - /* XXX: port ipv4 functionality to ipv6 */ - /* Check for port already in use */ - if (pico_is_port_free(PROTO(s), *port, &local_addr, s->net)) { - pico_err = PICO_ERR_EADDRINUSE; - return -1; - } - } else if (is_sock_ipv4(s)) { - struct pico_ip4 *ip = (struct pico_ip4 *) local_addr; - s->local_addr.ip4.addr = ip->addr; - } - return pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); -} - -int pico_socket_connect(struct pico_socket *s, void *remote_addr, uint16_t remote_port) -{ - int ret = -1; - pico_err = PICO_ERR_EPROTONOSUPPORT; - if (!s || remote_addr == NULL || remote_port == 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - s->remote_port = remote_port; - - if (s->local_port == 0) { - s->local_port = pico_socket_high_port(PROTO(s)); - if (!s->local_port) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (is_sock_ipv6(s)) { - struct pico_ip6 *ip = (struct pico_ip6 *) remote_addr; - memcpy(s->remote_addr.ip6.addr, ip, PICO_SIZE_IP6); - } else if (is_sock_ipv4(s)) { - struct pico_ip4 *local, *ip = (struct pico_ip4 *) remote_addr; - s->remote_addr.ip4.addr = ip->addr; - local = pico_ipv4_source_find(ip); - if (local) { - s->local_addr.ip4.addr = local->addr; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - return -1; - } - } - - pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED, 0, 0); - pico_err = PICO_ERR_NOERR; - ret = 0; - } -#endif - -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - if (pico_tcp_initconn(s) == 0) { - pico_socket_alter_state(s, PICO_SOCKET_STATE_CONNECTED | PICO_SOCKET_STATE_TCP_SYN_SENT, 0, 0); - pico_err = PICO_ERR_NOERR; - ret = 0; - } else { - pico_err = PICO_ERR_EHOSTUNREACH; - } - } -#endif - - return ret; -} - -#ifdef PICO_SUPPORT_TCP - -int pico_socket_listen(struct pico_socket *s, int backlog) -{ - if (!s || backlog < 1) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - - if (PROTO(s) == PICO_PROTO_UDP) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - pico_err = PICO_ERR_EISCONN; - return -1; - } - - if (backlog < 1) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (PROTO(s) == PICO_PROTO_TCP) - pico_socket_alter_state(s, PICO_SOCKET_STATE_TCP_SYN_SENT, 0, PICO_SOCKET_STATE_TCP_LISTEN); - s->max_backlog = backlog; - - return 0; -} - -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *port) -{ - if (!s || !orig || !port) { - pico_err = PICO_ERR_EINVAL; - return NULL; - } - - pico_err = PICO_ERR_EINVAL; - - if ((s->state & PICO_SOCKET_STATE_BOUND) == 0) { - return NULL; - } - - if (PROTO(s) == PICO_PROTO_UDP) { - return NULL; - } - - if (TCPSTATE(s) == PICO_SOCKET_STATE_TCP_LISTEN) { - struct pico_sockport *sp = pico_get_sockport(PICO_PROTO_TCP, s->local_port); - struct pico_socket *found; - /* If at this point no incoming connection socket is found, - * the accept call is valid, but no connection is established yet. - */ - pico_err = PICO_ERR_EAGAIN; - if (sp) { - struct pico_tree_node * index; - //RB_FOREACH(found, socket_tree, &sp->socks) { - pico_tree_foreach(index,&sp->socks){ - found = index->keyValue; - if (s == found->parent) { - found->parent = NULL; - pico_err = PICO_ERR_NOERR; - memcpy(orig, &found->remote_addr, sizeof(struct pico_ip4)); - *port = found->remote_port; - return found; - } - } - } - } - return NULL; -} - -#else - -int pico_socket_listen(struct pico_socket *s, int backlog) -{ - pico_err = PICO_ERR_EINVAL; - return -1; -} - -struct pico_socket *pico_socket_accept(struct pico_socket *s, void *orig, uint16_t *local_port) -{ - pico_err = PICO_ERR_EINVAL; - return NULL; -} - -#endif - -#define PICO_SOCKET_SETOPT_EN(socket,index) (socket->opt_flags |= (1 << index)) -#define PICO_SOCKET_SETOPT_DIS(socket,index) (socket->opt_flags &= ~(1 << index)) - -int pico_socket_setoption(struct pico_socket *s, int option, void *value) // XXX no check against proto (vs setsockopt) or implicit by socket? -{ - if (s == NULL) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - pico_err = PICO_ERR_NOERR; - - switch (option) - { -#ifdef PICO_SUPPORT_TCP - case PICO_TCP_NODELAY: - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (s->proto->proto_number == PICO_PROTO_TCP) { - int *val = (int*)value; - if (*val > 0) { - dbg("setsockopt: Nagle algorithm disabled.\n"); - PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_TCPNODELAY); - } else { - dbg("setsockopt: Nagle algorithm enabled.\n"); - PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_TCPNODELAY); - } - } else { - pico_err = PICO_ERR_EINVAL; - } - break; -#endif - - -#ifdef PICO_SUPPORT_MCAST - case PICO_IP_MULTICAST_IF: - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - break; - - case PICO_IP_MULTICAST_TTL: - if (s->proto->proto_number == PICO_PROTO_UDP) { - return pico_udp_set_mc_ttl(s, *((uint8_t *) value)); - } - break; - - case PICO_IP_MULTICAST_LOOP: - if (s->proto->proto_number == PICO_PROTO_UDP) { - switch (*(uint8_t *) value) - { - case 0: - /* do not loop back multicast datagram */ - PICO_SOCKET_SETOPT_DIS(s,PICO_SOCKET_OPT_MULTICAST_LOOP); - break; - - case 1: - /* do loop back multicast datagram */ - PICO_SOCKET_SETOPT_EN(s,PICO_SOCKET_OPT_MULTICAST_LOOP); - break; - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - } - break; - - case PICO_IP_ADD_MEMBERSHIP: - /* EXCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0; - struct pico_ip_mreq *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ipv4_link *mcast_link = NULL; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - s->MCASTListen = pico_zalloc(sizeof(struct pico_tree)); - if (!s->MCASTListen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - s->MCASTListen->root = &LEAF; - s->MCASTListen->compare = mcast_listen_cmp; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (listen) { - if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - so_mcast_dbg("pico_socket_setoption: ERROR duplicate PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - } else { - listen = pico_zalloc(sizeof(struct pico_mcast_listen)); - if (!listen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - listen->filter_mode = PICO_IP_MULTICAST_EXCLUDE; - listen->mcast_link = mreq->mcast_link_addr; - listen->mcast_group = mreq->mcast_group_addr; - listen->MCASTSources.root = &LEAF; - listen->MCASTSources.compare = mcast_sources_cmp; - pico_tree_insert(s->MCASTListen, listen); - } - - pico_tree_insert(&MCASTSockets, s); - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter); - } - break; - - case PICO_IP_DROP_MEMBERSHIP: - /* EXCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0; - struct pico_ip_mreq *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL; - struct pico_ipv4_link *mcast_link = NULL; - struct pico_tree_node *index, *_tmp; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(mreq, NULL); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - so_mcast_dbg("socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before any PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (!listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_MEMBERSHIP before PICO_IP_ADD_MEMBERSHIP/SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - pico_tree_foreach_safe(index, &listen->MCASTSources, _tmp) - { - source = index->keyValue; - pico_tree_delete(&listen->MCASTSources, source); - pico_free(source); - } - pico_tree_delete(s->MCASTListen, listen); - pico_free(listen); - if (pico_tree_empty(s->MCASTListen)) { - pico_free(s->MCASTListen); - s->MCASTListen = NULL; - pico_tree_delete(&MCASTSockets, s); - } - } - - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 1, filter_mode, &MCASTFilter); - } - break; - - case PICO_IP_UNBLOCK_SOURCE: - /* EXCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0; - struct pico_ip_mreq_source *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL, stest = {0}; - struct pico_ipv4_link *mcast_link = NULL; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq_source *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (!listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_UNBLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest.addr = mreq->mcast_source_addr.addr; - source = pico_tree_findKey(&listen->MCASTSources, &stest); - if (!source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to unblock not in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - pico_tree_delete(&listen->MCASTSources, source); - pico_free(source); - } - } - - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter); - } - break; - - case PICO_IP_BLOCK_SOURCE: - /* EXCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0; - struct pico_ip_mreq_source *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL, stest = {0}; - struct pico_ipv4_link *mcast_link = NULL; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq_source *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before any PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (!listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_BLOCK_SOURCE before PICO_IP_ADD_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - if (listen->filter_mode != PICO_IP_MULTICAST_EXCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR any-source multicast (exclude) on source-specific multicast (include)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest.addr = mreq->mcast_source_addr.addr; - source = pico_tree_findKey(&listen->MCASTSources, &stest); - if (source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to block already in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - source = pico_zalloc(sizeof(struct pico_ip4)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source->addr = mreq->mcast_source_addr.addr; - pico_tree_insert(&listen->MCASTSources, source); - } - } - - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, 0, filter_mode, &MCASTFilter); - } - break; - - case PICO_IP_ADD_SOURCE_MEMBERSHIP: - /* INCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0, reference_count = 0; - struct pico_ip_mreq_source *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL, stest = {0}; - struct pico_ipv4_link *mcast_link = NULL; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq_source *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - s->MCASTListen = pico_zalloc(sizeof(struct pico_tree)); - if (!s->MCASTListen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - s->MCASTListen->root = &LEAF; - s->MCASTListen->compare = mcast_listen_cmp; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (listen) { - if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest.addr = mreq->mcast_source_addr.addr; - source = pico_tree_findKey(&listen->MCASTSources, &stest); - if (source) { - so_mcast_dbg("pico_socket_setoption: ERROR source address to allow already in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - source = pico_zalloc(sizeof(struct pico_ip4)); - if (!source) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source->addr = mreq->mcast_source_addr.addr; - pico_tree_insert(&listen->MCASTSources, source); - } - } else { - listen = pico_zalloc(sizeof(struct pico_mcast_listen)); - if (!listen) { - pico_err = PICO_ERR_ENOMEM; - return -1; - } - listen->filter_mode = PICO_IP_MULTICAST_INCLUDE; - listen->mcast_link = mreq->mcast_link_addr; - listen->mcast_group = mreq->mcast_group_addr; - listen->MCASTSources.root = &LEAF; - listen->MCASTSources.compare = mcast_sources_cmp; - source = pico_zalloc(sizeof(struct pico_ip4)); - if (!source) { - pico_free(listen); - pico_err = PICO_ERR_ENOMEM; - return -1; - } - source->addr = mreq->mcast_source_addr.addr; - pico_tree_insert(&listen->MCASTSources, source); - pico_tree_insert(s->MCASTListen, listen); - reference_count = 1; - } - - pico_tree_insert(&MCASTSockets, s); - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_join(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter); - } - break; - - case PICO_IP_DROP_SOURCE_MEMBERSHIP: - /* INCLUDE mode */ - if (s->proto->proto_number == PICO_PROTO_UDP) { - uint8_t filter_mode = 0, reference_count = 0; - struct pico_ip_mreq_source *mreq = NULL; - struct pico_mcast_listen *listen = NULL, ltest = {0}; - struct pico_ip4 *source = NULL, stest = {0}; - struct pico_ipv4_link *mcast_link = NULL; - - if (!value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - mreq = (struct pico_ip_mreq_source *) value; - mcast_link = pico_socket_setoption_mcastargs_validation(NULL, mreq); - if (!mcast_link) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - if (!mreq->mcast_link_addr.addr) - mreq->mcast_link_addr.addr = mcast_link->address.addr; - - if (!s->MCASTListen) { /* No RBTree allocated yet */ - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before any PICO_IP_ADD_SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - ltest.mcast_link = mreq->mcast_link_addr; - ltest.mcast_group = mreq->mcast_group_addr; - listen = pico_tree_findKey(s->MCASTListen, <est); - if (!listen) { - so_mcast_dbg("pico_socket_setoption: ERROR PICO_IP_DROP_SOURCE_MEMBERSHIP before PICO_IP_ADD_SOURCE_MEMBERSHIP\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - if (listen->filter_mode != PICO_IP_MULTICAST_INCLUDE) { - so_mcast_dbg("pico_socket_setoption: ERROR source-specific multicast (include) on any-source multicast (exclude)\n"); - pico_err = PICO_ERR_EINVAL; - return -1; - } - stest.addr = mreq->mcast_source_addr.addr; - source = pico_tree_findKey(&listen->MCASTSources, &stest); - if (!source) { - so_mcast_dbg("pico_socket_setoption: ERROR address to drop not in source list\n"); - pico_err = PICO_ERR_EADDRNOTAVAIL; - return -1; - } else { - pico_tree_delete(&listen->MCASTSources, source); - pico_free(source); - if (pico_tree_empty(&listen->MCASTSources)) { /* 1 if empty, 0 otherwise */ - reference_count = 1; - pico_tree_delete(s->MCASTListen, listen); - pico_free(listen); - if (pico_tree_empty(s->MCASTListen)) { - pico_free(s->MCASTListen); - s->MCASTListen = NULL; - pico_tree_delete(&MCASTSockets, s); - } - } - } - } - - filter_mode = pico_socket_aggregate_mcastfilters(&mcast_link->address, &mreq->mcast_group_addr); - if (filter_mode < 0) - return -1; - - return pico_ipv4_mcast_leave(&mreq->mcast_link_addr, &mreq->mcast_group_addr, reference_count, filter_mode, &MCASTFilter); - } - break; -#endif /* PICO_SUPPORT_MCAST */ - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - if (pico_err != PICO_ERR_NOERR) - return -1; - else - return 0; -} - -#define PICO_SOCKET_GETOPT(socket,index) ((socket->opt_flags & (1 << index)) != 0) - -int pico_socket_getoption(struct pico_socket *s, int option, void *value) -{ - if (!s || !value) { - pico_err = PICO_ERR_EINVAL; - return -1; - } - - switch (option) - { -#ifdef PICO_SUPPORT_TCP - case PICO_TCP_NODELAY: - if (s->proto->proto_number == PICO_PROTO_TCP) - /* state of the NODELAY option */ - *(int *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_TCPNODELAY); - else - *(int *)value = 0; - break; -#endif - -#ifdef PICO_SUPPORT_MCAST - case PICO_IP_MULTICAST_IF: - pico_err = PICO_ERR_EOPNOTSUPP; - return -1; - break; - - case PICO_IP_MULTICAST_TTL: - if (s->proto->proto_number == PICO_PROTO_UDP) { - pico_udp_get_mc_ttl(s, (uint8_t *) value); - } else { - *(uint8_t *)value = 0; - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; - - case PICO_IP_MULTICAST_LOOP: - if (s->proto->proto_number == PICO_PROTO_UDP) { - *(uint8_t *)value = PICO_SOCKET_GETOPT(s,PICO_SOCKET_OPT_MULTICAST_LOOP); - } else { - *(uint8_t *)value = 0; - pico_err = PICO_ERR_EINVAL; - return -1; - } - break; -#endif /* PICO_SUPPORT_MCAST */ - - default: - pico_err = PICO_ERR_EINVAL; - return -1; - } - - return 0; -} - - -int pico_socket_shutdown(struct pico_socket *s, int mode) -{ - if (!s) { - pico_err = PICO_ERR_EINVAL; - return -1; - } else { - /* check if exists in tree */ - /* See task #178 */ - if (pico_check_socket(s) != 0) { - pico_free(s); /* close socket after bind or connect failed */ - return 0; - } - } - -#ifdef PICO_SUPPORT_UDP - if (PROTO(s) == PICO_PROTO_UDP) { - if (mode & PICO_SHUT_RDWR) - pico_socket_alter_state(s, PICO_SOCKET_STATE_CLOSED, PICO_SOCKET_STATE_CLOSING |PICO_SOCKET_STATE_BOUND | PICO_SOCKET_STATE_CONNECTED, 0); - else if (mode & PICO_SHUT_RD) - pico_socket_alter_state(s, PICO_SOCKET_STATE_BOUND, 0, 0); - } -#endif -#ifdef PICO_SUPPORT_TCP - if (PROTO(s) == PICO_PROTO_TCP) { - if (mode & PICO_SHUT_WR) - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL, 0, 0); - else if (mode & PICO_SHUT_RD) - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0); - else if (mode & PICO_SHUT_RDWR) - pico_socket_alter_state(s, PICO_SOCKET_STATE_SHUT_LOCAL | PICO_SOCKET_STATE_SHUT_REMOTE, 0, 0); - } -#endif - return 0; -} - -int pico_socket_close(struct pico_socket *s) -{ - return pico_socket_shutdown(s, PICO_SHUT_RDWR); -} - -#ifdef PICO_SUPPORT_CRC -static inline int pico_transport_crc_check(struct pico_frame *f) -{ - struct pico_ipv4_hdr *net_hdr = (struct pico_ipv4_hdr *) f->net_hdr; - struct pico_udp_hdr *udp_hdr = NULL; - uint16_t checksum_invalid = 1; - - switch (net_hdr->proto) - { - case PICO_PROTO_TCP: - checksum_invalid = short_be(pico_tcp_checksum_ipv4(f)); - //dbg("TCP CRC validation == %u\n", checksum_invalid); - if (checksum_invalid) { - //dbg("TCP CRC: validation failed!\n"); - pico_frame_discard(f); - return 0; - } - break; - - case PICO_PROTO_UDP: - udp_hdr = (struct pico_udp_hdr *) f->transport_hdr; - if (short_be(udp_hdr->crc)) { - checksum_invalid = short_be(pico_udp_checksum_ipv4(f)); - //dbg("UDP CRC validation == %u\n", checksum_invalid); - if (checksum_invalid) { - //dbg("UDP CRC: validation failed!\n"); - pico_frame_discard(f); - return 0; - } - } - break; - - default: - // Do nothing - break; - } - return 1; -} -#else -static inline int pico_transport_crc_check(struct pico_frame *f) -{ - return 1; -} -#endif /* PICO_SUPPORT_CRC */ - -int pico_transport_process_in(struct pico_protocol *self, struct pico_frame *f) -{ - struct pico_trans *hdr = (struct pico_trans *) f->transport_hdr; - int ret = 0; - - if (!hdr) { - pico_err = PICO_ERR_EFAULT; - return -1; - } - - ret = pico_transport_crc_check(f); - if (ret < 1) - return ret; - else - ret = 0; - - if ((hdr) && (pico_socket_deliver(self, f, hdr->dport) == 0)) - return ret; - - if (!IS_BCAST(f)) { - dbg("Socket not found... \n"); - pico_notify_socket_unreachable(f); -#ifdef PICO_SUPPORT_TCP - /* if tcp protocol send RST segment */ - //if (self->proto_number == PICO_PROTO_TCP) - // pico_tcp_reply_rst(f); -#endif - ret = -1; - pico_err = PICO_ERR_ENOENT; - } - pico_frame_discard(f); - return ret; -} - -#define SL_LOOP_MIN 1 - - -int pico_sockets_loop(int loop_score) -{ - static struct pico_tree_node *index_udp, * index_tcp; - - struct pico_sockport *start; - struct pico_socket *s; - -#ifdef PICO_SUPPORT_UDP - struct pico_frame *f; - - if (sp_udp == NULL) - { - index_udp = pico_tree_firstNode(UDPTable.root); - sp_udp = index_udp->keyValue; - } - - /* init start node */ - start = sp_udp; - - /* round-robin all transport protocols, break if traversed all protocols */ - while (loop_score > SL_LOOP_MIN && sp_udp != NULL) { - struct pico_tree_node * index; - - pico_tree_foreach(index,&sp_udp->socks){ - s = index->keyValue; - f = pico_dequeue(&s->q_out); - while (f && (loop_score > 0)) { - pico_proto_udp.push(&pico_proto_udp, f); - loop_score -= 1; - f = pico_dequeue(&s->q_out); - } - } - - index_udp = pico_tree_next(index_udp); - sp_udp = index_udp->keyValue; - - if (sp_udp == NULL) - { - index_udp = pico_tree_firstNode(UDPTable.root); - sp_udp = index_udp->keyValue; - } - if (sp_udp == start) - break; - } -#endif - -#ifdef PICO_SUPPORT_TCP - if (sp_tcp == NULL) - { - index_tcp = pico_tree_firstNode(TCPTable.root); - sp_tcp = index_tcp->keyValue; - } - - /* init start node */ - start = sp_tcp; - - while (loop_score > SL_LOOP_MIN && sp_tcp != NULL) { - struct pico_tree_node * index; - pico_tree_foreach(index, &sp_tcp->socks){ - s = index->keyValue; - loop_score = pico_tcp_output(s, loop_score); - if ((s->ev_pending) && s->wakeup) { - s->wakeup(s->ev_pending, s); - } - if (loop_score <= 0) { - loop_score = 0; - break; - } - } - - /* check if RB_FOREACH ended, if not, break to keep the cur sp_tcp */ - if (s != NULL) - break; - - index_tcp = pico_tree_next(index_tcp); - sp_tcp = index_tcp->keyValue; - - if (sp_tcp == NULL) - { - index_tcp = pico_tree_firstNode(TCPTable.root); - sp_tcp = index_tcp->keyValue; - } - if (sp_tcp == start) - break; - } -#endif - - return loop_score; -} - - -struct pico_frame *pico_socket_frame_alloc(struct pico_socket *s, int len) -{ - struct pico_frame *f = NULL; - -#ifdef PICO_SUPPORT_IPV6 - if (IS_SOCK_IPV6(s)) - f = pico_proto_ipv6.alloc(&pico_proto_ipv6, len); -#endif - -#ifdef PICO_SUPPORT_IPV4 - if (IS_SOCK_IPV4(s)) - f = pico_proto_ipv4.alloc(&pico_proto_ipv4, len); -#endif - if (!f) { - pico_err = PICO_ERR_ENOMEM; - return f; - } - f->payload = f->transport_hdr; - f->payload_len = len; - f->sock = s; - return f; -} - -int pico_transport_error(struct pico_frame *f, uint8_t proto, int code) -{ - int ret = -1; - struct pico_trans *trans = (struct pico_trans*) f->transport_hdr; - struct pico_sockport *port = NULL; - struct pico_socket *s = NULL; - switch (proto) { - - -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - port = pico_get_sockport(proto, trans->sport); - break; -#endif - -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - port = pico_get_sockport(proto, trans->sport); - break; -#endif - - default: - /* Protocol not available */ - ret = -1; - } - if (port) { - struct pico_tree_node * index; - ret = 0; - - pico_tree_foreach(index,&port->socks) { - s = index->keyValue; - if (trans->dport == s->remote_port) { - if (s->wakeup) { - //dbg("SOCKET ERROR FROM ICMP NOTIFICATION. (icmp code= %d)\n\n", code); - switch(code) { - case PICO_ICMP_UNREACH_PROTOCOL: - pico_err = PICO_ERR_EPROTO; - break; - - case PICO_ICMP_UNREACH_PORT: - pico_err = PICO_ERR_ECONNREFUSED; - break; - - case PICO_ICMP_UNREACH_NET: - case PICO_ICMP_UNREACH_NET_PROHIB: - case PICO_ICMP_UNREACH_NET_UNKNOWN: - pico_err = PICO_ERR_ENETUNREACH; - break; - - default: - pico_err = PICO_ERR_EHOSTUNREACH; - } - s->wakeup(PICO_SOCK_EV_ERR, s); - } - break; - } - } - } - pico_frame_discard(f); - return ret; -} -#endif -#endif
--- a/stack/pico_stack.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,733 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -. - -Authors: Daniele Lacamera -*********************************************************************/ - - -#include "pico_config.h" -#include "pico_frame.h" -#include "pico_device.h" -#include "pico_protocol.h" -#include "pico_stack.h" -#include "pico_addressing.h" -#include "pico_dns_client.h" - -#include "pico_eth.h" -#include "pico_arp.h" -#include "pico_ipv4.h" -#include "pico_ipv6.h" -#include "pico_icmp4.h" -#include "pico_igmp.h" -#include "pico_udp.h" -#include "pico_tcp.h" -#include "pico_socket.h" -#include "heap.h" - -#define IS_LIMITED_BCAST(f) ( ((struct pico_ipv4_hdr *) f->net_hdr)->dst.addr == PICO_IP4_BCAST ) - -#ifdef PICO_SUPPORT_MCAST -# define PICO_SIZE_MCAST 3 - const uint8_t PICO_ETHADDR_MCAST[6] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x00}; -#endif - -uint32_t cur_mem = 0; -uint32_t max_mem = 0; - - -volatile unsigned long pico_tick; -volatile pico_err_t pico_err; - -static uint32_t _rand_seed; - -void pico_rand_feed(uint32_t feed) -{ - if (!feed) - return; - _rand_seed *= 1664525; - _rand_seed += 1013904223; - _rand_seed ^= ~(feed); -} - -uint32_t pico_rand(void) -{ - pico_rand_feed(pico_tick); - return _rand_seed; -} - -/* NOTIFICATIONS: distributed notifications for stack internal errors. - */ - -int pico_notify_socket_unreachable(struct pico_frame *f) -{ - if (0) {} -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_port_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_port_unreachable(f); - } -#endif - - return 0; -} - -int pico_notify_proto_unreachable(struct pico_frame *f) -{ - if (0) {} -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_proto_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_proto_unreachable(f); - } -#endif - return 0; -} - -int pico_notify_dest_unreachable(struct pico_frame *f) -{ - if (0) {} -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_dest_unreachable(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_dest_unreachable(f); - } -#endif - return 0; -} - -int pico_notify_ttl_expired(struct pico_frame *f) -{ - if (0) {} -#ifdef PICO_SUPPORT_ICMP4 - else if (IS_IPV4(f)) { - pico_icmp4_ttl_expired(f); - } -#endif -#ifdef PICO_SUPPORT_ICMP6 - else if (IS_IPV6(f)) { - pico_icmp6_ttl_expired(f); - } -#endif - return 0; -} - - -/* Transport layer */ -int pico_transport_receive(struct pico_frame *f, uint8_t proto) -{ - int ret = -1; - switch (proto) { - -#ifdef PICO_SUPPORT_ICMP4 - case PICO_PROTO_ICMP4: - ret = pico_enqueue(pico_proto_icmp4.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_IGMP - case PICO_PROTO_IGMP: - ret = pico_enqueue(pico_proto_igmp.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_UDP - case PICO_PROTO_UDP: - ret = pico_enqueue(pico_proto_udp.q_in, f); - break; -#endif - -#ifdef PICO_SUPPORT_TCP - case PICO_PROTO_TCP: - ret = pico_enqueue(pico_proto_tcp.q_in, f); - break; -#endif - - default: - /* Protocol not available */ - dbg("pkt: no such protocol (%d)\n", proto); - pico_notify_proto_unreachable(f); - pico_frame_discard(f); - ret = -1; - } - return ret; -} - -int pico_transport_send(struct pico_frame *f) -{ - if (!f || !f->sock || !f->sock->proto) { - pico_frame_discard(f); - return -1; - } - return f->sock->proto->push(f->sock->net, f); -} - -int pico_network_receive(struct pico_frame *f) -{ - if (0) {} -#ifdef PICO_SUPPORT_IPV4 - else if (IS_IPV4(f)) { - pico_enqueue(pico_proto_ipv4.q_in, f); - } -#endif -#ifdef PICO_SUPPORT_IPV6 - else if (IS_IPV6(f)) { - pico_enqueue(pico_proto_ipv6.q_in, f); - } -#endif - else { - dbg("Network not found.\n"); - pico_frame_discard(f); - return -1; - } - return f->buffer_len; -} - - -/* Network layer: interface towards socket for frame sending */ -int pico_network_send(struct pico_frame *f) -{ - if (!f || !f->sock || !f->sock->net) { - pico_frame_discard(f); - return -1; - } - return f->sock->net->push(f->sock->net, f); -} - -int pico_destination_is_local(struct pico_frame *f) -{ - if (0) { } -#ifdef PICO_SUPPORT_IPV4 - else if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (pico_ipv4_link_find(&hdr->dst)) - return 1; - } -#endif -#ifdef PICO_SUPPORT_IPV6 - else if (IS_IPV6(f)) { - } -#endif - return 0; -} - -int pico_source_is_local(struct pico_frame *f) -{ - if (0) { } -#ifdef PICO_SUPPORT_IPV4 - else if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *)f->net_hdr; - if (hdr->src.addr == PICO_IPV4_INADDR_ANY) - return 1; - if (pico_ipv4_link_find(&hdr->src)) - return 1; - } -#endif -#ifdef PICO_SUPPORT_IPV6 - else if (IS_IPV6(f)) { - /* XXX */ - } -#endif - return 0; - - -} - - -/* DATALINK LEVEL: interface from network to the device - * and vice versa. - */ - -/* The pico_ethernet_receive() function is used by - * those devices supporting ETH in order to push packets up - * into the stack. - */ -int pico_ethernet_receive(struct pico_frame *f) -{ - struct pico_eth_hdr *hdr; - if (!f || !f->dev || !f->datalink_hdr) - goto discard; - hdr = (struct pico_eth_hdr *) f->datalink_hdr; - if ( (memcmp(hdr->daddr, f->dev->eth->mac.addr, PICO_SIZE_ETH) != 0) && -#ifdef PICO_SUPPORT_MCAST - (memcmp(hdr->daddr, PICO_ETHADDR_MCAST, PICO_SIZE_MCAST) != 0) && -#endif - (memcmp(hdr->daddr, PICO_ETHADDR_ALL, PICO_SIZE_ETH) != 0) ) - goto discard; - - f->net_hdr = f->datalink_hdr + sizeof(struct pico_eth_hdr); - if (hdr->proto == PICO_IDETH_ARP) - return pico_arp_receive(f); - if ((hdr->proto == PICO_IDETH_IPV4) || (hdr->proto == PICO_IDETH_IPV6)) - return pico_network_receive(f); -discard: - pico_frame_discard(f); - return -1; -} - -static int destination_is_bcast(struct pico_frame *f) -{ - if (!f) - return 0; - - if (IS_IPV6(f)) - return 0; -#ifdef PICO_SUPPORT_IPV4 - else { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - return pico_ipv4_is_broadcast(hdr->dst.addr); - } -#endif - return 0; -} - -#ifdef PICO_SUPPORT_MCAST -static int destination_is_mcast(struct pico_frame *f) -{ - if (!f) - return 0; - - if (IS_IPV6(f)) - return 0; -#ifdef PICO_SUPPORT_IPV4 - else { - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - return pico_ipv4_is_multicast(hdr->dst.addr); - } -#endif - return 0; -} - -static struct pico_eth *pico_ethernet_mcast_translate(struct pico_frame *f, uint8_t *pico_mcast_mac) -{ - struct pico_ipv4_hdr *hdr = (struct pico_ipv4_hdr *) f->net_hdr; - - /* place 23 lower bits of IP in lower 23 bits of MAC */ - pico_mcast_mac[5] = (long_be(hdr->dst.addr) & 0x000000FF); - pico_mcast_mac[4] = (long_be(hdr->dst.addr) & 0x0000FF00) >> 8; - pico_mcast_mac[3] = (long_be(hdr->dst.addr) & 0x007F0000) >> 16; - - return (struct pico_eth *)pico_mcast_mac; -} - - -#endif /* PICO_SUPPORT_MCAST */ - -/* This is called by dev loop in order to ensure correct ethernet addressing. - * Returns 0 if the destination is unknown, and -1 if the packet is not deliverable - * due to ethernet addressing (i.e., no arp association was possible. - * - * Only IP packets must pass by this. ARP will always use direct dev->send() function, so - * we assume IP is used. - */ -int pico_ethernet_send(struct pico_frame *f) -{ - struct pico_eth *dstmac = NULL; - - if (IS_IPV6(f)) { - /*TODO: Neighbor solicitation */ - dstmac = NULL; - } - - else if (IS_IPV4(f)) { - if (IS_BCAST(f) || destination_is_bcast(f)) { - dstmac = (struct pico_eth *) PICO_ETHADDR_ALL; - } -#ifdef PICO_SUPPORT_MCAST - else if (destination_is_mcast(f)) { - uint8_t pico_mcast_mac[6] = {0x01, 0x00, 0x5e, 0x00, 0x00, 0x00}; - dstmac = pico_ethernet_mcast_translate(f, pico_mcast_mac); - } -#endif - else { - dstmac = pico_arp_get(f); - if (!dstmac) - return 0; - } - /* This sets destination and source address, then pushes the packet to the device. */ - if (dstmac && (f->start > f->buffer) && ((f->start - f->buffer) >= PICO_SIZE_ETHHDR)) { - struct pico_eth_hdr *hdr; - f->start -= PICO_SIZE_ETHHDR; - f->len += PICO_SIZE_ETHHDR; - f->datalink_hdr = f->start; - hdr = (struct pico_eth_hdr *) f->datalink_hdr; - memcpy(hdr->saddr, f->dev->eth->mac.addr, PICO_SIZE_ETH); - memcpy(hdr->daddr, dstmac, PICO_SIZE_ETH); - hdr->proto = PICO_IDETH_IPV4; - if(!memcmp(hdr->daddr, hdr->saddr, PICO_SIZE_ETH)){ - dbg("sending out packet destined for our own mac\n"); - return pico_ethernet_receive(f); - }else if(IS_LIMITED_BCAST(f)){ - return pico_device_broadcast(f); - }else { - return f->dev->send(f->dev, f->start, f->len); - /* Frame is discarded after this return by the caller */ - } - } else { - return -1; - } - } /* End IPV4 ethernet addressing */ - return -1; -} - -void pico_store_network_origin(void *src, struct pico_frame *f) -{ - #ifdef PICO_SUPPORT_IPV4 - struct pico_ip4 *ip4; - #endif - - #ifdef PICO_SUPPORT_IPV6 - struct pico_ip6 *ip6; - #endif - - #ifdef PICO_SUPPORT_IPV4 - if (IS_IPV4(f)) { - struct pico_ipv4_hdr *hdr; - hdr = (struct pico_ipv4_hdr *) f->net_hdr; - ip4 = (struct pico_ip4 *) src; - ip4->addr = hdr->src.addr; - } - #endif - #ifdef PICO_SUPPORT_IPV6 - if (IS_IPV6(f)) { - struct pico_ipv6_hdr *hdr; - hdr = (struct pico_ipv6_hdr *) f->net_hdr; - ip6 = (struct pico_ip6 *) src; - memcpy(ip6->addr, hdr->src.addr, PICO_SIZE_IP6); - } - #endif -} - - -/* LOWEST LEVEL: interface towards devices. */ -/* Device driver will call this function which returns immediately. - * Incoming packet will be processed later on in the dev loop. - */ -int pico_stack_recv(struct pico_device *dev, uint8_t *buffer, int len) -{ - struct pico_frame *f; - int ret; - if (len <= 0) - return -1; - f = pico_frame_alloc(len); - if (!f) - return -1; - - /* Association to the device that just received the frame. */ - f->dev = dev; - - /* Setup the start pointer, lenght. */ - f->start = f->buffer; - f->len = f->buffer_len; - if (f->len > 8) { - int mid_frame = (f->buffer_len >> 2)<<1; - mid_frame -= (mid_frame % 4); - pico_rand_feed(*(uint32_t*)(f->buffer + mid_frame)); - } - memcpy(f->buffer, buffer, len); - ret = pico_enqueue(dev->q_in, f); - if (ret <= 0) { - pico_frame_discard(f); - } - return ret; -} - -int pico_sendto_dev(struct pico_frame *f) -{ - if (!f->dev) { - pico_frame_discard(f); - return -1; - } else { - if (f->len > 8) { - int mid_frame = (f->buffer_len >> 2)<<1; - mid_frame -= (mid_frame % 4); - pico_rand_feed(*(uint32_t*)(f->buffer + mid_frame)); - } - return pico_enqueue(f->dev->q_out, f); - } -} - -struct pico_timer -{ - unsigned long expire; - void *arg; - void (*timer)(unsigned long timestamp, void *arg); -}; - -typedef struct pico_timer pico_timer; - -DECLARE_HEAP(pico_timer, expire); - -static heap_pico_timer *Timers; - -void pico_check_timers(void) -{ - struct pico_timer timer; - struct pico_timer *t = heap_first(Timers); - pico_tick = PICO_TIME_MS(); - while((t) && (t->expire < pico_tick)) { - t->timer(pico_tick, t->arg); - heap_peek(Timers, &timer); - t = heap_first(Timers); - } -} - - -#define PROTO_DEF_NR 11 -#define PROTO_DEF_AVG_NR 4 -#define PROTO_DEF_SCORE 32 -#define PROTO_MIN_SCORE 32 -#define PROTO_MAX_SCORE 128 -#define PROTO_LAT_IND 1 /* latecy indication 0-3 (lower is better latency performance), x1, x2, x4, x8 */ -#define PROTO_MAX_LOOP (PROTO_MAX_SCORE<<PROTO_LAT_IND) /* max global loop score, so per tick */ - -static int calc_score(int *score, int *index, int avg[][PROTO_DEF_AVG_NR], int *ret) -{ - int temp, i, j, sum; - int max_total = PROTO_MAX_LOOP, total = 0; - - //dbg("USED SCORES> "); - - for (i = 0; i < PROTO_DEF_NR; i++) { - - /* if used looped score */ - if (ret[i] < score[i]) { - temp = score[i] - ret[i]; /* remaining loop score */ - - //dbg("%3d - ",temp); - - if (index[i] >= PROTO_DEF_AVG_NR) - index[i] = 0; /* reset index */ - j = index[i]; - avg[i][j] = temp; - - index[i]++; - - if (ret[i] == 0 && (score[i]<<1 <= PROTO_MAX_SCORE) && ((total+(score[i]<<1)) < max_total) ) { /* used all loop score -> increase next score directly */ - score[i] <<= 1; - total += score[i]; - continue; - } - - sum = 0; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - sum += avg[i][j]; /* calculate sum */ - - sum >>= 2; /* divide by 4 to get average used score */ - - /* criterion to increase next loop score */ - if (sum > (score[i] - (score[i]>>2)) && (score[i]<<1 <= PROTO_MAX_SCORE) && ((total+(score[i]<<1)) < max_total)) { /* > 3/4 */ - score[i] <<= 1; /* double loop score */ - total += score[i]; - continue; - } - - /* criterion to decrease next loop score */ - if (sum < (score[i]>>2) && (score[i]>>1 >= PROTO_MIN_SCORE)) { /* < 1/4 */ - score[i] >>= 1; /* half loop score */ - total += score[i]; - continue; - } - - /* also add non-changed scores */ - total += score[i]; - } - else if (ret[i] == score[i]) { - /* no used loop score - gradually decrease */ - - // dbg("%3d - ",0); - - if (index[i] >= PROTO_DEF_AVG_NR) - index[i] = 0; /* reset index */ - j = index[i]; - avg[i][j] = 0; - - index[i]++; - - sum = 0; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - sum += avg[i][j]; /* calculate sum */ - - sum >>= 2; /* divide by 4 to get average used score */ - - if ((sum == 0) && (score[i]>>1 >= PROTO_MIN_SCORE)) { - score[i] >>= 1; /* half loop score */ - total += score[i]; - for (j = 0; j < PROTO_DEF_AVG_NR; j++) - avg[i][j] = score[i]; - } - - } - } - - //dbg("\n"); - - return 0; -} - - - -/* - - . - .vS. - <aoSo. - .XoS22. - .S2S22. ._... ...... ..._. - :=|2S2X2|=++; <vSX2XX2z+ |vSSSXSSs>. :iXXZUZXXe= - )2SS2SS2S2S2I =oS2S2S2S2X22;. _vuXS22S2S2S22i ._wZZXZZZXZZXZX= - )22S2S2S2S2Sl |S2S2S22S2SSSXc: .S2SS2S2S22S2SS= .]#XZZZXZXZZZZZZ: - )oSS2SS2S2Sol |2}!"""!32S22S(. uS2S2Se**12oS2e ]dXZZXX2?YYXXXZ* - .:2S2So:..-. . :]S2S2e;=X2SS2o .)oc ]XZZXZ( =nX: - .S2S22. ___s_i,.)oS2So(;2SS2So, ` 3XZZZZc, - - .S2SSo. =oXXXSSS2XoS2S2o( XS2S2XSos;. ]ZZZZXXXX|= - .S2S22. .)S2S2S22S2S2S2S2o( "X2SS2S2S2Sus,, +3XZZZZZXZZoos_ - .S2S22. .]2S2SS22S222S2SS2o( ]S22S2S2S222So :3XXZZZZZZZZXXv - .S2S22. =u2SS2e"~---"{2S2So( -"12S2S2SSS2Su. "?SXXXZXZZZZXo - .S2SSo. )SS22z; :S2S2o( ={vS2S2S22v .<vXZZZZZZZ; - .S2S2S: ]oSS2c; =22S2o( -"S2SS2n ~4XXZXZ( - .2S2S2i )2S2S2[. .)XS2So( <;. .2S2S2o :<. ]XZZZX( - nX2S2S,,_s_=3oSS2SoaasuXXS2S2o( .oXoasi_aioSSS22l.]dZoaas_aadXZZXZ' - vS2SSSXXX2; )S2S2S2SoS2S2S2S2o( iS2S222XSoSS22So.)nXZZXXXZZXXZZXZo - +32S22S2Sn -+S2S2S2S2So22S2So( 12S2SS2S2SS22S}- )SXXZZZZZZZZZXX!- - .)S22222i .i2S2S2o>;:S2S2o( .<vSoSoSo2S(; :nXXXXXZXXX( - .-~~~~- --- . - - --~~~-- --^^~~- - . - - - ... curious about our source code? We are hiring! mailto:<recruiting@tass.be> - - -*/ - -void pico_stack_tick(void) -{ - static int score[PROTO_DEF_NR] = {PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE, PROTO_DEF_SCORE}; - static int index[PROTO_DEF_NR] = {0,0,0,0,0,0}; - static int avg[PROTO_DEF_NR][PROTO_DEF_AVG_NR]; - static int ret[PROTO_DEF_NR] = {0}; - - pico_check_timers(); - - //dbg("LOOP_SCORES> %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d - %3d\n",score[0],score[1],score[2],score[3],score[4],score[5],score[6],score[7],score[8],score[9],score[10]); - - //score = pico_protocols_loop(100); - - ret[0] = pico_devices_loop(score[0],PICO_LOOP_DIR_IN); - pico_rand_feed(ret[0]); - - ret[1] = pico_protocol_datalink_loop(score[1], PICO_LOOP_DIR_IN); - pico_rand_feed(ret[1]); - - ret[2] = pico_protocol_network_loop(score[2], PICO_LOOP_DIR_IN); - pico_rand_feed(ret[2]); - - ret[3] = pico_protocol_transport_loop(score[3], PICO_LOOP_DIR_IN); - pico_rand_feed(ret[3]); - - - ret[5] = score[5]; -#if defined (PICO_SUPPORT_IPV4) || defined (PICO_SUPPORT_IPV6) -#if defined (PICO_SUPPORT_TCP) || defined (PICO_SUPPORT_UDP) - ret[5] = pico_sockets_loop(score[5]); // swapped - pico_rand_feed(ret[5]); -#endif -#endif - - ret[4] = pico_protocol_socket_loop(score[4], PICO_LOOP_DIR_IN); - pico_rand_feed(ret[4]); - - - ret[6] = pico_protocol_socket_loop(score[6], PICO_LOOP_DIR_OUT); - pico_rand_feed(ret[6]); - - ret[7] = pico_protocol_transport_loop(score[7], PICO_LOOP_DIR_OUT); - pico_rand_feed(ret[7]); - - ret[8] = pico_protocol_network_loop(score[8], PICO_LOOP_DIR_OUT); - pico_rand_feed(ret[8]); - - ret[9] = pico_protocol_datalink_loop(score[9], PICO_LOOP_DIR_OUT); - pico_rand_feed(ret[9]); - - ret[10] = pico_devices_loop(score[10],PICO_LOOP_DIR_OUT); - pico_rand_feed(ret[10]); - - /* calculate new loop scores for next iteration */ - calc_score(score, index,(int (*)[]) avg, ret); -} - -void pico_stack_loop(void) -{ - while(1) { - pico_stack_tick(); - PICO_IDLE(); - } -} - -void pico_timer_add(unsigned long expire, void (*timer)(unsigned long, void *), void *arg) -{ - pico_timer t; - t.expire = PICO_TIME_MS() + expire; - t.arg = arg; - t.timer = timer; - heap_insert(Timers, &t); - if (Timers->n > PICO_MAX_TIMERS) { - dbg("Warning: I have %d timers\n", Timers->n); - } -} - -void pico_stack_init(void) -{ - -#ifdef PICO_SUPPORT_IPV4 - pico_protocol_init(&pico_proto_ipv4); -#endif - -#ifdef PICO_SUPPORT_IPV6 - pico_protocol_init(&pico_proto_ipv6); -#endif - -#ifdef PICO_SUPPORT_ICMP4 - pico_protocol_init(&pico_proto_icmp4); -#endif - -#ifdef PICO_SUPPORT_IGMP - pico_protocol_init(&pico_proto_igmp); -#endif - -#ifdef PICO_SUPPORT_UDP - pico_protocol_init(&pico_proto_udp); -#endif - -#ifdef PICO_SUPPORT_TCP - pico_protocol_init(&pico_proto_tcp); -#endif - -#ifdef PICO_SUPPORT_DNS_CLIENT - pico_dns_client_init(); -#endif - - pico_rand_feed(123456); - - /* Initialize timer heap */ - Timers = heap_init(); - pico_stack_tick(); - pico_stack_tick(); - pico_stack_tick(); -} -
--- a/stack/pico_tree.c Sun Jun 16 02:31:38 2013 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,486 +0,0 @@ -/********************************************************************* -PicoTCP. Copyright (c) 2012 TASS Belgium NV. Some rights reserved. -See LICENSE and COPYING for usage. - -Author: Andrei Carp <andrei.carp@tass.be> -*********************************************************************/ - -#include "pico_tree.h" -#include "pico_config.h" - -#define RED 0 -#define BLACK 1 - -// By default the null leafs are black -struct pico_tree_node LEAF = { - NULL, // key - &LEAF, &LEAF, &LEAF, // parent, left,right - BLACK, // color -}; - -#define IS_LEAF(x) (x == &LEAF) -#define IS_NOT_LEAF(x) (x != &LEAF) -#define INIT_LEAF (&LEAF) - -#define AM_I_LEFT_CHILD(x) (x == x->parent->leftChild) -#define AM_I_RIGHT_CHILD(x) (x == x->parent->rightChild) - -#define PARENT(x) (x->parent) -#define GRANPA(x) (x->parent->parent) - -/* - * Local Functions - */ -static struct pico_tree_node * create_node(struct pico_tree * tree,void *key); -static void rotateToLeft(struct pico_tree* tree, struct pico_tree_node* node); -static void rotateToRight(struct pico_tree* root, struct pico_tree_node* node); -static void fix_insert_collisions(struct pico_tree* tree, struct pico_tree_node* node); -static void fix_delete_collisions(struct pico_tree* tree, struct pico_tree_node * node); -static void switchNodes(struct pico_tree* tree, struct pico_tree_node* nodeA, struct pico_tree_node* nodeB); - -/* - * Exported functions - */ - -struct pico_tree_node *pico_tree_firstNode(struct pico_tree_node * node) -{ - while(IS_NOT_LEAF(node->leftChild)) - node = node->leftChild; - return node; -} - -struct pico_tree_node * pico_tree_lastNode(struct pico_tree_node * node) -{ - while(IS_NOT_LEAF(node->rightChild)) - node = node->rightChild; - return node; -} - -struct pico_tree_node * pico_tree_next(struct pico_tree_node * node) -{ - if(IS_NOT_LEAF(node->rightChild)) - { - node = node->rightChild; - while(IS_NOT_LEAF(node->leftChild)) - node = node->leftChild; - } - else - { - if (IS_NOT_LEAF(node->parent) && AM_I_LEFT_CHILD(node)) - node = node->parent; - else { - while (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node)) - node = node->parent; - - node = node->parent; - } - } - return node; -} - -struct pico_tree_node * pico_tree_prev(struct pico_tree_node * node) -{ - if (IS_NOT_LEAF(node->leftChild)) { - node = node->leftChild; - while (IS_NOT_LEAF(node->rightChild)) - node = node->rightChild; - } else { - if (IS_NOT_LEAF(node->parent) && AM_I_RIGHT_CHILD(node)) - node = node->parent; - else { - while (IS_NOT_LEAF(node) && AM_I_LEFT_CHILD(node)) - node = node->parent; - - node = node->parent; - } - } - return node; -} - -void * pico_tree_insert(struct pico_tree* tree, void * key){ - - struct pico_tree_node * last_node = INIT_LEAF; - struct pico_tree_node * temp = tree->root; - struct pico_tree_node * insert; - void * LocalKey; - int result = 0; - - LocalKey = (IS_NOT_LEAF(tree->root) ? pico_tree_findKey(tree,key) : NULL); - // if node already in, bail out - if(LocalKey) - return LocalKey; - else - insert = create_node(tree,key); - - // search for the place to insert the new node - while(IS_NOT_LEAF(temp)) - { - last_node = temp; - result = tree->compare(insert->keyValue,temp->keyValue); - - temp = (result < 0 ? temp->leftChild : temp->rightChild); - } - - // make the needed connections - insert->parent = last_node; - - if(IS_LEAF(last_node)) - tree->root = insert; - else{ - result = tree->compare(insert->keyValue,last_node->keyValue); - if(result < 0) - last_node->leftChild = insert; - else - last_node->rightChild = insert; - } - - // fix colour issues - fix_insert_collisions(tree, insert); - - return NULL; -} - -struct pico_tree_node * pico_tree_findNode(struct pico_tree * tree, void * key) -{ - struct pico_tree_node *found; - - found = tree->root; - - while(IS_NOT_LEAF(found)) - { - int result; - result = tree->compare(found->keyValue, key); - if(result == 0) - { - return found; - } - else if(result < 0) - found = found->rightChild; - else - found = found->leftChild; - } - - - - return NULL; -} - -void * pico_tree_findKey(struct pico_tree * tree, void * key) -{ - struct pico_tree_node *found; - - - found = tree->root; - - while(IS_NOT_LEAF(found)) - { - int result; - - result = tree->compare(found->keyValue, key); - if(result == 0) - return found->keyValue; - else if(result < 0) - found = found->rightChild; - else - found = found->leftChild; - - } - - return NULL; -} - -void * pico_tree_first(struct pico_tree * tree) -{ - return pico_tree_firstNode(tree->root)->keyValue; -} - -void * pico_tree_last(struct pico_tree * tree) -{ - return pico_tree_lastNode(tree->root)->keyValue; -} - -void * pico_tree_delete(struct pico_tree * tree, void * key){ - - uint8_t nodeColor; // keeps the color of the node to be deleted - void * lkey; // keeps a copy of the key which will be removed - struct pico_tree_node * delete; // keeps a copy of the node to be extracted - struct pico_tree_node * temp; // temporary - struct pico_tree_node * ltemp; // used for switching nodes, as a copy - - delete = pico_tree_findNode(tree, key); - ltemp = delete; - - // this key isn't in the tree, bail out - if(!delete) - return NULL; - - lkey = delete->keyValue; - nodeColor = delete->color; - - if(IS_LEAF(delete->leftChild)) - { - temp = ltemp->rightChild; - switchNodes(tree, ltemp, ltemp->rightChild); - } - else - if(IS_LEAF(delete->rightChild)) - { - struct pico_tree_node * ltemp = delete; - temp = ltemp->leftChild; - switchNodes(tree, ltemp, ltemp->leftChild); - } - else{ - struct pico_tree_node * min; - min = pico_tree_firstNode(delete->rightChild); - nodeColor = min->color; - - temp = min->rightChild; - if(min->parent == ltemp && IS_NOT_LEAF(temp)) - temp->parent = min; - else{ - switchNodes(tree, min, min->rightChild); - min->rightChild = ltemp->rightChild; - if(IS_NOT_LEAF(min->rightChild)) min->rightChild->parent = min; - } - switchNodes(tree, ltemp, min); - min->leftChild = ltemp->leftChild; - if(IS_NOT_LEAF(min->leftChild)) min->leftChild->parent = min; - min->color = ltemp->color; - } - - // deleted node is black, this will mess up the black path property - if(nodeColor == BLACK) - fix_delete_collisions(tree, temp); - - pico_free(delete); - - return lkey; -} - -int pico_tree_empty(struct pico_tree * tree) -{ - return (!tree->root || IS_LEAF(tree->root)); -} - -/* - * Private functions - */ -static void rotateToLeft(struct pico_tree* tree, struct pico_tree_node* node) -{ - struct pico_tree_node* temp; - - temp = node->rightChild; - - if(temp == &LEAF) return; - - node->rightChild = temp->leftChild; - - if(IS_NOT_LEAF(temp->leftChild)) - temp->leftChild->parent = node; - - temp->parent = node->parent; - - if(IS_LEAF(node->parent)) - tree->root = temp; - else - if(node == node->parent->leftChild) - node->parent->leftChild = temp; - else - node->parent->rightChild = temp; - - temp->leftChild = node; - node->parent = temp; -} - - -static void rotateToRight(struct pico_tree * tree, struct pico_tree_node * node) -{ - struct pico_tree_node* temp; - - temp = node->leftChild; - node->leftChild = temp->rightChild; - - if(temp == &LEAF) return; - - if(IS_NOT_LEAF(temp->rightChild)) - temp->rightChild->parent = node; - - temp->parent = node->parent; - - if(IS_LEAF(node->parent)) - tree->root = temp; - else - if(node == node->parent->rightChild) - node->parent->rightChild = temp; - else - node->parent->leftChild = temp; - - temp->rightChild = node; - node->parent = temp; - return; -} - -static struct pico_tree_node * create_node(struct pico_tree * tree, void* key) -{ - struct pico_tree_node *temp; - temp = (struct pico_tree_node *)pico_zalloc(sizeof(struct pico_tree_node)); - - if(!temp) - return NULL; - - temp->keyValue = key; - temp->parent = &LEAF; - temp->leftChild = &LEAF; - temp->rightChild = &LEAF; - // by default every new node is red - temp->color = RED; - return temp; -} - -/* - * This function fixes the possible collisions in the tree. - * Eg. if a node is red his children must be black ! - */ -static void fix_insert_collisions(struct pico_tree* tree, struct pico_tree_node* node) -{ - struct pico_tree_node* temp; - - while(node->parent->color == RED) - { - if(AM_I_RIGHT_CHILD(node->parent)) - { - temp = GRANPA(node)->leftChild; - if(temp->color == RED){ - node->parent->color = BLACK; - temp->color = BLACK; - GRANPA(node)->color = RED; - node = GRANPA(node); - } - else if(temp->color == BLACK){ - if(node == node->parent->leftChild){ - node = node->parent; - rotateToRight(tree, node); - } - node->parent->color = BLACK; - GRANPA(node)->color = RED; - rotateToLeft(tree, GRANPA(node)); - } - } - else if(AM_I_LEFT_CHILD(node->parent)) - { - temp = GRANPA(node)->rightChild; - if(temp->color == RED){ - node->parent->color = BLACK; - temp->color = BLACK; - GRANPA(node)->color = RED; - node = GRANPA(node); - } - else if(temp->color == BLACK){ - if(AM_I_RIGHT_CHILD(node)){ - node = node->parent; - rotateToLeft(tree, node); - } - node->parent->color = BLACK; - GRANPA(node)->color = RED; - rotateToRight(tree, GRANPA(node)); - } - } - } - - // make sure that the root of the tree stays black - tree->root->color = BLACK; -} - -static void switchNodes(struct pico_tree* tree, struct pico_tree_node* nodeA, struct pico_tree_node* nodeB) -{ - - if(IS_LEAF(nodeA->parent)) - tree->root = nodeB; - else - if(IS_NOT_LEAF(nodeA)) - { - if(AM_I_LEFT_CHILD(nodeA)) - nodeA->parent->leftChild = nodeB; - else - nodeA->parent->rightChild = nodeB; - } - - if(IS_NOT_LEAF(nodeB)) nodeB->parent = nodeA->parent; - -} - -/* - * This function fixes the possible collisions in the tree. - * Eg. if a node is red his children must be black ! - * In this case the function fixes the constant black path property. - */ -static void fix_delete_collisions(struct pico_tree* tree, struct pico_tree_node * node) -{ - struct pico_tree_node* temp; - - while( node != tree->root && node->color == BLACK && IS_NOT_LEAF(node)) - { - if(AM_I_LEFT_CHILD(node)){ - - temp = node->parent->rightChild; - if(temp->color == RED) - { - temp->color = BLACK; - node->parent->color = RED; - rotateToLeft(tree, node->parent); - temp = node->parent->rightChild; - } - if(temp->leftChild->color == BLACK && temp->rightChild->color == BLACK) - { - temp->color = RED; - node = node->parent; - } - else - { - if(temp->rightChild->color == BLACK) - { - temp->leftChild->color = BLACK; - temp->color = RED; - rotateToRight(tree, temp); - temp = temp->parent->rightChild; - } - temp->color = node->parent->color; - node->parent->color = BLACK; - temp->rightChild->color = BLACK; - rotateToLeft(tree, node->parent); - node = tree->root; - } - } - else{ - temp = node->parent->leftChild; - if(temp->color == RED) - { - temp->color = BLACK; - node->parent->color = RED; - rotateToRight(tree, node->parent); - temp = node->parent->leftChild; - } - if(temp->rightChild->color == BLACK && temp->leftChild->color == BLACK) - { - temp->color = RED; - node = node->parent; - } - else{ - if(temp->leftChild->color == BLACK) - { - temp->rightChild->color = BLACK; - temp->color = RED; - rotateToLeft(tree, temp); - temp = temp->parent->leftChild; - } - temp->color = node->parent->color; - node->parent->color = BLACK; - temp->leftChild->color = BLACK; - rotateToRight(tree, node->parent); - node = tree->root; - } - } - } - - node->color = BLACK; -}