diff options
author | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-06-16 14:50:08 -0700 |
---|---|---|
committer | Adam Ierymenko <adam.ierymenko@gmail.com> | 2016-06-16 14:50:08 -0700 |
commit | bc3d7d11fe13ce7b3a01b77e1002a78e53d99f83 (patch) | |
tree | 9e4da34ae7e734efe85d036ec6c6ca1208d10746 /ext/lwip/src/core | |
parent | 490d20e8fb1c936324e3501196004592f46b3ff4 (diff) | |
download | infinitytier-bc3d7d11fe13ce7b3a01b77e1002a78e53d99f83.tar.gz infinitytier-bc3d7d11fe13ce7b3a01b77e1002a78e53d99f83.zip |
Remove netcon from dev branch. This is moving to its own new ZeroTierSDK repo for future release under the SDK name.
Diffstat (limited to 'ext/lwip/src/core')
35 files changed, 0 insertions, 27008 deletions
diff --git a/ext/lwip/src/core/def.c b/ext/lwip/src/core/def.c deleted file mode 100644 index 352b5524..00000000 --- a/ext/lwip/src/core/def.c +++ /dev/null @@ -1,108 +0,0 @@ -/** - * @file - * Common functions used throughout the stack. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Simon Goldschmidt - * - */ - -#include "lwip/opt.h" -#include "lwip/def.h" - -/** - * These are reference implementations of the byte swapping functions. - * Again with the aim of being simple, correct and fully portable. - * Byte swapping is the second thing you would want to optimize. You will - * need to port it to your architecture and in your cc.h: - * - * #define LWIP_PLATFORM_BYTESWAP 1 - * #define LWIP_PLATFORM_HTONS(x) <your_htons> - * #define LWIP_PLATFORM_HTONL(x) <your_htonl> - * - * Note ntohs() and ntohl() are merely references to the htonx counterparts. - */ - -#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) - -/** - * Convert an u16_t from host- to network byte order. - * - * @param n u16_t in host byte order - * @return n in network byte order - */ -u16_t -lwip_htons(u16_t n) -{ - return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); -} - -/** - * Convert an u16_t from network- to host byte order. - * - * @param n u16_t in network byte order - * @return n in host byte order - */ -u16_t -lwip_ntohs(u16_t n) -{ - return lwip_htons(n); -} - -/** - * Convert an u32_t from host- to network byte order. - * - * @param n u32_t in host byte order - * @return n in network byte order - */ -u32_t -lwip_htonl(u32_t n) -{ - return ((n & 0xff) << 24) | - ((n & 0xff00) << 8) | - ((n & 0xff0000UL) >> 8) | - ((n & 0xff000000UL) >> 24); -} - -/** - * Convert an u32_t from network- to host byte order. - * - * @param n u32_t in network byte order - * @return n in host byte order - */ -u32_t -lwip_ntohl(u32_t n) -{ - return lwip_htonl(n); -} - -#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/ext/lwip/src/core/dhcp.c b/ext/lwip/src/core/dhcp.c deleted file mode 100644 index cf864a8f..00000000 --- a/ext/lwip/src/core/dhcp.c +++ /dev/null @@ -1,1770 +0,0 @@ -/** - * @file - * Dynamic Host Configuration Protocol client - * - */ - -/* - * - * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net> - * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. - * - * Author: Leon Woestenberg <leon.woestenberg@gmx.net> - * - * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform - * with RFC 2131 and RFC 2132. - * - * TODO: - * - Support for interfaces other than Ethernet (SLIP, PPP, ...) - * - * Please coordinate changes and requests with Leon Woestenberg - * <leon.woestenberg@gmx.net> - * - * Integration with your code: - * - * In lwip/dhcp.h - * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute) - * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer) - * - * Then have your application call dhcp_coarse_tmr() and - * dhcp_fine_tmr() on the defined intervals. - * - * dhcp_start(struct netif *netif); - * starts a DHCP client instance which configures the interface by - * obtaining an IP address lease and maintaining it. - * - * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif) - * to remove the DHCP client. - * - */ - -#include "lwip/opt.h" - -#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/stats.h" -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/def.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/dns.h" -#include "netif/etharp.h" - -#include <string.h> - -/** DHCP_CREATE_RAND_XID: if this is set to 1, the xid is created using - * LWIP_RAND() (this overrides DHCP_GLOBAL_XID) - */ -#ifndef DHCP_CREATE_RAND_XID -#define DHCP_CREATE_RAND_XID 1 -#endif - -/** Default for DHCP_GLOBAL_XID is 0xABCD0000 - * This can be changed by defining DHCP_GLOBAL_XID and DHCP_GLOBAL_XID_HEADER, e.g. - * #define DHCP_GLOBAL_XID_HEADER "stdlib.h" - * #define DHCP_GLOBAL_XID rand() - */ -#ifdef DHCP_GLOBAL_XID_HEADER -#include DHCP_GLOBAL_XID_HEADER /* include optional starting XID generation prototypes */ -#endif - -/** DHCP_OPTION_MAX_MSG_SIZE is set to the MTU - * MTU is checked to be big enough in dhcp_start */ -#define DHCP_MAX_MSG_LEN(netif) (netif->mtu) -#define DHCP_MAX_MSG_LEN_MIN_REQUIRED 576 -/** Minimum length for reply before packet is parsed */ -#define DHCP_MIN_REPLY_LEN 44 - -#define REBOOT_TRIES 2 - -/** Option handling: options are parsed in dhcp_parse_reply - * and saved in an array where other functions can load them from. - * This might be moved into the struct dhcp (not necessarily since - * lwIP is single-threaded and the array is only used while in recv - * callback). */ -#define DHCP_OPTION_IDX_OVERLOAD 0 -#define DHCP_OPTION_IDX_MSG_TYPE 1 -#define DHCP_OPTION_IDX_SERVER_ID 2 -#define DHCP_OPTION_IDX_LEASE_TIME 3 -#define DHCP_OPTION_IDX_T1 4 -#define DHCP_OPTION_IDX_T2 5 -#define DHCP_OPTION_IDX_SUBNET_MASK 6 -#define DHCP_OPTION_IDX_ROUTER 7 -#define DHCP_OPTION_IDX_DNS_SERVER 8 -#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) - -/** Holds the decoded option values, only valid while in dhcp_recv. - @todo: move this into struct dhcp? */ -u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; -/** Holds a flag which option was received and is contained in dhcp_rx_options_val, - only valid while in dhcp_recv. - @todo: move this into struct dhcp? */ -u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; - -#ifdef DHCP_GLOBAL_XID -static u32_t xid; -static u8_t xid_initialised; -#endif /* DHCP_GLOBAL_XID */ - -#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) -#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) -#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) -#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) -#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) -#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) - - -/* DHCP client state machine functions */ -static err_t dhcp_discover(struct netif *netif); -static err_t dhcp_select(struct netif *netif); -static void dhcp_bind(struct netif *netif); -#if DHCP_DOES_ARP_CHECK -static err_t dhcp_decline(struct netif *netif); -#endif /* DHCP_DOES_ARP_CHECK */ -static err_t dhcp_rebind(struct netif *netif); -static err_t dhcp_reboot(struct netif *netif); -static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); - -/* receive, unfold, parse and free incoming messages */ -static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); - -/* set the DHCP timers */ -static void dhcp_timeout(struct netif *netif); -static void dhcp_t1_timeout(struct netif *netif); -static void dhcp_t2_timeout(struct netif *netif); - -/* build outgoing messages */ -/* create a DHCP message, fill in common headers */ -static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); -/* free a DHCP request */ -static void dhcp_delete_msg(struct dhcp *dhcp); -/* add a DHCP option (type, then length in bytes) */ -static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); -/* add option values */ -static void dhcp_option_byte(struct dhcp *dhcp, u8_t value); -static void dhcp_option_short(struct dhcp *dhcp, u16_t value); -static void dhcp_option_long(struct dhcp *dhcp, u32_t value); -#if LWIP_NETIF_HOSTNAME -static void dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif); -#endif /* LWIP_NETIF_HOSTNAME */ -/* always add the DHCP options trailer to end and pad */ -static void dhcp_option_trailer(struct dhcp *dhcp); - -/** - * Back-off the DHCP client (because of a received NAK response). - * - * Back-off the DHCP client because of a received NAK. Receiving a - * NAK means the client asked for something non-sensible, for - * example when it tries to renew a lease obtained on another network. - * - * We clear any existing set IP address and restart DHCP negotiation - * afresh (as per RFC2131 3.2.3). - * - * @param netif the netif under DHCP control - */ -static void -dhcp_handle_nak(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* Set the interface down since the address must no longer be used, as per RFC2131 */ - netif_set_down(netif); - /* remove IP address from interface */ - netif_set_ipaddr(netif, IP_ADDR_ANY); - netif_set_gw(netif, IP_ADDR_ANY); - netif_set_netmask(netif, IP_ADDR_ANY); - /* Change to a defined state */ - dhcp_set_state(dhcp, DHCP_BACKING_OFF); - /* We can immediately restart discovery */ - dhcp_discover(netif); -} - -#if DHCP_DOES_ARP_CHECK -/** - * Checks if the offered IP address is already in use. - * - * It does so by sending an ARP request for the offered address and - * entering CHECKING state. If no ARP reply is received within a small - * interval, the address is assumed to be free for use by us. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_check(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0], - (s16_t)netif->name[1])); - dhcp_set_state(dhcp, DHCP_CHECKING); - /* create an ARP query for the offered IP address, expecting that no host - responds, as the IP address should not be in use. */ - result = etharp_query(netif, &dhcp->offered_ip_addr, NULL); - if (result != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_check: could not perform ARP query\n")); - } - dhcp->tries++; - msecs = 500; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs)); -} -#endif /* DHCP_DOES_ARP_CHECK */ - -/** - * Remember the configuration offered by a DHCP server. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_handle_offer(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* obtain the server address */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { - ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->server_ip_addr))); - /* remember offered address */ - ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_select(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); - } -} - -/** - * Select a DHCP server offer out of all offers. - * - * Simply select the first offer received. - * - * @param netif the netif under DHCP control - * @return lwIP specific error (see error.h) - */ -static err_t -dhcp_select(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - dhcp_set_state(dhcp, DHCP_REQUESTING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - /* MUST request the offered IP address */ - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr))); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); - dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); - dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); - dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - dhcp_option_trailer(dhcp); - /* shrink the pbuf to the actual content length */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* send broadcast to any DHCP server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * The DHCP timer that checks for lease renewal/rebind timeouts. - */ -void -dhcp_coarse_tmr() -{ - struct netif *netif = netif_list; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n")); - /* iterate through all network interfaces */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - if (netif->dhcp != NULL) { - /* timer is active (non zero), and triggers (zeroes) now? */ - if (netif->dhcp->t2_timeout-- == 1) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n")); - /* this clients' rebind timeout triggered */ - dhcp_t2_timeout(netif); - /* timer is active (non zero), and triggers (zeroes) now */ - } else if (netif->dhcp->t1_timeout-- == 1) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n")); - /* this clients' renewal timeout triggered */ - dhcp_t1_timeout(netif); - } - } - /* proceed to next netif */ - netif = netif->next; - } -} - -/** - * DHCP transaction timeout handling - * - * A DHCP server is expected to respond within a short period of time. - * This timer checks whether an outstanding DHCP request is timed out. - */ -void -dhcp_fine_tmr() -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on DHCP configured interfaces */ - if (netif->dhcp != NULL) { - /* timer is active (non zero), and is about to trigger now */ - if (netif->dhcp->request_timeout > 1) { - netif->dhcp->request_timeout--; - } - else if (netif->dhcp->request_timeout == 1) { - netif->dhcp->request_timeout--; - /* { netif->dhcp->request_timeout == 0 } */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); - /* this client's request timeout triggered */ - dhcp_timeout(netif); - } - } - /* proceed to next network interface */ - netif = netif->next; - } -} - -/** - * A DHCP negotiation transaction, or ARP request, has timed out. - * - * The timer that was started with the DHCP or ARP request has - * timed out, indicating no response was received in time. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout()\n")); - /* back-off period has passed, or server selection timed out */ - if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n")); - dhcp_discover(netif); - /* receiving the requested lease timed out */ - } else if (dhcp->state == DHCP_REQUESTING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n")); - if (dhcp->tries <= 5) { - dhcp_select(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n")); - dhcp_release(netif); - dhcp_discover(netif); - } -#if DHCP_DOES_ARP_CHECK - /* received no ARP reply for the offered address (which is good) */ - } else if (dhcp->state == DHCP_CHECKING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n")); - if (dhcp->tries <= 1) { - dhcp_check(netif); - /* no ARP replies on the offered address, - looks like the IP address is indeed free */ - } else { - /* bind the interface to the offered address */ - dhcp_bind(netif); - } -#endif /* DHCP_DOES_ARP_CHECK */ - } - /* did not get response to renew request? */ - else if (dhcp->state == DHCP_RENEWING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n")); - /* just retry renewal */ - /* note that the rebind timer will eventually time-out if renew does not work */ - dhcp_renew(netif); - /* did not get response to rebind request? */ - } else if (dhcp->state == DHCP_REBINDING) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n")); - if (dhcp->tries <= 8) { - dhcp_rebind(netif); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n")); - dhcp_release(netif); - dhcp_discover(netif); - } - } else if (dhcp->state == DHCP_REBOOTING) { - if (dhcp->tries < REBOOT_TRIES) { - dhcp_reboot(netif); - } else { - dhcp_discover(netif); - } - } -} - -/** - * The renewal period has timed out. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_t1_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || - (dhcp->state == DHCP_RENEWING)) { - /* just retry to renew - note that the rebind timer (t2) will - * eventually time-out if renew tries fail. */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("dhcp_t1_timeout(): must renew\n")); - /* This slightly different to RFC2131: DHCPREQUEST will be sent from state - DHCP_RENEWING, not DHCP_BOUND */ - dhcp_renew(netif); - } -} - -/** - * The rebind period has timed out. - * - * @param netif the netif under DHCP control - */ -static void -dhcp_t2_timeout(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || - (dhcp->state == DHCP_RENEWING)) { - /* just retry to rebind */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("dhcp_t2_timeout(): must rebind\n")); - /* This slightly different to RFC2131: DHCPREQUEST will be sent from state - DHCP_REBINDING, not DHCP_BOUND */ - dhcp_rebind(netif); - } -} - -/** - * Handle a DHCP ACK packet - * - * @param netif the netif under DHCP control - */ -static void -dhcp_handle_ack(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; -#if LWIP_DNS - u8_t n; -#endif /* LWIP_DNS */ - - /* clear options we might not get from the ACK */ - ip_addr_set_zero(&dhcp->offered_sn_mask); - ip_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip_addr_set_zero(&dhcp->offered_si_addr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* lease time given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { - /* remember offered lease time */ - dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); - } - /* renewal period given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { - /* remember given renewal period */ - dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); - } else { - /* calculate safe periods for renewal */ - dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; - } - - /* renewal period given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { - /* remember given rebind period */ - dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); - } else { - /* calculate safe periods for rebinding */ - dhcp->offered_t2_rebind = dhcp->offered_t0_lease; - } - - /* (y)our internet address */ - ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); - -#if LWIP_DHCP_BOOTP_FILE - /* copy boot server address, - boot file name copied in dhcp_parse_reply if not overloaded */ - ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* subnet mask given? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { - /* remember given subnet mask */ - ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); - dhcp->subnet_mask_given = 1; - } else { - dhcp->subnet_mask_given = 0; - } - - /* gateway router */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { - ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); - } - -#if LWIP_DNS - /* DNS servers */ - n = 0; - while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) { - ip_addr_t dns_addr; - ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); - dns_setserver(n, &dns_addr); - n++; - } -#endif /* LWIP_DNS */ -} - -/** Set a statically allocated struct dhcp to work with. - * Using this prevents dhcp_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct dhcp - * @param dhcp (uninitialised) dhcp struct allocated by the application - */ -void -dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("dhcp != NULL", dhcp != NULL); - LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); - - /* clear data structure */ - memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_OFF); */ - netif->dhcp = dhcp; -} - -/** Removes a struct dhcp from a netif. - * - * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the - * struct dhcp since the memory is passed back to the heap. - * - * @param netif the netif from which to remove the struct dhcp - */ -void dhcp_cleanup(struct netif *netif) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - - if (netif->dhcp != NULL) { - mem_free(netif->dhcp); - netif->dhcp = NULL; - } -} - -/** - * Start DHCP negotiation for a network interface. - * - * If no DHCP client instance was attached to this interface, - * a new client is created first. If a DHCP client instance - * was already present, it restarts negotiation. - * - * @param netif The lwIP network interface - * @return lwIP error code - * - ERR_OK - No error - * - ERR_MEM - Out of memory - */ -err_t -dhcp_start(struct netif *netif) -{ - struct dhcp *dhcp; - err_t result = ERR_OK; - - LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;); - dhcp = netif->dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - /* Remove the flag that says this netif is handled by DHCP, - it is set when we succeeded starting. */ - netif->flags &= ~NETIF_FLAG_DHCP; - - /* check hwtype of the netif */ - if ((netif->flags & NETIF_FLAG_ETHARP) == 0) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n")); - return ERR_ARG; - } - - /* check MTU of the netif */ - if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); - return ERR_MEM; - } - - /* no DHCP client attached yet? */ - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); - dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); - return ERR_MEM; - } - /* store this dhcp client in the netif */ - netif->dhcp = dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp")); - /* already has DHCP client attached */ - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_start(): restarting DHCP configuration\n")); - if (dhcp->pcb != NULL) { - udp_remove(dhcp->pcb); - } - LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); - } - - /* clear data structure */ - memset(dhcp, 0, sizeof(struct dhcp)); - /* dhcp_set_state(&dhcp, DHCP_OFF); */ - /* allocate UDP PCB */ - dhcp->pcb = udp_new(); - if (dhcp->pcb == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); - return ERR_MEM; - } - ip_set_option(dhcp->pcb, SOF_BROADCAST); - /* set up local and remote port for the pcb */ - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); - udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); - /* set up the recv callback and argument */ - udp_recv(dhcp->pcb, dhcp_recv, netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n")); - /* (re)start the DHCP negotiation */ - result = dhcp_discover(netif); - if (result != ERR_OK) { - /* free resources allocated above */ - dhcp_stop(netif); - return ERR_MEM; - } - /* Set the flag that says this netif is handled by DHCP. */ - netif->flags |= NETIF_FLAG_DHCP; - return result; -} - -/** - * Inform a DHCP server of our manual configuration. - * - * This informs DHCP servers of our fixed IP address configuration - * by sending an INFORM message. It does not involve DHCP address - * configuration, it is just here to be nice to the network. - * - * @param netif The lwIP network interface - */ -void -dhcp_inform(struct netif *netif) -{ - struct dhcp dhcp; - err_t result = ERR_OK; - struct udp_pcb *pcb; - - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - - memset(&dhcp, 0, sizeof(struct dhcp)); - dhcp_set_state(&dhcp, DHCP_INFORM); - - if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) { - /* re-use existing pcb */ - pcb = netif->dhcp->pcb; - } else { - pcb = udp_new(); - if (pcb == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); - return; - } - dhcp.pcb = pcb; - ip_set_option(dhcp.pcb, SOF_BROADCAST); - udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); - } - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); - if (result == ERR_OK) { - dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option_trailer(&dhcp); - - pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(&dhcp); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); - } - - if (dhcp.pcb != NULL) { - /* otherwise, the existing pcb was used */ - udp_remove(dhcp.pcb); - } -} - -/** Handle a possible change in the network configuration. - * - * This enters the REBOOTING state to verify that the currently bound - * address is still valid. - */ -void -dhcp_network_changed(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - if (!dhcp) - return; - switch (dhcp->state) { - case DHCP_REBINDING: - case DHCP_RENEWING: - case DHCP_BOUND: - case DHCP_REBOOTING: - netif_set_down(netif); - dhcp->tries = 0; - dhcp_reboot(netif); - break; - case DHCP_OFF: - /* stay off */ - break; - default: - dhcp->tries = 0; -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - dhcp_discover(netif); - break; - } -} - -#if DHCP_DOES_ARP_CHECK -/** - * Match an ARP reply with the offered IP address. - * - * @param netif the network interface on which the reply was received - * @param addr The IP address we received a reply from - */ -void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr) -{ - LWIP_ERROR("netif != NULL", (netif != NULL), return;); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); - /* is a DHCP client doing an ARP check? */ - if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", - ip4_addr_get_u32(addr))); - /* did a host respond with the address we - were offered by the DHCP server? */ - if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { - /* we will not accept the offered address */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("dhcp_arp_reply(): arp reply matched with offered address, declining\n")); - dhcp_decline(netif); - } - } -} - -/** - * Decline an offered lease. - * - * Tell the DHCP server we do not accept the offered address. - * One reason to decline the lease is when we find out the address - * is already in use by another host (through ARP). - * - * @param netif the netif under DHCP control - */ -static err_t -dhcp_decline(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); - dhcp_set_state(dhcp, DHCP_BACKING_OFF); - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option_trailer(dhcp); - /* resize pbuf to reflect true size of options */ - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* per section 4.4.4, broadcast DECLINE messages */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_decline: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = 10*1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} -#endif /* DHCP_DOES_ARP_CHECK */ - - -/** - * Start the DHCP process, discover a DHCP server. - * - * @param netif the netif under DHCP control - */ -static err_t -dhcp_discover(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result = ERR_OK; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); - ip_addr_set_any(&dhcp->offered_ip_addr); - dhcp_set_state(dhcp, DHCP_SELECTING); - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); - if (result == ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); - - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); - dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); - dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER); - dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST); - dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); - - dhcp_option_trailer(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n")); - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); - } - dhcp->tries++; -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->tries >= LWIP_DHCP_AUTOIP_COOP_TRIES && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) { - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON; - autoip_start(netif); - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - msecs = (dhcp->tries < 6 ? 1 << dhcp->tries : 60) * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * Bind the interface to the offered IP address. - * - * @param netif network interface to bind to the offered address - */ -static void -dhcp_bind(struct netif *netif) -{ - u32_t timeout; - struct dhcp *dhcp; - ip_addr_t sn_mask, gw_addr; - LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - - /* temporary DHCP lease? */ - if (dhcp->offered_t1_renew != 0xffffffffUL) { - /* set renewal period timer */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew)); - timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if(timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t1_timeout = (u16_t)timeout; - if (dhcp->t1_timeout == 0) { - dhcp->t1_timeout = 1; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000)); - } - /* set renewal period timer */ - if (dhcp->offered_t2_rebind != 0xffffffffUL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind)); - timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS; - if(timeout > 0xffff) { - timeout = 0xffff; - } - dhcp->t2_timeout = (u16_t)timeout; - if (dhcp->t2_timeout == 0) { - dhcp->t2_timeout = 1; - } - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); - } - - /* If we have sub 1 minute lease, t2 and t1 will kick in at the same time. */ - if ((dhcp->t1_timeout >= dhcp->t2_timeout) && (dhcp->t2_timeout > 0)) { - dhcp->t1_timeout = 0; - } - - if (dhcp->subnet_mask_given) { - /* copy offered network mask */ - ip_addr_copy(sn_mask, dhcp->offered_sn_mask); - } else { - /* subnet mask not given, choose a safe subnet mask given the network class */ - u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); - if (first_octet <= 127) { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); - } else if (first_octet >= 192) { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); - } else { - ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); - } - } - - ip_addr_copy(gw_addr, dhcp->offered_gw_addr); - /* gateway address not given? */ - if (ip_addr_isany(&gw_addr)) { - /* copy network address */ - ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); - /* use first host address on network as gateway */ - ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL)); - } - -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", - ip4_addr_get_u32(&dhcp->offered_ip_addr))); - netif_set_ipaddr(netif, &dhcp->offered_ip_addr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", - ip4_addr_get_u32(&sn_mask))); - netif_set_netmask(netif, &sn_mask); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", - ip4_addr_get_u32(&gw_addr))); - netif_set_gw(netif, &gw_addr); - /* bring the interface up */ - netif_set_up(netif); - /* netif is now bound to DHCP leased address */ - dhcp_set_state(dhcp, DHCP_BOUND); -} - -/** - * Renew an existing DHCP lease at the involved DHCP server. - * - * @param netif network interface which must renew its lease - */ -err_t -dhcp_renew(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); - dhcp_set_state(dhcp, DHCP_RENEWING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - -#if 0 - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); -#endif - -#if 0 - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); -#endif - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - - /* append DHCP message trailer */ - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_renew: could not allocate DHCP request\n")); - } - dhcp->tries++; - /* back-off on retries, but to a maximum of 20 seconds */ - msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Rebind with a DHCP server for an existing DHCP lease. - * - * @param netif network interface which must rebind with a DHCP server - */ -static err_t -dhcp_rebind(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); - dhcp_set_state(dhcp, DHCP_REBINDING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - -#if LWIP_NETIF_HOSTNAME - dhcp_option_hostname(dhcp, netif); -#endif /* LWIP_NETIF_HOSTNAME */ - -#if 0 - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); - - dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); -#endif - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - -/** - * Enter REBOOTING state to verify an existing lease - * - * @param netif network interface which must reboot - */ -static err_t -dhcp_reboot(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot()\n")); - dhcp_set_state(dhcp, DHCP_REBOOTING); - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); - if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, 576); - - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); - - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - /* broadcast to server */ - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot(): set request timeout %"U16_F" msecs\n", msecs)); - return result; -} - - -/** - * Release a DHCP lease. - * - * @param netif network interface which must release its lease - */ -err_t -dhcp_release(struct netif *netif) -{ - struct dhcp *dhcp = netif->dhcp; - err_t result; - u16_t msecs; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_release()\n")); - - /* idle DHCP client */ - dhcp_set_state(dhcp, DHCP_OFF); - /* clean old DHCP offer */ - ip_addr_set_zero(&dhcp->server_ip_addr); - ip_addr_set_zero(&dhcp->offered_ip_addr); - ip_addr_set_zero(&dhcp->offered_sn_mask); - ip_addr_set_zero(&dhcp->offered_gw_addr); -#if LWIP_DHCP_BOOTP_FILE - ip_addr_set_zero(&dhcp->offered_si_addr); -#endif /* LWIP_DHCP_BOOTP_FILE */ - dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; - - /* create and initialize the DHCP message header */ - result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); - if (result == ERR_OK) { - dhcp_option_trailer(dhcp); - - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); - - udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_msg(dhcp); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); - } - dhcp->tries++; - msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000; - dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs)); - /* bring the interface down */ - netif_set_down(netif); - /* remove IP address from interface */ - netif_set_ipaddr(netif, IP_ADDR_ANY); - netif_set_gw(netif, IP_ADDR_ANY); - netif_set_netmask(netif, IP_ADDR_ANY); - - return result; -} - -/** - * Remove the DHCP client from the interface. - * - * @param netif The network interface to stop DHCP on - */ -void -dhcp_stop(struct netif *netif) -{ - struct dhcp *dhcp; - LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - /* Remove the flag that says this netif is handled by DHCP. */ - netif->flags &= ~NETIF_FLAG_DHCP; - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_stop()\n")); - /* netif is DHCP configured? */ - if (dhcp != NULL) { -#if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } -#endif /* LWIP_DHCP_AUTOIP_COOP */ - - if (dhcp->pcb != NULL) { - udp_remove(dhcp->pcb); - dhcp->pcb = NULL; - } - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - dhcp_set_state(dhcp, DHCP_OFF); - } -} - -/* - * Set the DHCP state of a DHCP client. - * - * If the state changed, reset the number of tries. - */ -static void -dhcp_set_state(struct dhcp *dhcp, u8_t new_state) -{ - if (new_state != dhcp->state) { - dhcp->state = new_state; - dhcp->tries = 0; - dhcp->request_timeout = 0; - } -} - -/* - * Concatenate an option type and length field to the outgoing - * DHCP message. - * - */ -static void -dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len) -{ - LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = option_type; - dhcp->msg_out->options[dhcp->options_out_len++] = option_len; -} -/* - * Concatenate a single byte to the outgoing DHCP message. - * - */ -static void -dhcp_option_byte(struct dhcp *dhcp, u8_t value) -{ - LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = value; -} - -static void -dhcp_option_short(struct dhcp *dhcp, u16_t value) -{ - LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU); -} - -static void -dhcp_option_long(struct dhcp *dhcp, u32_t value) -{ - LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8); - dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL)); -} - -#if LWIP_NETIF_HOSTNAME -static void -dhcp_option_hostname(struct dhcp *dhcp, struct netif *netif) -{ - if (netif->hostname != NULL) { - size_t namelen = strlen(netif->hostname); - if (namelen > 0) { - u8_t len; - const char *p = netif->hostname; - /* Shrink len to available bytes (need 2 bytes for OPTION_HOSTNAME - and 1 byte for trailer) */ - size_t available = DHCP_OPTIONS_LEN - dhcp->options_out_len - 3; - LWIP_ASSERT("DHCP: hostname is too long!", namelen <= available); - len = LWIP_MIN(namelen, available); - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, len); - while (len--) { - dhcp_option_byte(dhcp, *p++); - } - } - } -} -#endif /* LWIP_NETIF_HOSTNAME */ - -/** - * Extract the DHCP message and the DHCP options. - * - * Extract the DHCP message and the DHCP options, each into a contiguous - * piece of memory. As a DHCP message is variable sized by its options, - * and also allows overriding some fields for options, the easy approach - * is to first unfold the options into a conitguous piece of memory, and - * use that further on. - * - */ -static err_t -dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) -{ - u8_t *options; - u16_t offset; - u16_t offset_max; - u16_t options_idx; - u16_t options_idx_max; - struct pbuf *q; - int parse_file_as_options = 0; - int parse_sname_as_options = 0; - - /* clear received options */ - dhcp_clear_all_options(dhcp); - /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ - if (p->len < DHCP_SNAME_OFS) { - return ERR_BUF; - } - dhcp->msg_in = (struct dhcp_msg *)p->payload; -#if LWIP_DHCP_BOOTP_FILE - /* clear boot file name */ - dhcp->boot_file_name[0] = 0; -#endif /* LWIP_DHCP_BOOTP_FILE */ - - /* parse options */ - - /* start with options field */ - options_idx = DHCP_OPTIONS_OFS; - /* parse options to the end of the received packet */ - options_idx_max = p->tot_len; -again: - q = p; - while((q != NULL) && (options_idx >= q->len)) { - options_idx -= q->len; - options_idx_max -= q->len; - q = q->next; - } - if (q == NULL) { - return ERR_BUF; - } - offset = options_idx; - offset_max = options_idx_max; - options = (u8_t*)q->payload; - /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ - while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { - u8_t op = options[offset]; - u8_t len; - u8_t decode_len = 0; - int decode_idx = -1; - u16_t val_offset = offset + 2; - /* len byte might be in the next pbuf */ - if (offset + 1 < q->len) { - len = options[offset + 1]; - } else { - len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); - } - /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ - decode_len = len; - switch(op) { - /* case(DHCP_OPTION_END): handled above */ - case(DHCP_OPTION_PAD): - /* special option: no len encoded */ - decode_len = len = 0; - /* will be increased below */ - offset--; - break; - case(DHCP_OPTION_SUBNET_MASK): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; - break; - case(DHCP_OPTION_ROUTER): - decode_len = 4; /* only copy the first given router */ - LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_ROUTER; - break; - case(DHCP_OPTION_DNS_SERVER): - /* special case: there might be more than one server */ - LWIP_ERROR("len % 4 == 0", len % 4 == 0, return ERR_VAL;); - /* limit number of DNS servers */ - decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); - LWIP_ERROR("len >= decode_len", len >= decode_len, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_DNS_SERVER; - break; - case(DHCP_OPTION_LEASE_TIME): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_LEASE_TIME; - break; - case(DHCP_OPTION_OVERLOAD): - LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_OVERLOAD; - break; - case(DHCP_OPTION_MESSAGE_TYPE): - LWIP_ERROR("len == 1", len == 1, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_MSG_TYPE; - break; - case(DHCP_OPTION_SERVER_ID): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_SERVER_ID; - break; - case(DHCP_OPTION_T1): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_T1; - break; - case(DHCP_OPTION_T2): - LWIP_ERROR("len == 4", len == 4, return ERR_VAL;); - decode_idx = DHCP_OPTION_IDX_T2; - break; - default: - decode_len = 0; - LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); - break; - } - offset += len + 2; - if (decode_len > 0) { - u32_t value = 0; - u16_t copy_len; -decode_next: - LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); - if (!dhcp_option_given(dhcp, decode_idx)) { - copy_len = LWIP_MIN(decode_len, 4); - pbuf_copy_partial(q, &value, copy_len, val_offset); - if (decode_len > 4) { - /* decode more than one u32_t */ - LWIP_ERROR("decode_len % 4 == 0", decode_len % 4 == 0, return ERR_VAL;); - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, htonl(value)); - decode_len -= 4; - val_offset += 4; - decode_idx++; - goto decode_next; - } else if (decode_len == 4) { - value = ntohl(value); - } else { - LWIP_ERROR("invalid decode_len", decode_len == 1, return ERR_VAL;); - value = ((u8_t*)&value)[0]; - } - dhcp_got_option(dhcp, decode_idx); - dhcp_set_option_value(dhcp, decode_idx, value); - } - } - if (offset >= q->len) { - offset -= q->len; - offset_max -= q->len; - if ((offset < offset_max) && offset_max) { - q = q->next; - LWIP_ASSERT("next pbuf was null", q); - options = (u8_t*)q->payload; - } else { - /* We've run out of bytes, probably no end marker. Don't proceed. */ - break; - } - } - } - /* is this an overloaded message? */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { - u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); - dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); - if (overload == DHCP_OVERLOAD_FILE) { - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME) { - parse_sname_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); - } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { - parse_sname_as_options = 1; - parse_file_as_options = 1; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); - } -#if LWIP_DHCP_BOOTP_FILE - if (!parse_file_as_options) { - /* only do this for ACK messages */ - if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && - (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) - /* copy bootp file name, don't care for sname (server hostname) */ - pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); - /* make sure the string is really NULL-terminated */ - dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; - } -#endif /* LWIP_DHCP_BOOTP_FILE */ - } - if (parse_file_as_options) { - /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ - parse_file_as_options = 0; - options_idx = DHCP_FILE_OFS; - options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; - goto again; - } else if (parse_sname_as_options) { - parse_sname_as_options = 0; - options_idx = DHCP_SNAME_OFS; - options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; - goto again; - } - return ERR_OK; -} - -/** - * If an incoming DHCP message is in response to us, then trigger the state machine - */ -static void -dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - struct netif *netif = (struct netif *)arg; - struct dhcp *dhcp = netif->dhcp; - struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; - u8_t msg_type; - u8_t i; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, - ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port)); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); - /* prevent warnings about unused arguments */ - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); - - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); - - if (p->len < DHCP_MIN_REPLY_LEN) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); - goto free_pbuf_and_return; - } - - if (reply_msg->op != DHCP_BOOTREPLY) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op)); - goto free_pbuf_and_return; - } - /* iterate through hardware address and match against DHCP message */ - for (i = 0; i < netif->hwaddr_len; i++) { - if (netif->hwaddr[i] != reply_msg->chaddr[i]) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n", - (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i])); - goto free_pbuf_and_return; - } - } - /* match transaction ID against what we expected */ - if (ntohl(reply_msg->xid) != dhcp->xid) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("transaction id mismatch reply_msg->xid(%"X32_F")!=dhcp->xid(%"X32_F")\n",ntohl(reply_msg->xid),dhcp->xid)); - goto free_pbuf_and_return; - } - /* option fields could be unfold? */ - if (dhcp_parse_reply(dhcp, p) != ERR_OK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("problem unfolding DHCP message - too short on memory?\n")); - goto free_pbuf_and_return; - } - - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); - /* obtain pointer to DHCP message type */ - if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); - goto free_pbuf_and_return; - } - - /* read DHCP message type */ - msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); - /* message type is DHCP ACK? */ - if (msg_type == DHCP_ACK) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); - /* in requesting state? */ - if (dhcp->state == DHCP_REQUESTING) { - dhcp_handle_ack(netif); -#if DHCP_DOES_ARP_CHECK - /* check if the acknowledged lease address is already in use */ - dhcp_check(netif); -#else - /* bind interface to the acknowledged lease address */ - dhcp_bind(netif); -#endif - } - /* already bound to the given lease address? */ - else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { - dhcp_bind(netif); - } - } - /* received a DHCP_NAK in appropriate state? */ - else if ((msg_type == DHCP_NAK) && - ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || - (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); - dhcp_handle_nak(netif); - } - /* received a DHCP_OFFER in DHCP_SELECTING state? */ - else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_OFFER received in DHCP_SELECTING state\n")); - dhcp->request_timeout = 0; - /* remember offered lease */ - dhcp_handle_offer(netif); - } -free_pbuf_and_return: - dhcp->msg_in = NULL; - pbuf_free(p); -} - -/** - * Create a DHCP request, fill in common headers - * - * @param netif the netif under DHCP control - * @param dhcp dhcp control struct - * @param message_type message type of the request - */ -static err_t -dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) -{ - u16_t i; -#ifndef DHCP_GLOBAL_XID - /** default global transaction identifier starting value (easy to match - * with a packet analyser). We simply increment for each new request. - * Predefine DHCP_GLOBAL_XID to a better value or a function call to generate one - * at runtime, any supporting function prototypes can be defined in DHCP_GLOBAL_XID_HEADER */ -#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) - static u32_t xid; -#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - static u32_t xid = 0xABCD0000; -#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ -#else - if (!xid_initialised) { - xid = DHCP_GLOBAL_XID; - xid_initialised = !xid_initialised; - } -#endif - LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); - LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); - LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); - LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); - dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); - if (dhcp->p_out == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_create_msg(): could not allocate pbuf\n")); - return ERR_MEM; - } - LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", - (dhcp->p_out->len >= sizeof(struct dhcp_msg))); - - /* reuse transaction identifier in retransmissions */ - if (dhcp->tries == 0) { -#if DHCP_CREATE_RAND_XID && defined(LWIP_RAND) - xid = LWIP_RAND(); -#else /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - xid++; -#endif /* DHCP_CREATE_RAND_XID && defined(LWIP_RAND) */ - } - dhcp->xid = xid; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, - ("transaction id xid(%"X32_F")\n", xid)); - - dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload; - - dhcp->msg_out->op = DHCP_BOOTREQUEST; - /* TODO: make link layer independent */ - dhcp->msg_out->htype = DHCP_HTYPE_ETH; - dhcp->msg_out->hlen = netif->hwaddr_len; - dhcp->msg_out->hops = 0; - dhcp->msg_out->xid = htonl(dhcp->xid); - dhcp->msg_out->secs = 0; - /* we don't need the broadcast flag since we can receive unicast traffic - before being fully configured! */ - dhcp->msg_out->flags = 0; - ip_addr_set_zero(&dhcp->msg_out->ciaddr); - /* set ciaddr to netif->ip_addr based on message_type and state */ - if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || - ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */ - ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) { - ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr); - } - ip_addr_set_zero(&dhcp->msg_out->yiaddr); - ip_addr_set_zero(&dhcp->msg_out->siaddr); - ip_addr_set_zero(&dhcp->msg_out->giaddr); - for (i = 0; i < DHCP_CHADDR_LEN; i++) { - /* copy netif hardware address, pad with zeroes */ - dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/; - } - for (i = 0; i < DHCP_SNAME_LEN; i++) { - dhcp->msg_out->sname[i] = 0; - } - for (i = 0; i < DHCP_FILE_LEN; i++) { - dhcp->msg_out->file[i] = 0; - } - dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); - dhcp->options_out_len = 0; - /* fill options field with an incrementing array (for debugging purposes) */ - for (i = 0; i < DHCP_OPTIONS_LEN; i++) { - dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ - } - /* Add option MESSAGE_TYPE */ - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, message_type); - return ERR_OK; -} - -/** - * Free previously allocated memory used to send a DHCP request. - * - * @param dhcp the dhcp struct to free the request from - */ -static void -dhcp_delete_msg(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); - LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); - if (dhcp->p_out != NULL) { - pbuf_free(dhcp->p_out); - } - dhcp->p_out = NULL; - dhcp->msg_out = NULL; -} - -/** - * Add a DHCP message trailer - * - * Adds the END option to the DHCP message, and if - * necessary, up to three padding bytes. - * - * @param dhcp DHCP state structure - */ -static void -dhcp_option_trailer(struct dhcp *dhcp) -{ - LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL); - LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); - dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END; - /* packet is too small, or not 4 byte aligned? */ - while (((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) && - (dhcp->options_out_len < DHCP_OPTIONS_LEN)) { - /* add a fill/padding byte */ - dhcp->msg_out->options[dhcp->options_out_len++] = 0; - } -} - -#endif /* LWIP_DHCP */ diff --git a/ext/lwip/src/core/dns.c b/ext/lwip/src/core/dns.c deleted file mode 100644 index d6336122..00000000 --- a/ext/lwip/src/core/dns.c +++ /dev/null @@ -1,970 +0,0 @@ -/** - * @file - * DNS - host name to IP address resolver. - * - */ - -/** - - * This file implements a DNS host name to IP address resolver. - - * Port to lwIP from uIP - * by Jim Pettinato April 2007 - - * uIP version Copyright (c) 2002-2003, Adam Dunkels. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote - * products derived from this software without specific prior - * written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY - * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE - * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING - * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - * - * - * DNS.C - * - * The lwIP DNS resolver functions are used to lookup a host name and - * map it to a numerical IP address. It maintains a list of resolved - * hostnames that can be queried with the dns_lookup() function. - * New hostnames can be resolved using the dns_query() function. - * - * The lwIP version of the resolver also adds a non-blocking version of - * gethostbyname() that will work with a raw API application. This function - * checks for an IP address string first and converts it if it is valid. - * gethostbyname() then does a dns_lookup() to see if the name is - * already in the table. If so, the IP is returned. If not, a query is - * issued and the function returns with a ERR_INPROGRESS status. The app - * using the dns client must then go into a waiting state. - * - * Once a hostname has been resolved (or found to be non-existent), - * the resolver code calls a specified callback function (which - * must be implemented by the module that uses the resolver). - */ - -/*----------------------------------------------------------------------------- - * RFC 1035 - Domain names - implementation and specification - * RFC 2181 - Clarifications to the DNS Specification - *----------------------------------------------------------------------------*/ - -/** @todo: define good default values (rfc compliance) */ -/** @todo: improve answer parsing, more checkings... */ -/** @todo: check RFC1035 - 7.3. Processing responses */ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/dns.h" - -#include <string.h> - -/** DNS server IP address */ -#ifndef DNS_SERVER_ADDRESS -#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */ -#endif - -/** DNS server port address */ -#ifndef DNS_SERVER_PORT -#define DNS_SERVER_PORT 53 -#endif - -/** DNS maximum number of retries when asking for a name, before "timeout". */ -#ifndef DNS_MAX_RETRIES -#define DNS_MAX_RETRIES 4 -#endif - -/** DNS resource record max. TTL (one week as default) */ -#ifndef DNS_MAX_TTL -#define DNS_MAX_TTL 604800 -#endif - -/* DNS protocol flags */ -#define DNS_FLAG1_RESPONSE 0x80 -#define DNS_FLAG1_OPCODE_STATUS 0x10 -#define DNS_FLAG1_OPCODE_INVERSE 0x08 -#define DNS_FLAG1_OPCODE_STANDARD 0x00 -#define DNS_FLAG1_AUTHORATIVE 0x04 -#define DNS_FLAG1_TRUNC 0x02 -#define DNS_FLAG1_RD 0x01 -#define DNS_FLAG2_RA 0x80 -#define DNS_FLAG2_ERR_MASK 0x0f -#define DNS_FLAG2_ERR_NONE 0x00 -#define DNS_FLAG2_ERR_NAME 0x03 - -/* DNS protocol states */ -#define DNS_STATE_UNUSED 0 -#define DNS_STATE_NEW 1 -#define DNS_STATE_ASKING 2 -#define DNS_STATE_DONE 3 - -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** DNS message header */ -struct dns_hdr { - PACK_STRUCT_FIELD(u16_t id); - PACK_STRUCT_FIELD(u8_t flags1); - PACK_STRUCT_FIELD(u8_t flags2); - PACK_STRUCT_FIELD(u16_t numquestions); - PACK_STRUCT_FIELD(u16_t numanswers); - PACK_STRUCT_FIELD(u16_t numauthrr); - PACK_STRUCT_FIELD(u16_t numextrarr); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -#define SIZEOF_DNS_HDR 12 - -/** DNS query message structure. - No packing needed: only used locally on the stack. */ -struct dns_query { - /* DNS query record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - u16_t type; - u16_t cls; -}; -#define SIZEOF_DNS_QUERY 4 - -/** DNS answer message structure. - No packing needed: only used locally on the stack. */ -struct dns_answer { - /* DNS answer record starts with either a domain name or a pointer - to a name already present somewhere in the packet. */ - u16_t type; - u16_t cls; - u32_t ttl; - u16_t len; -}; -#define SIZEOF_DNS_ANSWER 10 - -/** DNS table entry */ -struct dns_table_entry { - u8_t state; - u8_t numdns; - u8_t tmr; - u8_t retries; - u8_t seqno; - u8_t err; - u32_t ttl; - char name[DNS_MAX_NAME_LENGTH]; - ip_addr_t ipaddr; - /* pointer to callback on DNS query done */ - dns_found_callback found; - void *arg; -}; - -#if DNS_LOCAL_HOSTLIST - -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -/** Local host-list. For hostnames in this list, no - * external name resolution is performed */ -static struct local_hostlist_entry *local_hostlist_dynamic; -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -/** Defining this allows the local_hostlist_static to be placed in a different - * linker section (e.g. FLASH) */ -#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE -#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static -#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */ -/** Defining this allows the local_hostlist_static to be placed in a different - * linker section (e.g. FLASH) */ -#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST -#define DNS_LOCAL_HOSTLIST_STORAGE_POST -#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */ -DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[] - DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT; - -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - -static void dns_init_local(); -#endif /* DNS_LOCAL_HOSTLIST */ - - -/* forward declarations */ -static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); -static void dns_check_entries(void); - -/*----------------------------------------------------------------------------- - * Globales - *----------------------------------------------------------------------------*/ - -/* DNS variables */ -static struct udp_pcb *dns_pcb; -static u8_t dns_seqno; -static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; -static ip_addr_t dns_servers[DNS_MAX_SERVERS]; -/** Contiguous buffer for processing responses */ -static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)]; -static u8_t* dns_payload; - -/** - * Initialize the resolver: set up the UDP pcb and configure the default server - * (DNS_SERVER_ADDRESS). - */ -void -dns_init() -{ - ip_addr_t dnsserver; - - dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); - - /* initialize default DNS server address */ - DNS_SERVER_ADDRESS(&dnsserver); - - LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); - - /* if dns client not yet initialized... */ - if (dns_pcb == NULL) { - dns_pcb = udp_new(); - - if (dns_pcb != NULL) { - /* initialize DNS table not needed (initialized to zero since it is a - * global variable) */ - LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0", - DNS_STATE_UNUSED == 0); - - /* initialize DNS client */ - udp_bind(dns_pcb, IP_ADDR_ANY, 0); - udp_recv(dns_pcb, dns_recv, NULL); - - /* initialize default DNS primary server */ - dns_setserver(0, &dnsserver); - } - } -#if DNS_LOCAL_HOSTLIST - dns_init_local(); -#endif -} - -/** - * Initialize one of the DNS servers. - * - * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS - * @param dnsserver IP address of the DNS server to set - */ -void -dns_setserver(u8_t numdns, ip_addr_t *dnsserver) -{ - if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && - (dnsserver != NULL) && !ip_addr_isany(dnsserver)) { - dns_servers[numdns] = (*dnsserver); - } -} - -/** - * Obtain one of the currently configured DNS server. - * - * @param numdns the index of the DNS server - * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS - * server has not been configured. - */ -ip_addr_t -dns_getserver(u8_t numdns) -{ - if (numdns < DNS_MAX_SERVERS) { - return dns_servers[numdns]; - } else { - return *IP_ADDR_ANY; - } -} - -/** - * The DNS resolver client timer - handle retries and timeouts and should - * be called every DNS_TMR_INTERVAL milliseconds (every second by default). - */ -void -dns_tmr(void) -{ - if (dns_pcb != NULL) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n")); - dns_check_entries(); - } -} - -#if DNS_LOCAL_HOSTLIST -static void -dns_init_local() -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) - int i; - struct local_hostlist_entry *entry; - /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ - struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; - size_t namelen; - for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { - struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; - LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); - namelen = strlen(init_entry->name); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); - if (entry != NULL) { - entry->name = (char*)entry + sizeof(struct local_hostlist_entry); - MEMCPY((char*)entry->name, init_entry->name, namelen); - ((char*)entry->name)[namelen] = 0; - entry->addr = init_entry->addr; - entry->next = local_hostlist_dynamic; - local_hostlist_dynamic = entry; - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */ -} - -/** - * Scans the local host-list for a hostname. - * - * @param hostname Hostname to look for in the local host-list - * @return The first IP address for the hostname in the local host-list or - * IPADDR_NONE if not found. - */ -static u32_t -dns_lookup_local(const char *hostname) -{ -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC - struct local_hostlist_entry *entry = local_hostlist_dynamic; - while(entry != NULL) { - if(strcmp(entry->name, hostname) == 0) { - return ip4_addr_get_u32(&entry->addr); - } - entry = entry->next; - } -#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - int i; - for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { - if(strcmp(local_hostlist_static[i].name, hostname) == 0) { - return ip4_addr_get_u32(&local_hostlist_static[i].addr); - } - } -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - return IPADDR_NONE; -} - -#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC -/** Remove all entries from the local host-list for a specific hostname - * and/or IP addess - * - * @param hostname hostname for which entries shall be removed from the local - * host-list - * @param addr address for which entries shall be removed from the local host-list - * @return the number of removed entries - */ -int -dns_local_removehost(const char *hostname, const ip_addr_t *addr) -{ - int removed = 0; - struct local_hostlist_entry *entry = local_hostlist_dynamic; - struct local_hostlist_entry *last_entry = NULL; - while (entry != NULL) { - if (((hostname == NULL) || !strcmp(entry->name, hostname)) && - ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { - struct local_hostlist_entry *free_entry; - if (last_entry != NULL) { - last_entry->next = entry->next; - } else { - local_hostlist_dynamic = entry->next; - } - free_entry = entry; - entry = entry->next; - memp_free(MEMP_LOCALHOSTLIST, free_entry); - removed++; - } else { - last_entry = entry; - entry = entry->next; - } - } - return removed; -} - -/** - * Add a hostname/IP address pair to the local host-list. - * Duplicates are not checked. - * - * @param hostname hostname of the new entry - * @param addr IP address of the new entry - * @return ERR_OK if succeeded or ERR_MEM on memory error - */ -err_t -dns_local_addhost(const char *hostname, const ip_addr_t *addr) -{ - struct local_hostlist_entry *entry; - size_t namelen; - LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); - namelen = strlen(hostname); - LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); - entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); - if (entry == NULL) { - return ERR_MEM; - } - entry->name = (char*)entry + sizeof(struct local_hostlist_entry); - MEMCPY((char*)entry->name, hostname, namelen); - ((char*)entry->name)[namelen] = 0; - ip_addr_copy(entry->addr, *addr); - entry->next = local_hostlist_dynamic; - local_hostlist_dynamic = entry; - return ERR_OK; -} -#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/ -#endif /* DNS_LOCAL_HOSTLIST */ - -/** - * Look up a hostname in the array of known hostnames. - * - * @note This function only looks in the internal array of known - * hostnames, it does not send out a query for the hostname if none - * was found. The function dns_enqueue() can be used to send a query - * for a hostname. - * - * @param name the hostname to look up - * @return the hostname's IP address, as u32_t (instead of ip_addr_t to - * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname - * was not found in the cached dns_table. - */ -static u32_t -dns_lookup(const char *name) -{ - u8_t i; -#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) - u32_t addr; -#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ -#if DNS_LOCAL_HOSTLIST - if ((addr = dns_lookup_local(name)) != IPADDR_NONE) { - return addr; - } -#endif /* DNS_LOCAL_HOSTLIST */ -#ifdef DNS_LOOKUP_LOCAL_EXTERN - if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) { - return addr; - } -#endif /* DNS_LOOKUP_LOCAL_EXTERN */ - - /* Walk through name list, return entry if found. If not, return NULL. */ - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - if ((dns_table[i].state == DNS_STATE_DONE) && - (strcmp(name, dns_table[i].name) == 0)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); - ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - return ip4_addr_get_u32(&dns_table[i].ipaddr); - } - } - - return IPADDR_NONE; -} - -#if DNS_DOES_NAME_CHECK -/** - * Compare the "dotted" name "query" with the encoded name "response" - * to make sure an answer from the DNS server matches the current dns_table - * entry (otherwise, answers might arrive late for hostname not on the list - * any more). - * - * @param query hostname (not encoded) from the dns_table - * @param response encoded hostname in the DNS response - * @return 0: names equal; 1: names differ - */ -static u8_t -dns_compare_name(unsigned char *query, unsigned char *response) -{ - unsigned char n; - - do { - n = *response++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - if ((*query) != (*response)) { - return 1; - } - ++response; - ++query; - --n; - }; - ++query; - } - } while (*response != 0); - - return 0; -} -#endif /* DNS_DOES_NAME_CHECK */ - -/** - * Walk through a compact encoded DNS name and return the end of the name. - * - * @param query encoded DNS name in the DNS server response - * @return end of the name - */ -static unsigned char * -dns_parse_name(unsigned char *query) -{ - unsigned char n; - - do { - n = *query++; - /** @see RFC 1035 - 4.1.4. Message compression */ - if ((n & 0xc0) == 0xc0) { - /* Compressed name */ - break; - } else { - /* Not compressed name */ - while (n > 0) { - ++query; - --n; - }; - } - } while (*query != 0); - - return query + 1; -} - -/** - * Send a DNS query packet. - * - * @param numdns index of the DNS server in the dns_servers table - * @param name hostname to query - * @param id index of the hostname in dns_table, used as transaction ID in the - * DNS query packet - * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise - */ -static err_t -dns_send(u8_t numdns, const char* name, u8_t id) -{ - err_t err; - struct dns_hdr *hdr; - struct dns_query qry; - struct pbuf *p; - char *query, *nptr; - const char *pHostname; - u8_t n; - - LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", - (u16_t)(numdns), name)); - LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); - LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns])); - - /* if here, we have either a new query or a retry on a previous query to process */ - p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + - SIZEOF_DNS_QUERY, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("pbuf must be in one piece", p->next == NULL); - /* fill dns header */ - hdr = (struct dns_hdr*)p->payload; - memset(hdr, 0, SIZEOF_DNS_HDR); - hdr->id = htons(id); - hdr->flags1 = DNS_FLAG1_RD; - hdr->numquestions = PP_HTONS(1); - query = (char*)hdr + SIZEOF_DNS_HDR; - pHostname = name; - --pHostname; - - /* convert hostname into suitable query format. */ - do { - ++pHostname; - nptr = query; - ++query; - for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) { - *query = *pHostname; - ++query; - ++n; - } - *nptr = n; - } while(*pHostname != 0); - *query++='\0'; - - /* fill dns query */ - qry.type = PP_HTONS(DNS_RRTYPE_A); - qry.cls = PP_HTONS(DNS_RRCLASS_IN); - SMEMCPY(query, &qry, SIZEOF_DNS_QUERY); - - /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)))); - - /* connect to the server for faster receiving */ - udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); - /* send dns packet */ - err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT); - - /* free pbuf */ - pbuf_free(p); - } else { - err = ERR_MEM; - } - - return err; -} - -/** - * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query. - * Check an entry in the dns_table: - * - send out query for new entries - * - retry old pending entries on timeout (also with different servers) - * - remove completed entries from the table if their TTL has expired - * - * @param i index of the dns_table entry to check - */ -static void -dns_check_entry(u8_t i) -{ - err_t err; - struct dns_table_entry *pEntry = &dns_table[i]; - - LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); - - switch(pEntry->state) { - - case DNS_STATE_NEW: { - /* initialize new entry */ - pEntry->state = DNS_STATE_ASKING; - pEntry->numdns = 0; - pEntry->tmr = 1; - pEntry->retries = 0; - - /* send DNS packet for this entry */ - err = dns_send(pEntry->numdns, pEntry->name, i); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("dns_send returned error: %s\n", lwip_strerr(err))); - } - break; - } - - case DNS_STATE_ASKING: { - if (--pEntry->tmr == 0) { - if (++pEntry->retries == DNS_MAX_RETRIES) { - if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) { - /* change of server */ - pEntry->numdns++; - pEntry->tmr = 1; - pEntry->retries = 0; - break; - } else { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name)); - /* call specified callback function if provided */ - if (pEntry->found) - (*pEntry->found)(pEntry->name, NULL, pEntry->arg); - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - break; - } - } - - /* wait longer for the next retry */ - pEntry->tmr = pEntry->retries; - - /* send DNS packet for this entry */ - err = dns_send(pEntry->numdns, pEntry->name, i); - if (err != ERR_OK) { - LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("dns_send returned error: %s\n", lwip_strerr(err))); - } - } - break; - } - - case DNS_STATE_DONE: { - /* if the time to live is nul */ - if (--pEntry->ttl == 0) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name)); - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - } - break; - } - case DNS_STATE_UNUSED: - /* nothing to do */ - break; - default: - LWIP_ASSERT("unknown dns_table entry state:", 0); - break; - } -} - -/** - * Call dns_check_entry for each entry in dns_table - check all entries. - */ -static void -dns_check_entries(void) -{ - u8_t i; - - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - dns_check_entry(i); - } -} - -/** - * Receive input function for DNS response packets arriving for the dns UDP pcb. - * - * @params see udp.h - */ -static void -dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - u16_t i; - char *pHostname; - struct dns_hdr *hdr; - struct dns_answer ans; - struct dns_table_entry *pEntry; - u16_t nquestions, nanswers; - - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(addr); - LWIP_UNUSED_ARG(port); - - /* is the dns message too big ? */ - if (p->tot_len > DNS_MSG_SIZE) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); - /* free pbuf and return */ - goto memerr; - } - - /* is the dns message big enough ? */ - if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); - /* free pbuf and return */ - goto memerr; - } - - /* copy dns payload inside static buffer for processing */ - if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { - /* The ID in the DNS header should be our entry into the name table. */ - hdr = (struct dns_hdr*)dns_payload; - i = htons(hdr->id); - if (i < DNS_TABLE_SIZE) { - pEntry = &dns_table[i]; - if(pEntry->state == DNS_STATE_ASKING) { - /* This entry is now completed. */ - pEntry->state = DNS_STATE_DONE; - pEntry->err = hdr->flags2 & DNS_FLAG2_ERR_MASK; - - /* We only care about the question(s) and the answers. The authrr - and the extrarr are simply discarded. */ - nquestions = htons(hdr->numquestions); - nanswers = htons(hdr->numanswers); - - /* Check for error. If so, call callback to inform. */ - if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - goto responseerr; - } - -#if DNS_DOES_NAME_CHECK - /* Check if the name in the "question" part match with the name in the entry. */ - if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - goto responseerr; - } -#endif /* DNS_DOES_NAME_CHECK */ - - /* Skip the name in the "question" part */ - pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; - - while (nanswers > 0) { - /* skip answer resource record's host name */ - pHostname = (char *) dns_parse_name((unsigned char *)pHostname); - - /* Check for IP address type and Internet class. Others are discarded. */ - SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); - if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && - (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) { - /* read the answer resource record's TTL, and maximize it if needed */ - pEntry->ttl = ntohl(ans.ttl); - if (pEntry->ttl > DNS_MAX_TTL) { - pEntry->ttl = DNS_MAX_TTL; - } - /* read the IP address after answer resource record's header */ - SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t)); - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); - ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); - LWIP_DEBUGF(DNS_DEBUG, ("\n")); - /* call specified callback function if provided */ - if (pEntry->found) { - (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); - } - /* deallocate memory and return */ - goto memerr; - } else { - pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); - } - --nanswers; - } - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name)); - /* call callback to indicate error, clean up memory and return */ - goto responseerr; - } - } - } - - /* deallocate memory and return */ - goto memerr; - -responseerr: - /* ERROR: call specified callback function with NULL as name to indicate an error */ - if (pEntry->found) { - (*pEntry->found)(pEntry->name, NULL, pEntry->arg); - } - /* flush this entry */ - pEntry->state = DNS_STATE_UNUSED; - pEntry->found = NULL; - -memerr: - /* free pbuf */ - pbuf_free(p); - return; -} - -/** - * Queues a new hostname to resolve and sends out a DNS query for that hostname - * - * @param name the hostname that is to be queried - * @param found a callback founction to be called on success, failure or timeout - * @param callback_arg argument to pass to the callback function - * @return @return a err_t return code. - */ -static err_t -dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) -{ - u8_t i; - u8_t lseq, lseqi; - struct dns_table_entry *pEntry = NULL; - size_t namelen; - - /* search an unused entry, or the oldest one */ - lseq = lseqi = 0; - for (i = 0; i < DNS_TABLE_SIZE; ++i) { - pEntry = &dns_table[i]; - /* is it an unused entry ? */ - if (pEntry->state == DNS_STATE_UNUSED) - break; - - /* check if this is the oldest completed entry */ - if (pEntry->state == DNS_STATE_DONE) { - if ((dns_seqno - pEntry->seqno) > lseq) { - lseq = dns_seqno - pEntry->seqno; - lseqi = i; - } - } - } - - /* if we don't have found an unused entry, use the oldest completed one */ - if (i == DNS_TABLE_SIZE) { - if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) { - /* no entry can't be used now, table is full */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name)); - return ERR_MEM; - } else { - /* use the oldest completed one */ - i = lseqi; - pEntry = &dns_table[i]; - } - } - - /* use this entry */ - LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i))); - - /* fill the entry */ - pEntry->state = DNS_STATE_NEW; - pEntry->seqno = dns_seqno++; - pEntry->found = found; - pEntry->arg = callback_arg; - namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1); - MEMCPY(pEntry->name, name, namelen); - pEntry->name[namelen] = 0; - - /* force to send query without waiting timer */ - dns_check_entry(i); - - /* dns query is enqueued */ - return ERR_INPROGRESS; -} - -/** - * Resolve a hostname (string) into an IP address. - * NON-BLOCKING callback version for use with raw API!!! - * - * Returns immediately with one of err_t return codes: - * - ERR_OK if hostname is a valid IP address string or the host - * name is already in the local names table. - * - ERR_INPROGRESS enqueue a request to be sent to the DNS server - * for resolution if no errors are present. - * - ERR_ARG: dns client not initialized or invalid hostname - * - * @param hostname the hostname that is to be queried - * @param addr pointer to a ip_addr_t where to store the address if it is already - * cached in the dns_table (only valid if ERR_OK is returned!) - * @param found a callback function to be called on success, failure or timeout (only if - * ERR_INPROGRESS is returned!) - * @param callback_arg argument to pass to the callback function - * @return a err_t return code. - */ -err_t -dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, - void *callback_arg) -{ - u32_t ipaddr; - /* not initialized or no valid server yet, or invalid addr pointer - * or invalid hostname or invalid hostname length */ - if ((dns_pcb == NULL) || (addr == NULL) || - (!hostname) || (!hostname[0]) || - (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) { - return ERR_ARG; - } - -#if LWIP_HAVE_LOOPIF - if (strcmp(hostname, "localhost")==0) { - ip_addr_set_loopback(addr); - return ERR_OK; - } -#endif /* LWIP_HAVE_LOOPIF */ - - /* host name already in octet notation? set ip addr and return ERR_OK */ - ipaddr = ipaddr_addr(hostname); - if (ipaddr == IPADDR_NONE) { - /* already have this address cached? */ - ipaddr = dns_lookup(hostname); - } - if (ipaddr != IPADDR_NONE) { - ip4_addr_set_u32(addr, ipaddr); - return ERR_OK; - } - - /* queue query with specified callback */ - return dns_enqueue(hostname, found, callback_arg); -} - -#endif /* LWIP_DNS */ diff --git a/ext/lwip/src/core/init.c b/ext/lwip/src/core/init.c deleted file mode 100644 index 50cfff1a..00000000 --- a/ext/lwip/src/core/init.c +++ /dev/null @@ -1,332 +0,0 @@ -/** - * @file - * Modules initialization - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/init.h" -#include "lwip/stats.h" -#include "lwip/sys.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/netif.h" -#include "lwip/sockets.h" -#include "lwip/ip.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp_msg.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/timers.h" -#include "netif/etharp.h" -#include "lwip/api.h" - -/* Compile-time sanity checks for configuration errors. - * These can be done independently of LWIP_DEBUG, without penalty. - */ -#ifndef BYTE_ORDER - #error "BYTE_ORDER is not defined, you have to define it in your cc.h" -#endif -#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV) - #error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_UDPLITE) - #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_SNMP) - #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_DHCP) - #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_IGMP) - #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_SNMP) - #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if (!LWIP_UDP && LWIP_DNS) - #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" -#endif -#if !MEMP_MEM_MALLOC /* MEMP_NUM_* checks are disabled when not using the pool allocator */ -#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) - #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" -#endif -#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0)) - #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h" -#endif -#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0)) - #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h" -#endif -#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0)) - #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h" -#endif -#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) - #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" -#endif -#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0)) - #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h" -#endif -/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)) - #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" -#endif -#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) - #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!" -#endif -#endif /* !MEMP_MEM_MALLOC */ -#if (LWIP_TCP && (TCP_WND > 0xffff)) - #error "If you want to use TCP, TCP_WND must fit in an u16_t, so, you have to reduce it in your lwipopts.h" -#endif -#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) - #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" -#endif -#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) - #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" -#endif -#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) - #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" -#endif -#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff)) - #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t" -#endif -#if (LWIP_NETIF_API && (NO_SYS==1)) - #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" -#endif -#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1)) - #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h" -#endif -#if (!LWIP_NETCONN && LWIP_SOCKET) - #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h" -#endif -#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP) - #error "If you want to use DHCP/AUTOIP cooperation mode, you have to define LWIP_DHCP=1 and LWIP_AUTOIP=1 in your lwipopts.h" -#endif -#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK) - #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h" -#endif -#if (!LWIP_ARP && LWIP_AUTOIP) - #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h" -#endif -#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0)) - #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h" -#endif -#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0)) - #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h" -#endif -#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API))) - #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" -#endif -#if (MEM_LIBC_MALLOC && MEM_USE_POOLS) - #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h" -#endif -#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS) - #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h" -#endif -#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT) - #error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf" -#endif -#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT))) - #error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST" -#endif -#if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT - #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on" -#endif -#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) - #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" -#endif -#if LWIP_IGMP && !defined(LWIP_RAND) - #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" -#endif -#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING - #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" -#endif -#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE - #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" -#endif -#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF - #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" -#endif -#if LWIP_NETCONN && LWIP_TCP -#if NETCONN_COPY != TCP_WRITE_FLAG_COPY - #error "NETCONN_COPY != TCP_WRITE_FLAG_COPY" -#endif -#if NETCONN_MORE != TCP_WRITE_FLAG_MORE - #error "NETCONN_MORE != TCP_WRITE_FLAG_MORE" -#endif -#endif /* LWIP_NETCONN && LWIP_TCP */ -#if LWIP_SOCKET -/* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ -#if SO_ACCEPTCONN != SOF_ACCEPTCONN - #error "SO_ACCEPTCONN != SOF_ACCEPTCONN" -#endif -#if SO_REUSEADDR != SOF_REUSEADDR - #error "WARNING: SO_REUSEADDR != SOF_REUSEADDR" -#endif -#if SO_KEEPALIVE != SOF_KEEPALIVE - #error "WARNING: SO_KEEPALIVE != SOF_KEEPALIVE" -#endif -#if SO_BROADCAST != SOF_BROADCAST - #error "WARNING: SO_BROADCAST != SOF_BROADCAST" -#endif -#if SO_LINGER != SOF_LINGER - #error "WARNING: SO_LINGER != SOF_LINGER" -#endif -#endif /* LWIP_SOCKET */ - - -/* Compile-time checks for deprecated options. - */ -#ifdef MEMP_NUM_TCPIP_MSG - #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef MEMP_NUM_API_MSG - #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef TCP_REXMIT_DEBUG - #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef RAW_STATS - #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef ETHARP_QUEUE_FIRST - #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h." -#endif -#ifdef ETHARP_ALWAYS_INSERT - #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." -#endif - -#ifndef LWIP_DISABLE_TCP_SANITY_CHECKS -#define LWIP_DISABLE_TCP_SANITY_CHECKS 0 -#endif -#ifndef LWIP_DISABLE_MEMP_SANITY_CHECKS -#define LWIP_DISABLE_MEMP_SANITY_CHECKS 0 -#endif - -/* MEMP sanity checks */ -#if !LWIP_DISABLE_MEMP_SANITY_CHECKS -#if LWIP_NETCONN -#if MEMP_MEM_MALLOC -#if !MEMP_NUM_NETCONN && LWIP_SOCKET -#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN cannot be 0 when using sockets!" -#endif -#else /* MEMP_MEM_MALLOC */ -#if MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB) -#error "lwip_sanity_check: WARNING: MEMP_NUM_NETCONN should be less than the sum of MEMP_NUM_{TCP,RAW,UDP}_PCB+MEMP_NUM_TCP_PCB_LISTEN. If you know what you are doing, define LWIP_DISABLE_MEMP_SANITY_CHECKS to 1 to disable this error." -#endif -#endif /* MEMP_MEM_MALLOC */ -#endif /* LWIP_NETCONN */ -#endif /* !LWIP_DISABLE_MEMP_SANITY_CHECKS */ - -/* TCP sanity checks */ -#if !LWIP_DISABLE_TCP_SANITY_CHECKS -#if LWIP_TCP -#if !MEMP_MEM_MALLOC && (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) - #error "lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SND_BUF < (2 * TCP_MSS) - #error "lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF / TCP_MSS)) - #error "lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SNDLOWAT >= TCP_SND_BUF - #error "lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN - #error "lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if !MEMP_MEM_MALLOC && (TCP_WND > (PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - (PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN)))) - #error "lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE * (PBUF_POOL_BUFSIZE - protocol headers). If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#if TCP_WND < TCP_MSS - #error "lwip_sanity_check: WARNING: TCP_WND is smaller than MSS. If you know what you are doing, define LWIP_DISABLE_TCP_SANITY_CHECKS to 1 to disable this error." -#endif -#endif /* LWIP_TCP */ -#endif /* !LWIP_DISABLE_TCP_SANITY_CHECKS */ - -/** - * Perform Sanity check of user-configurable values, and initialize all modules. - */ -void -lwip_init(void) -{ - /* Modules initialization */ - stats_init(); -#if !NO_SYS - sys_init(); -#endif /* !NO_SYS */ - mem_init(); - memp_init(); - pbuf_init(); - netif_init(); -#if LWIP_SOCKET - //lwip_socket_init(); -#endif /* LWIP_SOCKET */ - ip_init(); -#if LWIP_ARP - etharp_init(); -#endif /* LWIP_ARP */ -#if LWIP_RAW - raw_init(); -#endif /* LWIP_RAW */ -#if LWIP_UDP - udp_init(); -#endif /* LWIP_UDP */ -#if LWIP_TCP - tcp_init(); -#endif /* LWIP_TCP */ -#if LWIP_SNMP - snmp_init(); -#endif /* LWIP_SNMP */ -#if LWIP_AUTOIP - autoip_init(); -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - igmp_init(); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - dns_init(); -#endif /* LWIP_DNS */ - -#if LWIP_TIMERS - sys_timeouts_init(); -#endif /* LWIP_TIMERS */ -} diff --git a/ext/lwip/src/core/ipv4/autoip.c b/ext/lwip/src/core/ipv4/autoip.c deleted file mode 100644 index b122da27..00000000 --- a/ext/lwip/src/core/ipv4/autoip.c +++ /dev/null @@ -1,528 +0,0 @@ -/** - * @file - * AutoIP Automatic LinkLocal IP Configuration - * - */ - -/* - * - * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de> - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Dominik Spies <kontakt@dspies.de> - * - * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform - * with RFC 3927. - * - * - * Please coordinate changes and requests with Dominik Spies - * <kontakt@dspies.de> - */ - -/******************************************************************************* - * USAGE: - * - * define LWIP_AUTOIP 1 in your lwipopts.h - * - * If you don't use tcpip.c (so, don't call, you don't call tcpip_init): - * - First, call autoip_init(). - * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces, - * that should be defined in autoip.h. - * I recommend a value of 100. The value must divide 1000 with a remainder almost 0. - * Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 .... - * - * Without DHCP: - * - Call autoip_start() after netif_add(). - * - * With DHCP: - * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h. - * - Configure your DHCP Client. - * - */ - -#include "lwip/opt.h" - -#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/autoip.h" -#include "netif/etharp.h" - -#include <stdlib.h> -#include <string.h> - -/* 169.254.0.0 */ -#define AUTOIP_NET 0xA9FE0000 -/* 169.254.1.0 */ -#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100) -/* 169.254.254.255 */ -#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF) - - -/** Pseudo random macro based on netif informations. - * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */ -#ifndef LWIP_AUTOIP_RAND -#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \ - ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \ - ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \ - ((u32_t)((netif->hwaddr[4]) & 0xff))) + \ - (netif->autoip?netif->autoip->tried_llipaddr:0)) -#endif /* LWIP_AUTOIP_RAND */ - -/** - * Macro that generates the initial IP address to be tried by AUTOIP. - * If you want to override this, define it to something else in lwipopts.h. - */ -#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR -#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \ - htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \ - ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8))) -#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */ - -/* static functions */ -static void autoip_handle_arp_conflict(struct netif *netif); - -/* creates a pseudo random LL IP-Address for a network interface */ -static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr); - -/* sends an ARP probe */ -static err_t autoip_arp_probe(struct netif *netif); - -/* sends an ARP announce */ -static err_t autoip_arp_announce(struct netif *netif); - -/* configure interface for use with current LL IP-Address */ -static err_t autoip_bind(struct netif *netif); - -/* start sending probes for llipaddr */ -static void autoip_start_probing(struct netif *netif); - - -/** Set a statically allocated struct autoip to work with. - * Using this prevents autoip_start to allocate it using mem_malloc. - * - * @param netif the netif for which to set the struct autoip - * @param dhcp (uninitialised) dhcp struct allocated by the application - */ -void -autoip_set_struct(struct netif *netif, struct autoip *autoip) -{ - LWIP_ASSERT("netif != NULL", netif != NULL); - LWIP_ASSERT("autoip != NULL", autoip != NULL); - LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); - - /* clear data structure */ - memset(autoip, 0, sizeof(struct autoip)); - /* autoip->state = AUTOIP_STATE_OFF; */ - netif->autoip = autoip; -} - -/** Restart AutoIP client and check the next address (conflict detected) - * - * @param netif The netif under AutoIP control - */ -static void -autoip_restart(struct netif *netif) -{ - netif->autoip->tried_llipaddr++; - autoip_start(netif); -} - -/** - * Handle a IP address conflict after an ARP conflict detection - */ -static void -autoip_handle_arp_conflict(struct netif *netif) -{ - /* Somehow detect if we are defending or retreating */ - unsigned char defend = 1; /* tbd */ - - if (defend) { - if (netif->autoip->lastconflict > 0) { - /* retreat, there was a conflicting ARP in the last - * DEFEND_INTERVAL seconds - */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); - - /* TODO: close all TCP sessions */ - autoip_restart(netif); - } else { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); - autoip_arp_announce(netif); - netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND; - } - } else { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); - /* TODO: close all TCP sessions */ - autoip_restart(netif); - } -} - -/** - * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * - * @param netif network interface on which create the IP-Address - * @param ipaddr ip address to initialize - */ -static void -autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr) -{ - /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 - * compliant to RFC 3927 Section 2.1 - * We have 254 * 256 possibilities */ - - u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif)); - addr += netif->autoip->tried_llipaddr; - addr = AUTOIP_NET | (addr & 0xffff); - /* Now, 169.254.0.0 <= addr <= 169.254.255.255 */ - - if (addr < AUTOIP_RANGE_START) { - addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - if (addr > AUTOIP_RANGE_END) { - addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1; - } - LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && - (addr <= AUTOIP_RANGE_END)); - ip4_addr_set_u32(ipaddr, htonl(addr)); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), - ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); -} - -/** - * Sends an ARP probe from a network interface - * - * @param netif network interface used to send the probe - */ -static err_t -autoip_arp_probe(struct netif *netif) -{ - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, ðzero, - &netif->autoip->llipaddr, ARP_REQUEST); -} - -/** - * Sends an ARP announce from a network interface - * - * @param netif network interface used to send the announce - */ -static err_t -autoip_arp_announce(struct netif *netif) -{ - return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, - (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero, - &netif->autoip->llipaddr, ARP_REQUEST); -} - -/** - * Configure interface for use with current LL IP-Address - * - * @param netif network interface to configure with current LL IP-Address - */ -static err_t -autoip_bind(struct netif *netif) -{ - struct autoip *autoip = netif->autoip; - ip_addr_t sn_mask, gw_addr; - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, - ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), - ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); - - IP4_ADDR(&sn_mask, 255, 255, 0, 0); - IP4_ADDR(&gw_addr, 0, 0, 0, 0); - - netif_set_ipaddr(netif, &autoip->llipaddr); - netif_set_netmask(netif, &sn_mask); - netif_set_gw(netif, &gw_addr); - - /* bring the interface up */ - netif_set_up(netif); - - return ERR_OK; -} - -/** - * Start AutoIP client - * - * @param netif network interface on which start the AutoIP client - */ -err_t -autoip_start(struct netif *netif) -{ - struct autoip *autoip = netif->autoip; - err_t result = ERR_OK; - - if (netif_is_up(netif)) { - netif_set_down(netif); - } - - /* Set IP-Address, Netmask and Gateway to 0 to make sure that - * ARP Packets are formed correctly - */ - ip_addr_set_zero(&netif->ip_addr); - ip_addr_set_zero(&netif->netmask); - ip_addr_set_zero(&netif->gw); - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], - netif->name[1], (u16_t)netif->num)); - if (autoip == NULL) { - /* no AutoIP client attached yet? */ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): starting new AUTOIP client\n")); - autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); - if (autoip == NULL) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_start(): could not allocate autoip\n")); - return ERR_MEM; - } - memset(autoip, 0, sizeof(struct autoip)); - /* store this AutoIP client in the netif */ - netif->autoip = autoip; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); - } else { - autoip->state = AUTOIP_STATE_OFF; - autoip->ttw = 0; - autoip->sent_num = 0; - ip_addr_set_zero(&autoip->llipaddr); - autoip->lastconflict = 0; - } - - autoip_create_addr(netif, &(autoip->llipaddr)); - autoip_start_probing(netif); - - return result; -} - -static void -autoip_start_probing(struct netif *netif) -{ - struct autoip *autoip = netif->autoip; - - autoip->state = AUTOIP_STATE_PROBING; - autoip->sent_num = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - - /* time to wait to first probe, this is randomly - * choosen out of 0 to PROBE_WAIT seconds. - * compliant to RFC 3927 Section 2.2.1 - */ - autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND)); - - /* - * if we tried more then MAX_CONFLICTS we must limit our rate for - * accquiring and probing address - * compliant to RFC 3927 Section 2.2.1 - */ - if (autoip->tried_llipaddr > MAX_CONFLICTS) { - autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND; - } -} - -/** - * Handle a possible change in the network configuration. - * - * If there is an AutoIP address configured, take the interface down - * and begin probing with the same address. - */ -void -autoip_network_changed(struct netif *netif) -{ - if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) { - netif_set_down(netif); - autoip_start_probing(netif); - } -} - -/** - * Stop AutoIP client - * - * @param netif network interface on which stop the AutoIP client - */ -err_t -autoip_stop(struct netif *netif) -{ - netif->autoip->state = AUTOIP_STATE_OFF; - netif_set_down(netif); - return ERR_OK; -} - -/** - * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds - */ -void -autoip_tmr() -{ - struct netif *netif = netif_list; - /* loop through netif's */ - while (netif != NULL) { - /* only act on AutoIP configured interfaces */ - if (netif->autoip != NULL) { - if (netif->autoip->lastconflict > 0) { - netif->autoip->lastconflict--; - } - - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n", - (u16_t)(netif->autoip->state), netif->autoip->ttw)); - - switch(netif->autoip->state) { - case AUTOIP_STATE_PROBING: - if (netif->autoip->ttw > 0) { - netif->autoip->ttw--; - } else { - if (netif->autoip->sent_num >= PROBE_NUM) { - netif->autoip->state = AUTOIP_STATE_ANNOUNCING; - netif->autoip->sent_num = 0; - netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - } else { - autoip_arp_probe(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() PROBING Sent Probe\n")); - netif->autoip->sent_num++; - /* calculate time to wait to next probe */ - netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) % - ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) + - PROBE_MIN * AUTOIP_TICKS_PER_SECOND); - } - } - break; - - case AUTOIP_STATE_ANNOUNCING: - if (netif->autoip->ttw > 0) { - netif->autoip->ttw--; - } else { - if (netif->autoip->sent_num == 0) { - /* We are here the first time, so we waited ANNOUNCE_WAIT seconds - * Now we can bind to an IP address and use it. - * - * autoip_bind calls netif_set_up. This triggers a gratuitous ARP - * which counts as an announcement. - */ - autoip_bind(netif); - } else { - autoip_arp_announce(netif); - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_tmr() ANNOUNCING Sent Announce\n")); - } - netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; - netif->autoip->sent_num++; - - if (netif->autoip->sent_num >= ANNOUNCE_NUM) { - netif->autoip->state = AUTOIP_STATE_BOUND; - netif->autoip->sent_num = 0; - netif->autoip->ttw = 0; - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), - ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); - } - } - break; - } - } - /* proceed to next network interface */ - netif = netif->next; - } -} - -/** - * Handles every incoming ARP Packet, called by etharp_arp_input. - * - * @param netif network interface to use for autoip processing - * @param hdr Incoming ARP packet - */ -void -autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) -{ - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n")); - if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) { - /* when ip.src == llipaddr && hw.src != netif->hwaddr - * - * when probing ip.dst == llipaddr && hw.src != netif->hwaddr - * we have a conflict and must solve it - */ - ip_addr_t sipaddr, dipaddr; - struct eth_addr netifaddr; - ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); - - /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without - * structure packing (not using structure copy which breaks strict-aliasing rules). - */ - IPADDR2_COPY(&sipaddr, &hdr->sipaddr); - IPADDR2_COPY(&dipaddr, &hdr->dipaddr); - - if ((netif->autoip->state == AUTOIP_STATE_PROBING) || - ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && - (netif->autoip->sent_num == 0))) { - /* RFC 3927 Section 2.2.1: - * from beginning to after ANNOUNCE_WAIT - * seconds we have a conflict if - * ip.src == llipaddr OR - * ip.dst == llipaddr && hw.src != own hwaddr - */ - if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) || - (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Probe Conflict detected\n")); - autoip_restart(netif); - } - } else { - /* RFC 3927 Section 2.5: - * in any state we have a conflict if - * ip.src == llipaddr && hw.src != own hwaddr - */ - if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) && - !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) { - LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, - ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); - autoip_handle_arp_conflict(netif); - } - } - } -} - -#endif /* LWIP_AUTOIP */ diff --git a/ext/lwip/src/core/ipv4/icmp.c b/ext/lwip/src/core/ipv4/icmp.c deleted file mode 100644 index 47ba8571..00000000 --- a/ext/lwip/src/core/ipv4/icmp.c +++ /dev/null @@ -1,339 +0,0 @@ -/** - * @file - * ICMP - Internet Control Message Protocol - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -/* Some ICMP messages should be passed to the transport protocols. This - is not implemented. */ - -#include "lwip/opt.h" - -#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" - -#include <string.h> - -/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be - * used to modify and send a response packet (and to 1 if this is not the case, - * e.g. when link header is stripped of when receiving) */ -#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN -#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1 -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ - -/* The amount of data from the original packet to return in a dest-unreachable */ -#define ICMP_DEST_UNREACH_DATASIZE 8 - -static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code); - -/** - * Processes ICMP input packets, called from ip_input(). - * - * Currently only processes icmp echo requests and sends - * out the echo response. - * - * @param p the icmp echo request packet, p->payload pointing to the ip header - * @param inp the netif on which this packet was received - */ -void -icmp_input(struct pbuf *p, struct netif *inp) -{ - u8_t type; -#ifdef LWIP_DEBUG - u8_t code; -#endif /* LWIP_DEBUG */ - struct icmp_echo_hdr *iecho; - struct ip_hdr *iphdr; - s16_t hlen; - - ICMP_STATS_INC(icmp.recv); - snmp_inc_icmpinmsgs(); - - - iphdr = (struct ip_hdr *)p->payload; - hlen = IPH_HL(iphdr) * 4; - if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); - goto lenerr; - } - - type = *((u8_t *)p->payload); -#ifdef LWIP_DEBUG - code = *(((u8_t *)p->payload)+1); -#endif /* LWIP_DEBUG */ - switch (type) { - case ICMP_ER: - /* This is OK, echo reply might have been parsed by a raw PCB - (as obviously, an echo request has been sent, too). */ - break; - case ICMP_ECHO: -#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING - { - int accepted = 1; -#if !LWIP_MULTICAST_PING - /* multicast destination address? */ - if (ip_addr_ismulticast(¤t_iphdr_dest)) { - accepted = 0; - } -#endif /* LWIP_MULTICAST_PING */ -#if !LWIP_BROADCAST_PING - /* broadcast destination address? */ - if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { - accepted = 0; - } -#endif /* LWIP_BROADCAST_PING */ - /* broadcast or multicast destination address not acceptd? */ - if (!accepted) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n")); - ICMP_STATS_INC(icmp.err); - pbuf_free(p); - return; - } - } -#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */ - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); - if (p->tot_len < sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); - goto lenerr; - } - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n")); - pbuf_free(p); - ICMP_STATS_INC(icmp.chkerr); - snmp_inc_icmpinerrors(); - return; - } -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN - if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) { - /* p is not big enough to contain link headers - * allocate a new one and copy p into it - */ - struct pbuf *r; - /* switch p->payload to ip header */ - if (pbuf_header(p, hlen)) { - LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0); - goto memerr; - } - /* allocate new packet buffer with space for link headers */ - r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); - if (r == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n")); - goto memerr; - } - LWIP_ASSERT("check that first pbuf can hold struct the ICMP header", - (r->len >= hlen + sizeof(struct icmp_echo_hdr))); - /* copy the whole packet including ip header */ - if (pbuf_copy(r, p) != ERR_OK) { - LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); - goto memerr; - } - iphdr = (struct ip_hdr *)r->payload; - /* switch r->payload back to icmp header */ - if (pbuf_header(r, -hlen)) { - LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); - goto memerr; - } - /* free the original p */ - pbuf_free(p); - /* we now have an identical copy of p that has room for link headers */ - p = r; - } else { - /* restore p->payload to point to icmp header */ - if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) { - LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); - goto memerr; - } - } -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ - /* At this point, all checks are OK. */ - /* We generate an answer by switching the dest and src ip addresses, - * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ - iecho = (struct icmp_echo_hdr *)p->payload; - ip_addr_copy(iphdr->src, *ip_current_dest_addr()); - ip_addr_copy(iphdr->dest, *ip_current_src_addr()); - ICMPH_TYPE_SET(iecho, ICMP_ER); -#if CHECKSUM_GEN_ICMP - /* adjust the checksum */ - if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; - } else { - iecho->chksum += PP_HTONS(ICMP_ECHO << 8); - } -#else /* CHECKSUM_GEN_ICMP */ - iecho->chksum = 0; -#endif /* CHECKSUM_GEN_ICMP */ - - /* Set the correct TTL and recalculate the header checksum. */ - IPH_TTL_SET(iphdr, ICMP_TTL); - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); -#endif /* CHECKSUM_GEN_IP */ - - ICMP_STATS_INC(icmp.xmit); - /* increase number of messages attempted to send */ - snmp_inc_icmpoutmsgs(); - /* increase number of echo replies attempted to send */ - snmp_inc_icmpoutechoreps(); - - if(pbuf_header(p, hlen)) { - LWIP_ASSERT("Can't move over header in packet", 0); - } else { - err_t ret; - /* send an ICMP packet, src addr is the dest addr of the curren packet */ - ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, - ICMP_TTL, 0, IP_PROTO_ICMP, inp); - if (ret != ERR_OK) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); - } - } - break; - default: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n", - (s16_t)type, (s16_t)code)); - ICMP_STATS_INC(icmp.proterr); - ICMP_STATS_INC(icmp.drop); - } - pbuf_free(p); - return; -lenerr: - pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); - snmp_inc_icmpinerrors(); - return; -#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN -memerr: - pbuf_free(p); - ICMP_STATS_INC(icmp.err); - snmp_inc_icmpinerrors(); - return; -#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */ -} - -/** - * Send an icmp 'destination unreachable' packet, called from ip_input() if - * the transport layer protocol is unknown and from udp_input() if the local - * port is not bound. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IP header - * @param t type of the 'unreachable' packet - */ -void -icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) -{ - icmp_send_response(p, ICMP_DUR, t); -} - -#if IP_FORWARD || IP_REASSEMBLY -/** - * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0. - * - * @param p the input packet for which the 'time exceeded' should be sent, - * p->payload pointing to the IP header - * @param t type of the 'time exceeded' packet - */ -void -icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) -{ - icmp_send_response(p, ICMP_TE, t); -} - -#endif /* IP_FORWARD || IP_REASSEMBLY */ - -/** - * Send an icmp packet in response to an incoming packet. - * - * @param p the input packet for which the 'unreachable' should be sent, - * p->payload pointing to the IP header - * @param type Type of the ICMP header - * @param code Code of the ICMP header - */ -static void -icmp_send_response(struct pbuf *p, u8_t type, u8_t code) -{ - struct pbuf *q; - struct ip_hdr *iphdr; - /* we can use the echo header here */ - struct icmp_echo_hdr *icmphdr; - ip_addr_t iphdr_src; - - /* ICMP header + IP header + 8 bytes of data */ - q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, - PBUF_RAM); - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); - - iphdr = (struct ip_hdr *)p->payload; - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); - ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); - LWIP_DEBUGF(ICMP_DEBUG, (" to ")); - ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); - LWIP_DEBUGF(ICMP_DEBUG, ("\n")); - - icmphdr = (struct icmp_echo_hdr *)q->payload; - icmphdr->type = type; - icmphdr->code = code; - icmphdr->id = 0; - icmphdr->seqno = 0; - - /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload, - IP_HLEN + ICMP_DEST_UNREACH_DATASIZE); - - /* calculate checksum */ - icmphdr->chksum = 0; - icmphdr->chksum = inet_chksum(icmphdr, q->len); - ICMP_STATS_INC(icmp.xmit); - /* increase number of messages attempted to send */ - snmp_inc_icmpoutmsgs(); - /* increase number of destination unreachable messages attempted to send */ - snmp_inc_icmpouttimeexcds(); - ip_addr_copy(iphdr_src, iphdr->src); - ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP); - pbuf_free(q); -} - -#endif /* LWIP_ICMP */ diff --git a/ext/lwip/src/core/ipv4/igmp.c b/ext/lwip/src/core/ipv4/igmp.c deleted file mode 100644 index 45bb5d95..00000000 --- a/ext/lwip/src/core/ipv4/igmp.c +++ /dev/null @@ -1,805 +0,0 @@ -/** - * @file - * IGMP - Internet Group Management Protocol - * - */ - -/* - * Copyright (c) 2002 CITEL Technologies Ltd. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * This file is a contribution to the lwIP TCP/IP stack. - * The Swedish Institute of Computer Science and Adam Dunkels - * are specifically granted permission to redistribute this - * source code. -*/ - -/*------------------------------------------------------------- -Note 1) -Although the rfc requires V1 AND V2 capability -we will only support v2 since now V1 is very old (August 1989) -V1 can be added if required - -a debug print and statistic have been implemented to -show this up. -------------------------------------------------------------- -------------------------------------------------------------- -Note 2) -A query for a specific group address (as opposed to ALLHOSTS) -has now been implemented as I am unsure if it is required - -a debug print and statistic have been implemented to -show this up. -------------------------------------------------------------- -------------------------------------------------------------- -Note 3) -The router alert rfc 2113 is implemented in outgoing packets -but not checked rigorously incoming -------------------------------------------------------------- -Steve Reynolds -------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------- - * RFC 988 - Host extensions for IP multicasting - V0 - * RFC 1054 - Host extensions for IP multicasting - - * RFC 1112 - Host extensions for IP multicasting - V1 - * RFC 2236 - Internet Group Management Protocol, Version 2 - V2 <- this code is based on this RFC (it's the "de facto" standard) - * RFC 3376 - Internet Group Management Protocol, Version 3 - V3 - * RFC 4604 - Using Internet Group Management Protocol Version 3... - V3+ - * RFC 2113 - IP Router Alert Option - - *----------------------------------------------------------------------------*/ - -/*----------------------------------------------------------------------------- - * Includes - *----------------------------------------------------------------------------*/ - -#include "lwip/opt.h" - -#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/igmp.h" -#include "lwip/debug.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/udp.h" -#include "lwip/tcp.h" -#include "lwip/stats.h" - -#include "string.h" - -/* - * IGMP constants - */ -#define IGMP_TTL 1 -#define IGMP_MINLEN 8 -#define ROUTER_ALERT 0x9404U -#define ROUTER_ALERTLEN 4 - -/* - * IGMP message types, including version number. - */ -#define IGMP_MEMB_QUERY 0x11 /* Membership query */ -#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ -#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ -#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ - -/* Group membership states */ -#define IGMP_GROUP_NON_MEMBER 0 -#define IGMP_GROUP_DELAYING_MEMBER 1 -#define IGMP_GROUP_IDLE_MEMBER 2 - -/** - * IGMP packet format. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct igmp_msg { - PACK_STRUCT_FIELD(u8_t igmp_msgtype); - PACK_STRUCT_FIELD(u8_t igmp_maxresp); - PACK_STRUCT_FIELD(u16_t igmp_checksum); - PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - - -static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr); -static err_t igmp_remove_group(struct igmp_group *group); -static void igmp_timeout( struct igmp_group *group); -static void igmp_start_timer(struct igmp_group *group, u8_t max_time); -static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); -static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); -static void igmp_send(struct igmp_group *group, u8_t type); - - -static struct igmp_group* igmp_group_list; -static ip_addr_t allsystems; -static ip_addr_t allrouters; - - -/** - * Initialize the IGMP module - */ -void -igmp_init(void) -{ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n")); - - IP4_ADDR(&allsystems, 224, 0, 0, 1); - IP4_ADDR(&allrouters, 224, 0, 0, 2); -} - -#ifdef LWIP_DEBUG -/** - * Dump global IGMP groups list - */ -void -igmp_dump_group_list() -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); - ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); - group = group->next; - } - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); -} -#else -#define igmp_dump_group_list() -#endif /* LWIP_DEBUG */ - -/** - * Start IGMP processing on interface - * - * @param netif network interface on which start IGMP processing - */ -err_t -igmp_start(struct netif *netif) -{ - struct igmp_group* group; - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif)); - - group = igmp_lookup_group(netif, &allsystems); - - if (group != NULL) { - group->group_state = IGMP_GROUP_IDLE_MEMBER; - group->use++; - - /* Allow the igmp messages at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); - ip_addr_debug_print(IGMP_DEBUG, &allsystems); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); - } - - return ERR_OK; - } - - return ERR_MEM; -} - -/** - * Stop IGMP processing on interface - * - * @param netif network interface on which stop IGMP processing - */ -err_t -igmp_stop(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - struct igmp_group *prev = NULL; - struct igmp_group *next; - - /* look for groups joined on this interface further down the list */ - while (group != NULL) { - next = group->next; - /* is it a group joined on this interface? */ - if (group->netif == netif) { - /* is it the first group of the list? */ - if (group == igmp_group_list) { - igmp_group_list = next; - } - /* is there a "previous" group defined? */ - if (prev != NULL) { - prev->next = next; - } - /* disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL ")); - ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER); - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - } else { - /* change the "previous" */ - prev = group; - } - /* move to "next" */ - group = next; - } - return ERR_OK; -} - -/** - * Report IGMP memberships for this interface - * - * @param netif network interface on which report IGMP memberships - */ -void -igmp_report_groups(struct netif *netif) -{ - struct igmp_group *group = igmp_group_list; - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); - - while (group != NULL) { - if (group->netif == netif) { - igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - } - group = group->next; - } -} - -/** - * Search for a group in the global igmp_group_list - * - * @param ifp the network interface for which to look - * @param addr the group ip address to search for - * @return a struct igmp_group* if the group has been found, - * NULL if the group wasn't found. - */ -struct igmp_group * -igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { - return group; - } - group = group->next; - } - - /* to be clearer, we return NULL here instead of - * 'group' (which is also NULL at this point). - */ - return NULL; -} - -/** - * Search for a specific igmp group and create a new one if not found- - * - * @param ifp the network interface for which to look - * @param addr the group ip address to search - * @return a struct igmp_group*, - * NULL on memory error. - */ -struct igmp_group * -igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) -{ - struct igmp_group *group = igmp_group_list; - - /* Search if the group already exists */ - group = igmp_lookfor_group(ifp, addr); - if (group != NULL) { - /* Group already exists. */ - return group; - } - - /* Group doesn't exist yet, create a new one */ - group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); - if (group != NULL) { - group->netif = ifp; - ip_addr_set(&(group->group_address), addr); - group->timer = 0; /* Not running */ - group->group_state = IGMP_GROUP_NON_MEMBER; - group->last_reporter_flag = 0; - group->use = 0; - group->next = igmp_group_list; - - igmp_group_list = group; - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to "))); - ip_addr_debug_print(IGMP_DEBUG, addr); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp)); - - return group; -} - -/** - * Remove a group in the global igmp_group_list - * - * @param group the group to remove from the global igmp_group_list - * @return ERR_OK if group was removed from the list, an err_t otherwise - */ -static err_t -igmp_remove_group(struct igmp_group *group) -{ - err_t err = ERR_OK; - - /* Is it the first group? */ - if (igmp_group_list == group) { - igmp_group_list = group->next; - } else { - /* look for group further down the list */ - struct igmp_group *tmpGroup; - for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) { - if (tmpGroup->next == group) { - tmpGroup->next = group->next; - break; - } - } - /* Group not found in the global igmp_group_list */ - if (tmpGroup == NULL) - err = ERR_ARG; - } - /* free group */ - memp_free(MEMP_IGMP_GROUP, group); - - return err; -} - -/** - * Called from ip_input() if a new IGMP packet is received. - * - * @param p received igmp packet, p->payload pointing to the ip header - * @param inp network interface on which the packet was received - * @param dest destination ip address of the igmp packet - */ -void -igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) -{ - struct ip_hdr * iphdr; - struct igmp_msg* igmp; - struct igmp_group* group; - struct igmp_group* groupref; - - IGMP_STATS_INC(igmp.recv); - - /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ - iphdr = (struct ip_hdr *)p->payload; - if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { - pbuf_free(p); - IGMP_STATS_INC(igmp.lenerr); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n")); - return; - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src)); - LWIP_DEBUGF(IGMP_DEBUG, (" to address ")); - ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp)); - - /* Now calculate and check the checksum */ - igmp = (struct igmp_msg *)p->payload; - if (inet_chksum(igmp, p->len)) { - pbuf_free(p); - IGMP_STATS_INC(igmp.chkerr); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n")); - return; - } - - /* Packet is ok so find an existing group */ - group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ - - /* If group can be found or create... */ - if (!group) { - pbuf_free(p); - IGMP_STATS_INC(igmp.drop); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); - return; - } - - /* NOW ACT ON THE INCOMING MESSAGE TYPE... */ - switch (igmp->igmp_msgtype) { - case IGMP_MEMB_QUERY: { - /* IGMP_MEMB_QUERY to the "all systems" address ? */ - if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { - /* THIS IS THE GENERAL QUERY */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - - if (igmp->igmp_maxresp == 0) { - IGMP_STATS_INC(igmp.rx_v1); - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); - igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; - } else { - IGMP_STATS_INC(igmp.rx_general); - } - - groupref = igmp_group_list; - while (groupref) { - /* Do not send messages on the all systems group address! */ - if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { - igmp_delaying_member(groupref, igmp->igmp_maxresp); - } - groupref = groupref->next; - } - } else { - /* IGMP_MEMB_QUERY to a specific group ? */ - if (!ip_addr_isany(&igmp->igmp_group_address)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); - ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); - if (ip_addr_cmp(dest, &allsystems)) { - ip_addr_t groupaddr; - LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - /* we first need to re-look for the group since we used dest last time */ - ip_addr_copy(groupaddr, igmp->igmp_group_address); - group = igmp_lookfor_group(inp, &groupaddr); - } else { - LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - } - - if (group != NULL) { - IGMP_STATS_INC(igmp.rx_group); - igmp_delaying_member(group, igmp->igmp_maxresp); - } else { - IGMP_STATS_INC(igmp.drop); - } - } else { - IGMP_STATS_INC(igmp.proterr); - } - } - break; - } - case IGMP_V2_MEMB_REPORT: { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); - IGMP_STATS_INC(igmp.rx_report); - if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { - /* This is on a specific group we have already looked up */ - group->timer = 0; /* stopped */ - group->group_state = IGMP_GROUP_IDLE_MEMBER; - group->last_reporter_flag = 0; - } - break; - } - default: { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", - igmp->igmp_msgtype, group->group_state, &group, group->netif)); - IGMP_STATS_INC(igmp.proterr); - break; - } - } - - pbuf_free(p); - return; -} - -/** - * Join a group on one network interface. - * - * @param ifaddr ip address of the network interface which should join a new group - * @param groupaddr the ip address of the group which to join - * @return ERR_OK if group was joined on the netif(s), an err_t otherwise - */ -err_t -igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct igmp_group *group; - struct netif *netif; - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we join this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { - /* find group or create a new one if not found */ - group = igmp_lookup_group(netif, groupaddr); - - if (group != NULL) { - /* This should create a new group, check the state to make sure */ - if (group->group_state != IGMP_GROUP_NON_MEMBER) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n")); - } else { - /* OK - it was new group */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* If first use of the group, allow the group at the MAC level */ - if ((group->use==0) && (netif->igmp_mac_filter != NULL)) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); - } - - IGMP_STATS_INC(igmp.tx_join); - igmp_send(group, IGMP_V2_MEMB_REPORT); - - igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); - - /* Need to work out where this timer comes from */ - group->group_state = IGMP_GROUP_DELAYING_MEMBER; - } - /* Increment group use */ - group->use++; - /* Join on this interface */ - err = ERR_OK; - } else { - /* Return an error even if some network interfaces are joined */ - /** @todo undo any other netif already joined */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n")); - return ERR_MEM; - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * Leave a group on one network interface. - * - * @param ifaddr ip address of the network interface which should leave a group - * @param groupaddr the ip address of the group which to leave - * @return ERR_OK if group was left on the netif(s), an err_t otherwise - */ -err_t -igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) -{ - err_t err = ERR_VAL; /* no matching interface */ - struct igmp_group *group; - struct netif *netif; - - /* make sure it is multicast address */ - LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;); - LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;); - - /* loop through netif's */ - netif = netif_list; - while (netif != NULL) { - /* Should we leave this interface ? */ - if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) { - /* find group */ - group = igmp_lookfor_group(netif, groupaddr); - - if (group != NULL) { - /* Only send a leave if the flag is set according to the state diagram */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* If there is no other use of the group */ - if (group->use <= 1) { - /* If we are the last reporter for this group */ - if (group->last_reporter_flag) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); - IGMP_STATS_INC(igmp.tx_leave); - igmp_send(group, IGMP_LEAVE_GROUP); - } - - /* Disable the group at the MAC level */ - if (netif->igmp_mac_filter != NULL) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER); - } - - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: ")); - ip_addr_debug_print(IGMP_DEBUG, groupaddr); - LWIP_DEBUGF(IGMP_DEBUG, ("\n")); - - /* Free the group */ - igmp_remove_group(group); - } else { - /* Decrement group use */ - group->use--; - } - /* Leave on this interface */ - err = ERR_OK; - } else { - /* It's not a fatal error on "leavegroup" */ - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n")); - } - } - /* proceed to next network interface */ - netif = netif->next; - } - - return err; -} - -/** - * The igmp timer function (both for NO_SYS=1 and =0) - * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default). - */ -void -igmp_tmr(void) -{ - struct igmp_group *group = igmp_group_list; - - while (group != NULL) { - if (group->timer > 0) { - group->timer--; - if (group->timer == 0) { - igmp_timeout(group); - } - } - group = group->next; - } -} - -/** - * Called if a timeout for one group is reached. - * Sends a report for this group. - * - * @param group an igmp_group for which a timeout is reached - */ -static void -igmp_timeout(struct igmp_group *group) -{ - /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ - if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); - ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); - - IGMP_STATS_INC(igmp.tx_report); - igmp_send(group, IGMP_V2_MEMB_REPORT); - } -} - -/** - * Start a timer for an igmp group - * - * @param group the igmp_group for which to start a timer - * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with - * every call to igmp_tmr()) - */ -static void -igmp_start_timer(struct igmp_group *group, u8_t max_time) -{ - /* ensure the input value is > 0 */ - if (max_time == 0) { - max_time = 1; - } - /* ensure the random value is > 0 */ - group->timer = (LWIP_RAND() % (max_time - 1)) + 1; -} - -/** - * Delaying membership report for a group if necessary - * - * @param group the igmp_group for which "delaying" membership report - * @param maxresp query delay - */ -static void -igmp_delaying_member(struct igmp_group *group, u8_t maxresp) -{ - if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || - ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && - ((group->timer == 0) || (maxresp < group->timer)))) { - igmp_start_timer(group, maxresp); - group->group_state = IGMP_GROUP_DELAYING_MEMBER; - } -} - - -/** - * Sends an IP packet on a network interface. This function constructs the IP header - * and calculates the IP header checksum. If the source IP address is NULL, - * the IP address of the outgoing network interface is filled in as source address. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - */ -static err_t -igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) -{ - /* This is the "router alert" option */ - u16_t ra[2]; - ra[0] = PP_HTONS(ROUTER_ALERT); - ra[1] = 0x0000; /* Router shall examine packet */ - IGMP_STATS_INC(igmp.xmit); - return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); -} - -/** - * Send an igmp packet to a specific group. - * - * @param group the group to which to send the packet - * @param type the type of igmp packet to send - */ -static void -igmp_send(struct igmp_group *group, u8_t type) -{ - struct pbuf* p = NULL; - struct igmp_msg* igmp = NULL; - ip_addr_t src = *IP_ADDR_ANY; - ip_addr_t* dest = NULL; - - /* IP header + "router alert" option + IGMP header */ - p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); - - if (p) { - igmp = (struct igmp_msg *)p->payload; - LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", - (p->len >= sizeof(struct igmp_msg))); - ip_addr_copy(src, group->netif->ip_addr); - - if (type == IGMP_V2_MEMB_REPORT) { - dest = &(group->group_address); - ip_addr_copy(igmp->igmp_group_address, group->group_address); - group->last_reporter_flag = 1; /* Remember we were the last to report */ - } else { - if (type == IGMP_LEAVE_GROUP) { - dest = &allrouters; - ip_addr_copy(igmp->igmp_group_address, group->group_address); - } - } - - if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) { - igmp->igmp_msgtype = type; - igmp->igmp_maxresp = 0; - igmp->igmp_checksum = 0; - igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); - - igmp_ip_output_if(p, &src, dest, group->netif); - } - - pbuf_free(p); - } else { - LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); - IGMP_STATS_INC(igmp.memerr); - } -} - -#endif /* LWIP_IGMP */ diff --git a/ext/lwip/src/core/ipv4/inet.c b/ext/lwip/src/core/ipv4/inet.c deleted file mode 100644 index e283a576..00000000 --- a/ext/lwip/src/core/ipv4/inet.c +++ /dev/null @@ -1,42 +0,0 @@ -/** - * @file - * Functions common to all TCP/IPv4 modules, such as the byte order functions. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet.h" - diff --git a/ext/lwip/src/core/ipv4/inet_chksum.c b/ext/lwip/src/core/ipv4/inet_chksum.c deleted file mode 100644 index 960252f6..00000000 --- a/ext/lwip/src/core/ipv4/inet_chksum.c +++ /dev/null @@ -1,450 +0,0 @@ -/** - * @file - * Incluse internet checksum functions. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/inet_chksum.h" -#include "lwip/def.h" - -#include <stddef.h> -#include <string.h> - -/* These are some reference implementations of the checksum algorithm, with the - * aim of being simple, correct and fully portable. Checksumming is the - * first thing you would want to optimize for your platform. If you create - * your own version, link it in and in your cc.h put: - * - * #define LWIP_CHKSUM <your_checksum_routine> - * - * Or you can select from the implementations below by defining - * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3. - */ - -#ifndef LWIP_CHKSUM -# define LWIP_CHKSUM lwip_standard_chksum -# ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 2 -# endif -#endif -/* If none set: */ -#ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 0 -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ -/** - * lwip checksum - * - * @param dataptr points to start of data to be summed at any boundary - * @param len length of data to be summed - * @return host order (!) lwip checksum (non-inverted Internet sum) - * - * @note accumulator size limits summable length to 64k - * @note host endianess is irrelevant (p3 RFC1071) - */ -static u16_t -lwip_standard_chksum(void *dataptr, u16_t len) -{ - u32_t acc; - u16_t src; - u8_t *octetptr; - - acc = 0; - /* dataptr may be at odd or even addresses */ - octetptr = (u8_t*)dataptr; - while (len > 1) { - /* declare first octet as most significant - thus assume network order, ignoring host order */ - src = (*octetptr) << 8; - octetptr++; - /* declare second octet as least significant */ - src |= (*octetptr); - octetptr++; - acc += src; - len -= 2; - } - if (len > 0) { - /* accumulate remaining octet */ - src = (*octetptr) << 8; - acc += src; - } - /* add deferred carry bits */ - acc = (acc >> 16) + (acc & 0x0000ffffUL); - if ((acc & 0xffff0000UL) != 0) { - acc = (acc >> 16) + (acc & 0x0000ffffUL); - } - /* This maybe a little confusing: reorder sum using htons() - instead of ntohs() since it has a little less call overhead. - The caller must invert bits for Internet sum ! */ - return htons((u16_t)acc); -} -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */ -/* - * Curt McDowell - * Broadcom Corp. - * csm@broadcom.com - * - * IP checksum two bytes at a time with support for - * unaligned buffer. - * Works for len up to and including 0x20000. - * by Curt McDowell, Broadcom Corp. 12/08/2005 - * - * @param dataptr points to start of data to be summed at any boundary - * @param len length of data to be summed - * @return host order (!) lwip checksum (non-inverted Internet sum) - */ - -static u16_t -lwip_standard_chksum(void *dataptr, int len) -{ - u8_t *pb = (u8_t *)dataptr; - u16_t *ps, t = 0; - u32_t sum = 0; - int odd = ((mem_ptr_t)pb & 1); - - /* Get aligned to u16_t */ - if (odd && len > 0) { - ((u8_t *)&t)[1] = *pb++; - len--; - } - - /* Add the bulk of the data */ - ps = (u16_t *)(void *)pb; - while (len > 1) { - sum += *ps++; - len -= 2; - } - - /* Consume left-over byte, if any */ - if (len > 0) { - ((u8_t *)&t)[0] = *(u8_t *)ps; - } - - /* Add end bytes */ - sum += t; - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - sum = FOLD_U32T(sum); - sum = FOLD_U32T(sum); - - /* Swap if alignment was odd */ - if (odd) { - sum = SWAP_BYTES_IN_WORD(sum); - } - - return (u16_t)sum; -} -#endif - -#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */ -/** - * An optimized checksum routine. Basically, it uses loop-unrolling on - * the checksum loop, treating the head and tail bytes specially, whereas - * the inner loop acts on 8 bytes at a time. - * - * @arg start of buffer to be checksummed. May be an odd byte address. - * @len number of bytes in the buffer to be checksummed. - * @return host order (!) lwip checksum (non-inverted Internet sum) - * - * by Curt McDowell, Broadcom Corp. December 8th, 2005 - */ - -static u16_t -lwip_standard_chksum(void *dataptr, int len) -{ - u8_t *pb = (u8_t *)dataptr; - u16_t *ps, t = 0; - u32_t *pl; - u32_t sum = 0, tmp; - /* starts at odd byte address? */ - int odd = ((mem_ptr_t)pb & 1); - - if (odd && len > 0) { - ((u8_t *)&t)[1] = *pb++; - len--; - } - - ps = (u16_t *)pb; - - if (((mem_ptr_t)ps & 3) && len > 1) { - sum += *ps++; - len -= 2; - } - - pl = (u32_t *)ps; - - while (len > 7) { - tmp = sum + *pl++; /* ping */ - if (tmp < sum) { - tmp++; /* add back carry */ - } - - sum = tmp + *pl++; /* pong */ - if (sum < tmp) { - sum++; /* add back carry */ - } - - len -= 8; - } - - /* make room in upper bits */ - sum = FOLD_U32T(sum); - - ps = (u16_t *)pl; - - /* 16-bit aligned word remaining? */ - while (len > 1) { - sum += *ps++; - len -= 2; - } - - /* dangling tail byte remaining? */ - if (len > 0) { /* include odd byte */ - ((u8_t *)&t)[0] = *(u8_t *)ps; - } - - sum += t; /* add end bytes */ - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - sum = FOLD_U32T(sum); - sum = FOLD_U32T(sum); - - if (odd) { - sum = SWAP_BYTES_IN_WORD(sum); - } - - return (u16_t)sum; -} -#endif - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len) -{ - u32_t acc; - u32_t addr; - struct pbuf *q; - u8_t swapped; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; q != NULL; q = q->next) { - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", - (void *)q, (void *)q->next)); - acc += LWIP_CHKSUM(q->payload, q->len); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* just executing this next line is probably faster that the if statement needed - to check whether we really need to execute it, and does no harm */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - addr = ip4_addr_get_u32(src); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - * IP addresses are expected to be in network byte order. - * - * @param p chain of pbufs over that a checksum should be calculated (ip data part) - * @param src source ip address (used for checksum of pseudo header) - * @param dst destination ip address (used for checksum of pseudo header) - * @param proto ip protocol (used for checksum of pseudo header) - * @param proto_len length of the ip data part (used for checksum of pseudo header) - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pseudo_partial(struct pbuf *p, - ip_addr_t *src, ip_addr_t *dest, - u8_t proto, u16_t proto_len, u16_t chksum_len) -{ - u32_t acc; - u32_t addr; - struct pbuf *q; - u8_t swapped; - u16_t chklen; - - acc = 0; - swapped = 0; - /* iterate through all pbuf in chain */ - for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) { - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n", - (void *)q, (void *)q->next)); - chklen = q->len; - if (chklen > chksum_len) { - chklen = chksum_len; - } - acc += LWIP_CHKSUM(q->payload, chklen); - chksum_len -= chklen; - LWIP_ASSERT("delete me", chksum_len < 0x7fff); - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/ - /* fold the upper bit down */ - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/ - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - addr = ip4_addr_get_u32(src); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - addr = ip4_addr_get_u32(dest); - acc += (addr & 0xffffUL); - acc += ((addr >> 16) & 0xffffUL); - acc += (u32_t)htons((u16_t)proto); - acc += (u32_t)htons(proto_len); - - /* Fold 32-bit sum to 16 bits - calling this twice is propably faster than if statements... */ - acc = FOLD_U32T(acc); - acc = FOLD_U32T(acc); - LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); - return (u16_t)~(acc & 0xffffUL); -} - -/* inet_chksum: - * - * Calculates the Internet checksum over a portion of memory. Used primarily for IP - * and ICMP. - * - * @param dataptr start of the buffer to calculate the checksum (no alignment needed) - * @param len length of the buffer to calculate the checksum - * @return checksum (as u16_t) to be saved directly in the protocol header - */ - -u16_t -inet_chksum(void *dataptr, u16_t len) -{ - return ~LWIP_CHKSUM(dataptr, len); -} - -/** - * Calculate a checksum over a chain of pbufs (without pseudo-header, much like - * inet_chksum only pbufs are used). - * - * @param p pbuf chain over that the checksum should be calculated - * @return checksum (as u16_t) to be saved directly in the protocol header - */ -u16_t -inet_chksum_pbuf(struct pbuf *p) -{ - u32_t acc; - struct pbuf *q; - u8_t swapped; - - acc = 0; - swapped = 0; - for(q = p; q != NULL; q = q->next) { - acc += LWIP_CHKSUM(q->payload, q->len); - acc = FOLD_U32T(acc); - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = SWAP_BYTES_IN_WORD(acc); - } - } - - if (swapped) { - acc = SWAP_BYTES_IN_WORD(acc); - } - return (u16_t)~(acc & 0xffffUL); -} - -/* These are some implementations for LWIP_CHKSUM_COPY, which copies data - * like MEMCPY but generates a checksum at the same time. Since this is a - * performance-sensitive function, you might want to create your own version - * in assembly targeted at your hardware by defining it in lwipopts.h: - * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) - */ - -#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ -/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. - * For architectures with big caches, data might still be in cache when - * generating the checksum after copying. - */ -u16_t -lwip_chksum_copy(void *dst, const void *src, u16_t len) -{ - MEMCPY(dst, src, len); - return LWIP_CHKSUM(dst, len); -} -#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/ext/lwip/src/core/ipv4/ip.c b/ext/lwip/src/core/ipv4/ip.c deleted file mode 100644 index 0e09b3c0..00000000 --- a/ext/lwip/src/core/ipv4/ip.c +++ /dev/null @@ -1,924 +0,0 @@ -/** - * @file - * This is the IPv4 layer implementation for incoming and outgoing IP traffic. - * - * @see ip_frag.c - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip_frag.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/igmp.h" -#include "lwip/raw.h" -#include "lwip/udp.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/stats.h" -#include "arch/perf.h" - -#include <string.h> - -/** Set this to 0 in the rare case of wanting to call an extra function to - * generate the IP checksum (in contrast to calculating it on-the-fly). */ -#ifndef LWIP_INLINE_IP_CHKSUM -#define LWIP_INLINE_IP_CHKSUM 1 -#endif -#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP -#define CHECKSUM_GEN_IP_INLINE 1 -#else -#define CHECKSUM_GEN_IP_INLINE 0 -#endif - -#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 - -/** Some defines for DHCP to let link-layer-addressed packets through while the - * netif is down. - * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT - * to return 1 if the port is accepted and 0 if the port is not accepted. - */ -#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) -/* accept DHCP client port and custom port */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ - || (LWIP_IP_ACCEPT_UDP_PORT(port))) -#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept custom port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(port)) -#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ -/* accept DHCP client port only */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) -#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ - -#else /* LWIP_DHCP */ -#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 -#endif /* LWIP_DHCP */ - -/** - * The interface that provided the packet for the current callback - * invocation. - */ -struct netif *current_netif; - -/** - * Header of the input packet currently being processed. - */ -const struct ip_hdr *current_header; -/** Source IP address of current_header */ -ip_addr_t current_iphdr_src; -/** Destination IP address of current_header */ -ip_addr_t current_iphdr_dest; - -/** The IP header ID of the next outgoing IP packet */ -static u16_t ip_id; - -/** - * Finds the appropriate network interface for a given IP address. It - * searches the list of network interfaces linearly. A match is found - * if the masked IP address of the network interface equals the masked - * IP address given to the function. - * - * @param dest the destination IP address for which to find the route - * @return the netif on which to send to reach dest - */ -struct netif * -ip_route(ip_addr_t *dest) -{ - struct netif *netif; - -#ifdef LWIP_HOOK_IP4_ROUTE - netif = LWIP_HOOK_IP4_ROUTE(dest); - if (netif != NULL) { - return netif; - } -#endif - - /* iterate through netifs */ - for (netif = netif_list; netif != NULL; netif = netif->next) { - /* network mask matches? */ - if (netif_is_up(netif)) { - if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { - /* return netif on which to forward IP packet */ - return netif; - } - } - } - if ((netif_default == NULL) || (!netif_is_up(netif_default))) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - snmp_inc_ipoutnoroutes(); - return NULL; - } - /* no matching netif found, use default netif */ - return netif_default; -} - -#if IP_FORWARD -/** - * Determine whether an IP address is in a reserved set of addresses - * that may not be forwarded, or whether datagrams to that destination - * may be forwarded. - * @param p the packet to forward - * @param dest the destination IP address - * @return 1: can forward 0: discard - */ -static int -ip_canforward(struct pbuf *p) -{ - u32_t addr = ip4_addr_get_u32(ip_current_dest_addr()); - - if (p->flags & PBUF_FLAG_LLBCAST) { - /* don't route link-layer broadcasts */ - return 0; - } - if ((p->flags & PBUF_FLAG_LLMCAST) && !IP_MULTICAST(addr)) { - /* don't route link-layer multicasts unless the destination address is an IP - multicast address */ - return 0; - } - if (IP_EXPERIMENTAL(addr)) { - return 0; - } - if (IP_CLASSA(addr)) { - u32_t net = addr & IP_CLASSA_NET; - if ((net == 0) || (net == (IP_LOOPBACKNET << IP_CLASSA_NSHIFT))) { - /* don't route loopback packets */ - return 0; - } - } - return 1; -} - -/** - * Forwards an IP packet. It finds an appropriate route for the - * packet, decrements the TTL value of the packet, adjusts the - * checksum and outputs the packet on the appropriate interface. - * - * @param p the packet to forward (p->payload points to IP header) - * @param iphdr the IP header of the input packet - * @param inp the netif on which this packet was received - */ -static void -ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) -{ - struct netif *netif; - - PERF_START; - - if (!ip_canforward(p)) { - goto return_noroute; - } - - /* RFC3927 2.7: do not forward link-local addresses */ - if (ip_addr_islinklocal(¤t_iphdr_dest)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - goto return_noroute; - } - - /* Find network interface where to forward this IP packet to. */ - netif = ip_route(¤t_iphdr_dest); - if (netif == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - /* @todo: send ICMP_DUR_NET? */ - goto return_noroute; - } -#if !IP_FORWARD_ALLOW_TX_ON_RX_NETIF - /* Do not forward packets onto the same network interface on which - * they arrived. */ - if (netif == inp) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); - goto return_noroute; - } -#endif /* IP_FORWARD_ALLOW_TX_ON_RX_NETIF */ - - /* decrement TTL */ - IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1); - /* send ICMP if TTL == 0 */ - if (IPH_TTL(iphdr) == 0) { - snmp_inc_ipinhdrerrors(); -#if LWIP_ICMP - /* Don't send ICMP messages in response to ICMP messages */ - if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) { - icmp_time_exceeded(p, ICMP_TE_TTL); - } -#endif /* LWIP_ICMP */ - return; - } - - /* Incrementally update the IP checksum. */ - if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); - } else { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); - } - - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), - ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); - - IP_STATS_INC(ip.fw); - IP_STATS_INC(ip.xmit); - snmp_inc_ipforwdatagrams(); - - PERF_STOP("ip_forward"); - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (p->tot_len > netif->mtu)) { - if ((IPH_OFFSET(iphdr) & PP_NTOHS(IP_DF)) == 0) { -#if IP_FRAG - ip_frag(p, netif, ip_current_dest_addr()); -#else /* IP_FRAG */ - /* @todo: send ICMP Destination Unreacheable code 13 "Communication administratively prohibited"? */ -#endif /* IP_FRAG */ - } else { - /* send ICMP Destination Unreacheable code 4: "Fragmentation Needed and DF Set" */ - icmp_dest_unreach(p, ICMP_DUR_FRAG); - } - return; - } - /* transmit pbuf on chosen interface */ - netif->output(netif, p, ¤t_iphdr_dest); - return; -return_noroute: - snmp_inc_ipoutnoroutes(); -} -#endif /* IP_FORWARD */ - -/** - * This function is called by the network interface device driver when - * an IP packet is received. The function does the basic checks of the - * IP header such as packet size being at least larger than the header - * size etc. If the packet was not destined for us, the packet is - * forwarded (using ip_forward). The IP checksum is always checked. - * - * Finally, the packet is sent to the upper layer protocol input function. - * - * @param p the received IP packet (p->payload points to IP header) - * @param inp the netif on which this packet was received - * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't - * processed, but currently always returns ERR_OK) - */ -err_t -ip_input(struct pbuf *p, struct netif *inp) -{ - struct ip_hdr *iphdr; - struct netif *netif; - u16_t iphdr_hlen; - u16_t iphdr_len; -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - int check_ip_src=1; -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - - IP_STATS_INC(ip.recv); - snmp_inc_ipinreceives(); - - /* identify the IP header */ - iphdr = (struct ip_hdr *)p->payload; - if (IPH_V(iphdr) != 4) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); - ip_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.err); - IP_STATS_INC(ip.drop); - snmp_inc_ipinhdrerrors(); - return ERR_OK; - } - -#ifdef LWIP_HOOK_IP4_INPUT - if (LWIP_HOOK_IP4_INPUT(p, inp)) { - /* the packet has been eaten */ - return ERR_OK; - } -#endif - - /* obtain IP header length in number of 32-bit words */ - iphdr_hlen = IPH_HL(iphdr); - /* calculate IP header length in bytes */ - iphdr_hlen *= 4; - /* obtain ip length in bytes */ - iphdr_len = ntohs(IPH_LEN(iphdr)); - - /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */ - if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) { - if (iphdr_hlen > p->len) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n", - iphdr_hlen, p->len)); - } - if (iphdr_len > p->tot_len) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n", - iphdr_len, p->tot_len)); - } - /* free (drop) packet pbufs */ - pbuf_free(p); - IP_STATS_INC(ip.lenerr); - IP_STATS_INC(ip.drop); - snmp_inc_ipindiscards(); - return ERR_OK; - } - - /* verify checksum */ -#if CHECKSUM_CHECK_IP - if (inet_chksum(iphdr, iphdr_hlen) != 0) { - - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen))); - ip_debug_print(p); - pbuf_free(p); - IP_STATS_INC(ip.chkerr); - IP_STATS_INC(ip.drop); - snmp_inc_ipinhdrerrors(); - return ERR_OK; - } -#endif - - /* Trim pbuf. This should have been done at the netif layer, - * but we'll do it anyway just to be sure that its done. */ - pbuf_realloc(p, iphdr_len); - - /* copy IP addresses to aligned ip_addr_t */ - ip_addr_copy(current_iphdr_dest, iphdr->dest); - ip_addr_copy(current_iphdr_src, iphdr->src); - - /* match packet against an interface, i.e. is this packet for us? */ -#if LWIP_IGMP - if (ip_addr_ismulticast(¤t_iphdr_dest)) { - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { - netif = inp; - } else { - netif = NULL; - } - } else -#endif /* LWIP_IGMP */ - { - /* start trying with inp. if that's not acceptable, start walking the - list of configured netifs. - 'first' is used as a boolean to mark whether we started walking the list */ - int first = 1; - netif = inp; - do { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", - ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), - ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), - ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), - ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); - - /* interface is up and configured? */ - if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { - /* unicast to this interface address? */ - if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || - /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; - } -#if LWIP_AUTOIP - /* connections to link-local addresses must persist after changing - the netif's address (RFC3927 ch. 1.9) */ - if ((netif->autoip != NULL) && - ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { - LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", - netif->name[0], netif->name[1])); - /* break out of for loop */ - break; - } -#endif /* LWIP_AUTOIP */ - } - if (first) { - first = 0; - netif = netif_list; - } else { - netif = netif->next; - } - if (netif == inp) { - netif = netif->next; - } - } while(netif != NULL); - } - -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed - * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. - * According to RFC 1542 section 3.1.1, referred by RFC 2131). - * - * If you want to accept private broadcast communication while a netif is down, - * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: - * - * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) - */ - if (netif == NULL) { - /* remote port is DHCP server? */ - if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { - struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", - ntohs(udphdr->dest))); - if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); - netif = inp; - check_ip_src = 0; - } - } - } -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - - /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ -#if IP_ACCEPT_LINK_LAYER_ADDRESSING - /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) -#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ - { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || - (ip_addr_ismulticast(¤t_iphdr_src))) { - /* packet source is not valid */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); - /* free (drop) packet pbufs */ - pbuf_free(p); - IP_STATS_INC(ip.drop); - snmp_inc_ipinaddrerrors(); - snmp_inc_ipindiscards(); - return ERR_OK; - } - } - - /* packet not for us? */ - if (netif == NULL) { - /* packet not for us, route or discard */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); -#if IP_FORWARD - /* non-broadcast packet? */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { - /* try to forward IP packet on (other) interfaces */ - ip_forward(p, iphdr, inp); - } else -#endif /* IP_FORWARD */ - { - snmp_inc_ipinaddrerrors(); - snmp_inc_ipindiscards(); - } - pbuf_free(p); - return ERR_OK; - } - /* packet consists of multiple fragments? */ - if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { -#if IP_REASSEMBLY /* packet fragment reassembly code present? */ - LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", - ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); - /* reassemble the packet*/ - p = ip_reass(p); - /* packet not fully reassembled yet? */ - if (p == NULL) { - return ERR_OK; - } - iphdr = (struct ip_hdr *)p->payload; -#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ - pbuf_free(p); - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", - ntohs(IPH_OFFSET(iphdr)))); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - snmp_inc_ipinunknownprotos(); - return ERR_OK; -#endif /* IP_REASSEMBLY */ - } - -#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */ - -#if LWIP_IGMP - /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ - if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { -#else - if (iphdr_hlen > IP_HLEN) { -#endif /* LWIP_IGMP */ - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n")); - pbuf_free(p); - IP_STATS_INC(ip.opterr); - IP_STATS_INC(ip.drop); - /* unsupported protocol feature */ - snmp_inc_ipinunknownprotos(); - return ERR_OK; - } -#endif /* IP_OPTIONS_ALLOWED == 0 */ - - /* send to upper layers */ - LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n")); - ip_debug_print(p); - LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len)); - - current_netif = inp; - current_header = iphdr; - -#if LWIP_RAW - /* raw input did not eat the packet? */ - if (raw_input(p, inp) == 0) -#endif /* LWIP_RAW */ - { - switch (IPH_PROTO(iphdr)) { -#if LWIP_UDP - case IP_PROTO_UDP: -#if LWIP_UDPLITE - case IP_PROTO_UDPLITE: -#endif /* LWIP_UDPLITE */ - snmp_inc_ipindelivers(); - udp_input(p, inp); - break; -#endif /* LWIP_UDP */ -#if LWIP_TCP - case IP_PROTO_TCP: - snmp_inc_ipindelivers(); - tcp_input(p, inp); - break; -#endif /* LWIP_TCP */ -#if LWIP_ICMP - case IP_PROTO_ICMP: - snmp_inc_ipindelivers(); - icmp_input(p, inp); - break; -#endif /* LWIP_ICMP */ -#if LWIP_IGMP - case IP_PROTO_IGMP: - igmp_input(p, inp, ¤t_iphdr_dest); - break; -#endif /* LWIP_IGMP */ - default: -#if LWIP_ICMP - /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && - !ip_addr_ismulticast(¤t_iphdr_dest)) { - p->payload = iphdr; - icmp_dest_unreach(p, ICMP_DUR_PROTO); - } -#endif /* LWIP_ICMP */ - pbuf_free(p); - - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr))); - - IP_STATS_INC(ip.proterr); - IP_STATS_INC(ip.drop); - snmp_inc_ipinunknownprotos(); - } - } - - current_netif = NULL; - current_header = NULL; - ip_addr_set_any(¤t_iphdr_src); - ip_addr_set_any(¤t_iphdr_dest); - - return ERR_OK; -} - -/** - * Sends an IP packet on a network interface. This function constructs - * the IP header and calculates the IP header checksum. If the source - * IP address is NULL, the IP address of the outgoing network - * interface is filled in as source address. - * If the destination IP address is IP_HDRINCL, p is assumed to already - * include an IP header and p->payload points to it instead of the data. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param netif the netif on which to send this packet - * @return ERR_OK if the packet was sent OK - * ERR_BUF if p doesn't have enough space for IP/LINK headers - * returns errors returned by netif->output - * - * @note ip_id: RFC791 "some host may be able to simply use - * unique identifiers independent of destination" - */ -err_t -ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, - u8_t proto, struct netif *netif) -{ -#if IP_OPTIONS_SEND - return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0); -} - -/** - * Same as ip_output_if() but with the possibility to include IP options: - * - * @ param ip_options pointer to the IP options, copied into the IP header - * @ param optlen length of ip_options - */ -err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, - u16_t optlen) -{ -#endif /* IP_OPTIONS_SEND */ - struct ip_hdr *iphdr; - ip_addr_t dest_addr; -#if CHECKSUM_GEN_IP_INLINE - u32_t chk_sum = 0; -#endif /* CHECKSUM_GEN_IP_INLINE */ - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - snmp_inc_ipoutrequests(); - - /* Should the IP header be generated or is it already included in p? */ - if (dest != IP_HDRINCL) { - u16_t ip_hlen = IP_HLEN; -#if IP_OPTIONS_SEND - u16_t optlen_aligned = 0; - if (optlen != 0) { -#if CHECKSUM_GEN_IP_INLINE - int i; -#endif /* CHECKSUM_GEN_IP_INLINE */ - /* round up to a multiple of 4 */ - optlen_aligned = ((optlen + 3) & ~3); - ip_hlen += optlen_aligned; - /* First write in the IP options */ - if (pbuf_header(p, optlen_aligned)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n")); - IP_STATS_INC(ip.err); - snmp_inc_ipoutdiscards(); - return ERR_BUF; - } - MEMCPY(p->payload, ip_options, optlen); - if (optlen < optlen_aligned) { - /* zero the remaining bytes */ - memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); - } -#if CHECKSUM_GEN_IP_INLINE - for (i = 0; i < optlen_aligned/2; i++) { - chk_sum += ((u16_t*)p->payload)[i]; - } -#endif /* CHECKSUM_GEN_IP_INLINE */ - } -#endif /* IP_OPTIONS_SEND */ - /* generate IP header */ - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n")); - - IP_STATS_INC(ip.err); - snmp_inc_ipoutdiscards(); - return ERR_BUF; - } - - iphdr = (struct ip_hdr *)p->payload; - LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", - (p->len >= sizeof(struct ip_hdr))); - - IPH_TTL_SET(iphdr, ttl); - IPH_PROTO_SET(iphdr, proto); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += LWIP_MAKE_U16(proto, ttl); -#endif /* CHECKSUM_GEN_IP_INLINE */ - - /* dest cannot be NULL here */ - ip_addr_copy(iphdr->dest, *dest); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; - chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; -#endif /* CHECKSUM_GEN_IP_INLINE */ - - IPH_VHL_SET(iphdr, 4, ip_hlen / 4); - IPH_TOS_SET(iphdr, tos); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += LWIP_MAKE_U16(tos, iphdr->_v_hl); -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_LEN_SET(iphdr, htons(p->tot_len)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_len; -#endif /* CHECKSUM_GEN_IP_INLINE */ - IPH_OFFSET_SET(iphdr, 0); - IPH_ID_SET(iphdr, htons(ip_id)); -#if CHECKSUM_GEN_IP_INLINE - chk_sum += iphdr->_id; -#endif /* CHECKSUM_GEN_IP_INLINE */ - ++ip_id; - - if (ip_addr_isany(src)) { - ip_addr_copy(iphdr->src, netif->ip_addr); - } else { - /* src cannot be NULL here */ - ip_addr_copy(iphdr->src, *src); - } - -#if CHECKSUM_GEN_IP_INLINE - chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; - chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; - chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); - chk_sum = (chk_sum >> 16) + chk_sum; - chk_sum = ~chk_sum; - iphdr->_chksum = chk_sum; /* network order */ -#else /* CHECKSUM_GEN_IP_INLINE */ - IPH_CHKSUM_SET(iphdr, 0); -#if CHECKSUM_GEN_IP - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); -#endif -#endif /* CHECKSUM_GEN_IP_INLINE */ - } else { - /* IP header already included in p */ - iphdr = (struct ip_hdr *)p->payload; - ip_addr_copy(dest_addr, iphdr->dest); - dest = &dest_addr; - } - - IP_STATS_INC(ip.xmit); - - LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num)); - ip_debug_print(p); - -#if ENABLE_LOOPBACK - if (ip_addr_cmp(dest, &netif->ip_addr)) { - /* Packet to self, enqueue it for loopback */ - LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); - return netif_loop_output(netif, p, dest); - } -#if LWIP_IGMP - if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { - netif_loop_output(netif, p, dest); - } -#endif /* LWIP_IGMP */ -#endif /* ENABLE_LOOPBACK */ -#if IP_FRAG - /* don't fragment if interface has mtu set to 0 [loopif] */ - if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip_frag(p, netif, dest); - } -#endif /* IP_FRAG */ - - LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); - return netif->output(netif, p, dest); -} - -/** - * Simple interface to ip_output_if. It finds the outgoing network - * interface and calls upon ip_output_if to do the actual work. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto) -{ - struct netif *netif; - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - return ip_output_if(p, src, dest, ttl, tos, proto, netif); -} - -#if LWIP_NETIF_HWADDRHINT -/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint - * before calling ip_output_if. - * - * @param p the packet to send (p->payload points to the data, e.g. next - protocol header; if dest == IP_HDRINCL, p already includes an IP - header and p->payload points to that IP header) - * @param src the source IP address to send from (if src == IP_ADDR_ANY, the - * IP address of the netif used to send is used as source address) - * @param dest the destination IP address to send the packet to - * @param ttl the TTL value to be set in the IP header - * @param tos the TOS value to be set in the IP header - * @param proto the PROTOCOL to be set in the IP header - * @param addr_hint address hint pointer set to netif->addr_hint before - * calling ip_output_if() - * - * @return ERR_RTE if no route is found - * see ip_output_if() for more return values - */ -err_t -ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, - u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) -{ - struct netif *netif; - err_t err; - - /* pbufs passed to IP must have a ref-count of 1 as their payload pointer - gets altered as the packet is passed down the stack */ - LWIP_ASSERT("p->ref == 1", p->ref == 1); - - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - NETIF_SET_HWADDRHINT(netif, addr_hint); - err = ip_output_if(p, src, dest, ttl, tos, proto, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - return err; -} -#endif /* LWIP_NETIF_HWADDRHINT*/ - -#if IP_DEBUG -/* Print an IP header by using LWIP_DEBUGF - * @param p an IP packet, p->payload pointing to the IP header - */ -void -ip_debug_print(struct pbuf *p) -{ - struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; - - LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" | 0x%02"X16_F" | %5"U16_F" | (v, hl, tos, len)\n", - IPH_V(iphdr), - IPH_HL(iphdr), - IPH_TOS(iphdr), - ntohs(IPH_LEN(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" |%"U16_F"%"U16_F"%"U16_F"| %4"U16_F" | (id, flags, offset)\n", - ntohs(IPH_ID(iphdr)), - ntohs(IPH_OFFSET(iphdr)) >> 15 & 1, - ntohs(IPH_OFFSET(iphdr)) >> 14 & 1, - ntohs(IPH_OFFSET(iphdr)) >> 13 & 1, - ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | 0x%04"X16_F" | (ttl, proto, chksum)\n", - IPH_TTL(iphdr), - IPH_PROTO(iphdr), - ntohs(IPH_CHKSUM(iphdr)))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", - ip4_addr1_16(&iphdr->src), - ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), - ip4_addr4_16(&iphdr->src))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", - ip4_addr1_16(&iphdr->dest), - ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), - ip4_addr4_16(&iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* IP_DEBUG */ diff --git a/ext/lwip/src/core/ipv4/ip_addr.c b/ext/lwip/src/core/ipv4/ip_addr.c deleted file mode 100644 index 8f633ff2..00000000 --- a/ext/lwip/src/core/ipv4/ip_addr.c +++ /dev/null @@ -1,312 +0,0 @@ -/** - * @file - * This is the IPv4 address tools implementation. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" - -/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ -const ip_addr_t ip_addr_any = { IPADDR_ANY }; -const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST }; - -/** - * Determine if an address is a broadcast address on a network interface - * - * @param addr address to be checked - * @param netif the network interface against which the address is checked - * @return returns non-zero if the address is a broadcast address - */ -u8_t -ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) -{ - ip_addr_t ipaddr; - ip4_addr_set_u32(&ipaddr, addr); - - /* all ones (broadcast) or all zeroes (old skool broadcast) */ - if ((~addr == IPADDR_ANY) || - (addr == IPADDR_ANY)) { - return 1; - /* no broadcast support on this network interface? */ - } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { - /* the given address cannot be a broadcast address - * nor can we check against any broadcast addresses */ - return 0; - /* address matches network interface address exactly? => no broadcast */ - } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { - return 0; - /* on the same (sub) network... */ - } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) - /* ...and host identifier bits are all ones? =>... */ - && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == - (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { - /* => network broadcast address */ - return 1; - } else { - return 0; - } -} - -/** Checks if a netmask is valid (starting with ones, then only zeros) - * - * @param netmask the IPv4 netmask to check (in network byte order!) - * @return 1 if the netmask is valid, 0 if it is not - */ -u8_t -ip4_addr_netmask_valid(u32_t netmask) -{ - u32_t mask; - u32_t nm_hostorder = lwip_htonl(netmask); - - /* first, check for the first zero */ - for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) == 0) { - break; - } - } - /* then check that there is no one */ - for (; mask != 0; mask >>= 1) { - if ((nm_hostorder & mask) != 0) { - /* there is a one after the first zero -> invalid */ - return 0; - } - } - /* no one after the first zero -> valid */ - return 1; -} - -/* Here for now until needed in other places in lwIP */ -#ifndef isprint -#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) -#define isprint(c) in_range(c, 0x20, 0x7f) -#define isdigit(c) in_range(c, '0', '9') -#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) -#define islower(c) in_range(c, 'a', 'z') -#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') -#endif - -/** - * Ascii internet address interpretation routine. - * The value returned is in network order. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @return ip address in network order - */ -u32_t -ipaddr_addr(const char *cp) -{ - ip_addr_t val; - - if (ipaddr_aton(cp, &val)) { - return ip4_addr_get_u32(&val); - } - return (IPADDR_NONE); -} - -/** - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -ipaddr_aton(const char *cp, ip_addr_t *addr) -{ - u32_t val; - u8_t base; - char c; - u32_t parts[4]; - u32_t *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, 1-9=decimal. - */ - if (!isdigit(c)) - return (0); - val = 0; - base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') { - base = 16; - c = *++cp; - } else - base = 8; - } - for (;;) { - if (isdigit(c)) { - val = (val * base) + (int)(c - '0'); - c = *++cp; - } else if (base == 16 && isxdigit(c)) { - val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) { - return (0); - } - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && !isspace(c)) { - return (0); - } - /* - * Concoct the address according to - * the number of parts specified. - */ - switch (pp - parts + 1) { - - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffffUL) { - return (0); - } - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) { - return (0); - } - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) { - return (0); - } - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - default: - LWIP_ASSERT("unhandled", 0); - break; - } - if (addr) { - ip4_addr_set_u32(addr, htonl(val)); - } - return (1); -} - -/** - * Convert numeric IP address into decimal dotted ASCII representation. - * returns ptr to static buffer; not reentrant! - * - * @param addr ip address in network order to convert - * @return pointer to a global static (!) buffer that holds the ASCII - * represenation of addr - */ -char * -ipaddr_ntoa(const ip_addr_t *addr) -{ - static char str[16]; - return ipaddr_ntoa_r(addr, str, 16); -} - -/** - * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. - * - * @param addr ip address in network order to convert - * @param buf target buffer where the string is stored - * @param buflen length of buf - * @return either pointer to buf which now holds the ASCII - * representation of addr or NULL if buf was too small - */ -char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) -{ - u32_t s_addr; - char inv[3]; - char *rp; - u8_t *ap; - u8_t rem; - u8_t n; - u8_t i; - int len = 0; - - s_addr = ip4_addr_get_u32(addr); - - rp = buf; - ap = (u8_t *)&s_addr; - for(n = 0; n < 4; n++) { - i = 0; - do { - rem = *ap % (u8_t)10; - *ap /= (u8_t)10; - inv[i++] = '0' + rem; - } while(*ap); - while(i--) { - if (len++ >= buflen) { - return NULL; - } - *rp++ = inv[i]; - } - if (len++ >= buflen) { - return NULL; - } - *rp++ = '.'; - ap++; - } - *--rp = 0; - return buf; -} diff --git a/ext/lwip/src/core/ipv4/ip_frag.c b/ext/lwip/src/core/ipv4/ip_frag.c deleted file mode 100644 index 8d184345..00000000 --- a/ext/lwip/src/core/ipv4/ip_frag.c +++ /dev/null @@ -1,863 +0,0 @@ -/** - * @file - * This is the IPv4 packet segmentation and reassembly implementation. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Jani Monoses <jani@iv.ro> - * Simon Goldschmidt - * original reassembly code by Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" -#include "lwip/ip_frag.h" -#include "lwip/def.h" -#include "lwip/inet_chksum.h" -#include "lwip/netif.h" -#include "lwip/snmp.h" -#include "lwip/stats.h" -#include "lwip/icmp.h" - -#include <string.h> - -#if IP_REASSEMBLY -/** - * The IP reassembly code currently has the following limitations: - * - IP header options are not supported - * - fragments must not overlap (e.g. due to different routes), - * currently, overlapping or duplicate fragments are thrown away - * if IP_REASS_CHECK_OVERLAP=1 (the default)! - * - * @todo: work with IP header options - */ - -/** Setting this to 0, you can turn off checking the fragments for overlapping - * regions. The code gets a little smaller. Only use this if you know that - * overlapping won't occur on your network! */ -#ifndef IP_REASS_CHECK_OVERLAP -#define IP_REASS_CHECK_OVERLAP 1 -#endif /* IP_REASS_CHECK_OVERLAP */ - -/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is - * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller. - * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA - * is set to 1, so one datagram can be reassembled at a time, only. */ -#ifndef IP_REASS_FREE_OLDEST -#define IP_REASS_FREE_OLDEST 1 -#endif /* IP_REASS_FREE_OLDEST */ - -#define IP_REASS_FLAG_LASTFRAG 0x01 - -/** This is a helper struct which holds the starting - * offset and the ending offset of this fragment to - * easily chain the fragments. - * It has the same packing requirements as the IP header, since it replaces - * the IP header in memory in incoming fragments (after copying it) to keep - * track of the various fragments. (-> If the IP header doesn't need packing, - * this struct doesn't need packing, too.) - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct ip_reass_helper { - PACK_STRUCT_FIELD(struct pbuf *next_pbuf); - PACK_STRUCT_FIELD(u16_t start); - PACK_STRUCT_FIELD(u16_t end); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif - -#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \ - (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \ - ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \ - IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0 - -/* global variables */ -static struct ip_reassdata *reassdatagrams; -static u16_t ip_reass_pbufcount; - -/* function prototypes */ -static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); -static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev); - -/** - * Reassembly timer base function - * for both NO_SYS == 0 and 1 (!). - * - * Should be called every 1000 msec (defined by IP_TMR_INTERVAL). - */ -void -ip_reass_tmr(void) -{ - struct ip_reassdata *r, *prev = NULL; - - r = reassdatagrams; - while (r != NULL) { - /* Decrement the timer. Once it reaches 0, - * clean up the incomplete fragment assembly */ - if (r->timer > 0) { - r->timer--; - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer)); - prev = r; - r = r->next; - } else { - /* reassembly timed out */ - struct ip_reassdata *tmp; - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n")); - tmp = r; - /* get the next pointer before freeing */ - r = r->next; - /* free the helper struct and all enqueued pbufs */ - ip_reass_free_complete_datagram(tmp, prev); - } - } -} - -/** - * Free a datagram (struct ip_reassdata) and all its pbufs. - * Updates the total count of enqueued pbufs (ip_reass_pbufcount), - * SNMP counters and sends an ICMP time exceeded packet. - * - * @param ipr datagram to free - * @param prev the previous datagram in the linked list - * @return the number of pbufs freed - */ -static int -ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) -{ - u16_t pbufs_freed = 0; - u8_t clen; - struct pbuf *p; - struct ip_reass_helper *iprh; - - LWIP_ASSERT("prev != ipr", prev != ipr); - if (prev != NULL) { - LWIP_ASSERT("prev->next == ipr", prev->next == ipr); - } - - snmp_inc_ipreasmfails(); -#if LWIP_ICMP - iprh = (struct ip_reass_helper *)ipr->p->payload; - if (iprh->start == 0) { - /* The first fragment was received, send ICMP time exceeded. */ - /* First, de-queue the first pbuf from r->p. */ - p = ipr->p; - ipr->p = iprh->next_pbuf; - /* Then, copy the original header into it. */ - SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); - icmp_time_exceeded(p, ICMP_TE_FRAG); - clen = pbuf_clen(p); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(p); - } -#endif /* LWIP_ICMP */ - - /* First, free all received pbufs. The individual pbufs need to be released - separately as they have not yet been chained */ - p = ipr->p; - while (p != NULL) { - struct pbuf *pcur; - iprh = (struct ip_reass_helper *)p->payload; - pcur = p; - /* get the next pointer before freeing */ - p = iprh->next_pbuf; - clen = pbuf_clen(pcur); - LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); - pbufs_freed += clen; - pbuf_free(pcur); - } - /* Then, unchain the struct ip_reassdata from the list and free it. */ - ip_reass_dequeue_datagram(ipr, prev); - LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed); - ip_reass_pbufcount -= pbufs_freed; - - return pbufs_freed; -} - -#if IP_REASS_FREE_OLDEST -/** - * Free the oldest datagram to make room for enqueueing new fragments. - * The datagram 'fraghdr' belongs to is not freed! - * - * @param fraghdr IP header of the current fragment - * @param pbufs_needed number of pbufs needed to enqueue - * (used for freeing other datagrams if not enough space) - * @return the number of pbufs freed - */ -static int -ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed) -{ - /* @todo Can't we simply remove the last datagram in the - * linked list behind reassdatagrams? - */ - struct ip_reassdata *r, *oldest, *prev; - int pbufs_freed = 0, pbufs_freed_current; - int other_datagrams; - - /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs, - * but don't free the datagram that 'fraghdr' belongs to! */ - do { - oldest = NULL; - prev = NULL; - other_datagrams = 0; - r = reassdatagrams; - while (r != NULL) { - if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) { - /* Not the same datagram as fraghdr */ - other_datagrams++; - if (oldest == NULL) { - oldest = r; - } else if (r->timer <= oldest->timer) { - /* older than the previous oldest */ - oldest = r; - } - } - if (r->next != NULL) { - prev = r; - } - r = r->next; - } - if (oldest != NULL) { - pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev); - pbufs_freed += pbufs_freed_current; - } - } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1)); - return pbufs_freed; -} -#endif /* IP_REASS_FREE_OLDEST */ - -/** - * Enqueues a new fragment into the fragment queue - * @param fraghdr points to the new fragments IP hdr - * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space) - * @return A pointer to the queue location into which the fragment was enqueued - */ -static struct ip_reassdata* -ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) -{ - struct ip_reassdata* ipr; - /* No matching previous fragment found, allocate a new reassdata struct */ - ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); - if (ipr == NULL) { -#if IP_REASS_FREE_OLDEST - if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { - ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); - } - if (ipr == NULL) -#endif /* IP_REASS_FREE_OLDEST */ - { - IPFRAG_STATS_INC(ip_frag.memerr); - LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n")); - return NULL; - } - } - memset(ipr, 0, sizeof(struct ip_reassdata)); - ipr->timer = IP_REASS_MAXAGE; - - /* enqueue the new structure to the front of the list */ - ipr->next = reassdatagrams; - reassdatagrams = ipr; - /* copy the ip header for later tests and input */ - /* @todo: no ip options supported? */ - SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN); - return ipr; -} - -/** - * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs. - * @param ipr points to the queue entry to dequeue - */ -static void -ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) -{ - - /* dequeue the reass struct */ - if (reassdatagrams == ipr) { - /* it was the first in the list */ - reassdatagrams = ipr->next; - } else { - /* it wasn't the first, so it must have a valid 'prev' */ - LWIP_ASSERT("sanity check linked list", prev != NULL); - prev->next = ipr->next; - } - - /* now we can free the ip_reass struct */ - memp_free(MEMP_REASSDATA, ipr); -} - -/** - * Chain a new pbuf into the pbuf list that composes the datagram. The pbuf list - * will grow over time as new pbufs are rx. - * Also checks that the datagram passes basic continuity checks (if the last - * fragment was received at least once). - * @param root_p points to the 'root' pbuf for the current datagram being assembled. - * @param new_p points to the pbuf for the current fragment - * @return 0 if invalid, >0 otherwise - */ -static int -ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p) -{ - struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL; - struct pbuf *q; - u16_t offset,len; - struct ip_hdr *fraghdr; - int valid = 1; - - /* Extract length and fragment offset from current fragment */ - fraghdr = (struct ip_hdr*)new_p->payload; - len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; - offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; - - /* overwrite the fragment's ip header from the pbuf with our helper struct, - * and setup the embedded helper structure. */ - /* make sure the struct ip_reass_helper fits into the IP header */ - LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN", - sizeof(struct ip_reass_helper) <= IP_HLEN); - iprh = (struct ip_reass_helper*)new_p->payload; - iprh->next_pbuf = NULL; - iprh->start = offset; - iprh->end = offset + len; - - /* Iterate through until we either get to the end of the list (append), - * or we find on with a larger offset (insert). */ - for (q = ipr->p; q != NULL;) { - iprh_tmp = (struct ip_reass_helper*)q->payload; - if (iprh->start < iprh_tmp->start) { - /* the new pbuf should be inserted before this */ - iprh->next_pbuf = q; - if (iprh_prev != NULL) { - /* not the fragment with the lowest offset */ -#if IP_REASS_CHECK_OVERLAP - if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) { - /* fragment overlaps with previous or following, throw away */ - goto freepbuf; - } -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = new_p; - } else { - /* fragment with the lowest offset */ - ipr->p = new_p; - } - break; - } else if(iprh->start == iprh_tmp->start) { - /* received the same datagram twice: no need to keep the datagram */ - goto freepbuf; -#if IP_REASS_CHECK_OVERLAP - } else if(iprh->start < iprh_tmp->end) { - /* overlap: no need to keep the new datagram */ - goto freepbuf; -#endif /* IP_REASS_CHECK_OVERLAP */ - } else { - /* Check if the fragments received so far have no wholes. */ - if (iprh_prev != NULL) { - if (iprh_prev->end != iprh_tmp->start) { - /* There is a fragment missing between the current - * and the previous fragment */ - valid = 0; - } - } - } - q = iprh_tmp->next_pbuf; - iprh_prev = iprh_tmp; - } - - /* If q is NULL, then we made it to the end of the list. Determine what to do now */ - if (q == NULL) { - if (iprh_prev != NULL) { - /* this is (for now), the fragment with the highest offset: - * chain it to the last fragment */ -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start); -#endif /* IP_REASS_CHECK_OVERLAP */ - iprh_prev->next_pbuf = new_p; - if (iprh_prev->end != iprh->start) { - valid = 0; - } - } else { -#if IP_REASS_CHECK_OVERLAP - LWIP_ASSERT("no previous fragment, this must be the first fragment!", - ipr->p == NULL); -#endif /* IP_REASS_CHECK_OVERLAP */ - /* this is the first fragment we ever received for this ip datagram */ - ipr->p = new_p; - } - } - - /* At this point, the validation part begins: */ - /* If we already received the last fragment */ - if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) { - /* and had no wholes so far */ - if (valid) { - /* then check if the rest of the fragments is here */ - /* Check if the queue starts with the first datagram */ - if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) { - valid = 0; - } else { - /* and check that there are no wholes after this datagram */ - iprh_prev = iprh; - q = iprh->next_pbuf; - while (q != NULL) { - iprh = (struct ip_reass_helper*)q->payload; - if (iprh_prev->end != iprh->start) { - valid = 0; - break; - } - iprh_prev = iprh; - q = iprh->next_pbuf; - } - /* if still valid, all fragments are received - * (because to the MF==0 already arrived */ - if (valid) { - LWIP_ASSERT("sanity check", ipr->p != NULL); - LWIP_ASSERT("sanity check", - ((struct ip_reass_helper*)ipr->p->payload) != iprh); - LWIP_ASSERT("validate_datagram:next_pbuf!=NULL", - iprh->next_pbuf == NULL); - LWIP_ASSERT("validate_datagram:datagram end!=datagram len", - iprh->end == ipr->datagram_len); - } - } - } - /* If valid is 0 here, there are some fragments missing in the middle - * (since MF == 0 has already arrived). Such datagrams simply time out if - * no more fragments are received... */ - return valid; - } - /* If we come here, not all fragments were received, yet! */ - return 0; /* not yet valid! */ -#if IP_REASS_CHECK_OVERLAP -freepbuf: - ip_reass_pbufcount -= pbuf_clen(new_p); - pbuf_free(new_p); - return 0; -#endif /* IP_REASS_CHECK_OVERLAP */ -} - -/** - * Reassembles incoming IP fragments into an IP datagram. - * - * @param p points to a pbuf chain of the fragment - * @return NULL if reassembly is incomplete, ? otherwise - */ -struct pbuf * -ip_reass(struct pbuf *p) -{ - struct pbuf *r; - struct ip_hdr *fraghdr; - struct ip_reassdata *ipr; - struct ip_reass_helper *iprh; - u16_t offset, len; - u8_t clen; - struct ip_reassdata *ipr_prev = NULL; - - IPFRAG_STATS_INC(ip_frag.recv); - snmp_inc_ipreasmreqds(); - - fraghdr = (struct ip_hdr*)p->payload; - - if ((IPH_HL(fraghdr) * 4) != IP_HLEN) { - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n")); - IPFRAG_STATS_INC(ip_frag.err); - goto nullreturn; - } - - offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8; - len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4; - - /* Check if we are allowed to enqueue more datagrams. */ - clen = pbuf_clen(p); - if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) { -#if IP_REASS_FREE_OLDEST - if (!ip_reass_remove_oldest_datagram(fraghdr, clen) || - ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)) -#endif /* IP_REASS_FREE_OLDEST */ - { - /* No datagram could be freed and still too many pbufs enqueued */ - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n", - ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS)); - IPFRAG_STATS_INC(ip_frag.memerr); - /* @todo: send ICMP time exceeded here? */ - /* drop this pbuf */ - goto nullreturn; - } - } - - /* Look for the datagram the fragment belongs to in the current datagram queue, - * remembering the previous in the queue for later dequeueing. */ - for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) { - /* Check if the incoming fragment matches the one currently present - in the reassembly buffer. If so, we proceed with copying the - fragment into the buffer. */ - if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n", - ntohs(IPH_ID(fraghdr)))); - IPFRAG_STATS_INC(ip_frag.cachehit); - break; - } - ipr_prev = ipr; - } - - if (ipr == NULL) { - /* Enqueue a new datagram into the datagram queue */ - ipr = ip_reass_enqueue_new_datagram(fraghdr, clen); - /* Bail if unable to enqueue */ - if(ipr == NULL) { - goto nullreturn; - } - } else { - if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) && - ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) { - /* ipr->iphdr is not the header from the first fragment, but fraghdr is - * -> copy fraghdr into ipr->iphdr since we want to have the header - * of the first fragment (for ICMP time exceeded and later, for copying - * all options, if supported)*/ - SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN); - } - } - /* Track the current number of pbufs current 'in-flight', in order to limit - the number of fragments that may be enqueued at any one time */ - ip_reass_pbufcount += clen; - - /* At this point, we have either created a new entry or pointing - * to an existing one */ - - /* check for 'no more fragments', and update queue entry*/ - if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { - ipr->flags |= IP_REASS_FLAG_LASTFRAG; - ipr->datagram_len = offset + len; - LWIP_DEBUGF(IP_REASS_DEBUG, - ("ip_reass: last fragment seen, total len %"S16_F"\n", - ipr->datagram_len)); - } - /* find the right place to insert this pbuf */ - /* @todo: trim pbufs if fragments are overlapping */ - if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) { - /* the totally last fragment (flag more fragments = 0) was received at least - * once AND all fragments are received */ - ipr->datagram_len += IP_HLEN; - - /* save the second pbuf before copying the header over the pointer */ - r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf; - - /* copy the original ip header back to the first pbuf */ - fraghdr = (struct ip_hdr*)(ipr->p->payload); - SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN); - IPH_LEN_SET(fraghdr, htons(ipr->datagram_len)); - IPH_OFFSET_SET(fraghdr, 0); - IPH_CHKSUM_SET(fraghdr, 0); - /* @todo: do we need to set calculate the correct checksum? */ - IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN)); - - p = ipr->p; - - /* chain together the pbufs contained within the reass_data list. */ - while(r != NULL) { - iprh = (struct ip_reass_helper*)r->payload; - - /* hide the ip header for every succeding fragment */ - pbuf_header(r, -IP_HLEN); - pbuf_cat(p, r); - r = iprh->next_pbuf; - } - /* release the sources allocate for the fragment queue entry */ - ip_reass_dequeue_datagram(ipr, ipr_prev); - - /* and adjust the number of pbufs currently queued for reassembly. */ - ip_reass_pbufcount -= pbuf_clen(p); - - /* Return the pbuf chain */ - return p; - } - /* the datagram is not (yet?) reassembled completely */ - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount)); - return NULL; - -nullreturn: - LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n")); - IPFRAG_STATS_INC(ip_frag.drop); - pbuf_free(p); - return NULL; -} -#endif /* IP_REASSEMBLY */ - -#if IP_FRAG -#if IP_FRAG_USES_STATIC_BUF -static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; -#else /* IP_FRAG_USES_STATIC_BUF */ - -#if !LWIP_NETIF_TX_SINGLE_PBUF -/** Allocate a new struct pbuf_custom_ref */ -static struct pbuf_custom_ref* -ip_frag_alloc_pbuf_custom_ref(void) -{ - return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); -} - -/** Free a struct pbuf_custom_ref */ -static void -ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) -{ - LWIP_ASSERT("p != NULL", p != NULL); - memp_free(MEMP_FRAG_PBUF, p); -} - -/** Free-callback function to free a 'struct pbuf_custom_ref', called by - * pbuf_free. */ -static void -ipfrag_free_pbuf_custom(struct pbuf *p) -{ - struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; - LWIP_ASSERT("pcr != NULL", pcr != NULL); - LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); - if (pcr->original != NULL) { - pbuf_free(pcr->original); - } - ip_frag_free_pbuf_custom_ref(pcr); -} -#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - -/** - * Fragment an IP datagram if too large for the netif. - * - * Chop the datagram in MTU sized chunks and send them in order - * by using a fixed size static memory buffer (PBUF_REF) or - * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF). - * - * @param p ip packet to send - * @param netif the netif on which to send - * @param dest destination ip address to which to send - * - * @return ERR_OK if sent successfully, err_t otherwise - */ -err_t -ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) -{ - struct pbuf *rambuf; -#if IP_FRAG_USES_STATIC_BUF - struct pbuf *header; -#else -#if !LWIP_NETIF_TX_SINGLE_PBUF - struct pbuf *newpbuf; -#endif - struct ip_hdr *original_iphdr; -#endif - struct ip_hdr *iphdr; - u16_t nfb; - u16_t left, cop; - u16_t mtu = netif->mtu; - u16_t ofo, omf; - u16_t last; - u16_t poff = IP_HLEN; - u16_t tmp; -#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF - u16_t newpbuflen = 0; - u16_t left_to_copy; -#endif - - /* Get a RAM based MTU sized pbuf */ -#if IP_FRAG_USES_STATIC_BUF - /* When using a static buffer, we use a PBUF_REF, which we will - * use to reference the packet (without link header). - * Layer and length is irrelevant. - */ - rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF); - if (rambuf == NULL) { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n")); - return ERR_MEM; - } - rambuf->tot_len = rambuf->len = mtu; - rambuf->payload = LWIP_MEM_ALIGN((void *)buf); - - /* Copy the IP header in it */ - iphdr = (struct ip_hdr *)rambuf->payload; - SMEMCPY(iphdr, p->payload, IP_HLEN); -#else /* IP_FRAG_USES_STATIC_BUF */ - original_iphdr = (struct ip_hdr *)p->payload; - iphdr = original_iphdr; -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Save original offset */ - tmp = ntohs(IPH_OFFSET(iphdr)); - ofo = tmp & IP_OFFMASK; - omf = tmp & IP_MF; - - left = p->tot_len - IP_HLEN; - - nfb = (mtu - IP_HLEN) / 8; - - while (left) { - last = (left <= mtu - IP_HLEN); - - /* Set new offset and MF flag */ - tmp = omf | (IP_OFFMASK & (ofo)); - if (!last) { - tmp = tmp | IP_MF; - } - - /* Fill this fragment */ - cop = last ? left : nfb * 8; - -#if IP_FRAG_USES_STATIC_BUF - poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); -#else /* IP_FRAG_USES_STATIC_BUF */ -#if LWIP_NETIF_TX_SINGLE_PBUF - rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); - if (rambuf == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); - poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); - /* make room for the IP header */ - if(pbuf_header(rambuf, IP_HLEN)) { - pbuf_free(rambuf); - return ERR_MEM; - } - /* fill in the IP header */ - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = rambuf->payload; -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - /* When not using a static buffer, create a chain of pbufs. - * The first will be a PBUF_RAM holding the link and IP header. - * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, - * but limited to the size of an mtu. - */ - rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM); - if (rambuf == NULL) { - return ERR_MEM; - } - LWIP_ASSERT("this needs a pbuf in one piece!", - (p->len >= (IP_HLEN))); - SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = (struct ip_hdr *)rambuf->payload; - - /* Can just adjust p directly for needed offset. */ - p->payload = (u8_t *)p->payload + poff; - p->len -= poff; - - left_to_copy = cop; - while (left_to_copy) { - struct pbuf_custom_ref *pcr; - newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; - /* Is this pbuf already empty? */ - if (!newpbuflen) { - p = p->next; - continue; - } - pcr = ip_frag_alloc_pbuf_custom_ref(); - if (pcr == NULL) { - pbuf_free(rambuf); - return ERR_MEM; - } - /* Mirror this pbuf, although we might not need all of it. */ - newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); - if (newpbuf == NULL) { - ip_frag_free_pbuf_custom_ref(pcr); - pbuf_free(rambuf); - return ERR_MEM; - } - pbuf_ref(p); - pcr->original = p; - pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; - - /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain - * so that it is removed when pbuf_dechain is later called on rambuf. - */ - pbuf_cat(rambuf, newpbuf); - left_to_copy -= newpbuflen; - if (left_to_copy) { - p = p->next; - } - } - poff = newpbuflen; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ -#endif /* IP_FRAG_USES_STATIC_BUF */ - - /* Correct header */ - IPH_OFFSET_SET(iphdr, htons(tmp)); - IPH_LEN_SET(iphdr, htons(cop + IP_HLEN)); - IPH_CHKSUM_SET(iphdr, 0); - IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); - -#if IP_FRAG_USES_STATIC_BUF - if (last) { - pbuf_realloc(rambuf, left + IP_HLEN); - } - - /* This part is ugly: we alloc a RAM based pbuf for - * the link level header for each chunk and then - * free it.A PBUF_ROM style pbuf for which pbuf_header - * worked would make things simpler. - */ - header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM); - if (header != NULL) { - pbuf_chain(header, rambuf); - netif->output(netif, header, dest); - IPFRAG_STATS_INC(ip_frag.xmit); - snmp_inc_ipfragcreates(); - pbuf_free(header); - } else { - LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n")); - pbuf_free(rambuf); - return ERR_MEM; - } -#else /* IP_FRAG_USES_STATIC_BUF */ - /* No need for separate header pbuf - we allowed room for it in rambuf - * when allocated. - */ - netif->output(netif, rambuf, dest); - IPFRAG_STATS_INC(ip_frag.xmit); - - /* Unfortunately we can't reuse rambuf - the hardware may still be - * using the buffer. Instead we free it (and the ensuing chain) and - * recreate it next time round the loop. If we're lucky the hardware - * will have already sent the packet, the free will really free, and - * there will be zero memory penalty. - */ - - pbuf_free(rambuf); -#endif /* IP_FRAG_USES_STATIC_BUF */ - left -= cop; - ofo += nfb; - } -#if IP_FRAG_USES_STATIC_BUF - pbuf_free(rambuf); -#endif /* IP_FRAG_USES_STATIC_BUF */ - snmp_inc_ipfragoks(); - return ERR_OK; -} -#endif /* IP_FRAG */ diff --git a/ext/lwip/src/core/ipv6/README b/ext/lwip/src/core/ipv6/README deleted file mode 100644 index 36200048..00000000 --- a/ext/lwip/src/core/ipv6/README +++ /dev/null @@ -1 +0,0 @@ -IPv6 support in lwIP is very experimental. diff --git a/ext/lwip/src/core/ipv6/icmp6.c b/ext/lwip/src/core/ipv6/icmp6.c deleted file mode 100644 index 4fcc8955..00000000 --- a/ext/lwip/src/core/ipv6/icmp6.c +++ /dev/null @@ -1,179 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -/* Some ICMP messages should be passed to the transport protocols. This - is not implemented. */ - -#include "lwip/opt.h" - -#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/icmp.h" -#include "lwip/inet.h" -#include "lwip/ip.h" -#include "lwip/def.h" -#include "lwip/stats.h" - -void -icmp_input(struct pbuf *p, struct netif *inp) -{ - u8_t type; - struct icmp_echo_hdr *iecho; - struct ip_hdr *iphdr; - struct ip_addr tmpaddr; - - ICMP_STATS_INC(icmp.recv); - - /* TODO: check length before accessing payload! */ - - type = ((u8_t *)p->payload)[0]; - - switch (type) { - case ICMP6_ECHO: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n")); - - if (p->tot_len < sizeof(struct icmp_echo_hdr)) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n")); - - pbuf_free(p); - ICMP_STATS_INC(icmp.lenerr); - return; - } - iecho = p->payload; - iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN); - if (inet_chksum_pbuf(p) != 0) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.chkerr); - /* return;*/ - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len)); - ip_addr_set(&tmpaddr, &(iphdr->src)); - ip_addr_set(&(iphdr->src), &(iphdr->dest)); - ip_addr_set(&(iphdr->dest), &tmpaddr); - iecho->type = ICMP6_ER; - /* adjust the checksum */ - if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) { - iecho->chksum += htons(ICMP6_ECHO << 8) + 1; - } else { - iecho->chksum += htons(ICMP6_ECHO << 8); - } - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len))); - ICMP_STATS_INC(icmp.xmit); - - /* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ - ip_output_if (p, &(iphdr->src), IP_HDRINCL, - iphdr->hoplim, IP_PROTO_ICMP, inp); - break; - default: - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type)); - ICMP_STATS_INC(icmp.proterr); - ICMP_STATS_INC(icmp.drop); - } - - pbuf_free(p); -} - -void -icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t) -{ - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_dur_hdr *idur; - - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (8 + IP_HLEN + 8))); - - iphdr = p->payload; - - idur = q->payload; - idur->type = (u8_t)ICMP6_DUR; - idur->icode = (u8_t)t; - - SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8); - - /* calculate checksum */ - idur->chksum = 0; - idur->chksum = inet_chksum(idur, q->len); - ICMP_STATS_INC(icmp.xmit); - - ip_output(q, NULL, - (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); - pbuf_free(q); -} - -void -icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t) -{ - struct pbuf *q; - struct ip_hdr *iphdr; - struct icmp_te_hdr *tehdr; - - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n")); - - /* @todo: can this be PBUF_LINK instead of PBUF_IP? */ - q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM); - /* ICMP header + IP header + 8 bytes of data */ - if (q == NULL) { - LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n")); - pbuf_free(p); - return; - } - LWIP_ASSERT("check that first pbuf can hold icmp message", - (q->len >= (8 + IP_HLEN + 8))); - - iphdr = p->payload; - - tehdr = q->payload; - tehdr->type = (u8_t)ICMP6_TE; - tehdr->icode = (u8_t)t; - - /* copy fields from original packet */ - SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8); - - /* calculate checksum */ - tehdr->chksum = 0; - tehdr->chksum = inet_chksum(tehdr, q->len); - ICMP_STATS_INC(icmp.xmit); - ip_output(q, NULL, - (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP); - pbuf_free(q); -} - -#endif /* LWIP_ICMP */ diff --git a/ext/lwip/src/core/ipv6/inet6.c b/ext/lwip/src/core/ipv6/inet6.c deleted file mode 100644 index c3de85c0..00000000 --- a/ext/lwip/src/core/ipv6/inet6.c +++ /dev/null @@ -1,163 +0,0 @@ -/** - * @file - * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the - * byte order functions. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/inet.h" - -/* chksum: - * - * Sums up all 16 bit words in a memory portion. Also includes any odd byte. - * This function is used by the other checksum functions. - * - * For now, this is not optimized. Must be optimized for the particular processor - * arcitecture on which it is to run. Preferebly coded in assembler. - */ - -static u32_t -chksum(void *dataptr, u16_t len) -{ - u16_t *sdataptr = dataptr; - u32_t acc; - - - for(acc = 0; len > 1; len -= 2) { - acc += *sdataptr++; - } - - /* add up any odd byte */ - if (len == 1) { - acc += htons((u16_t)(*(u8_t *)dataptr) << 8); - } - - return acc; - -} - -/* inet_chksum_pseudo: - * - * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain. - */ - -u16_t -inet_chksum_pseudo(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, - u8_t proto, u32_t proto_len) -{ - u32_t acc; - struct pbuf *q; - u8_t swapped, i; - - acc = 0; - swapped = 0; - for(q = p; q != NULL; q = q->next) { - acc += chksum(q->payload, q->len); - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - } - - if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - - for(i = 0; i < 8; i++) { - acc += ((u16_t *)src->addr)[i] & 0xffff; - acc += ((u16_t *)dest->addr)[i] & 0xffff; - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - } - acc += (u16_t)htons((u16_t)proto); - acc += ((u16_t *)&proto_len)[0] & 0xffff; - acc += ((u16_t *)&proto_len)[1] & 0xffff; - - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - return ~(acc & 0xffff); -} - -/* inet_chksum: - * - * Calculates the Internet checksum over a portion of memory. Used primarely for IP - * and ICMP. - */ - -u16_t -inet_chksum(void *dataptr, u16_t len) -{ - u32_t acc, sum; - - acc = chksum(dataptr, len); - sum = (acc & 0xffff) + (acc >> 16); - sum += (sum >> 16); - return ~(sum & 0xffff); -} - -u16_t -inet_chksum_pbuf(struct pbuf *p) -{ - u32_t acc; - struct pbuf *q; - u8_t swapped; - - acc = 0; - swapped = 0; - for(q = p; q != NULL; q = q->next) { - acc += chksum(q->payload, q->len); - while (acc >> 16) { - acc = (acc & 0xffff) + (acc >> 16); - } - if (q->len % 2 != 0) { - swapped = 1 - swapped; - acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8); - } - } - - if (swapped) { - acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8); - } - return ~(acc & 0xffff); -} diff --git a/ext/lwip/src/core/ipv6/ip6.c b/ext/lwip/src/core/ipv6/ip6.c deleted file mode 100644 index ad59b725..00000000 --- a/ext/lwip/src/core/ipv6/ip6.c +++ /dev/null @@ -1,397 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - - - -/* ip.c - * - * This is the code for the IP layer for IPv6. - * - */ - - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/ip.h" -#include "lwip/inet.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/udp.h" -#include "lwip/tcp_impl.h" - -#include "lwip/stats.h" - -#include "arch/perf.h" - -/* ip_init: - * - * Initializes the IP layer. - */ - -void -ip_init(void) -{ -} - -/* ip_route: - * - * Finds the appropriate network interface for a given IP address. It searches the - * list of network interfaces linearly. A match is found if the masked IP address of - * the network interface equals the masked IP address given to the function. - */ - -struct netif * -ip_route(struct ip_addr *dest) -{ - struct netif *netif; - - for(netif = netif_list; netif != NULL; netif = netif->next) { - if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) { - return netif; - } - } - - return netif_default; -} - -/* ip_forward: - * - * Forwards an IP packet. It finds an appropriate route for the packet, decrements - * the TTL value of the packet, adjusts the checksum and outputs the packet on the - * appropriate interface. - */ - -static void -ip_forward(struct pbuf *p, struct ip_hdr *iphdr) -{ - struct netif *netif; - - PERF_START; - - if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) { - - LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for ")); -#if IP_DEBUG - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); -#endif /* IP_DEBUG */ - LWIP_DEBUGF(IP_DEBUG, ("\n")); - pbuf_free(p); - return; - } - /* Decrement TTL and send ICMP if ttl == 0. */ - if (--iphdr->hoplim == 0) { -#if LWIP_ICMP - /* Don't send ICMP messages in response to ICMP messages */ - if (iphdr->nexthdr != IP_PROTO_ICMP) { - icmp_time_exceeded(p, ICMP_TE_TTL); - } -#endif /* LWIP_ICMP */ - pbuf_free(p); - return; - } - - /* Incremental update of the IP checksum. */ - /* if (iphdr->chksum >= htons(0xffff - 0x100)) { - iphdr->chksum += htons(0x100) + 1; - } else { - iphdr->chksum += htons(0x100); - }*/ - - - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to ")); -#if IP_DEBUG - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); -#endif /* IP_DEBUG */ - LWIP_DEBUGF(IP_DEBUG, ("\n")); - - IP_STATS_INC(ip.fw); - IP_STATS_INC(ip.xmit); - - PERF_STOP("ip_forward"); - - netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); -} - -/* ip_input: - * - * This function is called by the network interface device driver when an IP packet is - * received. The function does the basic checks of the IP header such as packet size - * being at least larger than the header size etc. If the packet was not destined for - * us, the packet is forwarded (using ip_forward). The IP checksum is always checked. - * - * Finally, the packet is sent to the upper layer protocol input function. - */ - -void -ip_input(struct pbuf *p, struct netif *inp) { - struct ip_hdr *iphdr; - struct netif *netif; - - - PERF_START; - -#if IP_DEBUG - ip_debug_print(p); -#endif /* IP_DEBUG */ - - - IP_STATS_INC(ip.recv); - - /* identify the IP header */ - iphdr = p->payload; - - - if (iphdr->v != 6) { - LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n")); -#if IP_DEBUG - ip_debug_print(p); -#endif /* IP_DEBUG */ - pbuf_free(p); - IP_STATS_INC(ip.err); - IP_STATS_INC(ip.drop); - return; - } - - /* is this packet for us? */ - for(netif = netif_list; netif != NULL; netif = netif->next) { -#if IP_DEBUG - LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest ")); - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr ")); - ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest))); - LWIP_DEBUGF(IP_DEBUG, ("\n")); -#endif /* IP_DEBUG */ - if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) { - break; - } - } - - - if (netif == NULL) { - /* packet not for us, route or discard */ -#if IP_FORWARD - ip_forward(p, iphdr); -#endif - pbuf_free(p); - return; - } - - pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len)); - - /* send to upper layers */ -#if IP_DEBUG - /* LWIP_DEBUGF("ip_input: \n"); - ip_debug_print(p); - LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/ -#endif /* IP_DEBUG */ - - if(pbuf_header(p, -IP_HLEN)) { - LWIP_ASSERT("Can't move over header in packet", 0); - return; - } - - switch (iphdr->nexthdr) { - case IP_PROTO_UDP: - udp_input(p, inp); - break; - case IP_PROTO_TCP: - tcp_input(p, inp); - break; -#if LWIP_ICMP - case IP_PROTO_ICMP: - icmp_input(p, inp); - break; -#endif /* LWIP_ICMP */ - default: -#if LWIP_ICMP - /* send ICMP destination protocol unreachable */ - icmp_dest_unreach(p, ICMP_DUR_PROTO); -#endif /* LWIP_ICMP */ - pbuf_free(p); - LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n", - iphdr->nexthdr)); - - IP_STATS_INC(ip.proterr); - IP_STATS_INC(ip.drop); - } - PERF_STOP("ip_input"); -} - - -/* ip_output_if: - * - * Sends an IP packet on a network interface. This function constructs the IP header - * and calculates the IP header checksum. If the source IP address is NULL, - * the IP address of the outgoing network interface is filled in as source address. - */ - -err_t -ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, - u8_t proto, struct netif *netif) -{ - struct ip_hdr *iphdr; - - PERF_START; - - LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); - if (pbuf_header(p, IP_HLEN)) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n")); - IP_STATS_INC(ip.err); - - return ERR_BUF; - } - LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len)); - - iphdr = p->payload; - - - if (dest != IP_HDRINCL) { - LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n")); - iphdr->hoplim = ttl; - iphdr->nexthdr = proto; - iphdr->len = htons(p->tot_len - IP_HLEN); - ip_addr_set(&(iphdr->dest), dest); - - iphdr->v = 6; - - if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); - } else { - ip_addr_set(&(iphdr->src), src); - } - - } else { - dest = &(iphdr->dest); - } - - IP_STATS_INC(ip.xmit); - - LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len)); -#if IP_DEBUG - ip_debug_print(p); -#endif /* IP_DEBUG */ - - PERF_STOP("ip_output_if"); - return netif->output(netif, p, dest); -} - -/* ip_output: - * - * Simple interface to ip_output_if. It finds the outgoing network interface and - * calls upon ip_output_if to do the actual work. - */ - -err_t -ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto) -{ - struct netif *netif; - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - return ip_output_if (p, src, dest, ttl, proto, netif); -} - -#if LWIP_NETIF_HWADDRHINT -err_t -ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) -{ - struct netif *netif; - err_t err; - - if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); - IP_STATS_INC(ip.rterr); - return ERR_RTE; - } - - LWIP_NETIF_HWADDRHINT(netif, addr_hint); - err = ip_output_if(p, src, dest, ttl, tos, proto, netif); - LWIP_NETIF_HWADDRHINT(netif, NULL); - - return err; -} -#endif /* LWIP_NETIF_HWADDRHINT*/ - -#if IP_DEBUG -void -ip_debug_print(struct pbuf *p) -{ - struct ip_hdr *iphdr = p->payload; - - LWIP_DEBUGF(IP_DEBUG, ("IP header:\n")); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" | %"X16_F"%"X16_F" | %"X16_F"%"X16_F" | (v, traffic class, flow label)\n", - iphdr->v, - iphdr->tclass1, iphdr->tclass2, - iphdr->flow1, iphdr->flow2)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %5"U16_F" | %2"U16_F" | %2"U16_F" | (len, nexthdr, hoplim)\n", - ntohs(iphdr->len), - iphdr->nexthdr, - iphdr->hoplim)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n", - (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff, - ntohl(iphdr->src.addr[0]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n", - (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff, - ntohl(iphdr->src.addr[1]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n", - (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff, - ntohl(iphdr->src.addr[2]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (src)\n", - (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff, - ntohl(iphdr->src.addr[3]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n", - (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff, - ntohl(iphdr->dest.addr[0]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n", - (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff, - ntohl(iphdr->dest.addr[1]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n", - (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff, - ntohl(iphdr->dest.addr[2]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("| %4"X32_F" | %4"X32_F" | (dest)\n", - (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff, - ntohl(iphdr->dest.addr[3]) & 0xffff)); - LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* IP_DEBUG */ diff --git a/ext/lwip/src/core/ipv6/ip6_addr.c b/ext/lwip/src/core/ipv6/ip6_addr.c deleted file mode 100644 index 2da6cea4..00000000 --- a/ext/lwip/src/core/ipv6/ip6_addr.c +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" -#include "lwip/ip_addr.h" -#include "lwip/inet.h" - -u8_t -ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, - struct ip_addr *mask) -{ - return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) && - (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) && - (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) && - (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3])); - -} - -u8_t -ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2) -{ - return(addr1->addr[0] == addr2->addr[0] && - addr1->addr[1] == addr2->addr[1] && - addr1->addr[2] == addr2->addr[2] && - addr1->addr[3] == addr2->addr[3]); -} - -void -ip_addr_set(struct ip_addr *dest, struct ip_addr *src) -{ - SMEMCPY(dest, src, sizeof(struct ip_addr)); - /* dest->addr[0] = src->addr[0]; - dest->addr[1] = src->addr[1]; - dest->addr[2] = src->addr[2]; - dest->addr[3] = src->addr[3];*/ -} - -u8_t -ip_addr_isany(struct ip_addr *addr) -{ - if (addr == NULL) return 1; - return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0); -} diff --git a/ext/lwip/src/core/mem.c b/ext/lwip/src/core/mem.c deleted file mode 100644 index f1bb3595..00000000 --- a/ext/lwip/src/core/mem.c +++ /dev/null @@ -1,675 +0,0 @@ -/** - * @file - * Dynamic memory manager - * - * This is a lightweight replacement for the standard C library malloc(). - * - * If you want to use the standard C library malloc() instead, define - * MEM_LIBC_MALLOC to 1 in your lwipopts.h - * - * To let mem_malloc() use pools (prevents fragmentation and is much faster than - * a heap but might waste some memory), define MEM_USE_POOLS to 1, define - * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list - * of pools like this (more pools can be added between _START and _END): - * - * Define three pools with sizes 256, 512, and 1512 bytes - * LWIP_MALLOC_MEMPOOL_START - * LWIP_MALLOC_MEMPOOL(20, 256) - * LWIP_MALLOC_MEMPOOL(10, 512) - * LWIP_MALLOC_MEMPOOL(5, 1512) - * LWIP_MALLOC_MEMPOOL_END - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/sys.h" -#include "lwip/stats.h" -#include "lwip/err.h" - -#include <string.h> - -#if MEM_USE_POOLS -/* lwIP head implemented with different sized pools */ - -/** - * Allocate memory: determine the smallest pool that is big enough - * to contain an element of 'size' and get an element from that pool. - * - * @param size the size in bytes of the memory needed - * @return a pointer to the allocated memory or NULL if the pool is empty - */ -void * -mem_malloc(mem_size_t size) -{ - void *ret; - struct memp_malloc_helper *element; - memp_t poolnr; - mem_size_t required_size = size + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - - for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { -#if MEM_USE_POOLS_TRY_BIGGER_POOL -again: -#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ - /* is this pool big enough to hold an element of the required size - plus a struct memp_malloc_helper that saves the pool this element came from? */ - if (required_size <= memp_sizes[poolnr]) { - break; - } - } - if (poolnr > MEMP_POOL_LAST) { - LWIP_ASSERT("mem_malloc(): no pool is that big!", 0); - return NULL; - } - element = (struct memp_malloc_helper*)memp_malloc(poolnr); - if (element == NULL) { - /* No need to DEBUGF or ASSERT: This error is already - taken care of in memp.c */ -#if MEM_USE_POOLS_TRY_BIGGER_POOL - /** Try a bigger pool if this one is empty! */ - if (poolnr < MEMP_POOL_LAST) { - poolnr++; - goto again; - } -#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ - return NULL; - } - - /* save the pool number this element came from */ - element->poolnr = poolnr; - /* and return a pointer to the memory directly after the struct memp_malloc_helper */ - ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)); - - return ret; -} - -/** - * Free memory previously allocated by mem_malloc. Loads the pool number - * and calls memp_free with that pool number to put the element back into - * its pool - * - * @param rmem the memory element to free - */ -void -mem_free(void *rmem) -{ - struct memp_malloc_helper *hmem; - - LWIP_ASSERT("rmem != NULL", (rmem != NULL)); - LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem))); - - /* get the original struct memp_malloc_helper */ - hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper))); - - LWIP_ASSERT("hmem != NULL", (hmem != NULL)); - LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem))); - LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX)); - - /* and put it in the pool we saved earlier */ - memp_free(hmem->poolnr, hmem); -} - -#else /* MEM_USE_POOLS */ -/* lwIP replacement for your libc malloc() */ - -/** - * The heap is made up as a list of structs of this type. - * This does not have to be aligned since for getting its size, - * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes. - */ -struct mem { - /** index (-> ram[next]) of the next struct */ - mem_size_t next; - /** index (-> ram[prev]) of the previous struct */ - mem_size_t prev; - /** 1: this area is used; 0: this area is unused */ - u8_t used; -}; - -/** All allocated blocks will be MIN_SIZE bytes big, at least! - * MIN_SIZE can be overridden to suit your needs. Smaller values save space, - * larger values could prevent too small blocks to fragment the RAM too much. */ -#ifndef MIN_SIZE -#define MIN_SIZE 12 -#endif /* MIN_SIZE */ -/* some alignment macros: we define them here for better source code layout */ -#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) -#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) -#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) - -/** If you want to relocate the heap to external memory, simply define - * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. - * If so, make sure the memory at that location is big enough (see below on - * how that space is calculated). */ -#ifndef LWIP_RAM_HEAP_POINTER -/** the heap. we need one struct mem at the end and some room for alignment */ -u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; -#define LWIP_RAM_HEAP_POINTER ram_heap -#endif /* LWIP_RAM_HEAP_POINTER */ - -/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ -static u8_t *ram; -/** the last entry, always unused! */ -static struct mem *ram_end; -/** pointer to the lowest free block, this is used for faster search */ -static struct mem *lfree; - -/** concurrent access protection */ -#if !NO_SYS -static sys_mutex_t mem_mutex; -#endif - -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - -static volatile u8_t mem_free_count; - -/* Allow mem_free from other (e.g. interrupt) context */ -#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free) -#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free) -#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free) -#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc) -#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc) - -#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -/* Protect the heap only by using a semaphore */ -#define LWIP_MEM_FREE_DECL_PROTECT() -#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) -#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) -/* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ -#define LWIP_MEM_ALLOC_DECL_PROTECT() -#define LWIP_MEM_ALLOC_PROTECT() -#define LWIP_MEM_ALLOC_UNPROTECT() - -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - -/** - * "Plug holes" by combining adjacent empty struct mems. - * After this function is through, there should not exist - * one empty struct mem pointing to another empty struct mem. - * - * @param mem this points to a struct mem which just has been freed - * @internal this function is only called by mem_free() and mem_trim() - * - * This assumes access to the heap is protected by the calling function - * already. - */ -static void -plug_holes(struct mem *mem) -{ - struct mem *nmem; - struct mem *pmem; - - LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram); - LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end); - LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0); - - /* plug hole forward */ - LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); - - nmem = (struct mem *)(void *)&ram[mem->next]; - if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { - /* if mem->next is unused and not end of ram, combine mem and mem->next */ - if (lfree == nmem) { - lfree = mem; - } - mem->next = nmem->next; - ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); - } - - /* plug hole backward */ - pmem = (struct mem *)(void *)&ram[mem->prev]; - if (pmem != mem && pmem->used == 0) { - /* if mem->prev is unused, combine mem and mem->prev */ - if (lfree == mem) { - lfree = pmem; - } - pmem->next = mem->next; - ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); - } -} - -/** - * Zero the heap and initialize start, end and lowest-free - */ -void -mem_init(void) -{ - struct mem *mem; - - LWIP_ASSERT("Sanity check alignment", - (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); - - /* align the heap */ - ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); - /* initialize the start of the heap */ - mem = (struct mem *)(void *)ram; - mem->next = MEM_SIZE_ALIGNED; - mem->prev = 0; - mem->used = 0; - /* initialize the end of the heap */ - ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; - ram_end->used = 1; - ram_end->next = MEM_SIZE_ALIGNED; - ram_end->prev = MEM_SIZE_ALIGNED; - - /* initialize the lowest-free pointer to the start of the heap */ - lfree = (struct mem *)(void *)ram; - - MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); - - if(sys_mutex_new(&mem_mutex) != ERR_OK) { - LWIP_ASSERT("failed to create mem_mutex", 0); - } -} - -/** - * Put a struct mem back on the heap - * - * @param rmem is the data portion of a struct mem as returned by a previous - * call to mem_malloc() - */ -void -mem_free(void *rmem) -{ - struct mem *mem; - LWIP_MEM_FREE_DECL_PROTECT(); - - if (rmem == NULL) { - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n")); - return; - } - LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0); - - LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return; - } - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - /* Get the corresponding struct mem ... */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... which has to be in a used state ... */ - LWIP_ASSERT("mem_free: mem->used", mem->used); - /* ... and is now unused. */ - mem->used = 0; - - if (mem < lfree) { - /* the newly freed struct is now the lowest */ - lfree = mem; - } - - MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); - - /* finally, see if prev or next are free also */ - plug_holes(mem); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); -} - -/** - * Shrink memory returned by mem_malloc(). - * - * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked - * @param newsize required size after shrinking (needs to be smaller than or - * equal to the previous size) - * @return for compatibility reasons: is always == rmem, at the moment - * or NULL if newsize is > old size, in which case rmem is NOT touched - * or freed! - */ -void * -mem_trim(void *rmem, mem_size_t newsize) -{ - mem_size_t size; - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; - /* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */ - LWIP_MEM_FREE_DECL_PROTECT(); - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - newsize = LWIP_MEM_ALIGN_SIZE(newsize); - - if(newsize < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - newsize = MIN_SIZE_ALIGNED; - } - - if (newsize > MEM_SIZE_ALIGNED) { - return NULL; - } - - LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && - (u8_t *)rmem < (u8_t *)ram_end); - - if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { - SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); - /* protect mem stats from concurrent access */ - SYS_ARCH_PROTECT(lev); - MEM_STATS_INC(illegal); - SYS_ARCH_UNPROTECT(lev); - return rmem; - } - /* Get the corresponding struct mem ... */ - mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); - /* ... and its offset pointer */ - ptr = (mem_size_t)((u8_t *)mem - ram); - - size = mem->next - ptr - SIZEOF_STRUCT_MEM; - LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); - if (newsize > size) { - /* not supported */ - return NULL; - } - if (newsize == size) { - /* No change in size, simply return */ - return rmem; - } - - /* protect the heap from concurrent access */ - LWIP_MEM_FREE_PROTECT(); - - mem2 = (struct mem *)(void *)&ram[mem->next]; - if(mem2->used == 0) { - /* The next struct is unused, we can simply move it at little */ - mem_size_t next; - /* remember the old next pointer */ - next = mem2->next; - /* create new struct mem which is moved directly after the shrinked mem */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - if (lfree == mem2) { - lfree = (struct mem *)(void *)&ram[ptr2]; - } - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - /* restore the next pointer */ - mem2->next = next; - /* link it back to mem */ - mem2->prev = ptr; - /* link mem to it */ - mem->next = ptr2; - /* last thing to restore linked list: as we have moved mem2, - * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not - * the end of the heap */ - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* no need to plug holes, we've already done that */ - } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { - /* Next struct is used but there's room for another struct mem with - * at least MIN_SIZE_ALIGNED of data. - * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem - * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED'). - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - mem2 = (struct mem *)(void *)&ram[ptr2]; - if (mem2 < lfree) { - lfree = mem2; - } - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - mem->next = ptr2; - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_DEC_USED(used, (size - newsize)); - /* the original mem->next is used, so no need to plug holes! */ - } - /* else { - next struct mem is used but size between mem and mem2 is not big enough - to create another struct mem - -> don't do anyhting. - -> the remaining space stays unused since it is too small - } */ -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 1; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_FREE_UNPROTECT(); - return rmem; -} - -/** - * Adam's mem_malloc() plus solution for bug #17922 - * Allocate a block of memory with a minimum of 'size' bytes. - * - * @param size is the minimum size of the requested block in bytes. - * @return pointer to allocated memory or NULL if no free memory was found. - * - * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT). - */ - #include <stdio.h> - -void * -mem_malloc(mem_size_t size) -{ - mem_size_t ptr, ptr2; - struct mem *mem, *mem2; -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - u8_t local_mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_MEM_ALLOC_DECL_PROTECT(); - - if (size == 0) { - return NULL; - } - - /* Expand the size of the allocated memory region so that we can - adjust for alignment. */ - size = LWIP_MEM_ALIGN_SIZE(size); - - if(size < MIN_SIZE_ALIGNED) { - /* every data block must be at least MIN_SIZE_ALIGNED long */ - size = MIN_SIZE_ALIGNED; - } - - if (size > MEM_SIZE_ALIGNED) { - return NULL; - } - - /* protect the heap from concurrent access */ - sys_mutex_lock(&mem_mutex); - LWIP_MEM_ALLOC_PROTECT(); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* run as long as a mem_free disturbed mem_malloc or mem_trim */ - do { - local_mem_free_count = 0; -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - - /* Scan through the heap searching for a free block that is big enough, - * beginning with the lowest free block. - */ - printf("ptr = (mem_size_t)((u8_t *)lfree - ram) = %d\n", (mem_size_t)((u8_t *)lfree - ram)); - printf("MEM_SIZE_ALIGNED - size = %d\n", MEM_SIZE_ALIGNED - size); - //printf("\n", ); - - for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; - ptr = ((struct mem *)(void *)&ram[ptr])->next) { - -printf("ptr = 0x%x\n", ptr); - mem = (struct mem *)(void *)&ram[ptr]; - printf("mem = 0x%x\n", mem); -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - printf("A\n"); - LWIP_MEM_ALLOC_UNPROTECT(); - /* allow mem_free or mem_trim to run */ - printf("B\n"); - LWIP_MEM_ALLOC_PROTECT(); - printf("C\n"); - if (mem_free_count != 0) { - printf("mem_free_count != 0\n"); - /* If mem_free or mem_trim have run, we have to restart since they - could have altered our current struct mem. */ - local_mem_free_count = 1; - break; - } -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - -if(mem == NULL) - printf("mem == NULL\n"); - - if ((!mem->used) && - (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) { - /* mem is not used and at least perfect fit is possible: - * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */ - - if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) { - /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing - * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem') - * -> split large block, create empty remainder, - * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if - * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size, - * struct mem would fit in but no data between mem2 and mem2->next - * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty - * region that couldn't hold data, but when mem->next gets freed, - * the 2 regions would be combined, resulting in more free memory - */ - ptr2 = ptr + SIZEOF_STRUCT_MEM + size; - /* create mem2 struct */ - mem2 = (struct mem *)(void *)&ram[ptr2]; - mem2->used = 0; - mem2->next = mem->next; - mem2->prev = ptr; - /* and insert it between mem and mem->next */ - mem->next = ptr2; - mem->used = 1; - - if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; - } - MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); - } else { - /* (a mem2 struct does no fit into the user data space of mem and mem->next will always - * be used at this point: if not we have 2 unused structs in a row, plug_holes should have - * take care of this). - * -> near fit or excact fit: do not split, no mem2 creation - * also can't move mem->next directly behind mem, since mem->next - * will always be used at this point! - */ - mem->used = 1; - MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); - } -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT -mem_malloc_adjust_lfree: -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - if (mem == lfree) { - struct mem *cur = lfree; - /* Find next free block after mem and update lowest free pointer */ - while (cur->used && cur != ram_end) { -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - mem_free_count = 0; - LWIP_MEM_ALLOC_UNPROTECT(); - /* prevent high interrupt latency... */ - LWIP_MEM_ALLOC_PROTECT(); - if (mem_free_count != 0) { - /* If mem_free or mem_trim have run, we have to restart since they - could have altered our current struct mem or lfree. */ - goto mem_malloc_adjust_lfree; - } -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - cur = (struct mem *)(void *)&ram[cur->next]; - } - lfree = cur; - LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); - } - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", - (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); - LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", - ((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0); - LWIP_ASSERT("mem_malloc: sanity check alignment", - (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0); - - return (u8_t *)mem + SIZEOF_STRUCT_MEM; - } - } -#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT - /* if we got interrupted by a mem_free, try again */ - } while(local_mem_free_count != 0); -#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); - MEM_STATS_INC(err); - LWIP_MEM_ALLOC_UNPROTECT(); - sys_mutex_unlock(&mem_mutex); - return NULL; -} - -#endif /* MEM_USE_POOLS */ -/** - * Contiguously allocates enough space for count objects that are size bytes - * of memory each and returns a pointer to the allocated memory. - * - * The allocated memory is filled with bytes of value zero. - * - * @param count number of objects to allocate - * @param size size of the objects to allocate - * @return pointer to allocated memory / NULL pointer if there is an error - */ -void *mem_calloc(mem_size_t count, mem_size_t size) -{ - void *p; - - /* allocate 'count' objects of size 'size' */ - p = mem_malloc(count * size); - if (p) { - /* zero the memory */ - memset(p, 0, count * size); - } - return p; -} - -#endif /* !MEM_LIBC_MALLOC */ diff --git a/ext/lwip/src/core/memp.c b/ext/lwip/src/core/memp.c deleted file mode 100644 index 9f680e24..00000000 --- a/ext/lwip/src/core/memp.c +++ /dev/null @@ -1,470 +0,0 @@ -/** - * @file - * Dynamic pool memory manager - * - * lwIP has dedicated pools for many structures (netconn, protocol control blocks, - * packet buffers, ...). All these pools are managed here. - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/udp.h" -#include "lwip/raw.h" -#include "lwip/tcp_impl.h" -#include "lwip/igmp.h" -#include "lwip/api.h" -#include "lwip/api_msg.h" -#include "lwip/tcpip.h" -#include "lwip/sys.h" -#include "lwip/timers.h" -#include "lwip/stats.h" -#include "netif/etharp.h" -#include "lwip/ip_frag.h" -#include "lwip/snmp_structs.h" -#include "lwip/snmp_msg.h" -#include "lwip/dns.h" -#include "netif/ppp_oe.h" - -#include <string.h> - -#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ - -struct memp { - struct memp *next; -#if MEMP_OVERFLOW_CHECK - const char *file; - int line; -#endif /* MEMP_OVERFLOW_CHECK */ -}; - -#if MEMP_OVERFLOW_CHECK -/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning - * and at the end of each element, initialize them as 0xcd and check - * them later. */ -/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free, - * every single element in each pool is checked! - * This is VERY SLOW but also very helpful. */ -/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in - * lwipopts.h to change the amount reserved for checking. */ -#ifndef MEMP_SANITY_REGION_BEFORE -#define MEMP_SANITY_REGION_BEFORE 16 -#endif /* MEMP_SANITY_REGION_BEFORE*/ -#if MEMP_SANITY_REGION_BEFORE > 0 -#define MEMP_SANITY_REGION_BEFORE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE) -#else -#define MEMP_SANITY_REGION_BEFORE_ALIGNED 0 -#endif /* MEMP_SANITY_REGION_BEFORE*/ -#ifndef MEMP_SANITY_REGION_AFTER -#define MEMP_SANITY_REGION_AFTER 16 -#endif /* MEMP_SANITY_REGION_AFTER*/ -#if MEMP_SANITY_REGION_AFTER > 0 -#define MEMP_SANITY_REGION_AFTER_ALIGNED LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER) -#else -#define MEMP_SANITY_REGION_AFTER_ALIGNED 0 -#endif /* MEMP_SANITY_REGION_AFTER*/ - -/* MEMP_SIZE: save space for struct memp and for sanity check */ -#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED) -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED) - -#else /* MEMP_OVERFLOW_CHECK */ - -/* No sanity checks - * We don't need to preserve the struct memp while not allocated, so we - * can save a little space and set MEMP_SIZE to 0. - */ -#define MEMP_SIZE 0 -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) - -#endif /* MEMP_OVERFLOW_CHECK */ - -/** This array holds the first free element of each pool. - * Elements form a linked list. */ -static struct memp *memp_tab[MEMP_MAX]; - -#else /* MEMP_MEM_MALLOC */ - -#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x)) - -#endif /* MEMP_MEM_MALLOC */ - -/** This array holds the element sizes of each pool. */ -#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC -static -#endif -const u16_t memp_sizes[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size), -#include "lwip/memp_std.h" -}; - -#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */ - -/** This array holds the number of elements in each pool. */ -static const u16_t memp_num[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc) (num), -#include "lwip/memp_std.h" -}; - -/** This array holds a textual description of each pool. */ -#ifdef LWIP_DEBUG -static const char *memp_desc[MEMP_MAX] = { -#define LWIP_MEMPOOL(name,num,size,desc) (desc), -#include "lwip/memp_std.h" -}; -#endif /* LWIP_DEBUG */ - -#if MEMP_SEPARATE_POOLS - -/** This creates each memory pool. These are named memp_memory_XXX_base (where - * XXX is the name of the pool defined in memp_std.h). - * To relocate a pool, declare it as extern in cc.h. Example for GCC: - * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[]; - */ -#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \ - [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; -#include "lwip/memp_std.h" - -/** This array holds the base of each memory pool. */ -static u8_t *const memp_bases[] = { -#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base, -#include "lwip/memp_std.h" -}; - -#else /* MEMP_SEPARATE_POOLS */ - -/** This is the actual memory used by the pools (all pools in one big block). */ -static u8_t memp_memory[MEM_ALIGNMENT - 1 -#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) -#include "lwip/memp_std.h" -]; - -#endif /* MEMP_SEPARATE_POOLS */ - -#if MEMP_SANITY_CHECK -/** - * Check that memp-lists don't form a circle, using "Floyd's cycle-finding algorithm". - */ -static int -memp_sanity(void) -{ - s16_t i; - struct memp *t, *h; - - for (i = 0; i < MEMP_MAX; i++) { - t = memp_tab[i]; - if(t != NULL) { - for (h = t->next; (t != NULL) && (h != NULL); t = t->next, - h = (((h->next != NULL) && (h->next->next != NULL)) ? h->next->next : NULL)) { - if (t == h) { - return 0; - } - } - } - } - return 1; -} -#endif /* MEMP_SANITY_CHECK*/ -#if MEMP_OVERFLOW_CHECK -#if defined(LWIP_DEBUG) && MEMP_STATS -static const char * memp_overflow_names[] = { -#define LWIP_MEMPOOL(name,num,size,desc) "/"desc, -#include "lwip/memp_std.h" - }; -#endif - -/** - * Check if a memp element was victim of an overflow - * (e.g. the restricted area after it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void -memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; - for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp overflow in pool "; - char digit[] = "0"; - if(memp_type >= 10) { - digit[0] = '0' + (memp_type/10); - strcat(errstr, digit); - } - digit[0] = '0' + (memp_type%10); - strcat(errstr, digit); -#if defined(LWIP_DEBUG) && MEMP_STATS - strcat(errstr, memp_overflow_names[memp_type]); -#endif - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Check if a memp element was victim of an underflow - * (e.g. the restricted area before it has been altered) - * - * @param p the memp element to check - * @param memp_type the pool p comes from - */ -static void -memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) -{ - u16_t k; - u8_t *m; -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { - if (m[k] != 0xcd) { - char errstr[128] = "detected memp underflow in pool "; - char digit[] = "0"; - if(memp_type >= 10) { - digit[0] = '0' + (memp_type/10); - strcat(errstr, digit); - } - digit[0] = '0' + (memp_type%10); - strcat(errstr, digit); -#if defined(LWIP_DEBUG) && MEMP_STATS - strcat(errstr, memp_overflow_names[memp_type]); -#endif - LWIP_ASSERT(errstr, 0); - } - } -#endif -} - -/** - * Do an overflow check for all elements in every pool. - * - * @see memp_overflow_check_element for a description of the check - */ -static void -memp_overflow_check_all(void) -{ - u16_t i, j; - struct memp *p; - - p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); - for (i = 0; i < MEMP_MAX; ++i) { - p = p; - for (j = 0; j < memp_num[i]; ++j) { - memp_overflow_check_element_overflow(p, i); - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } - p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); - for (i = 0; i < MEMP_MAX; ++i) { - p = p; - for (j = 0; j < memp_num[i]; ++j) { - memp_overflow_check_element_underflow(p, i); - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } -} - -/** - * Initialize the restricted areas of all memp elements in every pool. - */ -static void -memp_overflow_init(void) -{ - u16_t i, j; - struct memp *p; - u8_t *m; - - p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); - for (i = 0; i < MEMP_MAX; ++i) { - p = p; - for (j = 0; j < memp_num[i]; ++j) { -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED); -#endif -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_sizes[i]; - memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED); -#endif - p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); - } - } -} -#endif /* MEMP_OVERFLOW_CHECK */ - -/** - * Initialize this module. - * - * Carves out memp_memory into linked lists for each pool-type. - */ -void -memp_init(void) -{ - struct memp *memp; - u16_t i, j; - - for (i = 0; i < MEMP_MAX; ++i) { - MEMP_STATS_AVAIL(used, i, 0); - MEMP_STATS_AVAIL(max, i, 0); - MEMP_STATS_AVAIL(err, i, 0); - MEMP_STATS_AVAIL(avail, i, memp_num[i]); - } - -#if !MEMP_SEPARATE_POOLS - memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory); -#endif /* !MEMP_SEPARATE_POOLS */ - /* for every pool: */ - for (i = 0; i < MEMP_MAX; ++i) { - memp_tab[i] = NULL; -#if MEMP_SEPARATE_POOLS - memp = (struct memp*)memp_bases[i]; -#endif /* MEMP_SEPARATE_POOLS */ - /* create a linked list of memp elements */ - for (j = 0; j < memp_num[i]; ++j) { - memp->next = memp_tab[i]; - memp_tab[i] = memp; - memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] -#if MEMP_OVERFLOW_CHECK - + MEMP_SANITY_REGION_AFTER_ALIGNED -#endif - ); - } - } -#if MEMP_OVERFLOW_CHECK - memp_overflow_init(); - /* check everything a first time to see if it worked */ - memp_overflow_check_all(); -#endif /* MEMP_OVERFLOW_CHECK */ -} - -/** - * Get an element from a specific pool. - * - * @param type the pool to get an element from - * - * the debug version has two more parameters: - * @param file file name calling this function - * @param line number of line where this function is called - * - * @return a pointer to the allocated memory or a NULL pointer on error - */ -void * -#if !MEMP_OVERFLOW_CHECK -memp_malloc(memp_t type) -#else -memp_malloc_fn(memp_t type, const char* file, const int line) -#endif -{ - struct memp *memp; - SYS_ARCH_DECL_PROTECT(old_level); - - LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;); - - SYS_ARCH_PROTECT(old_level); -#if MEMP_OVERFLOW_CHECK >= 2 - memp_overflow_check_all(); -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ - - memp = memp_tab[type]; - - if (memp != NULL) { - memp_tab[type] = memp->next; -#if MEMP_OVERFLOW_CHECK - memp->next = NULL; - memp->file = file; - memp->line = line; -#endif /* MEMP_OVERFLOW_CHECK */ - MEMP_STATS_INC_USED(used, type); - LWIP_ASSERT("memp_malloc: memp properly aligned", - ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); - memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE); - } else { - LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); - MEMP_STATS_INC(err, type); - } - - SYS_ARCH_UNPROTECT(old_level); - - return memp; -} - -/** - * Put an element back into its pool. - * - * @param type the pool where to put mem - * @param mem the memp element to free - */ -void -memp_free(memp_t type, void *mem) -{ - struct memp *memp; - SYS_ARCH_DECL_PROTECT(old_level); - - if (mem == NULL) { - return; - } - LWIP_ASSERT("memp_free: mem properly aligned", - ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); - - memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); - - SYS_ARCH_PROTECT(old_level); -#if MEMP_OVERFLOW_CHECK -#if MEMP_OVERFLOW_CHECK >= 2 - memp_overflow_check_all(); -#else - memp_overflow_check_element_overflow(memp, type); - memp_overflow_check_element_underflow(memp, type); -#endif /* MEMP_OVERFLOW_CHECK >= 2 */ -#endif /* MEMP_OVERFLOW_CHECK */ - - MEMP_STATS_DEC(used, type); - - memp->next = memp_tab[type]; - memp_tab[type] = memp; - -#if MEMP_SANITY_CHECK - LWIP_ASSERT("memp sanity", memp_sanity()); -#endif /* MEMP_SANITY_CHECK */ - - SYS_ARCH_UNPROTECT(old_level); -} - -#endif /* MEMP_MEM_MALLOC */ diff --git a/ext/lwip/src/core/netif.c b/ext/lwip/src/core/netif.c deleted file mode 100644 index 8c1e4e58..00000000 --- a/ext/lwip/src/core/netif.c +++ /dev/null @@ -1,774 +0,0 @@ -/** - * @file - * lwIP network interface abstraction - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/tcp_impl.h" -#include "lwip/snmp.h" -#include "lwip/igmp.h" -#include "netif/etharp.h" -#include "lwip/stats.h" -#if ENABLE_LOOPBACK -#include "lwip/sys.h" -#if LWIP_NETIF_LOOPBACK_MULTITHREADING -#include "lwip/tcpip.h" -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ - -#if LWIP_AUTOIP -#include "lwip/autoip.h" -#endif /* LWIP_AUTOIP */ -#if LWIP_DHCP -#include "lwip/dhcp.h" -#endif /* LWIP_DHCP */ - -#if LWIP_NETIF_STATUS_CALLBACK -#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) -#else -#define NETIF_STATUS_CALLBACK(n) -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -#if LWIP_NETIF_LINK_CALLBACK -#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) -#else -#define NETIF_LINK_CALLBACK(n) -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -struct netif *netif_list; -struct netif *netif_default; - -static u8_t netif_num; - -#if LWIP_HAVE_LOOPIF -static struct netif loop_netif; - -/** - * Initialize a lwip network interface structure for a loopback interface - * - * @param netif the lwip network interface structure for this loopif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - */ -static err_t -netif_loopif_init(struct netif *netif) -{ - /* initialize the snmp variables and counters inside the struct netif - * ifSpeed: no assumption can be made! - */ - NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); - - netif->name[0] = 'l'; - netif->name[1] = 'o'; - netif->output = netif_loop_output; - return ERR_OK; -} -#endif /* LWIP_HAVE_LOOPIF */ - -void -netif_init(void) -{ -#if LWIP_HAVE_LOOPIF - ip_addr_t loop_ipaddr, loop_netmask, loop_gw; - IP4_ADDR(&loop_gw, 127,0,0,1); - IP4_ADDR(&loop_ipaddr, 127,0,0,1); - IP4_ADDR(&loop_netmask, 255,0,0,0); - -#if NO_SYS - netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); -#else /* NO_SYS */ - netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); -#endif /* NO_SYS */ - netif_set_up(&loop_netif); - -#endif /* LWIP_HAVE_LOOPIF */ -} - -/** - * Add a network interface to the list of lwIP netifs. - * - * @param netif a pre-allocated netif structure - * @param ipaddr IP address for the new netif - * @param netmask network mask for the new netif - * @param gw default gateway IP address for the new netif - * @param state opaque data passed to the new netif - * @param init callback function that initializes the interface - * @param input callback function that is called to pass - * ingress packets up in the protocol layer stack. - * - * @return netif, or NULL if failed. - */ -struct netif * -netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) -{ - - LWIP_ASSERT("No init function given", init != NULL); - - /* reset new interface configuration state */ - ip_addr_set_zero(&netif->ip_addr); - ip_addr_set_zero(&netif->netmask); - ip_addr_set_zero(&netif->gw); - netif->flags = 0; -#if LWIP_DHCP - /* netif not under DHCP control by default */ - netif->dhcp = NULL; -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - /* netif not under AutoIP control by default */ - netif->autoip = NULL; -#endif /* LWIP_AUTOIP */ -#if LWIP_NETIF_STATUS_CALLBACK - netif->status_callback = NULL; -#endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_LINK_CALLBACK - netif->link_callback = NULL; -#endif /* LWIP_NETIF_LINK_CALLBACK */ -#if LWIP_IGMP - netif->igmp_mac_filter = NULL; -#endif /* LWIP_IGMP */ -#if ENABLE_LOOPBACK - netif->loop_first = NULL; - netif->loop_last = NULL; -#endif /* ENABLE_LOOPBACK */ - - /* remember netif specific state information data */ - netif->state = state; - netif->num = netif_num++; - netif->input = input; - NETIF_SET_HWADDRHINT(netif, NULL); -#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS - netif->loop_cnt_current = 0; -#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */ - - netif_set_addr(netif, ipaddr, netmask, gw); - - /* call user specified initialization function for netif */ - if (init(netif) != ERR_OK) { - return NULL; - } - - /* add this netif to the list */ - netif->next = netif_list; - netif_list = netif; - snmp_inc_iflist(); - -#if LWIP_IGMP - /* start IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_start(netif); - } -#endif /* LWIP_IGMP */ - - LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ", - netif->name[0], netif->name[1])); - ip_addr_debug_print(NETIF_DEBUG, ipaddr); - LWIP_DEBUGF(NETIF_DEBUG, (" netmask ")); - ip_addr_debug_print(NETIF_DEBUG, netmask); - LWIP_DEBUGF(NETIF_DEBUG, (" gw ")); - ip_addr_debug_print(NETIF_DEBUG, gw); - LWIP_DEBUGF(NETIF_DEBUG, ("\n")); - return netif; -} - -/** - * Change IP address configuration for a network interface (including netmask - * and default gateway). - * - * @param netif the network interface to change - * @param ipaddr the new IP address - * @param netmask the new netmask - * @param gw the new default gateway - */ -void -netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, - ip_addr_t *gw) -{ - netif_set_ipaddr(netif, ipaddr); - netif_set_netmask(netif, netmask); - netif_set_gw(netif, gw); -} - -/** - * Remove a network interface from the list of lwIP netifs. - * - * @param netif the network interface to remove - */ -void -netif_remove(struct netif *netif) -{ - if (netif == NULL) { - return; - } - -#if LWIP_IGMP - /* stop IGMP processing */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_stop(netif); - } -#endif /* LWIP_IGMP */ - if (netif_is_up(netif)) { - /* set netif down before removing (call callback function) */ - netif_set_down(netif); - } - - snmp_delete_ipaddridx_tree(netif); - - /* is it the first netif? */ - if (netif_list == netif) { - netif_list = netif->next; - } else { - /* look for netif further down the list */ - struct netif * tmpNetif; - for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { - if (tmpNetif->next == netif) { - tmpNetif->next = netif->next; - break; - } - } - if (tmpNetif == NULL) - return; /* we didn't find any netif today */ - } - snmp_dec_iflist(); - /* this netif is default? */ - if (netif_default == netif) { - /* reset default netif */ - netif_set_default(NULL); - } -#if LWIP_NETIF_REMOVE_CALLBACK - if (netif->remove_callback) { - netif->remove_callback(netif); - } -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); -} - -/** - * Find a network interface by searching for its name - * - * @param name the name of the netif (like netif->name) plus concatenated number - * in ascii representation (e.g. 'en0') - */ -struct netif * -netif_find(char *name) -{ - struct netif *netif; - u8_t num; - - if (name == NULL) { - return NULL; - } - - num = name[2] - '0'; - - for(netif = netif_list; netif != NULL; netif = netif->next) { - if (num == netif->num && - name[0] == netif->name[0] && - name[1] == netif->name[1]) { - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1])); - return netif; - } - } - LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1])); - return NULL; -} - -/** - * Change the IP address of a network interface - * - * @param netif the network interface to change - * @param ipaddr the new IP address - * - * @note call netif_set_addr() if you also want to change netmask and - * default gateway - */ -void -netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) -{ - /* TODO: Handling of obsolete pcbs */ - /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ -#if LWIP_TCP - struct tcp_pcb *pcb; - struct tcp_pcb_listen *lpcb; - - /* address is actually being changed? */ - if (ipaddr && (ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { - /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); - pcb = tcp_active_pcbs; - while (pcb != NULL) { - /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) -#if LWIP_AUTOIP - /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ - && !ip_addr_islinklocal(&(pcb->local_ip)) -#endif /* LWIP_AUTOIP */ - ) { - /* this connection must be aborted */ - struct tcp_pcb *next = pcb->next; - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); - tcp_abort(pcb); - pcb = next; - } else { - pcb = pcb->next; - } - } - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - /* PCB bound to current local interface address? */ - if ((!(ip_addr_isany(&(lpcb->local_ip)))) && - (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) { - /* The PCB is listening to the old ipaddr and - * is set to listen to the new one instead */ - ip_addr_set(&(lpcb->local_ip), ipaddr); - } - } - } -#endif - snmp_delete_ipaddridx_tree(netif); - snmp_delete_iprteidx_tree(0,netif); - /* set new IP address to netif */ - ip_addr_set(&(netif->ip_addr), ipaddr); - snmp_insert_ipaddridx_tree(netif); - snmp_insert_iprteidx_tree(0,netif); - - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->ip_addr), - ip4_addr2_16(&netif->ip_addr), - ip4_addr3_16(&netif->ip_addr), - ip4_addr4_16(&netif->ip_addr))); -} - -/** - * Change the default gateway for a network interface - * - * @param netif the network interface to change - * @param gw the new default gateway - * - * @note call netif_set_addr() if you also want to change ip address and netmask - */ -void -netif_set_gw(struct netif *netif, ip_addr_t *gw) -{ - ip_addr_set(&(netif->gw), gw); - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->gw), - ip4_addr2_16(&netif->gw), - ip4_addr3_16(&netif->gw), - ip4_addr4_16(&netif->gw))); -} - -/** - * Change the netmask of a network interface - * - * @param netif the network interface to change - * @param netmask the new netmask - * - * @note call netif_set_addr() if you also want to change ip address and - * default gateway - */ -void -netif_set_netmask(struct netif *netif, ip_addr_t *netmask) -{ - snmp_delete_iprteidx_tree(0, netif); - /* set new netmask to netif */ - ip_addr_set(&(netif->netmask), netmask); - snmp_insert_iprteidx_tree(0, netif); - LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - netif->name[0], netif->name[1], - ip4_addr1_16(&netif->netmask), - ip4_addr2_16(&netif->netmask), - ip4_addr3_16(&netif->netmask), - ip4_addr4_16(&netif->netmask))); -} - -/** - * Set a network interface as the default network interface - * (used to output all packets for which no specific route is found) - * - * @param netif the default network interface - */ -void -netif_set_default(struct netif *netif) -{ - if (netif == NULL) { - /* remove default route */ - snmp_delete_iprteidx_tree(1, netif); - } else { - /* install default route */ - snmp_insert_iprteidx_tree(1, netif); - } - netif_default = netif; - LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n", - netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\'')); -} - -/** - * Bring an interface up, available for processing - * traffic. - * - * @note: Enabling DHCP on a down interface will make it come - * up once configured. - * - * @see dhcp_start() - */ -void netif_set_up(struct netif *netif) -{ - if (!(netif->flags & NETIF_FLAG_UP)) { - netif->flags |= NETIF_FLAG_UP; - -#if LWIP_SNMP - snmp_get_sysuptime(&netif->ts); -#endif /* LWIP_SNMP */ - - NETIF_STATUS_CALLBACK(netif); - - if (netif->flags & NETIF_FLAG_LINK_UP) { -#if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & (NETIF_FLAG_ETHARP)) { - etharp_gratuitous(netif); - } -#endif /* LWIP_ARP */ - -#if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } -#endif /* LWIP_IGMP */ - } - } -} - -/** - * Bring an interface down, disabling any traffic processing. - * - * @note: Enabling DHCP on a down interface will make it come - * up once configured. - * - * @see dhcp_start() - */ -void netif_set_down(struct netif *netif) -{ - if (netif->flags & NETIF_FLAG_UP) { - netif->flags &= ~NETIF_FLAG_UP; -#if LWIP_SNMP - snmp_get_sysuptime(&netif->ts); -#endif - -#if LWIP_ARP - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_cleanup_netif(netif); - } -#endif /* LWIP_ARP */ - NETIF_STATUS_CALLBACK(netif); - } -} - -#if LWIP_NETIF_STATUS_CALLBACK -/** - * Set callback to be called when interface is brought up/down - */ -void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) -{ - if (netif) { - netif->status_callback = status_callback; - } -} -#endif /* LWIP_NETIF_STATUS_CALLBACK */ - -#if LWIP_NETIF_REMOVE_CALLBACK -/** - * Set callback to be called when the interface has been removed - */ -void -netif_set_remove_callback(struct netif *netif, netif_status_callback_fn remove_callback) -{ - if (netif) { - netif->remove_callback = remove_callback; - } -} -#endif /* LWIP_NETIF_REMOVE_CALLBACK */ - -/** - * Called by a driver when its link goes up - */ -void netif_set_link_up(struct netif *netif ) -{ - if (!(netif->flags & NETIF_FLAG_LINK_UP)) { - netif->flags |= NETIF_FLAG_LINK_UP; - -#if LWIP_DHCP - if (netif->dhcp) { - dhcp_network_changed(netif); - } -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP - if (netif->autoip) { - autoip_network_changed(netif); - } -#endif /* LWIP_AUTOIP */ - - if (netif->flags & NETIF_FLAG_UP) { -#if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_gratuitous(netif); - } -#endif /* LWIP_ARP */ - -#if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } -#endif /* LWIP_IGMP */ - } - NETIF_LINK_CALLBACK(netif); - } -} - -/** - * Called by a driver when its link goes down - */ -void netif_set_link_down(struct netif *netif ) -{ - if (netif->flags & NETIF_FLAG_LINK_UP) { - netif->flags &= ~NETIF_FLAG_LINK_UP; - NETIF_LINK_CALLBACK(netif); - } -} - -#if LWIP_NETIF_LINK_CALLBACK -/** - * Set callback to be called when link is brought up/down - */ -void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) -{ - if (netif) { - netif->link_callback = link_callback; - } -} -#endif /* LWIP_NETIF_LINK_CALLBACK */ - -#if ENABLE_LOOPBACK -/** - * Send an IP packet to be received on the same netif (loopif-like). - * The pbuf is simply copied and handed back to netif->input. - * In multithreaded mode, this is done directly since netif->input must put - * the packet on a queue. - * In callback mode, the packet is put on an internal queue and is fed to - * netif->input by netif_poll(). - * - * @param netif the lwip network interface structure - * @param p the (IP) packet to 'send' - * @param ipaddr the ip address to send the packet to (not used) - * @return ERR_OK if the packet has been sent - * ERR_MEM if the pbuf used to copy the packet couldn't be allocated - */ -err_t -netif_loop_output(struct netif *netif, struct pbuf *p, - ip_addr_t *ipaddr) -{ - struct pbuf *r; - err_t err; - struct pbuf *last; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = 0; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if LWIP_SNMP -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* LWIP_SNMP */ - SYS_ARCH_DECL_PROTECT(lev); - LWIP_UNUSED_ARG(ipaddr); - - /* Allocate a new pbuf */ - r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); - if (r == NULL) { - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return ERR_MEM; - } -#if LWIP_LOOPBACK_MAX_PBUFS - clen = pbuf_clen(r); - /* check for overflow or too many pbuf on queue */ - if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || - ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { - pbuf_free(r); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return ERR_MEM; - } - netif->loop_cnt_current += clen; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - - /* Copy the whole pbuf queue p into the single pbuf r */ - if ((err = pbuf_copy(r, p)) != ERR_OK) { - pbuf_free(r); - LINK_STATS_INC(link.memerr); - LINK_STATS_INC(link.drop); - snmp_inc_ifoutdiscards(stats_if); - return err; - } - - /* Put the packet on a linked list which gets emptied through calling - netif_poll(). */ - - /* let last point to the last pbuf in chain r */ - for (last = r; last->next != NULL; last = last->next); - - SYS_ARCH_PROTECT(lev); - if(netif->loop_first != NULL) { - LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL); - netif->loop_last->next = r; - netif->loop_last = last; - } else { - netif->loop_first = r; - netif->loop_last = last; - } - SYS_ARCH_UNPROTECT(lev); - - LINK_STATS_INC(link.xmit); - snmp_add_ifoutoctets(stats_if, p->tot_len); - snmp_inc_ifoutucastpkts(stats_if); - -#if LWIP_NETIF_LOOPBACK_MULTITHREADING - /* For multithreading environment, schedule a call to netif_poll */ - tcpip_callback((tcpip_callback_fn)netif_poll, netif); -#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ - - return ERR_OK; -} - -/** - * Call netif_poll() in the main loop of your application. This is to prevent - * reentering non-reentrant functions like tcp_input(). Packets passed to - * netif_loop_output() are put on a list that is passed to netif->input() by - * netif_poll(). - */ -void -netif_poll(struct netif *netif) -{ - struct pbuf *in; - /* If we have a loopif, SNMP counters are adjusted for it, - * if not they are adjusted for 'netif'. */ -#if LWIP_SNMP -#if LWIP_HAVE_LOOPIF - struct netif *stats_if = &loop_netif; -#else /* LWIP_HAVE_LOOPIF */ - struct netif *stats_if = netif; -#endif /* LWIP_HAVE_LOOPIF */ -#endif /* LWIP_SNMP */ - SYS_ARCH_DECL_PROTECT(lev); - - do { - /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ - SYS_ARCH_PROTECT(lev); - in = netif->loop_first; - if (in != NULL) { - struct pbuf *in_end = in; -#if LWIP_LOOPBACK_MAX_PBUFS - u8_t clen = pbuf_clen(in); - /* adjust the number of pbufs on queue */ - LWIP_ASSERT("netif->loop_cnt_current underflow", - ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); - netif->loop_cnt_current -= clen; -#endif /* LWIP_LOOPBACK_MAX_PBUFS */ - while (in_end->len != in_end->tot_len) { - LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); - in_end = in_end->next; - } - /* 'in_end' now points to the last pbuf from 'in' */ - if (in_end == netif->loop_last) { - /* this was the last pbuf in the list */ - netif->loop_first = netif->loop_last = NULL; - } else { - /* pop the pbuf off the list */ - netif->loop_first = in_end->next; - LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL); - } - /* De-queue the pbuf from its successors on the 'loop_' list. */ - in_end->next = NULL; - } - SYS_ARCH_UNPROTECT(lev); - - if (in != NULL) { - LINK_STATS_INC(link.recv); - snmp_add_ifinoctets(stats_if, in->tot_len); - snmp_inc_ifinucastpkts(stats_if); - /* loopback packets are always IP packets! */ - if (ip_input(in, netif) != ERR_OK) { - pbuf_free(in); - } - /* Don't reference the packet any more! */ - in = NULL; - } - /* go on while there is a packet on the list */ - } while (netif->loop_first != NULL); -} - -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -/** - * Calls netif_poll() for every netif on the netif_list. - */ -void -netif_poll_all(void) -{ - struct netif *netif = netif_list; - /* loop through netifs */ - while (netif != NULL) { - netif_poll(netif); - /* proceed to next network interface */ - netif = netif->next; - } -} -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ -#endif /* ENABLE_LOOPBACK */ diff --git a/ext/lwip/src/core/pbuf.c b/ext/lwip/src/core/pbuf.c deleted file mode 100644 index bd9bf916..00000000 --- a/ext/lwip/src/core/pbuf.c +++ /dev/null @@ -1,1179 +0,0 @@ -/** - * @file - * Packet buffer management - * - * Packets are built from the pbuf data structure. It supports dynamic - * memory allocation for packet contents or can reference externally - * managed packet contents both in RAM and ROM. Quick allocation for - * incoming packets is provided through pools with fixed sized pbufs. - * - * A packet may span over multiple pbufs, chained as a singly linked - * list. This is called a "pbuf chain". - * - * Multiple packets may be queued, also using this singly linked list. - * This is called a "packet queue". - * - * So, a packet queue consists of one or more pbuf chains, each of - * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE - * NOT SUPPORTED!!! Use helper structs to queue multiple packets. - * - * The differences between a pbuf chain and a packet queue are very - * precise but subtle. - * - * The last pbuf of a packet has a ->tot_len field that equals the - * ->len field. It can be found by traversing the list. If the last - * pbuf of a packet has a ->next field other than NULL, more packets - * are on the queue. - * - * Therefore, looping through a pbuf of a single packet, has an - * loop end condition (tot_len == p->len), NOT (next == NULL). - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/stats.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/pbuf.h" -#include "lwip/sys.h" -#include "arch/perf.h" -#if LWIP_TCP && TCP_QUEUE_OOSEQ -#include "lwip/tcp_impl.h" -#endif -#if LWIP_CHECKSUM_ON_COPY -#include "lwip/inet_chksum.h" -#endif - -#include <string.h> - -#define SIZEOF_STRUCT_PBUF LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf)) -/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically - aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ -#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) - -#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ -#define PBUF_POOL_IS_EMPTY() -#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ - -#if !NO_SYS -#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL -#include "lwip/tcpip.h" -#define PBUF_POOL_FREE_OOSEQ_QUEUE_CALL() do { \ - if(tcpip_callback_with_block(pbuf_free_ooseq_callback, NULL, 0) != ERR_OK) { \ - SYS_ARCH_PROTECT(old_level); \ - pbuf_free_ooseq_pending = 0; \ - SYS_ARCH_UNPROTECT(old_level); \ - } } while(0) -#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ -#endif /* !NO_SYS */ - -volatile u8_t pbuf_free_ooseq_pending; -#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty() - -/** - * Attempt to reclaim some memory from queued out-of-sequence TCP segments - * if we run out of pool pbufs. It's better to give priority to new packets - * if we're running out. - * - * This must be done in the correct thread context therefore this function - * can only be used with NO_SYS=0 and through tcpip_callback. - */ -#if !NO_SYS -static -#endif /* !NO_SYS */ -void -pbuf_free_ooseq(void) -{ - struct tcp_pcb* pcb; - SYS_ARCH_DECL_PROTECT(old_level); - - SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_pending = 0; - SYS_ARCH_UNPROTECT(old_level); - - for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { - if (NULL != pcb->ooseq) { - /** Free the ooseq pbufs of one PCB only */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n")); - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - return; - } - } -} - -#if !NO_SYS -/** - * Just a callback function for tcpip_timeout() that calls pbuf_free_ooseq(). - */ -static void -pbuf_free_ooseq_callback(void *arg) -{ - LWIP_UNUSED_ARG(arg); - pbuf_free_ooseq(); -} -#endif /* !NO_SYS */ - -/** Queue a call to pbuf_free_ooseq if not already queued. */ -static void -pbuf_pool_is_empty(void) -{ -#ifndef PBUF_POOL_FREE_OOSEQ_QUEUE_CALL - SYS_ARCH_DECL_PROTECT(old_level); - SYS_ARCH_PROTECT(old_level); - pbuf_free_ooseq_pending = 1; - SYS_ARCH_UNPROTECT(old_level); -#else /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ - u8_t queued; - SYS_ARCH_DECL_PROTECT(old_level); - SYS_ARCH_PROTECT(old_level); - queued = pbuf_free_ooseq_pending; - pbuf_free_ooseq_pending = 1; - SYS_ARCH_UNPROTECT(old_level); - - if(!queued) { - /* queue a call to pbuf_free_ooseq if not already queued */ - //PBUF_POOL_FREE_OOSEQ_QUEUE_CALL(); - } -#endif /* PBUF_POOL_FREE_OOSEQ_QUEUE_CALL */ -} -#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || !PBUF_POOL_FREE_OOSEQ */ - -/** - * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). - * - * The actual memory allocated for the pbuf is determined by the - * layer at which the pbuf is allocated and the requested size - * (from the size parameter). - * - * @param layer flag to define header size - * @param length size of the pbuf's payload - * @param type this parameter decides how and where the pbuf - * should be allocated as follows: - * - * - PBUF_RAM: buffer memory for pbuf is allocated as one large - * chunk. This includes protocol headers as well. - * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for - * protocol headers. Additional headers must be prepended - * by allocating another pbuf and chain in to the front of - * the ROM pbuf. It is assumed that the memory used is really - * similar to ROM in that it is immutable and will not be - * changed. Memory which is dynamic should generally not - * be attached to PBUF_ROM pbufs. Use PBUF_REF instead. - * - PBUF_REF: no buffer memory is allocated for the pbuf, even for - * protocol headers. It is assumed that the pbuf is only - * being used in a single thread. If the pbuf gets queued, - * then pbuf_take should be called to copy the buffer. - * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from - * the pbuf pool that is allocated during pbuf_init(). - * - * @return the allocated pbuf. If multiple pbufs where allocated, this - * is the first pbuf of a pbuf chain. - */ -struct pbuf * -pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) -{ - struct pbuf *p, *q, *r; - u16_t offset; - s32_t rem_len; /* remaining length */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length)); - - /* determine header offset */ - switch (layer) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; - break; - case PBUF_IP: - /* add room for IP layer header */ - offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; - break; - case PBUF_LINK: - /* add room for link layer header */ - offset = PBUF_LINK_HLEN; - break; - case PBUF_RAW: - offset = 0; - break; - default: - LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); - return NULL; - } - - switch (type) { - case PBUF_POOL: - /* allocate head of pbuf chain into p */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); - if (p == NULL) { - PBUF_POOL_IS_EMPTY(); - return NULL; - } - p->type = type; - p->next = NULL; - - /* make the payload pointer point 'offset' bytes into pbuf data memory */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset))); - LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - /* the total length of the pbuf chain is the requested size */ - p->tot_len = length; - /* set the length of the first pbuf in the chain */ - p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT", - (PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 ); - /* set reference count (needed here in case we fail) */ - p->ref = 1; - - /* now allocate the tail of the pbuf chain */ - - /* remember first pbuf for linkage in next iteration */ - r = p; - /* remaining length to be allocated */ - rem_len = length - p->len; - /* any remaining pbufs to be allocated? */ - while (rem_len > 0) { - q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); - if (q == NULL) { - PBUF_POOL_IS_EMPTY(); - /* free chain so far allocated */ - pbuf_free(p); - /* bail out unsuccesfully */ - return NULL; - } - q->type = type; - q->flags = 0; - q->next = NULL; - /* make previous pbuf point to this pbuf */ - r->next = q; - /* set total length of this pbuf and next in chain */ - LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff); - q->tot_len = (u16_t)rem_len; - /* this pbuf length is pool size, unless smaller sized tail */ - q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED); - q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF); - LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned", - ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("check p->payload + p->len does not overflow pbuf", - ((u8_t*)p->payload + p->len <= - (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED)); - q->ref = 1; - /* calculate remaining length to be allocated */ - rem_len -= q->len; - /* remember this pbuf for linkage in next iteration */ - r = q; - } - /* end of chain */ - /*r->next = NULL;*/ - - break; - case PBUF_RAM: - /* If pbuf is to be allocated in RAM, allocate memory for it. */ - p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length)); - if (p == NULL) { - return NULL; - } - /* Set up internal structure of the pbuf. */ - p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset)); - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - - LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned", - ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0); - break; - /* pbuf references existing (non-volatile static constant) ROM payload? */ - case PBUF_ROM: - /* pbuf references existing (externally allocated) RAM payload? */ - case PBUF_REF: - /* only allocate memory for the pbuf structure */ - p = (struct pbuf *)memp_malloc(MEMP_PBUF); - if (p == NULL) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", - (type == PBUF_ROM) ? "ROM" : "REF")); - return NULL; - } - /* caller must set this field properly, afterwards */ - p->payload = NULL; - p->len = p->tot_len = length; - p->next = NULL; - p->type = type; - break; - default: - LWIP_ASSERT("pbuf_alloc: erroneous type", 0); - return NULL; - } - /* set reference count */ - p->ref = 1; - /* set flags */ - p->flags = 0; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); - return p; -} - -#if LWIP_SUPPORT_CUSTOM_PBUF -/** Initialize a custom pbuf (already allocated). - * - * @param layer flag to define header size - * @param length size of the pbuf's payload - * @param type type of the pbuf (only used to treat the pbuf accordingly, as - * this function allocates no memory) - * @param p pointer to the custom pbuf to initialize (already allocated) - * @param payload_mem pointer to the buffer that is used for payload and headers, - * must be at least big enough to hold 'length' plus the header size, - * may be NULL if set later. - * ATTENTION: The caller is responsible for correct alignment of this buffer!! - * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least - * big enough to hold 'length' plus the header size - */ -struct pbuf* -pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, - void *payload_mem, u16_t payload_mem_len) -{ - u16_t offset; - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); - - /* determine header offset */ - switch (l) { - case PBUF_TRANSPORT: - /* add room for transport (often TCP) layer header */ - offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN; - break; - case PBUF_IP: - /* add room for IP layer header */ - offset = PBUF_LINK_HLEN + PBUF_IP_HLEN; - break; - case PBUF_LINK: - /* add room for link layer header */ - offset = PBUF_LINK_HLEN; - break; - case PBUF_RAW: - offset = 0; - break; - default: - LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); - return NULL; - } - - if (LWIP_MEM_ALIGN_SIZE(offset) + length > payload_mem_len) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); - return NULL; - } - - p->pbuf.next = NULL; - if (payload_mem != NULL) { - p->pbuf.payload = (u8_t *)payload_mem + LWIP_MEM_ALIGN_SIZE(offset); - } else { - p->pbuf.payload = NULL; - } - p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; - p->pbuf.len = p->pbuf.tot_len = length; - p->pbuf.type = type; - p->pbuf.ref = 1; - return &p->pbuf; -} -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - -/** - * Shrink a pbuf chain to a desired length. - * - * @param p pbuf to shrink. - * @param new_len desired new length of pbuf chain - * - * Depending on the desired length, the first few pbufs in a chain might - * be skipped and left unchanged. The new last pbuf in the chain will be - * resized, and any remaining pbufs will be freed. - * - * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted. - * @note May not be called on a packet queue. - * - * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain). - */ -void -pbuf_realloc(struct pbuf *p, u16_t new_len) -{ - struct pbuf *q; - u16_t rem_len; /* remaining length */ - s32_t grow; - - LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL); - LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL || - p->type == PBUF_ROM || - p->type == PBUF_RAM || - p->type == PBUF_REF); - - /* desired length larger than current length? */ - if (new_len >= p->tot_len) { - /* enlarging not yet supported */ - return; - } - - /* the pbuf chain grows by (new_len - p->tot_len) bytes - * (which may be negative in case of shrinking) */ - grow = new_len - p->tot_len; - - /* first, step over any pbufs that should remain in the chain */ - rem_len = new_len; - q = p; - /* should this pbuf be kept? */ - while (rem_len > q->len) { - /* decrease remaining length by pbuf length */ - rem_len -= q->len; - /* decrease total length indicator */ - LWIP_ASSERT("grow < max_u16_t", grow < 0xffff); - q->tot_len += (u16_t)grow; - /* proceed to next pbuf in chain */ - q = q->next; - LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL); - } - /* we have now reached the new last pbuf (in q) */ - /* rem_len == desired length for pbuf q */ - - /* shrink allocated memory for PBUF_RAM */ - /* (other types merely adjust their length fields */ - if ((q->type == PBUF_RAM) && (rem_len != q->len)) { - /* reallocate and adjust the length of the pbuf that will be split */ - q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); - LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); - } - /* adjust length fields for new last pbuf */ - q->len = rem_len; - q->tot_len = q->len; - - /* any remaining pbufs in chain? */ - if (q->next != NULL) { - /* free remaining pbufs in chain */ - pbuf_free(q->next); - } - /* q is last packet in chain */ - q->next = NULL; - -} - -/** - * Adjusts the payload pointer to hide or reveal headers in the payload. - * - * Adjusts the ->payload pointer so that space for a header - * (dis)appears in the pbuf payload. - * - * The ->payload, ->tot_len and ->len fields are adjusted. - * - * @param p pbuf to change the header size. - * @param header_size_increment Number of bytes to increment header size which - * increases the size of the pbuf. New space is on the front. - * (Using a negative value decreases the header size.) - * If hdr_size_inc is 0, this function does nothing and returns succesful. - * - * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so - * the call will fail. A check is made that the increase in header size does - * not move the payload pointer in front of the start of the buffer. - * @return non-zero on failure, zero on success. - * - */ -u8_t -pbuf_header(struct pbuf *p, s16_t header_size_increment) -{ - u16_t type; - void *payload; - u16_t increment_magnitude; - - LWIP_ASSERT("p != NULL", p != NULL); - if ((header_size_increment == 0) || (p == NULL)) { - return 0; - } - - if (header_size_increment < 0){ - increment_magnitude = -header_size_increment; - /* Check that we aren't going to move off the end of the pbuf */ - LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;); - } else { - increment_magnitude = header_size_increment; -#if 0 - /* Can't assert these as some callers speculatively call - pbuf_header() to see if it's OK. Will return 1 below instead. */ - /* Check that we've got the correct type of pbuf to work with */ - LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL", - p->type == PBUF_RAM || p->type == PBUF_POOL); - /* Check that we aren't going to move off the beginning of the pbuf */ - LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF", - (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF); -#endif - } - - type = p->type; - /* remember current payload pointer */ - payload = p->payload; - - /* pbuf types containing payloads? */ - if (type == PBUF_RAM || type == PBUF_POOL) { - /* set new payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - /* boundary check fails? */ - if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_header: failed as %p < %p (not enough space for new header size)\n", - (void *)p->payload, (void *)(p + 1))); - /* restore old payload pointer */ - p->payload = payload; - /* bail out unsuccesfully */ - return 1; - } - /* pbuf types refering to external payloads? */ - } else if (type == PBUF_REF || type == PBUF_ROM) { - /* hide a header in the payload? */ - if ((header_size_increment < 0) && (increment_magnitude <= p->len)) { - /* increase payload pointer */ - p->payload = (u8_t *)p->payload - header_size_increment; - } else { - /* cannot expand payload to front (yet!) - * bail out unsuccesfully */ - return 1; - } - } else { - /* Unknown type */ - LWIP_ASSERT("bad pbuf type", 0); - return 1; - } - /* modify pbuf length fields */ - p->len += header_size_increment; - p->tot_len += header_size_increment; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n", - (void *)payload, (void *)p->payload, header_size_increment)); - - return 0; -} - -/** - * Dereference a pbuf chain or queue and deallocate any no-longer-used - * pbufs at the head of this chain or queue. - * - * Decrements the pbuf reference count. If it reaches zero, the pbuf is - * deallocated. - * - * For a pbuf chain, this is repeated for each pbuf in the chain, - * up to the first pbuf which has a non-zero reference count after - * decrementing. So, when all reference counts are one, the whole - * chain is free'd. - * - * @param p The pbuf (chain) to be dereferenced. - * - * @return the number of pbufs that were de-allocated - * from the head of the chain. - * - * @note MUST NOT be called on a packet queue (Not verified to work yet). - * @note the reference counter of a pbuf equals the number of pointers - * that refer to the pbuf (or into the pbuf). - * - * @internal examples: - * - * Assuming existing chains a->b->c with the following reference - * counts, calling pbuf_free(a) results in: - * - * 1->2->3 becomes ...1->3 - * 3->3->3 becomes 2->3->3 - * 1->1->2 becomes ......1 - * 2->1->1 becomes 1->1->1 - * 1->1->1 becomes ....... - * - */ -u8_t -pbuf_free(struct pbuf *p) -{ - u16_t type; - struct pbuf *q; - u8_t count; - - if (p == NULL) { - LWIP_ASSERT("p != NULL", p != NULL); - /* if assertions are disabled, proceed with debug output */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("pbuf_free(p == NULL) was called.\n")); - return 0; - } - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p)); - - PERF_START; - - LWIP_ASSERT("pbuf_free: sane type", - p->type == PBUF_RAM || p->type == PBUF_ROM || - p->type == PBUF_REF || p->type == PBUF_POOL); - - count = 0; - /* de-allocate all consecutive pbufs from the head of the chain that - * obtain a zero reference count after decrementing*/ - while (p != NULL) { - u16_t ref; - SYS_ARCH_DECL_PROTECT(old_level); - /* Since decrementing ref cannot be guaranteed to be a single machine operation - * we must protect it. We put the new ref into a local variable to prevent - * further protection. */ - SYS_ARCH_PROTECT(old_level); - /* all pbufs in a chain are referenced at least once */ - LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0); - /* decrease reference count (number of pointers to pbuf) */ - ref = --(p->ref); - SYS_ARCH_UNPROTECT(old_level); - /* this pbuf is no longer referenced to? */ - if (ref == 0) { - /* remember next pbuf in chain for next iteration */ - q = p->next; - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); - type = p->type; -#if LWIP_SUPPORT_CUSTOM_PBUF - /* is this a custom pbuf? */ - if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { - struct pbuf_custom *pc = (struct pbuf_custom*)p; - LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); - pc->custom_free_function(p); - } else -#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ - { - /* is this a pbuf from the pool? */ - if (type == PBUF_POOL) { - memp_free(MEMP_PBUF_POOL, p); - /* is this a ROM or RAM referencing pbuf? */ - } else if (type == PBUF_ROM || type == PBUF_REF) { - memp_free(MEMP_PBUF, p); - /* type == PBUF_RAM */ - } else { - mem_free(p); - } - } - count++; - /* proceed to next pbuf */ - p = q; - /* p->ref > 0, this pbuf is still referenced to */ - /* (and so the remaining pbufs in chain as well) */ - } else { - LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref)); - /* stop walking through the chain */ - p = NULL; - } - } - PERF_STOP("pbuf_free"); - /* return number of de-allocated pbufs */ - return count; -} - -/** - * Count number of pbufs in a chain - * - * @param p first pbuf of chain - * @return the number of pbufs in a chain - */ - -u8_t -pbuf_clen(struct pbuf *p) -{ - u8_t len; - - len = 0; - while (p != NULL) { - ++len; - p = p->next; - } - return len; -} - -/** - * Increment the reference count of the pbuf. - * - * @param p pbuf to increase reference counter of - * - */ -void -pbuf_ref(struct pbuf *p) -{ - SYS_ARCH_DECL_PROTECT(old_level); - /* pbuf given? */ - if (p != NULL) { - SYS_ARCH_PROTECT(old_level); - ++(p->ref); - SYS_ARCH_UNPROTECT(old_level); - } -} - -/** - * Concatenate two pbufs (each may be a pbuf chain) and take over - * the caller's reference of the tail pbuf. - * - * @note The caller MAY NOT reference the tail pbuf afterwards. - * Use pbuf_chain() for that purpose. - * - * @see pbuf_chain() - */ - -void -pbuf_cat(struct pbuf *h, struct pbuf *t) -{ - struct pbuf *p; - - LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)", - ((h != NULL) && (t != NULL)), return;); - - /* proceed to last pbuf of chain */ - for (p = h; p->next != NULL; p = p->next) { - /* add total length of second chain to all totals of first chain */ - p->tot_len += t->tot_len; - } - /* { p is last pbuf of first h chain, p->next == NULL } */ - LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len); - LWIP_ASSERT("p->next == NULL", p->next == NULL); - /* add total length of second chain to last pbuf total of first chain */ - p->tot_len += t->tot_len; - /* chain last pbuf of head (p) with first of tail (t) */ - p->next = t; - /* p->next now references t, but the caller will drop its reference to t, - * so netto there is no change to the reference count of t. - */ -} - -/** - * Chain two pbufs (or pbuf chains) together. - * - * The caller MUST call pbuf_free(t) once it has stopped - * using it. Use pbuf_cat() instead if you no longer use t. - * - * @param h head pbuf (chain) - * @param t tail pbuf (chain) - * @note The pbufs MUST belong to the same packet. - * @note MAY NOT be called on a packet queue. - * - * The ->tot_len fields of all pbufs of the head chain are adjusted. - * The ->next field of the last pbuf of the head chain is adjusted. - * The ->ref field of the first pbuf of the tail chain is adjusted. - * - */ -void -pbuf_chain(struct pbuf *h, struct pbuf *t) -{ - pbuf_cat(h, t); - /* t is now referenced by h */ - pbuf_ref(t); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t)); -} - -/** - * Dechains the first pbuf from its succeeding pbufs in the chain. - * - * Makes p->tot_len field equal to p->len. - * @param p pbuf to dechain - * @return remainder of the pbuf chain, or NULL if it was de-allocated. - * @note May not be called on a packet queue. - */ -struct pbuf * -pbuf_dechain(struct pbuf *p) -{ - struct pbuf *q; - u8_t tail_gone = 1; - /* tail */ - q = p->next; - /* pbuf has successor in chain? */ - if (q != NULL) { - /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ - LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len); - /* enforce invariant if assertion is disabled */ - q->tot_len = p->tot_len - p->len; - /* decouple pbuf from remainder */ - p->next = NULL; - /* total length of pbuf p is its own length only */ - p->tot_len = p->len; - /* q is no longer referenced by p, free it */ - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); - tail_gone = pbuf_free(q); - if (tail_gone > 0) { - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, - ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q)); - } - /* return remaining tail or NULL if deallocated */ - } - /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ - LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len); - return ((tail_gone > 0) ? NULL : q); -} - -/** - * - * Create PBUF_RAM copies of pbufs. - * - * Used to queue packets on behalf of the lwIP stack, such as - * ARP based queueing. - * - * @note You MUST explicitly use p = pbuf_take(p); - * - * @note Only one packet is copied, no packet queue! - * - * @param p_to pbuf destination of the copy - * @param p_from pbuf source of the copy - * - * @return ERR_OK if pbuf was copied - * ERR_ARG if one of the pbufs is NULL or p_to is not big - * enough to hold p_from - */ -err_t -pbuf_copy(struct pbuf *p_to, struct pbuf *p_from) -{ - u16_t offset_to=0, offset_from=0, len; - - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n", - (void*)p_to, (void*)p_from)); - - /* is the target big enough to hold the source? */ - LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) && - (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;); - - /* iterate through pbuf chain */ - do - { - /* copy one part of the original chain */ - if ((p_to->len - offset_to) >= (p_from->len - offset_from)) { - /* complete current p_from fits into current p_to */ - len = p_from->len - offset_from; - } else { - /* current p_from does not fit into current p_to */ - len = p_to->len - offset_to; - } - MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len); - offset_to += len; - offset_from += len; - LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len); - LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len); - if (offset_from >= p_from->len) { - /* on to next p_from (if any) */ - offset_from = 0; - p_from = p_from->next; - } - if (offset_to == p_to->len) { - /* on to next p_to (if any) */ - offset_to = 0; - p_to = p_to->next; - LWIP_ERROR("p_to != NULL", (p_to != NULL) || (p_from == NULL) , return ERR_ARG;); - } - - if((p_from != NULL) && (p_from->len == p_from->tot_len)) { - /* don't copy more than one packet! */ - LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", - (p_from->next == NULL), return ERR_VAL;); - } - if((p_to != NULL) && (p_to->len == p_to->tot_len)) { - /* don't copy more than one packet! */ - LWIP_ERROR("pbuf_copy() does not allow packet queues!\n", - (p_to->next == NULL), return ERR_VAL;); - } - } while (p_from); - LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n")); - return ERR_OK; -} - -/** - * Copy (part of) the contents of a packet buffer - * to an application supplied buffer. - * - * @param buf the pbuf from which to copy data - * @param dataptr the application supplied buffer - * @param len length of data to copy (dataptr must be big enough). No more - * than buf->tot_len will be copied, irrespective of len - * @param offset offset into the packet buffer from where to begin copying len bytes - * @return the number of bytes copied, or 0 on failure - */ -u16_t -pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset) -{ - struct pbuf *p; - u16_t left; - u16_t buf_copy_len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;); - - left = 0; - - if((buf == NULL) || (dataptr == NULL)) { - return 0; - } - - /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ - for(p = buf; len != 0 && p != NULL; p = p->next) { - if ((offset != 0) && (offset >= p->len)) { - /* don't copy from this buffer -> on to the next */ - offset -= p->len; - } else { - /* copy from this buffer. maybe only partially. */ - buf_copy_len = p->len - offset; - if (buf_copy_len > len) - buf_copy_len = len; - /* copy the necessary parts of the buffer */ - MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len); - copied_total += buf_copy_len; - left += buf_copy_len; - len -= buf_copy_len; - offset = 0; - } - } - return copied_total; -} - -/** - * Copy application supplied data into a pbuf. - * This function can only be used to copy the equivalent of buf->tot_len data. - * - * @param buf pbuf to fill with data - * @param dataptr application supplied data buffer - * @param len length of the application supplied data buffer - * - * @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough - */ -err_t -pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) -{ - struct pbuf *p; - u16_t buf_copy_len; - u16_t total_copy_len = len; - u16_t copied_total = 0; - - LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;); - LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;); - - if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) { - return ERR_ARG; - } - - /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */ - for(p = buf; total_copy_len != 0; p = p->next) { - LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL); - buf_copy_len = total_copy_len; - if (buf_copy_len > p->len) { - /* this pbuf cannot hold all remaining data */ - buf_copy_len = p->len; - } - /* copy the necessary parts of the buffer */ - MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len); - total_copy_len -= buf_copy_len; - copied_total += buf_copy_len; - } - LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len); - return ERR_OK; -} - -/** - * Creates a single pbuf out of a queue of pbufs. - * - * @remark: Either the source pbuf 'p' is freed by this function or the original - * pbuf 'p' is returned, therefore the caller has to check the result! - * - * @param p the source pbuf - * @param layer pbuf_layer of the new pbuf - * - * @return a new, single pbuf (p->next is NULL) - * or the old pbuf if allocation fails - */ -struct pbuf* -pbuf_coalesce(struct pbuf *p, pbuf_layer layer) -{ - struct pbuf *q; - err_t err; - if (p->next == NULL) { - return p; - } - q = pbuf_alloc(layer, p->tot_len, PBUF_RAM); - if (q == NULL) { - /* @todo: what do we do now? */ - return p; - } - err = pbuf_copy(q, p); - LWIP_ASSERT("pbuf_copy failed", err == ERR_OK); - pbuf_free(p); - return q; -} - -#if LWIP_CHECKSUM_ON_COPY -/** - * Copies data into a single pbuf (*not* into a pbuf queue!) and updates - * the checksum while copying - * - * @param p the pbuf to copy data into - * @param start_offset offset of p->payload where to copy the data to - * @param dataptr data to copy into the pbuf - * @param len length of data to copy into the pbuf - * @param chksum pointer to the checksum which is updated - * @return ERR_OK if successful, another error if the data does not fit - * within the (first) pbuf (no pbuf queues!) - */ -err_t -pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, - u16_t len, u16_t *chksum) -{ - u32_t acc; - u16_t copy_chksum; - char *dst_ptr; - LWIP_ASSERT("p != NULL", p != NULL); - LWIP_ASSERT("dataptr != NULL", dataptr != NULL); - LWIP_ASSERT("chksum != NULL", chksum != NULL); - LWIP_ASSERT("len != 0", len != 0); - - if ((start_offset >= p->len) || (start_offset + len > p->len)) { - return ERR_ARG; - } - - dst_ptr = ((char*)p->payload) + start_offset; - copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); - if ((start_offset & 1) != 0) { - copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); - } - acc = *chksum; - acc += copy_chksum; - *chksum = FOLD_U32T(acc); - return ERR_OK; -} -#endif /* LWIP_CHECKSUM_ON_COPY */ - - /** Get one byte from the specified position in a pbuf - * WARNING: returns zero for offset >= p->tot_len - * - * @param p pbuf to parse - * @param offset offset into p of the byte to return - * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len - */ -u8_t -pbuf_get_at(struct pbuf* p, u16_t offset) -{ - u16_t copy_from = offset; - struct pbuf* q = p; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= copy_from)) { - copy_from -= q->len; - q = q->next; - } - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > copy_from)) { - return ((u8_t*)q->payload)[copy_from]; - } - return 0; -} - -/** Compare pbuf contents at specified offset with memory s2, both of length n - * - * @param p pbuf to compare - * @param offset offset into p at wich to start comparing - * @param s2 buffer to compare - * @param n length of buffer to compare - * @return zero if equal, nonzero otherwise - * (0xffff if p is too short, diffoffset+1 otherwise) - */ -u16_t -pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) -{ - u16_t start = offset; - struct pbuf* q = p; - - /* get the correct pbuf */ - while ((q != NULL) && (q->len <= start)) { - start -= q->len; - q = q->next; - } - /* return requested data if pbuf is OK */ - if ((q != NULL) && (q->len > start)) { - u16_t i; - for(i = 0; i < n; i++) { - u8_t a = pbuf_get_at(q, start + i); - u8_t b = ((u8_t*)s2)[i]; - if (a != b) { - return i+1; - } - } - return 0; - } - return 0xffff; -} - -/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset - * start_offset. - * - * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as - * return value 'not found' - * @param mem search for the contents of this buffer - * @param mem_len length of 'mem' - * @param start_offset offset into p at which to start searching - * @return 0xFFFF if substr was not found in p or the index where it was found - */ -u16_t -pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) -{ - u16_t i; - u16_t max = p->tot_len - mem_len; - if (p->tot_len >= mem_len + start_offset) { - for(i = start_offset; i <= max; ) { - u16_t plus = pbuf_memcmp(p, i, mem, mem_len); - if (plus == 0) { - return i; - } else { - i += plus; - } - } - } - return 0xFFFF; -} - -/** Find occurrence of substr with length substr_len in pbuf p, start at offset - * start_offset - * WARNING: in contrast to strstr(), this one does not stop at the first \0 in - * the pbuf/source string! - * - * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as - * return value 'not found' - * @param substr string to search for in p, maximum length is 0xFFFE - * @return 0xFFFF if substr was not found in p or the index where it was found - */ -u16_t -pbuf_strstr(struct pbuf* p, const char* substr) -{ - size_t substr_len; - if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { - return 0xFFFF; - } - substr_len = strlen(substr); - if (substr_len >= 0xFFFF) { - return 0xFFFF; - } - return pbuf_memfind(p, substr, (u16_t)substr_len, 0); -} diff --git a/ext/lwip/src/core/raw.c b/ext/lwip/src/core/raw.c deleted file mode 100644 index 7160c0fb..00000000 --- a/ext/lwip/src/core/raw.c +++ /dev/null @@ -1,350 +0,0 @@ -/** - * @file - * Implementation of raw protocol PCBs for low-level handling of - * different types of protocols besides (or overriding) those - * already available in lwIP. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/raw.h" -#include "lwip/stats.h" -#include "arch/perf.h" - -#include <string.h> - -/** The list of RAW PCBs */ -static struct raw_pcb *raw_pcbs; - -/** - * Determine if in incoming IP packet is covered by a RAW PCB - * and if so, pass it to a user-provided receive callback function. - * - * Given an incoming IP datagram (as a chain of pbufs) this function - * finds a corresponding RAW PCB and calls the corresponding receive - * callback function. - * - * @param p pbuf to be demultiplexed to a RAW PCB. - * @param inp network interface on which the datagram was received. - * @return - 1 if the packet has been eaten by a RAW PCB receive - * callback function. The caller MAY NOT not reference the - * packet any longer, and MAY NOT call pbuf_free(). - * @return - 0 if packet is not eaten (pbuf is still referenced by the - * caller). - * - */ -u8_t -raw_input(struct pbuf *p, struct netif *inp) -{ - struct raw_pcb *pcb, *prev; - struct ip_hdr *iphdr; - s16_t proto; - u8_t eaten = 0; - - LWIP_UNUSED_ARG(inp); - - iphdr = (struct ip_hdr *)p->payload; - proto = IPH_PROTO(iphdr); - - prev = NULL; - pcb = raw_pcbs; - /* loop through all raw pcbs until the packet is eaten by one */ - /* this allows multiple pcbs to match against the packet by design */ - while ((eaten == 0) && (pcb != NULL)) { - if ((pcb->protocol == proto) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) { -#if IP_SOF_BROADCAST_RECV - /* broadcast filter? */ - if (ip_get_option(pcb, SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp)) -#endif /* IP_SOF_BROADCAST_RECV */ - { - /* receive callback function available? */ - if (pcb->recv != NULL) { - /* the receive callback function did not eat the packet? */ - if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) { - /* receive function ate the packet */ - p = NULL; - eaten = 1; - if (prev != NULL) { - /* move the pcb to the front of raw_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - } - } - /* no receive callback function was set for this raw PCB */ - } - /* drop the packet */ - } - prev = pcb; - pcb = pcb->next; - } - return eaten; -} - -/** - * Bind a RAW PCB. - * - * @param pcb RAW PCB to be bound with a local address ipaddr. - * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to - * bind to all local interfaces. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_USE. The specified IP address is already bound to by - * another RAW PCB. - * - * @see raw_disconnect() - */ -err_t -raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) -{ - ip_addr_set(&pcb->local_ip, ipaddr); - return ERR_OK; -} - -/** - * Connect an RAW PCB. This function is required by upper layers - * of lwip. Using the raw api you could use raw_sendto() instead - * - * This will associate the RAW PCB with the remote address. - * - * @param pcb RAW PCB to be connected with remote address ipaddr and port. - * @param ipaddr remote IP address to connect with. - * - * @return lwIP error code - * - * @see raw_disconnect() and raw_sendto() - */ -err_t -raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) -{ - ip_addr_set(&pcb->remote_ip, ipaddr); - return ERR_OK; -} - - -/** - * Set the callback function for received packets that match the - * raw PCB's protocol and binding. - * - * The callback function MUST either - * - eat the packet by calling pbuf_free() and returning non-zero. The - * packet will not be passed to other raw PCBs or other protocol layers. - * - not free the packet, and return zero. The packet will be matched - * against further PCBs and/or forwarded to another protocol layers. - * - * @return non-zero if the packet was free()d, zero if the packet remains - * available for others. - */ -void -raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * Send the raw IP packet to the given address. Note that actually you cannot - * modify the IP headers (this is inconsistent with the receive callback where - * you actually get the IP headers), you can only specify the IP payload here. - * It requires some more changes in lwIP. (there will be a raw_send() function - * then.) - * - * @param pcb the raw pcb which to send - * @param p the IP payload to send - * @param ipaddr the destination address of the IP packet - * - */ -err_t -raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) -{ - err_t err; - struct netif *netif; - ip_addr_t *src_ip; - struct pbuf *q; /* q will be sent down the stack */ - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); - - /* not enough space to add an IP header to first pbuf in given p chain? */ - if (pbuf_header(p, IP_HLEN)) { - /* allocate header in new pbuf */ - q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p */ - pbuf_chain(q, p); - } - /* { first pbuf q points to header pbuf } */ - LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* first pbuf q equals given pbuf */ - q = p; - if(pbuf_header(q, -IP_HLEN)) { - LWIP_ASSERT("Can't restore header we just removed!", 0); - return ERR_MEM; - } - } - - if ((netif = ip_route(ipaddr)) == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_RTE; - } - -#if IP_SOF_BROADCAST - /* broadcast filter? */ - if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(ipaddr, netif)) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - /* free any temporary header pbuf allocated by pbuf_header() */ - if (q != p) { - pbuf_free(q); - } - return ERR_VAL; - } -#endif /* IP_SOF_BROADCAST */ - - if (ip_addr_isany(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* use RAW PCB local IP address as source address */ - src_ip = &(pcb->local_ip); - } - - NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - - /* did we chain a header earlier? */ - if (q != p) { - /* free the header */ - pbuf_free(q); - } - return err; -} - -/** - * Send the raw IP packet to the address given by raw_connect() - * - * @param pcb the raw pcb which to send - * @param p the IP payload to send - * - */ -err_t -raw_send(struct raw_pcb *pcb, struct pbuf *p) -{ - return raw_sendto(pcb, p, &pcb->remote_ip); -} - -/** - * Remove an RAW PCB. - * - * @param pcb RAW PCB to be removed. The PCB is removed from the list of - * RAW PCB's and the data structure is freed from memory. - * - * @see raw_new() - */ -void -raw_remove(struct raw_pcb *pcb) -{ - struct raw_pcb *pcb2; - /* pcb to be removed is first in list? */ - if (raw_pcbs == pcb) { - /* make list start at 2nd pcb */ - raw_pcbs = raw_pcbs->next; - /* pcb not 1st in list */ - } else { - for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { - /* find pcb in raw_pcbs list */ - if (pcb2->next != NULL && pcb2->next == pcb) { - /* remove pcb from list */ - pcb2->next = pcb->next; - } - } - } - memp_free(MEMP_RAW_PCB, pcb); -} - -/** - * Create a RAW PCB. - * - * @return The RAW PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP) - * - * @see raw_remove() - */ -struct raw_pcb * -raw_new(u8_t proto) -{ - struct raw_pcb *pcb; - - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); - - pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); - /* could allocate RAW PCB? */ - if (pcb != NULL) { - /* initialize PCB to all zeroes */ - memset(pcb, 0, sizeof(struct raw_pcb)); - pcb->protocol = proto; - pcb->ttl = RAW_TTL; - pcb->next = raw_pcbs; - raw_pcbs = pcb; - } - return pcb; -} - -#endif /* LWIP_RAW */ diff --git a/ext/lwip/src/core/snmp/asn1_dec.c b/ext/lwip/src/core/snmp/asn1_dec.c deleted file mode 100644 index 1d565820..00000000 --- a/ext/lwip/src/core/snmp/asn1_dec.c +++ /dev/null @@ -1,657 +0,0 @@ -/** - * @file - * Abstract Syntax Notation One (ISO 8824, 8825) decoding - * - * @todo not optimised (yet), favor correctness over speed, favor speed over size - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp_asn1.h" - -/** - * Retrieves type field from incoming pbuf chain. - * - * @param p points to a pbuf holding an ASN1 coded type field - * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field - * @param type return ASN1 type - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - *type = *msg_ptr; - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Decodes length field from incoming pbuf chain into host length. - * - * @param p points to a pbuf holding an ASN1 coded length - * @param ofs points to the offset within the pbuf chain of the ASN1 coded length - * @param octets_used returns number of octets used by the length code - * @param length return host order length, upto 64k - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - if (*msg_ptr < 0x80) - { - /* primitive definite length format */ - *octets_used = 1; - *length = *msg_ptr; - return ERR_OK; - } - else if (*msg_ptr == 0x80) - { - /* constructed indefinite length format, termination with two zero octets */ - u8_t zeros; - u8_t i; - - *length = 0; - zeros = 0; - while (zeros != 2) - { - i = 2; - while (i > 0) - { - i--; - (*length) += 1; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - if (*msg_ptr == 0) - { - zeros++; - if (zeros == 2) - { - /* stop while (i > 0) */ - i = 0; - } - } - else - { - zeros = 0; - } - } - } - *octets_used = 1; - return ERR_OK; - } - else if (*msg_ptr == 0x81) - { - /* constructed definite length format, one octet */ - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - *length = *msg_ptr; - *octets_used = 2; - return ERR_OK; - } - else if (*msg_ptr == 0x82) - { - u8_t i; - - /* constructed definite length format, two octets */ - i = 2; - while (i > 0) - { - i--; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - if (i == 0) - { - /* least significant length octet */ - *length |= *msg_ptr; - } - else - { - /* most significant length octet */ - *length = (*msg_ptr) << 8; - } - } - *octets_used = 3; - return ERR_OK; - } - else - { - /* constructed definite length format 3..127 octets, this is too big (>64k) */ - /** @todo: do we need to accept inefficient codings with many leading zero's? */ - *octets_used = 1 + ((*msg_ptr) & 0x7f); - return ERR_ARG; - } - } - p = p->next; - } - - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Decodes positive integer (counter, gauge, timeticks) into u32_t. - * - * @param p points to a pbuf holding an ASN1 coded integer - * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer - * @param len length of the coded integer field - * @param value return host order integer - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -err_t -snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - if ((len > 0) && (len < 6)) - { - /* start from zero */ - *value = 0; - if (*msg_ptr & 0x80) - { - /* negative, expecting zero sign bit! */ - return ERR_ARG; - } - else - { - /* positive */ - if ((len > 1) && (*msg_ptr == 0)) - { - /* skip leading "sign byte" octet 0x00 */ - len--; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - } - /* OR octets with value */ - while (len > 1) - { - len--; - *value |= *msg_ptr; - *value <<= 8; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - *value |= *msg_ptr; - return ERR_OK; - } - else - { - return ERR_ARG; - } - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Decodes integer into s32_t. - * - * @param p points to a pbuf holding an ASN1 coded integer - * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer - * @param len length of the coded integer field - * @param value return host order integer - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - * - * @note ASN coded integers are _always_ signed! - */ -err_t -snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) -{ - u16_t plen, base; - u8_t *msg_ptr; -#if BYTE_ORDER == LITTLE_ENDIAN - u8_t *lsb_ptr = (u8_t*)value; -#endif -#if BYTE_ORDER == BIG_ENDIAN - u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1; -#endif - u8_t sign; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - if ((len > 0) && (len < 5)) - { - if (*msg_ptr & 0x80) - { - /* negative, start from -1 */ - *value = -1; - sign = 1; - } - else - { - /* positive, start from 0 */ - *value = 0; - sign = 0; - } - /* OR/AND octets with value */ - while (len > 1) - { - len--; - if (sign) - { - *lsb_ptr &= *msg_ptr; - *value <<= 8; - *lsb_ptr |= 255; - } - else - { - *lsb_ptr |= *msg_ptr; - *value <<= 8; - } - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - if (sign) - { - *lsb_ptr &= *msg_ptr; - } - else - { - *lsb_ptr |= *msg_ptr; - } - return ERR_OK; - } - else - { - return ERR_ARG; - } - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Decodes object identifier from incoming message into array of s32_t. - * - * @param p points to a pbuf holding an ASN1 coded object identifier - * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier - * @param len length of the coded object identifier - * @param oid return object identifier struct - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) -{ - u16_t plen, base; - u8_t *msg_ptr; - s32_t *oid_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - oid->len = 0; - oid_ptr = &oid->id[0]; - if (len > 0) - { - /* first compressed octet */ - if (*msg_ptr == 0x2B) - { - /* (most) common case 1.3 (iso.org) */ - *oid_ptr = 1; - oid_ptr++; - *oid_ptr = 3; - oid_ptr++; - } - else if (*msg_ptr < 40) - { - *oid_ptr = 0; - oid_ptr++; - *oid_ptr = *msg_ptr; - oid_ptr++; - } - else if (*msg_ptr < 80) - { - *oid_ptr = 1; - oid_ptr++; - *oid_ptr = (*msg_ptr) - 40; - oid_ptr++; - } - else - { - *oid_ptr = 2; - oid_ptr++; - *oid_ptr = (*msg_ptr) - 80; - oid_ptr++; - } - oid->len = 2; - } - else - { - /* accepting zero length identifiers e.g. for - getnext operation. uncommon but valid */ - return ERR_OK; - } - len--; - if (len > 0) - { - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN)) - { - /* sub-identifier uses multiple octets */ - if (*msg_ptr & 0x80) - { - s32_t sub_id = 0; - - while ((*msg_ptr & 0x80) && (len > 1)) - { - len--; - sub_id = (sub_id << 7) + (*msg_ptr & ~0x80); - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - if (!(*msg_ptr & 0x80) && (len > 0)) - { - /* last octet sub-identifier */ - len--; - sub_id = (sub_id << 7) + *msg_ptr; - *oid_ptr = sub_id; - } - } - else - { - /* !(*msg_ptr & 0x80) sub-identifier uses single octet */ - len--; - *oid_ptr = *msg_ptr; - } - if (len > 0) - { - /* remaining oid bytes available ... */ - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - oid_ptr++; - oid->len++; - } - if (len == 0) - { - /* len == 0, end of oid */ - return ERR_OK; - } - else - { - /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */ - return ERR_ARG; - } - - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding) - * from incoming message into array. - * - * @param p points to a pbuf holding an ASN1 coded raw data - * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data - * @param len length of the coded raw data (zero is valid, e.g. empty string!) - * @param raw_len length of the raw return value - * @param raw return raw bytes - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode - */ -err_t -snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw) -{ - u16_t plen, base; - u8_t *msg_ptr; - - if (len > 0) - { - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - if (raw_len >= len) - { - while (len > 1) - { - /* copy len - 1 octets */ - len--; - *raw = *msg_ptr; - raw++; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - /* copy last octet */ - *raw = *msg_ptr; - return ERR_OK; - } - else - { - /* raw_len < len, not enough dst space */ - return ERR_ARG; - } - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; - } - else - { - /* len == 0, empty string */ - return ERR_OK; - } -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/snmp/asn1_enc.c b/ext/lwip/src/core/snmp/asn1_enc.c deleted file mode 100644 index 64dfc5f6..00000000 --- a/ext/lwip/src/core/snmp/asn1_enc.c +++ /dev/null @@ -1,611 +0,0 @@ -/** - * @file - * Abstract Syntax Notation One (ISO 8824, 8825) encoding - * - * @todo not optimised (yet), favor correctness over speed, favor speed over size - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp_asn1.h" - -/** - * Returns octet count for length. - * - * @param length - * @param octets_needed points to the return value - */ -void -snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed) -{ - if (length < 0x80U) - { - *octets_needed = 1; - } - else if (length < 0x100U) - { - *octets_needed = 2; - } - else - { - *octets_needed = 3; - } -} - -/** - * Returns octet count for an u32_t. - * - * @param value - * @param octets_needed points to the return value - * - * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded - * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value - * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!! - */ -void -snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed) -{ - if (value < 0x80UL) - { - *octets_needed = 1; - } - else if (value < 0x8000UL) - { - *octets_needed = 2; - } - else if (value < 0x800000UL) - { - *octets_needed = 3; - } - else if (value < 0x80000000UL) - { - *octets_needed = 4; - } - else - { - *octets_needed = 5; - } -} - -/** - * Returns octet count for an s32_t. - * - * @param value - * @param octets_needed points to the return value - * - * @note ASN coded integers are _always_ signed. - */ -void -snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed) -{ - if (value < 0) - { - value = ~value; - } - if (value < 0x80L) - { - *octets_needed = 1; - } - else if (value < 0x8000L) - { - *octets_needed = 2; - } - else if (value < 0x800000L) - { - *octets_needed = 3; - } - else - { - *octets_needed = 4; - } -} - -/** - * Returns octet count for an object identifier. - * - * @param ident_len object identifier array length - * @param ident points to object identifier array - * @param octets_needed points to the return value - */ -void -snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed) -{ - s32_t sub_id; - u8_t cnt; - - cnt = 0; - if (ident_len > 1) - { - /* compressed prefix in one octet */ - cnt++; - ident_len -= 2; - ident += 2; - } - while(ident_len > 0) - { - ident_len--; - sub_id = *ident; - - sub_id >>= 7; - cnt++; - while(sub_id > 0) - { - sub_id >>= 7; - cnt++; - } - ident++; - } - *octets_needed = cnt; -} - -/** - * Encodes ASN type field into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode value into - * @param ofs points to the offset within the pbuf chain - * @param type input ASN1 type - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - *msg_ptr = type; - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Encodes host order length field into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode length into - * @param ofs points to the offset within the pbuf chain - * @param length is the host order length to be encoded - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - if (length < 0x80) - { - *msg_ptr = (u8_t)length; - return ERR_OK; - } - else if (length < 0x100) - { - *msg_ptr = 0x81; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - *msg_ptr = (u8_t)length; - return ERR_OK; - } - else - { - u8_t i; - - /* length >= 0x100 && length <= 0xFFFF */ - *msg_ptr = 0x82; - i = 2; - while (i > 0) - { - i--; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - if (i == 0) - { - /* least significant length octet */ - *msg_ptr = (u8_t)length; - } - else - { - /* most significant length octet */ - *msg_ptr = (u8_t)(length >> 8); - } - } - return ERR_OK; - } - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode value into - * @param ofs points to the offset within the pbuf chain - * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt()) - * @param value is the host order u32_t value to be encoded - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - * - * @see snmp_asn1_enc_u32t_cnt() - */ -err_t -snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - if (octets_needed == 5) - { - /* not enough bits in 'value' add leading 0x00 */ - octets_needed--; - *msg_ptr = 0x00; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - while (octets_needed > 1) - { - octets_needed--; - *msg_ptr = (u8_t)(value >> (octets_needed << 3)); - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - /* (only) one least significant octet */ - *msg_ptr = (u8_t)value; - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Encodes s32_t integer into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode value into - * @param ofs points to the offset within the pbuf chain - * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt()) - * @param value is the host order s32_t value to be encoded - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - * - * @see snmp_asn1_enc_s32t_cnt() - */ -err_t -snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - while (octets_needed > 1) - { - octets_needed--; - *msg_ptr = (u8_t)(value >> (octets_needed << 3)); - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - /* (only) one least significant octet */ - *msg_ptr = (u8_t)value; - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Encodes object identifier into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode oid into - * @param ofs points to the offset within the pbuf chain - * @param ident_len object identifier array length - * @param ident points to object identifier array - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - if (ident_len > 1) - { - if ((ident[0] == 1) && (ident[1] == 3)) - { - /* compressed (most common) prefix .iso.org */ - *msg_ptr = 0x2b; - } - else - { - /* calculate prefix */ - *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]); - } - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - ident_len -= 2; - ident += 2; - } - else - { -/* @bug: allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression?? */ - /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */ - return ERR_ARG; - } - while (ident_len > 0) - { - s32_t sub_id; - u8_t shift, tail; - - ident_len--; - sub_id = *ident; - tail = 0; - shift = 28; - while(shift > 0) - { - u8_t code; - - code = (u8_t)(sub_id >> shift); - if ((code != 0) || (tail != 0)) - { - tail = 1; - *msg_ptr = code | 0x80; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - shift -= 7; - } - *msg_ptr = (u8_t)sub_id & 0x7F; - if (ident_len > 0) - { - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - /* proceed to next sub-identifier */ - ident++; - } - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -/** - * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg. - * - * @param p points to output pbuf to encode raw data into - * @param ofs points to the offset within the pbuf chain - * @param raw_len raw data length - * @param raw points raw data - * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode - */ -err_t -snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw) -{ - u16_t plen, base; - u8_t *msg_ptr; - - plen = 0; - while (p != NULL) - { - base = plen; - plen += p->len; - if (ofs < plen) - { - msg_ptr = (u8_t*)p->payload; - msg_ptr += ofs - base; - - while (raw_len > 1) - { - /* copy raw_len - 1 octets */ - raw_len--; - *msg_ptr = *raw; - raw++; - ofs += 1; - if (ofs >= plen) - { - /* next octet in next pbuf */ - p = p->next; - if (p == NULL) { return ERR_ARG; } - msg_ptr = (u8_t*)p->payload; - plen += p->len; - } - else - { - /* next octet in same pbuf */ - msg_ptr++; - } - } - if (raw_len > 0) - { - /* copy last or single octet */ - *msg_ptr = *raw; - } - return ERR_OK; - } - p = p->next; - } - /* p == NULL, ofs >= plen */ - return ERR_ARG; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/snmp/mib2.c b/ext/lwip/src/core/snmp/mib2.c deleted file mode 100644 index 4775ba99..00000000 --- a/ext/lwip/src/core/snmp/mib2.c +++ /dev/null @@ -1,4146 +0,0 @@ -/** - * @file - * Management Information Base II (RFC1213) objects and functions. - * - * @note the object identifiers for this MIB-2 and private MIB tree - * must be kept in sorted ascending order. This to ensure correct getnext operation. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp.h" -#include "lwip/netif.h" -#include "lwip/ip.h" -#include "lwip/ip_frag.h" -#include "lwip/mem.h" -#include "lwip/tcp_impl.h" -#include "lwip/udp.h" -#include "lwip/snmp_asn1.h" -#include "lwip/snmp_structs.h" -#include "lwip/sys.h" -#include "netif/etharp.h" - -/** - * IANA assigned enterprise ID for lwIP is 26381 - * @see http://www.iana.org/assignments/enterprise-numbers - * - * @note this enterprise ID is assigned to the lwIP project, - * all object identifiers living under this ID are assigned - * by the lwIP maintainers (contact Christiaan Simons)! - * @note don't change this define, use snmp_set_sysobjid() - * - * If you need to create your own private MIB you'll need - * to apply for your own enterprise ID with IANA: - * http://www.iana.org/numbers.html - */ -#define SNMP_ENTERPRISE_ID 26381 -#define SNMP_SYSOBJID_LEN 7 -#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID} - -#ifndef SNMP_SYSSERVICES -#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2)) -#endif - -#ifndef SNMP_GET_SYSUPTIME -#define SNMP_GET_SYSUPTIME(sysuptime) (sysuptime = (sys_now() / 10)) -#endif - -static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void system_get_value(struct obj_def *od, u16_t len, void *value); -static u8_t system_set_test(struct obj_def *od, u16_t len, void *value); -static void system_set_value(struct obj_def *od, u16_t len, void *value); -static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void interfaces_get_value(struct obj_def *od, u16_t len, void *value); -static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void ifentry_get_value(struct obj_def *od, u16_t len, void *value); -#if !SNMP_SAFE_REQUESTS -static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value); -static void ifentry_set_value (struct obj_def *od, u16_t len, void *value); -#endif /* SNMP_SAFE_REQUESTS */ -static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void atentry_get_value(struct obj_def *od, u16_t len, void *value); -static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void ip_get_value(struct obj_def *od, u16_t len, void *value); -static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value); -static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value); -static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value); -static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value); -static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void icmp_get_value(struct obj_def *od, u16_t len, void *value); -#if LWIP_TCP -static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void tcp_get_value(struct obj_def *od, u16_t len, void *value); -#ifdef THIS_SEEMS_UNUSED -static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value); -#endif -#endif -static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void udp_get_value(struct obj_def *od, u16_t len, void *value); -static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void udpentry_get_value(struct obj_def *od, u16_t len, void *value); -static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); -static void snmp_get_value(struct obj_def *od, u16_t len, void *value); -static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value); -static void snmp_set_value(struct obj_def *od, u16_t len, void *value); - - -/* snmp .1.3.6.1.2.1.11 */ -const mib_scalar_node snmp_scalar = { - &snmp_get_object_def, - &snmp_get_value, - &snmp_set_test, - &snmp_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t snmp_ids[28] = { - 1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16, - 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30 -}; -struct mib_node* const snmp_nodes[28] = { - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, - (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar -}; -const struct mib_array_node snmp = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 28, - snmp_ids, - snmp_nodes -}; - -/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */ -/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */ -/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */ - -/* udp .1.3.6.1.2.1.7 */ -/** index root node for udpTable */ -struct mib_list_rootnode udp_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t udpentry_ids[2] = { 1, 2 }; -struct mib_node* const udpentry_nodes[2] = { - (struct mib_node*)&udp_root, (struct mib_node*)&udp_root, -}; -const struct mib_array_node udpentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 2, - udpentry_ids, - udpentry_nodes -}; - -s32_t udptable_id = 1; -struct mib_node* udptable_node = (struct mib_node*)&udpentry; -struct mib_ram_array_node udptable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &udptable_id, - &udptable_node -}; - -const mib_scalar_node udp_scalar = { - &udp_get_object_def, - &udp_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 }; -struct mib_node* const udp_nodes[5] = { - (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, - (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, - (struct mib_node*)&udptable -}; -const struct mib_array_node udp = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 5, - udp_ids, - udp_nodes -}; - -/* tcp .1.3.6.1.2.1.6 */ -#if LWIP_TCP -/* only if the TCP protocol is available may implement this group */ -/** index root node for tcpConnTable */ -struct mib_list_rootnode tcpconntree_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 }; -struct mib_node* const tcpconnentry_nodes[5] = { - (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, - (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, - (struct mib_node*)&tcpconntree_root -}; -const struct mib_array_node tcpconnentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 5, - tcpconnentry_ids, - tcpconnentry_nodes -}; - -s32_t tcpconntable_id = 1; -struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry; -struct mib_ram_array_node tcpconntable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, -/** @todo update maxlength when inserting / deleting from table - 0 when table is empty, 1 when more than one entry */ - 0, - &tcpconntable_id, - &tcpconntable_node -}; - -const mib_scalar_node tcp_scalar = { - &tcp_get_object_def, - &tcp_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; -struct mib_node* const tcp_nodes[15] = { - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar, - (struct mib_node*)&tcp_scalar -}; -const struct mib_array_node tcp = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 15, - tcp_ids, - tcp_nodes -}; -#endif - -/* icmp .1.3.6.1.2.1.5 */ -const mib_scalar_node icmp_scalar = { - &icmp_get_object_def, - &icmp_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; -struct mib_node* const icmp_nodes[26] = { - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, - (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar -}; -const struct mib_array_node icmp = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 26, - icmp_ids, - icmp_nodes -}; - -/** index root node for ipNetToMediaTable */ -struct mib_list_rootnode ipntomtree_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 }; -struct mib_node* const ipntomentry_nodes[4] = { - (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root, - (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root -}; -const struct mib_array_node ipntomentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 4, - ipntomentry_ids, - ipntomentry_nodes -}; - -s32_t ipntomtable_id = 1; -struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry; -struct mib_ram_array_node ipntomtable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &ipntomtable_id, - &ipntomtable_node -}; - -/** index root node for ipRouteTable */ -struct mib_list_rootnode iprtetree_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; -struct mib_node* const iprteentry_nodes[13] = { - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, - (struct mib_node*)&iprtetree_root -}; -const struct mib_array_node iprteentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 13, - iprteentry_ids, - iprteentry_nodes -}; - -s32_t iprtetable_id = 1; -struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry; -struct mib_ram_array_node iprtetable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &iprtetable_id, - &iprtetable_node -}; - -/** index root node for ipAddrTable */ -struct mib_list_rootnode ipaddrtree_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 }; -struct mib_node* const ipaddrentry_nodes[5] = { - (struct mib_node*)&ipaddrtree_root, - (struct mib_node*)&ipaddrtree_root, - (struct mib_node*)&ipaddrtree_root, - (struct mib_node*)&ipaddrtree_root, - (struct mib_node*)&ipaddrtree_root -}; -const struct mib_array_node ipaddrentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 5, - ipaddrentry_ids, - ipaddrentry_nodes -}; - -s32_t ipaddrtable_id = 1; -struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry; -struct mib_ram_array_node ipaddrtable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &ipaddrtable_id, - &ipaddrtable_node -}; - -/* ip .1.3.6.1.2.1.4 */ -const mib_scalar_node ip_scalar = { - &ip_get_object_def, - &ip_get_value, - &ip_set_test, - &noleafs_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; -struct mib_node* const ip_nodes[23] = { - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, - (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable, - (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable, - (struct mib_node*)&ip_scalar -}; -const struct mib_array_node mib2_ip = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 23, - ip_ids, - ip_nodes -}; - -/** index root node for atTable */ -struct mib_list_rootnode arptree_root = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t atentry_ids[3] = { 1, 2, 3 }; -struct mib_node* const atentry_nodes[3] = { - (struct mib_node*)&arptree_root, - (struct mib_node*)&arptree_root, - (struct mib_node*)&arptree_root -}; -const struct mib_array_node atentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 3, - atentry_ids, - atentry_nodes -}; - -const s32_t attable_id = 1; -struct mib_node* const attable_node = (struct mib_node*)&atentry; -const struct mib_array_node attable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 1, - &attable_id, - &attable_node -}; - -/* at .1.3.6.1.2.1.3 */ -s32_t at_id = 1; -struct mib_node* mib2_at_node = (struct mib_node*)&attable; -struct mib_ram_array_node at = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &at_id, - &mib2_at_node -}; - -/** index root node for ifTable */ -struct mib_list_rootnode iflist_root = { - &ifentry_get_object_def, - &ifentry_get_value, -#if SNMP_SAFE_REQUESTS - &noleafs_set_test, - &noleafs_set_value, -#else /* SNMP_SAFE_REQUESTS */ - &ifentry_set_test, - &ifentry_set_value, -#endif /* SNMP_SAFE_REQUESTS */ - MIB_NODE_LR, - 0, - NULL, - NULL, - 0 -}; -const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; -struct mib_node* const ifentry_nodes[22] = { - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, - (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root -}; -const struct mib_array_node ifentry = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 22, - ifentry_ids, - ifentry_nodes -}; - -s32_t iftable_id = 1; -struct mib_node* iftable_node = (struct mib_node*)&ifentry; -struct mib_ram_array_node iftable = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_RA, - 0, - &iftable_id, - &iftable_node -}; - -/* interfaces .1.3.6.1.2.1.2 */ -const mib_scalar_node interfaces_scalar = { - &interfaces_get_object_def, - &interfaces_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t interfaces_ids[2] = { 1, 2 }; -struct mib_node* const interfaces_nodes[2] = { - (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable -}; -const struct mib_array_node interfaces = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 2, - interfaces_ids, - interfaces_nodes -}; - - -/* 0 1 2 3 4 5 6 */ -/* system .1.3.6.1.2.1.1 */ -const mib_scalar_node sys_tem_scalar = { - &system_get_object_def, - &system_get_value, - &system_set_test, - &system_set_value, - MIB_NODE_SC, - 0 -}; -const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 }; -struct mib_node* const sys_tem_nodes[7] = { - (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, - (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, - (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, - (struct mib_node*)&sys_tem_scalar -}; -/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */ -const struct mib_array_node sys_tem = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 7, - sys_tem_ids, - sys_tem_nodes -}; - -/* mib-2 .1.3.6.1.2.1 */ -#if LWIP_TCP -#define MIB2_GROUPS 8 -#else -#define MIB2_GROUPS 7 -#endif -const s32_t mib2_ids[MIB2_GROUPS] = -{ - 1, - 2, - 3, - 4, - 5, -#if LWIP_TCP - 6, -#endif - 7, - 11 -}; -struct mib_node* const mib2_nodes[MIB2_GROUPS] = { - (struct mib_node*)&sys_tem, - (struct mib_node*)&interfaces, - (struct mib_node*)&at, - (struct mib_node*)&mib2_ip, - (struct mib_node*)&icmp, -#if LWIP_TCP - (struct mib_node*)&tcp, -#endif - (struct mib_node*)&udp, - (struct mib_node*)&snmp -}; - -const struct mib_array_node mib2 = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - MIB2_GROUPS, - mib2_ids, - mib2_nodes -}; - -/* mgmt .1.3.6.1.2 */ -const s32_t mgmt_ids[1] = { 1 }; -struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 }; -const struct mib_array_node mgmt = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 1, - mgmt_ids, - mgmt_nodes -}; - -/* internet .1.3.6.1 */ -#if SNMP_PRIVATE_MIB -/* When using a private MIB, you have to create a file 'private_mib.h' that contains - * a 'struct mib_array_node mib_private' which contains your MIB. */ -s32_t internet_ids[2] = { 2, 4 }; -struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private }; -const struct mib_array_node internet = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 2, - internet_ids, - internet_nodes -}; -#else -const s32_t internet_ids[1] = { 2 }; -struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt }; -const struct mib_array_node internet = { - &noleafs_get_object_def, - &noleafs_get_value, - &noleafs_set_test, - &noleafs_set_value, - MIB_NODE_AR, - 1, - internet_ids, - internet_nodes -}; -#endif - -/** mib-2.system.sysObjectID */ -static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID}; -/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */ -static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}}; -/** mib-2.system.sysServices */ -static const s32_t sysservices = SNMP_SYSSERVICES; - -/** mib-2.system.sysDescr */ -static const u8_t sysdescr_len_default = 4; -static const u8_t sysdescr_default[] = "lwIP"; -static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default; -static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0]; -/** mib-2.system.sysContact */ -static const u8_t syscontact_len_default = 0; -static const u8_t syscontact_default[] = ""; -static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default; -static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0]; -/** mib-2.system.sysName */ -static const u8_t sysname_len_default = 8; -static const u8_t sysname_default[] = "FQDN-unk"; -static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default; -static u8_t* sysname_ptr = (u8_t*)&sysname_default[0]; -/** mib-2.system.sysLocation */ -static const u8_t syslocation_len_default = 0; -static const u8_t syslocation_default[] = ""; -static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default; -static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0]; -/** mib-2.snmp.snmpEnableAuthenTraps */ -static const u8_t snmpenableauthentraps_default = 2; /* disabled */ -static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default; - -/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */ -static const struct snmp_obj_id ifspecific = {2, {0, 0}}; -/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */ -static const struct snmp_obj_id iprouteinfo = {2, {0, 0}}; - - - -/* mib-2.system counter(s) */ -static u32_t sysuptime = 0; - -/* mib-2.ip counter(s) */ -static u32_t ipinreceives = 0, - ipinhdrerrors = 0, - ipinaddrerrors = 0, - ipforwdatagrams = 0, - ipinunknownprotos = 0, - ipindiscards = 0, - ipindelivers = 0, - ipoutrequests = 0, - ipoutdiscards = 0, - ipoutnoroutes = 0, - ipreasmreqds = 0, - ipreasmoks = 0, - ipreasmfails = 0, - ipfragoks = 0, - ipfragfails = 0, - ipfragcreates = 0, - iproutingdiscards = 0; -/* mib-2.icmp counter(s) */ -static u32_t icmpinmsgs = 0, - icmpinerrors = 0, - icmpindestunreachs = 0, - icmpintimeexcds = 0, - icmpinparmprobs = 0, - icmpinsrcquenchs = 0, - icmpinredirects = 0, - icmpinechos = 0, - icmpinechoreps = 0, - icmpintimestamps = 0, - icmpintimestampreps = 0, - icmpinaddrmasks = 0, - icmpinaddrmaskreps = 0, - icmpoutmsgs = 0, - icmpouterrors = 0, - icmpoutdestunreachs = 0, - icmpouttimeexcds = 0, - icmpoutparmprobs = 0, - icmpoutsrcquenchs = 0, - icmpoutredirects = 0, - icmpoutechos = 0, - icmpoutechoreps = 0, - icmpouttimestamps = 0, - icmpouttimestampreps = 0, - icmpoutaddrmasks = 0, - icmpoutaddrmaskreps = 0; -/* mib-2.tcp counter(s) */ -static u32_t tcpactiveopens = 0, - tcppassiveopens = 0, - tcpattemptfails = 0, - tcpestabresets = 0, - tcpinsegs = 0, - tcpoutsegs = 0, - tcpretranssegs = 0, - tcpinerrs = 0, - tcpoutrsts = 0; -/* mib-2.udp counter(s) */ -static u32_t udpindatagrams = 0, - udpnoports = 0, - udpinerrors = 0, - udpoutdatagrams = 0; -/* mib-2.snmp counter(s) */ -static u32_t snmpinpkts = 0, - snmpoutpkts = 0, - snmpinbadversions = 0, - snmpinbadcommunitynames = 0, - snmpinbadcommunityuses = 0, - snmpinasnparseerrs = 0, - snmpintoobigs = 0, - snmpinnosuchnames = 0, - snmpinbadvalues = 0, - snmpinreadonlys = 0, - snmpingenerrs = 0, - snmpintotalreqvars = 0, - snmpintotalsetvars = 0, - snmpingetrequests = 0, - snmpingetnexts = 0, - snmpinsetrequests = 0, - snmpingetresponses = 0, - snmpintraps = 0, - snmpouttoobigs = 0, - snmpoutnosuchnames = 0, - snmpoutbadvalues = 0, - snmpoutgenerrs = 0, - snmpoutgetrequests = 0, - snmpoutgetnexts = 0, - snmpoutsetrequests = 0, - snmpoutgetresponses = 0, - snmpouttraps = 0; - - - -/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */ -/** - * Copy octet string. - * - * @param dst points to destination - * @param src points to source - * @param n number of octets to copy. - */ -static void ocstrncpy(u8_t *dst, u8_t *src, u16_t n) -{ - u16_t i = n; - while (i > 0) { - i--; - *dst++ = *src++; - } -} - -/** - * Copy object identifier (s32_t) array. - * - * @param dst points to destination - * @param src points to source - * @param n number of sub identifiers to copy. - */ -void objectidncpy(s32_t *dst, s32_t *src, u8_t n) -{ - u8_t i = n; - while(i > 0) { - i--; - *dst++ = *src++; - } -} - -/** - * Initializes sysDescr pointers. - * - * @param str if non-NULL then copy str pointer - * @param len points to string length, excluding zero terminator - */ -void snmp_set_sysdesr(u8_t *str, u8_t *len) -{ - if (str != NULL) - { - sysdescr_ptr = str; - sysdescr_len_ptr = len; - } -} - -void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid) -{ - *oid = &sysobjid; -} - -/** - * Initializes sysObjectID value. - * - * @param oid points to stuct snmp_obj_id to copy - */ -void snmp_set_sysobjid(struct snmp_obj_id *oid) -{ - sysobjid = *oid; -} - -/** - * Must be called at regular 10 msec interval from a timer interrupt - * or signal handler depending on your runtime environment. - */ -void snmp_inc_sysuptime(void) -{ - sysuptime++; -} - -void snmp_add_sysuptime(u32_t value) -{ - sysuptime+=value; -} - -void snmp_get_sysuptime(u32_t *value) -{ - SNMP_GET_SYSUPTIME(sysuptime); - *value = sysuptime; -} - -/** - * Initializes sysContact pointers, - * e.g. ptrs to non-volatile memory external to lwIP. - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator - */ -void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen) -{ - if (ocstr != NULL) - { - syscontact_ptr = ocstr; - syscontact_len_ptr = ocstrlen; - } -} - -/** - * Initializes sysName pointers, - * e.g. ptrs to non-volatile memory external to lwIP. - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator - */ -void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen) -{ - if (ocstr != NULL) - { - sysname_ptr = ocstr; - sysname_len_ptr = ocstrlen; - } -} - -/** - * Initializes sysLocation pointers, - * e.g. ptrs to non-volatile memory external to lwIP. - * - * @param ocstr if non-NULL then copy str pointer - * @param ocstrlen points to string length, excluding zero terminator - */ -void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen) -{ - if (ocstr != NULL) - { - syslocation_ptr = ocstr; - syslocation_len_ptr = ocstrlen; - } -} - - -void snmp_add_ifinoctets(struct netif *ni, u32_t value) -{ - ni->ifinoctets += value; -} - -void snmp_inc_ifinucastpkts(struct netif *ni) -{ - (ni->ifinucastpkts)++; -} - -void snmp_inc_ifinnucastpkts(struct netif *ni) -{ - (ni->ifinnucastpkts)++; -} - -void snmp_inc_ifindiscards(struct netif *ni) -{ - (ni->ifindiscards)++; -} - -void snmp_add_ifoutoctets(struct netif *ni, u32_t value) -{ - ni->ifoutoctets += value; -} - -void snmp_inc_ifoutucastpkts(struct netif *ni) -{ - (ni->ifoutucastpkts)++; -} - -void snmp_inc_ifoutnucastpkts(struct netif *ni) -{ - (ni->ifoutnucastpkts)++; -} - -void snmp_inc_ifoutdiscards(struct netif *ni) -{ - (ni->ifoutdiscards)++; -} - -void snmp_inc_iflist(void) -{ - struct mib_list_node *if_node = NULL; - - snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node); - /* enable getnext traversal on filled table */ - iftable.maxlength = 1; -} - -void snmp_dec_iflist(void) -{ - snmp_mib_node_delete(&iflist_root, iflist_root.tail); - /* disable getnext traversal on empty table */ - if(iflist_root.count == 0) iftable.maxlength = 0; -} - -/** - * Inserts ARP table indexes (.xIfIndex.xNetAddress) - * into arp table index trees (both atTable and ipNetToMediaTable). - */ -void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip) -{ - struct mib_list_rootnode *at_rn; - struct mib_list_node *at_node; - s32_t arpidx[5]; - u8_t level, tree; - - LWIP_ASSERT("ni != NULL", ni != NULL); - snmp_netiftoifindex(ni, &arpidx[0]); - snmp_iptooid(ip, &arpidx[1]); - - for (tree = 0; tree < 2; tree++) - { - if (tree == 0) - { - at_rn = &arptree_root; - } - else - { - at_rn = &ipntomtree_root; - } - for (level = 0; level < 5; level++) - { - at_node = NULL; - snmp_mib_node_insert(at_rn, arpidx[level], &at_node); - if ((level != 4) && (at_node != NULL)) - { - if (at_node->nptr == NULL) - { - at_rn = snmp_mib_lrn_alloc(); - at_node->nptr = (struct mib_node*)at_rn; - if (at_rn != NULL) - { - if (level == 3) - { - if (tree == 0) - { - at_rn->get_object_def = atentry_get_object_def; - at_rn->get_value = atentry_get_value; - } - else - { - at_rn->get_object_def = ip_ntomentry_get_object_def; - at_rn->get_value = ip_ntomentry_get_value; - } - at_rn->set_test = noleafs_set_test; - at_rn->set_value = noleafs_set_value; - } - } - else - { - /* at_rn == NULL, malloc failure */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full")); - break; - } - } - else - { - at_rn = (struct mib_list_rootnode*)at_node->nptr; - } - } - } - } - /* enable getnext traversal on filled tables */ - at.maxlength = 1; - ipntomtable.maxlength = 1; -} - -/** - * Removes ARP table indexes (.xIfIndex.xNetAddress) - * from arp table index trees. - */ -void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip) -{ - struct mib_list_rootnode *at_rn, *next, *del_rn[5]; - struct mib_list_node *at_n, *del_n[5]; - s32_t arpidx[5]; - u8_t fc, tree, level, del_cnt; - - snmp_netiftoifindex(ni, &arpidx[0]); - snmp_iptooid(ip, &arpidx[1]); - - for (tree = 0; tree < 2; tree++) - { - /* mark nodes for deletion */ - if (tree == 0) - { - at_rn = &arptree_root; - } - else - { - at_rn = &ipntomtree_root; - } - level = 0; - del_cnt = 0; - while ((level < 5) && (at_rn != NULL)) - { - fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n); - if (fc == 0) - { - /* arpidx[level] does not exist */ - del_cnt = 0; - at_rn = NULL; - } - else if (fc == 1) - { - del_rn[del_cnt] = at_rn; - del_n[del_cnt] = at_n; - del_cnt++; - at_rn = (struct mib_list_rootnode*)(at_n->nptr); - } - else if (fc == 2) - { - /* reset delete (2 or more childs) */ - del_cnt = 0; - at_rn = (struct mib_list_rootnode*)(at_n->nptr); - } - level++; - } - /* delete marked index nodes */ - while (del_cnt > 0) - { - del_cnt--; - - at_rn = del_rn[del_cnt]; - at_n = del_n[del_cnt]; - - next = snmp_mib_node_delete(at_rn, at_n); - if (next != NULL) - { - LWIP_ASSERT("next_count == 0",next->count == 0); - snmp_mib_lrn_free(next); - } - } - } - /* disable getnext traversal on empty tables */ - if(arptree_root.count == 0) at.maxlength = 0; - if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0; -} - -void snmp_inc_ipinreceives(void) -{ - ipinreceives++; -} - -void snmp_inc_ipinhdrerrors(void) -{ - ipinhdrerrors++; -} - -void snmp_inc_ipinaddrerrors(void) -{ - ipinaddrerrors++; -} - -void snmp_inc_ipforwdatagrams(void) -{ - ipforwdatagrams++; -} - -void snmp_inc_ipinunknownprotos(void) -{ - ipinunknownprotos++; -} - -void snmp_inc_ipindiscards(void) -{ - ipindiscards++; -} - -void snmp_inc_ipindelivers(void) -{ - ipindelivers++; -} - -void snmp_inc_ipoutrequests(void) -{ - ipoutrequests++; -} - -void snmp_inc_ipoutdiscards(void) -{ - ipoutdiscards++; -} - -void snmp_inc_ipoutnoroutes(void) -{ - ipoutnoroutes++; -} - -void snmp_inc_ipreasmreqds(void) -{ - ipreasmreqds++; -} - -void snmp_inc_ipreasmoks(void) -{ - ipreasmoks++; -} - -void snmp_inc_ipreasmfails(void) -{ - ipreasmfails++; -} - -void snmp_inc_ipfragoks(void) -{ - ipfragoks++; -} - -void snmp_inc_ipfragfails(void) -{ - ipfragfails++; -} - -void snmp_inc_ipfragcreates(void) -{ - ipfragcreates++; -} - -void snmp_inc_iproutingdiscards(void) -{ - iproutingdiscards++; -} - -/** - * Inserts ipAddrTable indexes (.ipAdEntAddr) - * into index tree. - */ -void snmp_insert_ipaddridx_tree(struct netif *ni) -{ - struct mib_list_rootnode *ipa_rn; - struct mib_list_node *ipa_node; - s32_t ipaddridx[4]; - u8_t level; - - LWIP_ASSERT("ni != NULL", ni != NULL); - snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); - - level = 0; - ipa_rn = &ipaddrtree_root; - while (level < 4) - { - ipa_node = NULL; - snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node); - if ((level != 3) && (ipa_node != NULL)) - { - if (ipa_node->nptr == NULL) - { - ipa_rn = snmp_mib_lrn_alloc(); - ipa_node->nptr = (struct mib_node*)ipa_rn; - if (ipa_rn != NULL) - { - if (level == 2) - { - ipa_rn->get_object_def = ip_addrentry_get_object_def; - ipa_rn->get_value = ip_addrentry_get_value; - ipa_rn->set_test = noleafs_set_test; - ipa_rn->set_value = noleafs_set_value; - } - } - else - { - /* ipa_rn == NULL, malloc failure */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full")); - break; - } - } - else - { - ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr; - } - } - level++; - } - /* enable getnext traversal on filled table */ - ipaddrtable.maxlength = 1; -} - -/** - * Removes ipAddrTable indexes (.ipAdEntAddr) - * from index tree. - */ -void snmp_delete_ipaddridx_tree(struct netif *ni) -{ - struct mib_list_rootnode *ipa_rn, *next, *del_rn[4]; - struct mib_list_node *ipa_n, *del_n[4]; - s32_t ipaddridx[4]; - u8_t fc, level, del_cnt; - - LWIP_ASSERT("ni != NULL", ni != NULL); - snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); - - /* mark nodes for deletion */ - level = 0; - del_cnt = 0; - ipa_rn = &ipaddrtree_root; - while ((level < 4) && (ipa_rn != NULL)) - { - fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n); - if (fc == 0) - { - /* ipaddridx[level] does not exist */ - del_cnt = 0; - ipa_rn = NULL; - } - else if (fc == 1) - { - del_rn[del_cnt] = ipa_rn; - del_n[del_cnt] = ipa_n; - del_cnt++; - ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); - } - else if (fc == 2) - { - /* reset delete (2 or more childs) */ - del_cnt = 0; - ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr); - } - level++; - } - /* delete marked index nodes */ - while (del_cnt > 0) - { - del_cnt--; - - ipa_rn = del_rn[del_cnt]; - ipa_n = del_n[del_cnt]; - - next = snmp_mib_node_delete(ipa_rn, ipa_n); - if (next != NULL) - { - LWIP_ASSERT("next_count == 0",next->count == 0); - snmp_mib_lrn_free(next); - } - } - /* disable getnext traversal on empty table */ - if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0; -} - -/** - * Inserts ipRouteTable indexes (.ipRouteDest) - * into index tree. - * - * @param dflt non-zero for the default rte, zero for network rte - * @param ni points to network interface for this rte - * - * @todo record sysuptime for _this_ route when it is installed - * (needed for ipRouteAge) in the netif. - */ -void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) -{ - u8_t insert = 0; - ip_addr_t dst; - - if (dflt != 0) - { - /* the default route 0.0.0.0 */ - ip_addr_set_any(&dst); - insert = 1; - } - else - { - /* route to the network address */ - ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); - /* exclude 0.0.0.0 network (reserved for default rte) */ - if (!ip_addr_isany(&dst)) { - insert = 1; - } - } - if (insert) - { - struct mib_list_rootnode *iprte_rn; - struct mib_list_node *iprte_node; - s32_t iprteidx[4]; - u8_t level; - - snmp_iptooid(&dst, &iprteidx[0]); - level = 0; - iprte_rn = &iprtetree_root; - while (level < 4) - { - iprte_node = NULL; - snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node); - if ((level != 3) && (iprte_node != NULL)) - { - if (iprte_node->nptr == NULL) - { - iprte_rn = snmp_mib_lrn_alloc(); - iprte_node->nptr = (struct mib_node*)iprte_rn; - if (iprte_rn != NULL) - { - if (level == 2) - { - iprte_rn->get_object_def = ip_rteentry_get_object_def; - iprte_rn->get_value = ip_rteentry_get_value; - iprte_rn->set_test = noleafs_set_test; - iprte_rn->set_value = noleafs_set_value; - } - } - else - { - /* iprte_rn == NULL, malloc failure */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full")); - break; - } - } - else - { - iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr; - } - } - level++; - } - } - /* enable getnext traversal on filled table */ - iprtetable.maxlength = 1; -} - -/** - * Removes ipRouteTable indexes (.ipRouteDest) - * from index tree. - * - * @param dflt non-zero for the default rte, zero for network rte - * @param ni points to network interface for this rte or NULL - * for default route to be removed. - */ -void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni) -{ - u8_t del = 0; - ip_addr_t dst; - - if (dflt != 0) - { - /* the default route 0.0.0.0 */ - ip_addr_set_any(&dst); - del = 1; - } - else - { - /* route to the network address */ - ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); - /* exclude 0.0.0.0 network (reserved for default rte) */ - if (!ip_addr_isany(&dst)) { - del = 1; - } - } - if (del) - { - struct mib_list_rootnode *iprte_rn, *next, *del_rn[4]; - struct mib_list_node *iprte_n, *del_n[4]; - s32_t iprteidx[4]; - u8_t fc, level, del_cnt; - - snmp_iptooid(&dst, &iprteidx[0]); - /* mark nodes for deletion */ - level = 0; - del_cnt = 0; - iprte_rn = &iprtetree_root; - while ((level < 4) && (iprte_rn != NULL)) - { - fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n); - if (fc == 0) - { - /* iprteidx[level] does not exist */ - del_cnt = 0; - iprte_rn = NULL; - } - else if (fc == 1) - { - del_rn[del_cnt] = iprte_rn; - del_n[del_cnt] = iprte_n; - del_cnt++; - iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); - } - else if (fc == 2) - { - /* reset delete (2 or more childs) */ - del_cnt = 0; - iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr); - } - level++; - } - /* delete marked index nodes */ - while (del_cnt > 0) - { - del_cnt--; - - iprte_rn = del_rn[del_cnt]; - iprte_n = del_n[del_cnt]; - - next = snmp_mib_node_delete(iprte_rn, iprte_n); - if (next != NULL) - { - LWIP_ASSERT("next_count == 0",next->count == 0); - snmp_mib_lrn_free(next); - } - } - } - /* disable getnext traversal on empty table */ - if (iprtetree_root.count == 0) iprtetable.maxlength = 0; -} - - -void snmp_inc_icmpinmsgs(void) -{ - icmpinmsgs++; -} - -void snmp_inc_icmpinerrors(void) -{ - icmpinerrors++; -} - -void snmp_inc_icmpindestunreachs(void) -{ - icmpindestunreachs++; -} - -void snmp_inc_icmpintimeexcds(void) -{ - icmpintimeexcds++; -} - -void snmp_inc_icmpinparmprobs(void) -{ - icmpinparmprobs++; -} - -void snmp_inc_icmpinsrcquenchs(void) -{ - icmpinsrcquenchs++; -} - -void snmp_inc_icmpinredirects(void) -{ - icmpinredirects++; -} - -void snmp_inc_icmpinechos(void) -{ - icmpinechos++; -} - -void snmp_inc_icmpinechoreps(void) -{ - icmpinechoreps++; -} - -void snmp_inc_icmpintimestamps(void) -{ - icmpintimestamps++; -} - -void snmp_inc_icmpintimestampreps(void) -{ - icmpintimestampreps++; -} - -void snmp_inc_icmpinaddrmasks(void) -{ - icmpinaddrmasks++; -} - -void snmp_inc_icmpinaddrmaskreps(void) -{ - icmpinaddrmaskreps++; -} - -void snmp_inc_icmpoutmsgs(void) -{ - icmpoutmsgs++; -} - -void snmp_inc_icmpouterrors(void) -{ - icmpouterrors++; -} - -void snmp_inc_icmpoutdestunreachs(void) -{ - icmpoutdestunreachs++; -} - -void snmp_inc_icmpouttimeexcds(void) -{ - icmpouttimeexcds++; -} - -void snmp_inc_icmpoutparmprobs(void) -{ - icmpoutparmprobs++; -} - -void snmp_inc_icmpoutsrcquenchs(void) -{ - icmpoutsrcquenchs++; -} - -void snmp_inc_icmpoutredirects(void) -{ - icmpoutredirects++; -} - -void snmp_inc_icmpoutechos(void) -{ - icmpoutechos++; -} - -void snmp_inc_icmpoutechoreps(void) -{ - icmpoutechoreps++; -} - -void snmp_inc_icmpouttimestamps(void) -{ - icmpouttimestamps++; -} - -void snmp_inc_icmpouttimestampreps(void) -{ - icmpouttimestampreps++; -} - -void snmp_inc_icmpoutaddrmasks(void) -{ - icmpoutaddrmasks++; -} - -void snmp_inc_icmpoutaddrmaskreps(void) -{ - icmpoutaddrmaskreps++; -} - -void snmp_inc_tcpactiveopens(void) -{ - tcpactiveopens++; -} - -void snmp_inc_tcppassiveopens(void) -{ - tcppassiveopens++; -} - -void snmp_inc_tcpattemptfails(void) -{ - tcpattemptfails++; -} - -void snmp_inc_tcpestabresets(void) -{ - tcpestabresets++; -} - -void snmp_inc_tcpinsegs(void) -{ - tcpinsegs++; -} - -void snmp_inc_tcpoutsegs(void) -{ - tcpoutsegs++; -} - -void snmp_inc_tcpretranssegs(void) -{ - tcpretranssegs++; -} - -void snmp_inc_tcpinerrs(void) -{ - tcpinerrs++; -} - -void snmp_inc_tcpoutrsts(void) -{ - tcpoutrsts++; -} - -void snmp_inc_udpindatagrams(void) -{ - udpindatagrams++; -} - -void snmp_inc_udpnoports(void) -{ - udpnoports++; -} - -void snmp_inc_udpinerrors(void) -{ - udpinerrors++; -} - -void snmp_inc_udpoutdatagrams(void) -{ - udpoutdatagrams++; -} - -/** - * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort) - * into index tree. - */ -void snmp_insert_udpidx_tree(struct udp_pcb *pcb) -{ - struct mib_list_rootnode *udp_rn; - struct mib_list_node *udp_node; - s32_t udpidx[5]; - u8_t level; - - LWIP_ASSERT("pcb != NULL", pcb != NULL); - snmp_iptooid(&pcb->local_ip, &udpidx[0]); - udpidx[4] = pcb->local_port; - - udp_rn = &udp_root; - for (level = 0; level < 5; level++) - { - udp_node = NULL; - snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node); - if ((level != 4) && (udp_node != NULL)) - { - if (udp_node->nptr == NULL) - { - udp_rn = snmp_mib_lrn_alloc(); - udp_node->nptr = (struct mib_node*)udp_rn; - if (udp_rn != NULL) - { - if (level == 3) - { - udp_rn->get_object_def = udpentry_get_object_def; - udp_rn->get_value = udpentry_get_value; - udp_rn->set_test = noleafs_set_test; - udp_rn->set_value = noleafs_set_value; - } - } - else - { - /* udp_rn == NULL, malloc failure */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full")); - break; - } - } - else - { - udp_rn = (struct mib_list_rootnode*)udp_node->nptr; - } - } - } - udptable.maxlength = 1; -} - -/** - * Removes udpTable indexes (.udpLocalAddress.udpLocalPort) - * from index tree. - */ -void snmp_delete_udpidx_tree(struct udp_pcb *pcb) -{ - struct udp_pcb *npcb; - struct mib_list_rootnode *udp_rn, *next, *del_rn[5]; - struct mib_list_node *udp_n, *del_n[5]; - s32_t udpidx[5]; - u8_t bindings, fc, level, del_cnt; - - LWIP_ASSERT("pcb != NULL", pcb != NULL); - snmp_iptooid(&pcb->local_ip, &udpidx[0]); - udpidx[4] = pcb->local_port; - - /* count PCBs for a given binding - (e.g. when reusing ports or for temp output PCBs) */ - bindings = 0; - npcb = udp_pcbs; - while ((npcb != NULL)) - { - if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) && - (npcb->local_port == udpidx[4])) - { - bindings++; - } - npcb = npcb->next; - } - if (bindings == 1) - { - /* selectively remove */ - /* mark nodes for deletion */ - level = 0; - del_cnt = 0; - udp_rn = &udp_root; - while ((level < 5) && (udp_rn != NULL)) - { - fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n); - if (fc == 0) - { - /* udpidx[level] does not exist */ - del_cnt = 0; - udp_rn = NULL; - } - else if (fc == 1) - { - del_rn[del_cnt] = udp_rn; - del_n[del_cnt] = udp_n; - del_cnt++; - udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); - } - else if (fc == 2) - { - /* reset delete (2 or more childs) */ - del_cnt = 0; - udp_rn = (struct mib_list_rootnode*)(udp_n->nptr); - } - level++; - } - /* delete marked index nodes */ - while (del_cnt > 0) - { - del_cnt--; - - udp_rn = del_rn[del_cnt]; - udp_n = del_n[del_cnt]; - - next = snmp_mib_node_delete(udp_rn, udp_n); - if (next != NULL) - { - LWIP_ASSERT("next_count == 0",next->count == 0); - snmp_mib_lrn_free(next); - } - } - } - /* disable getnext traversal on empty table */ - if (udp_root.count == 0) udptable.maxlength = 0; -} - - -void snmp_inc_snmpinpkts(void) -{ - snmpinpkts++; -} - -void snmp_inc_snmpoutpkts(void) -{ - snmpoutpkts++; -} - -void snmp_inc_snmpinbadversions(void) -{ - snmpinbadversions++; -} - -void snmp_inc_snmpinbadcommunitynames(void) -{ - snmpinbadcommunitynames++; -} - -void snmp_inc_snmpinbadcommunityuses(void) -{ - snmpinbadcommunityuses++; -} - -void snmp_inc_snmpinasnparseerrs(void) -{ - snmpinasnparseerrs++; -} - -void snmp_inc_snmpintoobigs(void) -{ - snmpintoobigs++; -} - -void snmp_inc_snmpinnosuchnames(void) -{ - snmpinnosuchnames++; -} - -void snmp_inc_snmpinbadvalues(void) -{ - snmpinbadvalues++; -} - -void snmp_inc_snmpinreadonlys(void) -{ - snmpinreadonlys++; -} - -void snmp_inc_snmpingenerrs(void) -{ - snmpingenerrs++; -} - -void snmp_add_snmpintotalreqvars(u8_t value) -{ - snmpintotalreqvars += value; -} - -void snmp_add_snmpintotalsetvars(u8_t value) -{ - snmpintotalsetvars += value; -} - -void snmp_inc_snmpingetrequests(void) -{ - snmpingetrequests++; -} - -void snmp_inc_snmpingetnexts(void) -{ - snmpingetnexts++; -} - -void snmp_inc_snmpinsetrequests(void) -{ - snmpinsetrequests++; -} - -void snmp_inc_snmpingetresponses(void) -{ - snmpingetresponses++; -} - -void snmp_inc_snmpintraps(void) -{ - snmpintraps++; -} - -void snmp_inc_snmpouttoobigs(void) -{ - snmpouttoobigs++; -} - -void snmp_inc_snmpoutnosuchnames(void) -{ - snmpoutnosuchnames++; -} - -void snmp_inc_snmpoutbadvalues(void) -{ - snmpoutbadvalues++; -} - -void snmp_inc_snmpoutgenerrs(void) -{ - snmpoutgenerrs++; -} - -void snmp_inc_snmpoutgetrequests(void) -{ - snmpoutgetrequests++; -} - -void snmp_inc_snmpoutgetnexts(void) -{ - snmpoutgetnexts++; -} - -void snmp_inc_snmpoutsetrequests(void) -{ - snmpoutsetrequests++; -} - -void snmp_inc_snmpoutgetresponses(void) -{ - snmpoutgetresponses++; -} - -void snmp_inc_snmpouttraps(void) -{ - snmpouttraps++; -} - -void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid) -{ - *oid = &snmpgrp_id; -} - -void snmp_set_snmpenableauthentraps(u8_t *value) -{ - if (value != NULL) - { - snmpenableauthentraps_ptr = value; - } -} - -void snmp_get_snmpenableauthentraps(u8_t *value) -{ - *value = *snmpenableauthentraps_ptr; -} - -void -noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - LWIP_UNUSED_ARG(ident_len); - LWIP_UNUSED_ARG(ident); - od->instance = MIB_OBJECT_NONE; -} - -void -noleafs_get_value(struct obj_def *od, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(od); - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value); -} - -u8_t -noleafs_set_test(struct obj_def *od, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(od); - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value); - /* can't set */ - return 0; -} - -void -noleafs_set_value(struct obj_def *od, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(od); - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value); -} - - -/** - * Returns systems object definitions. - * - * @param ident_len the address length (2) - * @param ident points to objectname.0 (object id trailer) - * @param od points to object definition. - */ -static void -system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - u8_t id; - - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id)); - switch (id) - { - case 1: /* sysDescr */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = *sysdescr_len_ptr; - break; - case 2: /* sysObjectID */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); - od->v_len = sysobjid.len * sizeof(s32_t); - break; - case 3: /* sysUpTime */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); - od->v_len = sizeof(u32_t); - break; - case 4: /* sysContact */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = *syscontact_len_ptr; - break; - case 5: /* sysName */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = *sysname_len_ptr; - break; - case 6: /* sysLocation */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = *syslocation_len_ptr; - break; - case 7: /* sysServices */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -/** - * Returns system object value. - * - * @param ident_len the address length (2) - * @param ident points to objectname.0 (object id trailer) - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value into. - */ -static void -system_get_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* sysDescr */ - ocstrncpy((u8_t*)value, sysdescr_ptr, len); - break; - case 2: /* sysObjectID */ - objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t))); - break; - case 3: /* sysUpTime */ - { - snmp_get_sysuptime((u32_t*)value); - } - break; - case 4: /* sysContact */ - ocstrncpy((u8_t*)value, syscontact_ptr, len); - break; - case 5: /* sysName */ - ocstrncpy((u8_t*)value, sysname_ptr, len); - break; - case 6: /* sysLocation */ - ocstrncpy((u8_t*)value, syslocation_ptr, len); - break; - case 7: /* sysServices */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = sysservices; - } - break; - }; -} - -static u8_t -system_set_test(struct obj_def *od, u16_t len, void *value) -{ - u8_t id, set_ok; - - LWIP_UNUSED_ARG(value); - set_ok = 0; - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 4: /* sysContact */ - if ((syscontact_ptr != syscontact_default) && - (len <= 255)) - { - set_ok = 1; - } - break; - case 5: /* sysName */ - if ((sysname_ptr != sysname_default) && - (len <= 255)) - { - set_ok = 1; - } - break; - case 6: /* sysLocation */ - if ((syslocation_ptr != syslocation_default) && - (len <= 255)) - { - set_ok = 1; - } - break; - }; - return set_ok; -} - -static void -system_set_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - - LWIP_ASSERT("invalid len", len <= 0xff); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 4: /* sysContact */ - ocstrncpy(syscontact_ptr, (u8_t*)value, len); - *syscontact_len_ptr = (u8_t)len; - break; - case 5: /* sysName */ - ocstrncpy(sysname_ptr, (u8_t*)value, len); - *sysname_len_ptr = (u8_t)len; - break; - case 6: /* sysLocation */ - ocstrncpy(syslocation_ptr, (u8_t*)value, len); - *syslocation_len_ptr = (u8_t)len; - break; - }; -} - -/** - * Returns interfaces.ifnumber object definition. - * - * @param ident_len the address length (2) - * @param ident points to objectname.index - * @param od points to object definition. - */ -static void -interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -/** - * Returns interfaces.ifnumber object value. - * - * @param ident_len the address length (2) - * @param ident points to objectname.0 (object id trailer) - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value into. - */ -static void -interfaces_get_value(struct obj_def *od, u16_t len, void *value) -{ - LWIP_UNUSED_ARG(len); - if (od->id_inst_ptr[0] == 1) - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = iflist_root.count; - } -} - -/** - * Returns ifentry object definitions. - * - * @param ident_len the address length (2) - * @param ident points to objectname.index - * @param od points to object definition. - */ -static void -ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - u8_t id; - - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id)); - switch (id) - { - case 1: /* ifIndex */ - case 3: /* ifType */ - case 4: /* ifMtu */ - case 8: /* ifOperStatus */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 2: /* ifDescr */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - /** @todo this should be some sort of sizeof(struct netif.name) */ - od->v_len = 2; - break; - case 5: /* ifSpeed */ - case 21: /* ifOutQLen */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); - od->v_len = sizeof(u32_t); - break; - case 6: /* ifPhysAddress */ - { - struct netif *netif; - - snmp_ifindextonetif(ident[1], &netif); - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = netif->hwaddr_len; - } - break; - case 7: /* ifAdminStatus */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 9: /* ifLastChange */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS); - od->v_len = sizeof(u32_t); - break; - case 10: /* ifInOctets */ - case 11: /* ifInUcastPkts */ - case 12: /* ifInNUcastPkts */ - case 13: /* ifInDiscarts */ - case 14: /* ifInErrors */ - case 15: /* ifInUnkownProtos */ - case 16: /* ifOutOctets */ - case 17: /* ifOutUcastPkts */ - case 18: /* ifOutNUcastPkts */ - case 19: /* ifOutDiscarts */ - case 20: /* ifOutErrors */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - break; - case 22: /* ifSpecific */ - /** @note returning zeroDotZero (0.0) no media specific MIB support */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); - od->v_len = ifspecific.len * sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -/** - * Returns ifentry object value. - * - * @param ident_len the address length (2) - * @param ident points to objectname.0 (object id trailer) - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value into. - */ -static void -ifentry_get_value(struct obj_def *od, u16_t len, void *value) -{ - struct netif *netif; - u8_t id; - - snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* ifIndex */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = od->id_inst_ptr[1]; - } - break; - case 2: /* ifDescr */ - ocstrncpy((u8_t*)value, (u8_t*)netif->name, len); - break; - case 3: /* ifType */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = netif->link_type; - } - break; - case 4: /* ifMtu */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = netif->mtu; - } - break; - case 5: /* ifSpeed */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->link_speed; - } - break; - case 6: /* ifPhysAddress */ - ocstrncpy((u8_t*)value, netif->hwaddr, len); - break; - case 7: /* ifAdminStatus */ - { - s32_t *sint_ptr = (s32_t*)value; - if (netif_is_up(netif)) - { - if (netif_is_link_up(netif)) - { - *sint_ptr = 1; /* up */ - } - else - { - *sint_ptr = 7; /* lowerLayerDown */ - } - } - else - { - *sint_ptr = 2; /* down */ - } - } - break; - case 8: /* ifOperStatus */ - { - s32_t *sint_ptr = (s32_t*)value; - if (netif_is_up(netif)) - { - *sint_ptr = 1; - } - else - { - *sint_ptr = 2; - } - } - break; - case 9: /* ifLastChange */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ts; - } - break; - case 10: /* ifInOctets */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifinoctets; - } - break; - case 11: /* ifInUcastPkts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifinucastpkts; - } - break; - case 12: /* ifInNUcastPkts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifinnucastpkts; - } - break; - case 13: /* ifInDiscarts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifindiscards; - } - break; - case 14: /* ifInErrors */ - case 15: /* ifInUnkownProtos */ - /** @todo add these counters! */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = 0; - } - break; - case 16: /* ifOutOctets */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifoutoctets; - } - break; - case 17: /* ifOutUcastPkts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifoutucastpkts; - } - break; - case 18: /* ifOutNUcastPkts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifoutnucastpkts; - } - break; - case 19: /* ifOutDiscarts */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = netif->ifoutdiscards; - } - break; - case 20: /* ifOutErrors */ - /** @todo add this counter! */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = 0; - } - break; - case 21: /* ifOutQLen */ - /** @todo figure out if this must be 0 (no queue) or 1? */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = 0; - } - break; - case 22: /* ifSpecific */ - objectidncpy((s32_t*)value, (s32_t*)ifspecific.id, (u8_t)(len / sizeof(s32_t))); - break; - }; -} - -#if !SNMP_SAFE_REQUESTS -static u8_t -ifentry_set_test(struct obj_def *od, u16_t len, void *value) -{ - struct netif *netif; - u8_t id, set_ok; - LWIP_UNUSED_ARG(len); - - set_ok = 0; - snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 7: /* ifAdminStatus */ - { - s32_t *sint_ptr = (s32_t*)value; - if (*sint_ptr == 1 || *sint_ptr == 2) - set_ok = 1; - } - break; - } - return set_ok; -} - -static void -ifentry_set_value(struct obj_def *od, u16_t len, void *value) -{ - struct netif *netif; - u8_t id; - LWIP_UNUSED_ARG(len); - - snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 7: /* ifAdminStatus */ - { - s32_t *sint_ptr = (s32_t*)value; - if (*sint_ptr == 1) - { - netif_set_up(netif); - } - else if (*sint_ptr == 2) - { - netif_set_down(netif); - } - } - break; - } -} -#endif /* SNMP_SAFE_REQUESTS */ - -/** - * Returns atentry object definitions. - * - * @param ident_len the address length (6) - * @param ident points to objectname.atifindex.atnetaddress - * @param od points to object definition. - */ -static void -atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (5) */ - ident_len += 5; - ident -= 5; - - if (ident_len == 6) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - switch (ident[0]) - { - case 1: /* atIfIndex */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 2: /* atPhysAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = 6; /** @todo try to use netif::hwaddr_len */ - break; - case 3: /* atNetAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - } - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -atentry_get_value(struct obj_def *od, u16_t len, void *value) -{ -#if LWIP_ARP - u8_t id; - struct eth_addr* ethaddr_ret; - ip_addr_t* ipaddr_ret; -#endif /* LWIP_ARP */ - ip_addr_t ip; - struct netif *netif; - - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ - - snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - snmp_oidtoip(&od->id_inst_ptr[2], &ip); - -#if LWIP_ARP /** @todo implement a netif_find_addr */ - if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) - { - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* atIfIndex */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = od->id_inst_ptr[1]; - } - break; - case 2: /* atPhysAddress */ - { - struct eth_addr *dst = (struct eth_addr*)value; - - *dst = *ethaddr_ret; - } - break; - case 3: /* atNetAddress */ - { - ip_addr_t *dst = (ip_addr_t*)value; - - *dst = *ipaddr_ret; - } - break; - } - } -#endif /* LWIP_ARP */ -} - -static void -ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - u8_t id; - - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id)); - switch (id) - { - case 1: /* ipForwarding */ - case 2: /* ipDefaultTTL */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 3: /* ipInReceives */ - case 4: /* ipInHdrErrors */ - case 5: /* ipInAddrErrors */ - case 6: /* ipForwDatagrams */ - case 7: /* ipInUnknownProtos */ - case 8: /* ipInDiscards */ - case 9: /* ipInDelivers */ - case 10: /* ipOutRequests */ - case 11: /* ipOutDiscards */ - case 12: /* ipOutNoRoutes */ - case 14: /* ipReasmReqds */ - case 15: /* ipReasmOKs */ - case 16: /* ipReasmFails */ - case 17: /* ipFragOKs */ - case 18: /* ipFragFails */ - case 19: /* ipFragCreates */ - case 23: /* ipRoutingDiscards */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - break; - case 13: /* ipReasmTimeout */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -ip_get_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* ipForwarding */ - { - s32_t *sint_ptr = (s32_t*)value; -#if IP_FORWARD - /* forwarding */ - *sint_ptr = 1; -#else - /* not-forwarding */ - *sint_ptr = 2; -#endif - } - break; - case 2: /* ipDefaultTTL */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = IP_DEFAULT_TTL; - } - break; - case 3: /* ipInReceives */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipinreceives; - } - break; - case 4: /* ipInHdrErrors */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipinhdrerrors; - } - break; - case 5: /* ipInAddrErrors */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipinaddrerrors; - } - break; - case 6: /* ipForwDatagrams */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipforwdatagrams; - } - break; - case 7: /* ipInUnknownProtos */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipinunknownprotos; - } - break; - case 8: /* ipInDiscards */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipindiscards; - } - break; - case 9: /* ipInDelivers */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipindelivers; - } - break; - case 10: /* ipOutRequests */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipoutrequests; - } - break; - case 11: /* ipOutDiscards */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipoutdiscards; - } - break; - case 12: /* ipOutNoRoutes */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipoutnoroutes; - } - break; - case 13: /* ipReasmTimeout */ - { - s32_t *sint_ptr = (s32_t*)value; -#if IP_REASSEMBLY - *sint_ptr = IP_REASS_MAXAGE; -#else - *sint_ptr = 0; -#endif - } - break; - case 14: /* ipReasmReqds */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipreasmreqds; - } - break; - case 15: /* ipReasmOKs */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipreasmoks; - } - break; - case 16: /* ipReasmFails */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipreasmfails; - } - break; - case 17: /* ipFragOKs */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipfragoks; - } - break; - case 18: /* ipFragFails */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipfragfails; - } - break; - case 19: /* ipFragCreates */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = ipfragcreates; - } - break; - case 23: /* ipRoutingDiscards */ - /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ - { - u32_t *uint_ptr = (u32_t*)value; - *uint_ptr = iproutingdiscards; - } - break; - }; -} - -/** - * Test ip object value before setting. - * - * @param od is the object definition - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value from. - * - * @note we allow set if the value matches the hardwired value, - * otherwise return badvalue. - */ -static u8_t -ip_set_test(struct obj_def *od, u16_t len, void *value) -{ - u8_t id, set_ok; - s32_t *sint_ptr = (s32_t*)value; - - LWIP_UNUSED_ARG(len); - set_ok = 0; - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* ipForwarding */ -#if IP_FORWARD - /* forwarding */ - if (*sint_ptr == 1) -#else - /* not-forwarding */ - if (*sint_ptr == 2) -#endif - { - set_ok = 1; - } - break; - case 2: /* ipDefaultTTL */ - if (*sint_ptr == IP_DEFAULT_TTL) - { - set_ok = 1; - } - break; - }; - return set_ok; -} - -static void -ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (4) */ - ident_len += 4; - ident -= 4; - - if (ident_len == 5) - { - u8_t id; - - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - switch (id) - { - case 1: /* ipAdEntAddr */ - case 3: /* ipAdEntNetMask */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - case 2: /* ipAdEntIfIndex */ - case 4: /* ipAdEntBcastAddr */ - case 5: /* ipAdEntReasmMaxSize */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - } - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - u16_t ifidx; - ip_addr_t ip; - struct netif *netif = netif_list; - - LWIP_UNUSED_ARG(len); - snmp_oidtoip(&od->id_inst_ptr[1], &ip); - ifidx = 0; - while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) - { - netif = netif->next; - ifidx++; - } - - if (netif != NULL) - { - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* ipAdEntAddr */ - { - ip_addr_t *dst = (ip_addr_t*)value; - *dst = netif->ip_addr; - } - break; - case 2: /* ipAdEntIfIndex */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = ifidx + 1; - } - break; - case 3: /* ipAdEntNetMask */ - { - ip_addr_t *dst = (ip_addr_t*)value; - *dst = netif->netmask; - } - break; - case 4: /* ipAdEntBcastAddr */ - { - s32_t *sint_ptr = (s32_t*)value; - - /* lwIP oddity, there's no broadcast - address in the netif we can rely on */ - *sint_ptr = IPADDR_BROADCAST & 1; - } - break; - case 5: /* ipAdEntReasmMaxSize */ - { - s32_t *sint_ptr = (s32_t*)value; -#if IP_REASSEMBLY - /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, - * but only if receiving one fragmented packet at a time. - * The current solution is to calculate for 2 simultaneous packets... - */ - *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) * - (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN))); -#else - /** @todo returning MTU would be a bad thing and - returning a wild guess like '576' isn't good either */ - *sint_ptr = 0; -#endif - } - break; - } - } -} - -/** - * @note - * lwIP IP routing is currently using the network addresses in netif_list. - * if no suitable network IP is found in netif_list, the default_netif is used. - */ -static void -ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - u8_t id; - - /* return to object name, adding index depth (4) */ - ident_len += 4; - ident -= 4; - - if (ident_len == 5) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - switch (id) - { - case 1: /* ipRouteDest */ - case 7: /* ipRouteNextHop */ - case 11: /* ipRouteMask */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - case 2: /* ipRouteIfIndex */ - case 3: /* ipRouteMetric1 */ - case 4: /* ipRouteMetric2 */ - case 5: /* ipRouteMetric3 */ - case 6: /* ipRouteMetric4 */ - case 8: /* ipRouteType */ - case 10: /* ipRouteAge */ - case 12: /* ipRouteMetric5 */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 9: /* ipRouteProto */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 13: /* ipRouteInfo */ - /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID); - od->v_len = iprouteinfo.len * sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - } - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) -{ - struct netif *netif; - ip_addr_t dest; - s32_t *ident; - u8_t id; - - ident = od->id_inst_ptr; - snmp_oidtoip(&ident[1], &dest); - - if (ip_addr_isany(&dest)) - { - /* ip_route() uses default netif for default route */ - netif = netif_default; - } - else - { - /* not using ip_route(), need exact match! */ - netif = netif_list; - while ((netif != NULL) && - !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) ) - { - netif = netif->next; - } - } - if (netif != NULL) - { - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - switch (id) - { - case 1: /* ipRouteDest */ - { - ip_addr_t *dst = (ip_addr_t*)value; - - if (ip_addr_isany(&dest)) - { - /* default rte has 0.0.0.0 dest */ - ip_addr_set_zero(dst); - } - else - { - /* netifs have netaddress dest */ - ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask); - } - } - break; - case 2: /* ipRouteIfIndex */ - { - s32_t *sint_ptr = (s32_t*)value; - - snmp_netiftoifindex(netif, sint_ptr); - } - break; - case 3: /* ipRouteMetric1 */ - { - s32_t *sint_ptr = (s32_t*)value; - - if (ip_addr_isany(&dest)) - { - /* default rte has metric 1 */ - *sint_ptr = 1; - } - else - { - /* other rtes have metric 0 */ - *sint_ptr = 0; - } - } - break; - case 4: /* ipRouteMetric2 */ - case 5: /* ipRouteMetric3 */ - case 6: /* ipRouteMetric4 */ - case 12: /* ipRouteMetric5 */ - { - s32_t *sint_ptr = (s32_t*)value; - /* not used */ - *sint_ptr = -1; - } - break; - case 7: /* ipRouteNextHop */ - { - ip_addr_t *dst = (ip_addr_t*)value; - - if (ip_addr_isany(&dest)) - { - /* default rte: gateway */ - *dst = netif->gw; - } - else - { - /* other rtes: netif ip_addr */ - *dst = netif->ip_addr; - } - } - break; - case 8: /* ipRouteType */ - { - s32_t *sint_ptr = (s32_t*)value; - - if (ip_addr_isany(&dest)) - { - /* default rte is indirect */ - *sint_ptr = 4; - } - else - { - /* other rtes are direct */ - *sint_ptr = 3; - } - } - break; - case 9: /* ipRouteProto */ - { - s32_t *sint_ptr = (s32_t*)value; - /* locally defined routes */ - *sint_ptr = 2; - } - break; - case 10: /* ipRouteAge */ - { - s32_t *sint_ptr = (s32_t*)value; - /** @todo (sysuptime - timestamp last change) / 100 - @see snmp_insert_iprteidx_tree() */ - *sint_ptr = 0; - } - break; - case 11: /* ipRouteMask */ - { - ip_addr_t *dst = (ip_addr_t*)value; - - if (ip_addr_isany(&dest)) - { - /* default rte use 0.0.0.0 mask */ - ip_addr_set_zero(dst); - } - else - { - /* other rtes use netmask */ - *dst = netif->netmask; - } - } - break; - case 13: /* ipRouteInfo */ - objectidncpy((s32_t*)value, (s32_t*)iprouteinfo.id, (u8_t)(len / sizeof(s32_t))); - break; - } - } -} - -static void -ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (5) */ - ident_len += 5; - ident -= 5; - - if (ident_len == 6) - { - u8_t id; - - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - switch (id) - { - case 1: /* ipNetToMediaIfIndex */ - case 4: /* ipNetToMediaType */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 2: /* ipNetToMediaPhysAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR); - od->v_len = 6; /** @todo try to use netif::hwaddr_len */ - break; - case 3: /* ipNetToMediaNetAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - } - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) -{ -#if LWIP_ARP - u8_t id; - struct eth_addr* ethaddr_ret; - ip_addr_t* ipaddr_ret; -#endif /* LWIP_ARP */ - ip_addr_t ip; - struct netif *netif; - - LWIP_UNUSED_ARG(len); - LWIP_UNUSED_ARG(value);/* if !LWIP_ARP */ - - snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - snmp_oidtoip(&od->id_inst_ptr[2], &ip); - -#if LWIP_ARP /** @todo implement a netif_find_addr */ - if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) - { - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* ipNetToMediaIfIndex */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = od->id_inst_ptr[1]; - } - break; - case 2: /* ipNetToMediaPhysAddress */ - { - struct eth_addr *dst = (struct eth_addr*)value; - - *dst = *ethaddr_ret; - } - break; - case 3: /* ipNetToMediaNetAddress */ - { - ip_addr_t *dst = (ip_addr_t*)value; - - *dst = *ipaddr_ret; - } - break; - case 4: /* ipNetToMediaType */ - { - s32_t *sint_ptr = (s32_t*)value; - /* dynamic (?) */ - *sint_ptr = 3; - } - break; - } - } -#endif /* LWIP_ARP */ -} - -static void -icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if ((ident_len == 2) && - (ident[0] > 0) && (ident[0] < 27)) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -icmp_get_value(struct obj_def *od, u16_t len, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* icmpInMsgs */ - *uint_ptr = icmpinmsgs; - break; - case 2: /* icmpInErrors */ - *uint_ptr = icmpinerrors; - break; - case 3: /* icmpInDestUnreachs */ - *uint_ptr = icmpindestunreachs; - break; - case 4: /* icmpInTimeExcds */ - *uint_ptr = icmpintimeexcds; - break; - case 5: /* icmpInParmProbs */ - *uint_ptr = icmpinparmprobs; - break; - case 6: /* icmpInSrcQuenchs */ - *uint_ptr = icmpinsrcquenchs; - break; - case 7: /* icmpInRedirects */ - *uint_ptr = icmpinredirects; - break; - case 8: /* icmpInEchos */ - *uint_ptr = icmpinechos; - break; - case 9: /* icmpInEchoReps */ - *uint_ptr = icmpinechoreps; - break; - case 10: /* icmpInTimestamps */ - *uint_ptr = icmpintimestamps; - break; - case 11: /* icmpInTimestampReps */ - *uint_ptr = icmpintimestampreps; - break; - case 12: /* icmpInAddrMasks */ - *uint_ptr = icmpinaddrmasks; - break; - case 13: /* icmpInAddrMaskReps */ - *uint_ptr = icmpinaddrmaskreps; - break; - case 14: /* icmpOutMsgs */ - *uint_ptr = icmpoutmsgs; - break; - case 15: /* icmpOutErrors */ - *uint_ptr = icmpouterrors; - break; - case 16: /* icmpOutDestUnreachs */ - *uint_ptr = icmpoutdestunreachs; - break; - case 17: /* icmpOutTimeExcds */ - *uint_ptr = icmpouttimeexcds; - break; - case 18: /* icmpOutParmProbs */ - *uint_ptr = icmpoutparmprobs; - break; - case 19: /* icmpOutSrcQuenchs */ - *uint_ptr = icmpoutsrcquenchs; - break; - case 20: /* icmpOutRedirects */ - *uint_ptr = icmpoutredirects; - break; - case 21: /* icmpOutEchos */ - *uint_ptr = icmpoutechos; - break; - case 22: /* icmpOutEchoReps */ - *uint_ptr = icmpoutechoreps; - break; - case 23: /* icmpOutTimestamps */ - *uint_ptr = icmpouttimestamps; - break; - case 24: /* icmpOutTimestampReps */ - *uint_ptr = icmpouttimestampreps; - break; - case 25: /* icmpOutAddrMasks */ - *uint_ptr = icmpoutaddrmasks; - break; - case 26: /* icmpOutAddrMaskReps */ - *uint_ptr = icmpoutaddrmaskreps; - break; - } -} - -#if LWIP_TCP -/** @todo tcp grp */ -static void -tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - u8_t id; - - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); - - switch (id) - { - case 1: /* tcpRtoAlgorithm */ - case 2: /* tcpRtoMin */ - case 3: /* tcpRtoMax */ - case 4: /* tcpMaxConn */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 5: /* tcpActiveOpens */ - case 6: /* tcpPassiveOpens */ - case 7: /* tcpAttemptFails */ - case 8: /* tcpEstabResets */ - case 10: /* tcpInSegs */ - case 11: /* tcpOutSegs */ - case 12: /* tcpRetransSegs */ - case 14: /* tcpInErrs */ - case 15: /* tcpOutRsts */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - break; - case 9: /* tcpCurrEstab */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE); - od->v_len = sizeof(u32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -tcp_get_value(struct obj_def *od, u16_t len, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - s32_t *sint_ptr = (s32_t*)value; - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* tcpRtoAlgorithm, vanj(4) */ - *sint_ptr = 4; - break; - case 2: /* tcpRtoMin */ - /* @todo not the actual value, a guess, - needs to be calculated */ - *sint_ptr = 1000; - break; - case 3: /* tcpRtoMax */ - /* @todo not the actual value, a guess, - needs to be calculated */ - *sint_ptr = 60000; - break; - case 4: /* tcpMaxConn */ - *sint_ptr = MEMP_NUM_TCP_PCB; - break; - case 5: /* tcpActiveOpens */ - *uint_ptr = tcpactiveopens; - break; - case 6: /* tcpPassiveOpens */ - *uint_ptr = tcppassiveopens; - break; - case 7: /* tcpAttemptFails */ - *uint_ptr = tcpattemptfails; - break; - case 8: /* tcpEstabResets */ - *uint_ptr = tcpestabresets; - break; - case 9: /* tcpCurrEstab */ - { - u16_t tcpcurrestab = 0; - struct tcp_pcb *pcb = tcp_active_pcbs; - while (pcb != NULL) - { - if ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT)) - { - tcpcurrestab++; - } - pcb = pcb->next; - } - *uint_ptr = tcpcurrestab; - } - break; - case 10: /* tcpInSegs */ - *uint_ptr = tcpinsegs; - break; - case 11: /* tcpOutSegs */ - *uint_ptr = tcpoutsegs; - break; - case 12: /* tcpRetransSegs */ - *uint_ptr = tcpretranssegs; - break; - case 14: /* tcpInErrs */ - *uint_ptr = tcpinerrs; - break; - case 15: /* tcpOutRsts */ - *uint_ptr = tcpoutrsts; - break; - } -} -#ifdef THIS_SEEMS_UNUSED -static void -tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (10) */ - ident_len += 10; - ident -= 10; - - if (ident_len == 11) - { - u8_t id; - - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - id = ident[0]; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); - - switch (id) - { - case 1: /* tcpConnState */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - case 2: /* tcpConnLocalAddress */ - case 4: /* tcpConnRemAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - case 3: /* tcpConnLocalPort */ - case 5: /* tcpConnRemPort */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value) -{ - ip_addr_t lip, rip; - u16_t lport, rport; - s32_t *ident; - - ident = od->id_inst_ptr; - snmp_oidtoip(&ident[1], &lip); - lport = ident[5]; - snmp_oidtoip(&ident[6], &rip); - rport = ident[10]; - - /** @todo find matching PCB */ -} -#endif /* if 0 */ -#endif - -static void -udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if ((ident_len == 2) && - (ident[0] > 0) && (ident[0] < 6)) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -udp_get_value(struct obj_def *od, u16_t len, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* udpInDatagrams */ - *uint_ptr = udpindatagrams; - break; - case 2: /* udpNoPorts */ - *uint_ptr = udpnoports; - break; - case 3: /* udpInErrors */ - *uint_ptr = udpinerrors; - break; - case 4: /* udpOutDatagrams */ - *uint_ptr = udpoutdatagrams; - break; - } -} - -static void -udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (5) */ - ident_len += 5; - ident -= 5; - - if (ident_len == 6) - { - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - switch (ident[0]) - { - case 1: /* udpLocalAddress */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR); - od->v_len = 4; - break; - case 2: /* udpLocalPort */ - od->instance = MIB_OBJECT_TAB; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - } - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -udpentry_get_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - struct udp_pcb *pcb; - ip_addr_t ip; - u16_t port; - - LWIP_UNUSED_ARG(len); - snmp_oidtoip(&od->id_inst_ptr[1], &ip); - LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff)); - port = (u16_t)od->id_inst_ptr[5]; - - pcb = udp_pcbs; - while ((pcb != NULL) && - !(ip_addr_cmp(&pcb->local_ip, &ip) && - (pcb->local_port == port))) - { - pcb = pcb->next; - } - - if (pcb != NULL) - { - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* udpLocalAddress */ - { - ip_addr_t *dst = (ip_addr_t*)value; - *dst = pcb->local_ip; - } - break; - case 2: /* udpLocalPort */ - { - s32_t *sint_ptr = (s32_t*)value; - *sint_ptr = pcb->local_port; - } - break; - } - } -} - -static void -snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) -{ - /* return to object name, adding index depth (1) */ - ident_len += 1; - ident -= 1; - if (ident_len == 2) - { - u8_t id; - - od->id_inst_len = ident_len; - od->id_inst_ptr = ident; - - LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); - id = (u8_t)ident[0]; - switch (id) - { - case 1: /* snmpInPkts */ - case 2: /* snmpOutPkts */ - case 3: /* snmpInBadVersions */ - case 4: /* snmpInBadCommunityNames */ - case 5: /* snmpInBadCommunityUses */ - case 6: /* snmpInASNParseErrs */ - case 8: /* snmpInTooBigs */ - case 9: /* snmpInNoSuchNames */ - case 10: /* snmpInBadValues */ - case 11: /* snmpInReadOnlys */ - case 12: /* snmpInGenErrs */ - case 13: /* snmpInTotalReqVars */ - case 14: /* snmpInTotalSetVars */ - case 15: /* snmpInGetRequests */ - case 16: /* snmpInGetNexts */ - case 17: /* snmpInSetRequests */ - case 18: /* snmpInGetResponses */ - case 19: /* snmpInTraps */ - case 20: /* snmpOutTooBigs */ - case 21: /* snmpOutNoSuchNames */ - case 22: /* snmpOutBadValues */ - case 24: /* snmpOutGenErrs */ - case 25: /* snmpOutGetRequests */ - case 26: /* snmpOutGetNexts */ - case 27: /* snmpOutSetRequests */ - case 28: /* snmpOutGetResponses */ - case 29: /* snmpOutTraps */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_ONLY; - od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER); - od->v_len = sizeof(u32_t); - break; - case 30: /* snmpEnableAuthenTraps */ - od->instance = MIB_OBJECT_SCALAR; - od->access = MIB_OBJECT_READ_WRITE; - od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG); - od->v_len = sizeof(s32_t); - break; - default: - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n")); - od->instance = MIB_OBJECT_NONE; - break; - }; - } - else - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n")); - od->instance = MIB_OBJECT_NONE; - } -} - -static void -snmp_get_value(struct obj_def *od, u16_t len, void *value) -{ - u32_t *uint_ptr = (u32_t*)value; - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - switch (id) - { - case 1: /* snmpInPkts */ - *uint_ptr = snmpinpkts; - break; - case 2: /* snmpOutPkts */ - *uint_ptr = snmpoutpkts; - break; - case 3: /* snmpInBadVersions */ - *uint_ptr = snmpinbadversions; - break; - case 4: /* snmpInBadCommunityNames */ - *uint_ptr = snmpinbadcommunitynames; - break; - case 5: /* snmpInBadCommunityUses */ - *uint_ptr = snmpinbadcommunityuses; - break; - case 6: /* snmpInASNParseErrs */ - *uint_ptr = snmpinasnparseerrs; - break; - case 8: /* snmpInTooBigs */ - *uint_ptr = snmpintoobigs; - break; - case 9: /* snmpInNoSuchNames */ - *uint_ptr = snmpinnosuchnames; - break; - case 10: /* snmpInBadValues */ - *uint_ptr = snmpinbadvalues; - break; - case 11: /* snmpInReadOnlys */ - *uint_ptr = snmpinreadonlys; - break; - case 12: /* snmpInGenErrs */ - *uint_ptr = snmpingenerrs; - break; - case 13: /* snmpInTotalReqVars */ - *uint_ptr = snmpintotalreqvars; - break; - case 14: /* snmpInTotalSetVars */ - *uint_ptr = snmpintotalsetvars; - break; - case 15: /* snmpInGetRequests */ - *uint_ptr = snmpingetrequests; - break; - case 16: /* snmpInGetNexts */ - *uint_ptr = snmpingetnexts; - break; - case 17: /* snmpInSetRequests */ - *uint_ptr = snmpinsetrequests; - break; - case 18: /* snmpInGetResponses */ - *uint_ptr = snmpingetresponses; - break; - case 19: /* snmpInTraps */ - *uint_ptr = snmpintraps; - break; - case 20: /* snmpOutTooBigs */ - *uint_ptr = snmpouttoobigs; - break; - case 21: /* snmpOutNoSuchNames */ - *uint_ptr = snmpoutnosuchnames; - break; - case 22: /* snmpOutBadValues */ - *uint_ptr = snmpoutbadvalues; - break; - case 24: /* snmpOutGenErrs */ - *uint_ptr = snmpoutgenerrs; - break; - case 25: /* snmpOutGetRequests */ - *uint_ptr = snmpoutgetrequests; - break; - case 26: /* snmpOutGetNexts */ - *uint_ptr = snmpoutgetnexts; - break; - case 27: /* snmpOutSetRequests */ - *uint_ptr = snmpoutsetrequests; - break; - case 28: /* snmpOutGetResponses */ - *uint_ptr = snmpoutgetresponses; - break; - case 29: /* snmpOutTraps */ - *uint_ptr = snmpouttraps; - break; - case 30: /* snmpEnableAuthenTraps */ - *uint_ptr = *snmpenableauthentraps_ptr; - break; - }; -} - -/** - * Test snmp object value before setting. - * - * @param od is the object definition - * @param len return value space (in bytes) - * @param value points to (varbind) space to copy value from. - */ -static u8_t -snmp_set_test(struct obj_def *od, u16_t len, void *value) -{ - u8_t id, set_ok; - - LWIP_UNUSED_ARG(len); - set_ok = 0; - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - if (id == 30) - { - /* snmpEnableAuthenTraps */ - s32_t *sint_ptr = (s32_t*)value; - - if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default) - { - /* we should have writable non-volatile mem here */ - if ((*sint_ptr == 1) || (*sint_ptr == 2)) - { - set_ok = 1; - } - } - else - { - /* const or hardwired value */ - if (*sint_ptr == snmpenableauthentraps_default) - { - set_ok = 1; - } - } - } - return set_ok; -} - -static void -snmp_set_value(struct obj_def *od, u16_t len, void *value) -{ - u8_t id; - - LWIP_UNUSED_ARG(len); - LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); - id = (u8_t)od->id_inst_ptr[0]; - if (id == 30) - { - /* snmpEnableAuthenTraps */ - /* @todo @fixme: which kind of pointer is 'value'? s32_t or u8_t??? */ - u8_t *ptr = (u8_t*)value; - *snmpenableauthentraps_ptr = *ptr; - } -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/snmp/mib_structs.c b/ext/lwip/src/core/snmp/mib_structs.c deleted file mode 100644 index 2f185cb4..00000000 --- a/ext/lwip/src/core/snmp/mib_structs.c +++ /dev/null @@ -1,1174 +0,0 @@ -/** - * @file - * MIB tree access/construction functions. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp_structs.h" -#include "lwip/memp.h" -#include "lwip/netif.h" - -/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ -const s32_t prefix[4] = {1, 3, 6, 1}; - -#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN) -/** node stack entry (old news?) */ -struct nse -{ - /** right child */ - struct mib_node* r_ptr; - /** right child identifier */ - s32_t r_id; - /** right child next level */ - u8_t r_nl; -}; -static u8_t node_stack_cnt; -static struct nse node_stack[NODE_STACK_SIZE]; - -/** - * Pushes nse struct onto stack. - */ -static void -push_node(struct nse* node) -{ - LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE); - LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id)); - if (node_stack_cnt < NODE_STACK_SIZE) - { - node_stack[node_stack_cnt] = *node; - node_stack_cnt++; - } -} - -/** - * Pops nse struct from stack. - */ -static void -pop_node(struct nse* node) -{ - if (node_stack_cnt > 0) - { - node_stack_cnt--; - *node = node_stack[node_stack_cnt]; - } - LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id)); -} - -/** - * Conversion from ifIndex to lwIP netif - * @param ifindex is a s32_t object sub-identifier - * @param netif points to returned netif struct pointer - */ -void -snmp_ifindextonetif(s32_t ifindex, struct netif **netif) -{ - struct netif *nif = netif_list; - s32_t i, ifidx; - - ifidx = ifindex - 1; - i = 0; - while ((nif != NULL) && (i < ifidx)) - { - nif = nif->next; - i++; - } - *netif = nif; -} - -/** - * Conversion from lwIP netif to ifIndex - * @param netif points to a netif struct - * @param ifidx points to s32_t object sub-identifier - */ -void -snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) -{ - struct netif *nif = netif_list; - u16_t i; - - i = 0; - while ((nif != NULL) && (nif != netif)) - { - nif = nif->next; - i++; - } - *ifidx = i+1; -} - -/** - * Conversion from oid to lwIP ip_addr - * @param ident points to s32_t ident[4] input - * @param ip points to output struct - */ -void -snmp_oidtoip(s32_t *ident, ip_addr_t *ip) -{ - IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]); -} - -/** - * Conversion from lwIP ip_addr to oid - * @param ip points to input struct - * @param ident points to s32_t ident[4] output - */ -void -snmp_iptooid(ip_addr_t *ip, s32_t *ident) -{ - ident[0] = ip4_addr1(ip); - ident[1] = ip4_addr2(ip); - ident[2] = ip4_addr3(ip); - ident[3] = ip4_addr4(ip); -} - -struct mib_list_node * -snmp_mib_ln_alloc(s32_t id) -{ - struct mib_list_node *ln; - - ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE); - if (ln != NULL) - { - ln->prev = NULL; - ln->next = NULL; - ln->objid = id; - ln->nptr = NULL; - } - return ln; -} - -void -snmp_mib_ln_free(struct mib_list_node *ln) -{ - memp_free(MEMP_SNMP_NODE, ln); -} - -struct mib_list_rootnode * -snmp_mib_lrn_alloc(void) -{ - struct mib_list_rootnode *lrn; - - lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE); - if (lrn != NULL) - { - lrn->get_object_def = noleafs_get_object_def; - lrn->get_value = noleafs_get_value; - lrn->set_test = noleafs_set_test; - lrn->set_value = noleafs_set_value; - lrn->node_type = MIB_NODE_LR; - lrn->maxlength = 0; - lrn->head = NULL; - lrn->tail = NULL; - lrn->count = 0; - } - return lrn; -} - -void -snmp_mib_lrn_free(struct mib_list_rootnode *lrn) -{ - memp_free(MEMP_SNMP_ROOTNODE, lrn); -} - -/** - * Inserts node in idx list in a sorted - * (ascending order) fashion and - * allocates the node if needed. - * - * @param rn points to the root node - * @param objid is the object sub identifier - * @param insn points to a pointer to the inserted node - * used for constructing the tree. - * @return -1 if failed, 1 if inserted, 2 if present. - */ -s8_t -snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn) -{ - struct mib_list_node *nn; - s8_t insert; - - LWIP_ASSERT("rn != NULL",rn != NULL); - - /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */ - insert = 0; - if (rn->head == NULL) - { - /* empty list, add first node */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid)); - nn = snmp_mib_ln_alloc(objid); - if (nn != NULL) - { - rn->head = nn; - rn->tail = nn; - *insn = nn; - insert = 1; - } - else - { - insert = -1; - } - } - else - { - struct mib_list_node *n; - /* at least one node is present */ - n = rn->head; - while ((n != NULL) && (insert == 0)) - { - if (n->objid == objid) - { - /* node is already there */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid)); - *insn = n; - insert = 2; - } - else if (n->objid < objid) - { - if (n->next == NULL) - { - /* alloc and insert at the tail */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid)); - nn = snmp_mib_ln_alloc(objid); - if (nn != NULL) - { - nn->next = NULL; - nn->prev = n; - n->next = nn; - rn->tail = nn; - *insn = nn; - insert = 1; - } - else - { - /* insertion failure */ - insert = -1; - } - } - else - { - /* there's more to explore: traverse list */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n")); - n = n->next; - } - } - else - { - /* n->objid > objid */ - /* alloc and insert between n->prev and n */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid)); - nn = snmp_mib_ln_alloc(objid); - if (nn != NULL) - { - if (n->prev == NULL) - { - /* insert at the head */ - nn->next = n; - nn->prev = NULL; - rn->head = nn; - n->prev = nn; - } - else - { - /* insert in the middle */ - nn->next = n; - nn->prev = n->prev; - n->prev->next = nn; - n->prev = nn; - } - *insn = nn; - insert = 1; - } - else - { - /* insertion failure */ - insert = -1; - } - } - } - } - if (insert == 1) - { - rn->count += 1; - } - LWIP_ASSERT("insert != 0",insert != 0); - return insert; -} - -/** - * Finds node in idx list and returns deletion mark. - * - * @param rn points to the root node - * @param objid is the object sub identifier - * @param fn returns pointer to found node - * @return 0 if not found, 1 if deletable, - * 2 can't delete (2 or more children), 3 not a list_node - */ -s8_t -snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn) -{ - s8_t fc; - struct mib_list_node *n; - - LWIP_ASSERT("rn != NULL",rn != NULL); - n = rn->head; - while ((n != NULL) && (n->objid != objid)) - { - n = n->next; - } - if (n == NULL) - { - fc = 0; - } - else if (n->nptr == NULL) - { - /* leaf, can delete node */ - fc = 1; - } - else - { - struct mib_list_rootnode *r; - - if (n->nptr->node_type == MIB_NODE_LR) - { - r = (struct mib_list_rootnode *)n->nptr; - if (r->count > 1) - { - /* can't delete node */ - fc = 2; - } - else - { - /* count <= 1, can delete node */ - fc = 1; - } - } - else - { - /* other node type */ - fc = 3; - } - } - *fn = n; - return fc; -} - -/** - * Removes node from idx list - * if it has a single child left. - * - * @param rn points to the root node - * @param n points to the node to delete - * @return the nptr to be freed by caller - */ -struct mib_list_rootnode * -snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) -{ - struct mib_list_rootnode *next; - - LWIP_ASSERT("rn != NULL",rn != NULL); - LWIP_ASSERT("n != NULL",n != NULL); - - /* caller must remove this sub-tree */ - next = (struct mib_list_rootnode*)(n->nptr); - rn->count -= 1; - - if (n == rn->head) - { - rn->head = n->next; - if (n->next != NULL) - { - /* not last node, new list begin */ - n->next->prev = NULL; - } - } - else if (n == rn->tail) - { - rn->tail = n->prev; - if (n->prev != NULL) - { - /* not last node, new list end */ - n->prev->next = NULL; - } - } - else - { - /* node must be in the middle */ - n->prev->next = n->next; - n->next->prev = n->prev; - } - LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid)); - snmp_mib_ln_free(n); - if (rn->count == 0) - { - rn->head = NULL; - rn->tail = NULL; - } - return next; -} - - - -/** - * Searches tree for the supplied (scalar?) object identifier. - * - * @param node points to the root of the tree ('.internet') - * @param ident_len the length of the supplied object identifier - * @param ident points to the array of sub identifiers - * @param np points to the found object instance (return) - * @return pointer to the requested parent (!) node if success, NULL otherwise - */ -struct mib_node * -snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np) -{ - u8_t node_type, ext_level; - - ext_level = 0; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident)); - while (node != NULL) - { - node_type = node->node_type; - if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) - { - struct mib_array_node *an; - u16_t i; - - if (ident_len > 0) - { - /* array node (internal ROM or RAM, fixed length) */ - an = (struct mib_array_node *)node; - i = 0; - while ((i < an->maxlength) && (an->objid[i] != *ident)) - { - i++; - } - if (i < an->maxlength) - { - /* found it, if available proceed to child, otherwise inspect leaf */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); - if (an->nptr[i] == NULL) - { - /* a scalar leaf OR table, - inspect remaining instance number / table index */ - np->ident_len = ident_len; - np->ident = ident; - return (struct mib_node*)an; - } - else - { - /* follow next child pointer */ - ident++; - ident_len--; - node = an->nptr[i]; - } - } - else - { - /* search failed, identifier mismatch (nosuchname) */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident)); - return NULL; - } - } - else - { - /* search failed, short object identifier (nosuchname) */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n")); - return NULL; - } - } - else if(node_type == MIB_NODE_LR) - { - struct mib_list_rootnode *lrn; - struct mib_list_node *ln; - - if (ident_len > 0) - { - /* list root node (internal 'RAM', variable length) */ - lrn = (struct mib_list_rootnode *)node; - ln = lrn->head; - /* iterate over list, head to tail */ - while ((ln != NULL) && (ln->objid != *ident)) - { - ln = ln->next; - } - if (ln != NULL) - { - /* found it, proceed to child */; - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); - if (ln->nptr == NULL) - { - np->ident_len = ident_len; - np->ident = ident; - return (struct mib_node*)lrn; - } - else - { - /* follow next child pointer */ - ident_len--; - ident++; - node = ln->nptr; - } - } - else - { - /* search failed */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident)); - return NULL; - } - } - else - { - /* search failed, short object identifier (nosuchname) */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n")); - return NULL; - } - } - else if(node_type == MIB_NODE_EX) - { - struct mib_external_node *en; - u16_t i, len; - - if (ident_len > 0) - { - /* external node (addressing and access via functions) */ - en = (struct mib_external_node *)node; - - i = 0; - len = en->level_length(en->addr_inf,ext_level); - while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0)) - { - i++; - } - if (i < len) - { - s32_t debug_id; - - en->get_objid(en->addr_inf,ext_level,i,&debug_id); - LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident)); - if ((ext_level + 1) == en->tree_levels) - { - np->ident_len = ident_len; - np->ident = ident; - return (struct mib_node*)en; - } - else - { - /* found it, proceed to child */ - ident_len--; - ident++; - ext_level++; - } - } - else - { - /* search failed */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident)); - return NULL; - } - } - else - { - /* search failed, short object identifier (nosuchname) */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n")); - return NULL; - } - } - else if (node_type == MIB_NODE_SC) - { - mib_scalar_node *sn; - - sn = (mib_scalar_node *)node; - if ((ident_len == 1) && (*ident == 0)) - { - np->ident_len = ident_len; - np->ident = ident; - return (struct mib_node*)sn; - } - else - { - /* search failed, short object identifier (nosuchname) */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n")); - return NULL; - } - } - else - { - /* unknown node_type */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type)); - return NULL; - } - } - /* done, found nothing */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node)); - return NULL; -} - -/** - * Test table for presence of at least one table entry. - */ -static u8_t -empty_table(struct mib_node *node) -{ - u8_t node_type; - u8_t empty = 0; - - if (node != NULL) - { - node_type = node->node_type; - if (node_type == MIB_NODE_LR) - { - struct mib_list_rootnode *lrn; - lrn = (struct mib_list_rootnode *)node; - if ((lrn->count == 0) || (lrn->head == NULL)) - { - empty = 1; - } - } - else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) - { - struct mib_array_node *an; - an = (struct mib_array_node *)node; - if ((an->maxlength == 0) || (an->nptr == NULL)) - { - empty = 1; - } - } - else if (node_type == MIB_NODE_EX) - { - struct mib_external_node *en; - en = (struct mib_external_node *)node; - if (en->tree_levels == 0) - { - empty = 1; - } - } - } - return empty; -} - -/** - * Tree expansion. - */ -struct mib_node * -snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) -{ - u8_t node_type, ext_level, climb_tree; - - ext_level = 0; - /* reset node stack */ - node_stack_cnt = 0; - while (node != NULL) - { - climb_tree = 0; - node_type = node->node_type; - if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA)) - { - struct mib_array_node *an; - u16_t i; - - /* array node (internal ROM or RAM, fixed length) */ - an = (struct mib_array_node *)node; - if (ident_len > 0) - { - i = 0; - while ((i < an->maxlength) && (an->objid[i] < *ident)) - { - i++; - } - if (i < an->maxlength) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident)); - /* add identifier to oidret */ - oidret->id[oidret->len] = an->objid[i]; - (oidret->len)++; - - if (an->nptr[i] == NULL) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); - /* leaf node (e.g. in a fixed size table) */ - if (an->objid[i] > *ident) - { - return (struct mib_node*)an; - } - else if ((i + 1) < an->maxlength) - { - /* an->objid[i] == *ident */ - (oidret->len)--; - oidret->id[oidret->len] = an->objid[i + 1]; - (oidret->len)++; - return (struct mib_node*)an; - } - else - { - /* (i + 1) == an->maxlength */ - (oidret->len)--; - climb_tree = 1; - } - } - else - { - u8_t j; - struct nse cur_node; - - LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); - /* non-leaf, store right child ptr and id */ - LWIP_ASSERT("i < 0xff", i < 0xff); - j = (u8_t)i + 1; - while ((j < an->maxlength) && (empty_table(an->nptr[j]))) - { - j++; - } - if (j < an->maxlength) - { - cur_node.r_ptr = an->nptr[j]; - cur_node.r_id = an->objid[j]; - cur_node.r_nl = 0; - } - else - { - cur_node.r_ptr = NULL; - } - push_node(&cur_node); - if (an->objid[i] == *ident) - { - ident_len--; - ident++; - } - else - { - /* an->objid[i] < *ident */ - ident_len = 0; - } - /* follow next child pointer */ - node = an->nptr[i]; - } - } - else - { - /* i == an->maxlength */ - climb_tree = 1; - } - } - else - { - u8_t j; - /* ident_len == 0, complete with leftmost '.thing' */ - j = 0; - while ((j < an->maxlength) && empty_table(an->nptr[j])) - { - j++; - } - if (j < an->maxlength) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j])); - oidret->id[oidret->len] = an->objid[j]; - (oidret->len)++; - if (an->nptr[j] == NULL) - { - /* leaf node */ - return (struct mib_node*)an; - } - else - { - /* no leaf, continue */ - node = an->nptr[j]; - } - } - else - { - /* j == an->maxlength */ - climb_tree = 1; - } - } - } - else if(node_type == MIB_NODE_LR) - { - struct mib_list_rootnode *lrn; - struct mib_list_node *ln; - - /* list root node (internal 'RAM', variable length) */ - lrn = (struct mib_list_rootnode *)node; - if (ident_len > 0) - { - ln = lrn->head; - /* iterate over list, head to tail */ - while ((ln != NULL) && (ln->objid < *ident)) - { - ln = ln->next; - } - if (ln != NULL) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident)); - oidret->id[oidret->len] = ln->objid; - (oidret->len)++; - if (ln->nptr == NULL) - { - /* leaf node */ - if (ln->objid > *ident) - { - return (struct mib_node*)lrn; - } - else if (ln->next != NULL) - { - /* ln->objid == *ident */ - (oidret->len)--; - oidret->id[oidret->len] = ln->next->objid; - (oidret->len)++; - return (struct mib_node*)lrn; - } - else - { - /* ln->next == NULL */ - (oidret->len)--; - climb_tree = 1; - } - } - else - { - struct mib_list_node *jn; - struct nse cur_node; - - /* non-leaf, store right child ptr and id */ - jn = ln->next; - while ((jn != NULL) && empty_table(jn->nptr)) - { - jn = jn->next; - } - if (jn != NULL) - { - cur_node.r_ptr = jn->nptr; - cur_node.r_id = jn->objid; - cur_node.r_nl = 0; - } - else - { - cur_node.r_ptr = NULL; - } - push_node(&cur_node); - if (ln->objid == *ident) - { - ident_len--; - ident++; - } - else - { - /* ln->objid < *ident */ - ident_len = 0; - } - /* follow next child pointer */ - node = ln->nptr; - } - - } - else - { - /* ln == NULL */ - climb_tree = 1; - } - } - else - { - struct mib_list_node *jn; - /* ident_len == 0, complete with leftmost '.thing' */ - jn = lrn->head; - while ((jn != NULL) && empty_table(jn->nptr)) - { - jn = jn->next; - } - if (jn != NULL) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid)); - oidret->id[oidret->len] = jn->objid; - (oidret->len)++; - if (jn->nptr == NULL) - { - /* leaf node */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n")); - return (struct mib_node*)lrn; - } - else - { - /* no leaf, continue */ - node = jn->nptr; - } - } - else - { - /* jn == NULL */ - climb_tree = 1; - } - } - } - else if(node_type == MIB_NODE_EX) - { - struct mib_external_node *en; - s32_t ex_id; - - /* external node (addressing and access via functions) */ - en = (struct mib_external_node *)node; - if (ident_len > 0) - { - u16_t i, len; - - i = 0; - len = en->level_length(en->addr_inf,ext_level); - while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0)) - { - i++; - } - if (i < len) - { - /* add identifier to oidret */ - en->get_objid(en->addr_inf,ext_level,i,&ex_id); - LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident)); - oidret->id[oidret->len] = ex_id; - (oidret->len)++; - - if ((ext_level + 1) == en->tree_levels) - { - LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n")); - /* leaf node */ - if (ex_id > *ident) - { - return (struct mib_node*)en; - } - else if ((i + 1) < len) - { - /* ex_id == *ident */ - en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id); - (oidret->len)--; - oidret->id[oidret->len] = ex_id; - (oidret->len)++; - return (struct mib_node*)en; - } - else - { - /* (i + 1) == len */ - (oidret->len)--; - climb_tree = 1; - } - } - else - { - u8_t j; - struct nse cur_node; - - LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); - /* non-leaf, store right child ptr and id */ - LWIP_ASSERT("i < 0xff", i < 0xff); - j = (u8_t)i + 1; - if (j < len) - { - /* right node is the current external node */ - cur_node.r_ptr = node; - en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id); - cur_node.r_nl = ext_level + 1; - } - else - { - cur_node.r_ptr = NULL; - } - push_node(&cur_node); - if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0) - { - ident_len--; - ident++; - } - else - { - /* external id < *ident */ - ident_len = 0; - } - /* proceed to child */ - ext_level++; - } - } - else - { - /* i == len (en->level_len()) */ - climb_tree = 1; - } - } - else - { - /* ident_len == 0, complete with leftmost '.thing' */ - en->get_objid(en->addr_inf,ext_level,0,&ex_id); - LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id)); - oidret->id[oidret->len] = ex_id; - (oidret->len)++; - if ((ext_level + 1) == en->tree_levels) - { - /* leaf node */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n")); - return (struct mib_node*)en; - } - else - { - /* no leaf, proceed to child */ - ext_level++; - } - } - } - else if(node_type == MIB_NODE_SC) - { - mib_scalar_node *sn; - - /* scalar node */ - sn = (mib_scalar_node *)node; - if (ident_len > 0) - { - /* at .0 */ - climb_tree = 1; - } - else - { - /* ident_len == 0, complete object identifier */ - oidret->id[oidret->len] = 0; - (oidret->len)++; - /* leaf node */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n")); - return (struct mib_node*)sn; - } - } - else - { - /* unknown/unhandled node_type */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type)); - return NULL; - } - - if (climb_tree) - { - struct nse child; - - /* find right child ptr */ - child.r_ptr = NULL; - child.r_id = 0; - child.r_nl = 0; - while ((node_stack_cnt > 0) && (child.r_ptr == NULL)) - { - pop_node(&child); - /* trim returned oid */ - (oidret->len)--; - } - if (child.r_ptr != NULL) - { - /* incoming ident is useless beyond this point */ - ident_len = 0; - oidret->id[oidret->len] = child.r_id; - oidret->len++; - node = child.r_ptr; - ext_level = child.r_nl; - } - else - { - /* tree ends here ... */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n")); - return NULL; - } - } - } - /* done, found nothing */ - LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node)); - return NULL; -} - -/** - * Test object identifier for the iso.org.dod.internet prefix. - * - * @param ident_len the length of the supplied object identifier - * @param ident points to the array of sub identifiers - * @return 1 if it matches, 0 otherwise - */ -u8_t -snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident) -{ - if ((ident_len > 3) && - (ident[0] == 1) && (ident[1] == 3) && - (ident[2] == 6) && (ident[3] == 1)) - { - return 1; - } - else - { - return 0; - } -} - -/** - * Expands object identifier to the iso.org.dod.internet - * prefix for use in getnext operation. - * - * @param ident_len the length of the supplied object identifier - * @param ident points to the array of sub identifiers - * @param oidret points to returned expanded object identifier - * @return 1 if it matches, 0 otherwise - * - * @note ident_len 0 is allowed, expanding to the first known object id!! - */ -u8_t -snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret) -{ - const s32_t *prefix_ptr; - s32_t *ret_ptr; - u8_t i; - - i = 0; - prefix_ptr = &prefix[0]; - ret_ptr = &oidret->id[0]; - ident_len = ((ident_len < 4)?ident_len:4); - while ((i < ident_len) && ((*ident) <= (*prefix_ptr))) - { - *ret_ptr++ = *prefix_ptr++; - ident++; - i++; - } - if (i == ident_len) - { - /* match, complete missing bits */ - while (i < 4) - { - *ret_ptr++ = *prefix_ptr++; - i++; - } - oidret->len = i; - return 1; - } - else - { - /* i != ident_len */ - return 0; - } -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/snmp/msg_in.c b/ext/lwip/src/core/snmp/msg_in.c deleted file mode 100644 index be940c62..00000000 --- a/ext/lwip/src/core/snmp/msg_in.c +++ /dev/null @@ -1,1453 +0,0 @@ -/** - * @file - * SNMP input message processing (RFC1157). - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/snmp.h" -#include "lwip/snmp_asn1.h" -#include "lwip/snmp_msg.h" -#include "lwip/snmp_structs.h" -#include "lwip/ip_addr.h" -#include "lwip/memp.h" -#include "lwip/udp.h" -#include "lwip/stats.h" - -#include <string.h> - -/* public (non-static) constants */ -/** SNMP v1 == 0 */ -const s32_t snmp_version = 0; -/** default SNMP community string */ -const char snmp_publiccommunity[7] = "public"; - -/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */ -struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; -/* UDP Protocol Control Block */ -struct udp_pcb *snmp1_pcb; - -static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); -static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); -static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); - - -/** - * Starts SNMP Agent. - * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161. - */ -void -snmp_init(void) -{ - struct snmp_msg_pstat *msg_ps; - u8_t i; - - snmp1_pcb = udp_new(); - if (snmp1_pcb != NULL) - { - udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT); - udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT); - } - msg_ps = &msg_input_list[0]; - for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++) - { - msg_ps->state = SNMP_MSG_EMPTY; - msg_ps->error_index = 0; - msg_ps->error_status = SNMP_ES_NOERROR; - msg_ps++; - } - trap_msg.pcb = snmp1_pcb; - -#ifdef SNMP_PRIVATE_MIB_INIT - /* If defined, this must be a function-like define to initialize the - * private MIB after the stack has been initialized. - * The private MIB can also be initialized in tcpip_callback (or after - * the stack is initialized), this define is only for convenience. */ - SNMP_PRIVATE_MIB_INIT(); -#endif /* SNMP_PRIVATE_MIB_INIT */ - - /* The coldstart trap will only be output - if our outgoing interface is up & configured */ - snmp_coldstart_trap(); -} - -static void -snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error) -{ - /* move names back from outvb to invb */ - int v; - struct snmp_varbind *vbi = msg_ps->invb.head; - struct snmp_varbind *vbo = msg_ps->outvb.head; - for (v=0; v<msg_ps->vb_idx; v++) { - vbi->ident_len = vbo->ident_len; - vbo->ident_len = 0; - vbi->ident = vbo->ident; - vbo->ident = NULL; - vbi = vbi->next; - vbo = vbo->next; - } - /* free outvb */ - snmp_varbind_list_free(&msg_ps->outvb); - /* we send invb back */ - msg_ps->outvb = msg_ps->invb; - msg_ps->invb.head = NULL; - msg_ps->invb.tail = NULL; - msg_ps->invb.count = 0; - msg_ps->error_status = error; - /* error index must be 0 for error too big */ - msg_ps->error_index = (error != SNMP_ES_TOOBIG) ? (1 + msg_ps->vb_idx) : 0; - snmp_send_response(msg_ps); - snmp_varbind_list_free(&msg_ps->outvb); - msg_ps->state = SNMP_MSG_EMPTY; -} - -static void -snmp_ok_response(struct snmp_msg_pstat *msg_ps) -{ - err_t err_ret; - - err_ret = snmp_send_response(msg_ps); - if (err_ret == ERR_MEM) - { - /* serious memory problem, can't return tooBig */ - } - else - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status)); - } - /* free varbinds (if available) */ - snmp_varbind_list_free(&msg_ps->invb); - snmp_varbind_list_free(&msg_ps->outvb); - msg_ps->state = SNMP_MSG_EMPTY; -} - -/** - * Service an internal or external event for SNMP GET. - * - * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) - * @param msg_ps points to the assosicated message process state - */ -static void -snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) -{ - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); - - if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) - { - struct mib_external_node *en; - struct snmp_name_ptr np; - - /* get_object_def() answer*/ - en = msg_ps->ext_mib_node; - np = msg_ps->ext_name_ptr; - - /* translate answer into a known lifeform */ - en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); - if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) && - (msg_ps->ext_object_def.access & MIB_ACCESS_READ)) - { - msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; - en->get_value_q(request_id, &msg_ps->ext_object_def); - } - else - { - en->get_object_def_pc(request_id, np.ident_len, np.ident); - /* search failed, object id points to unknown object (nosuchname) */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) - { - struct mib_external_node *en; - struct snmp_varbind *vb; - - /* get_value() answer */ - en = msg_ps->ext_mib_node; - - /* allocate output varbind */ - vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); - if (vb != NULL) - { - vb->next = NULL; - vb->prev = NULL; - - /* move name from invb to outvb */ - vb->ident = msg_ps->vb_ptr->ident; - vb->ident_len = msg_ps->vb_ptr->ident_len; - /* ensure this memory is refereced once only */ - msg_ps->vb_ptr->ident = NULL; - msg_ps->vb_ptr->ident_len = 0; - - vb->value_type = msg_ps->ext_object_def.asn_type; - LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); - vb->value_len = (u8_t)msg_ps->ext_object_def.v_len; - if (vb->value_len > 0) - { - LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); - vb->value = memp_malloc(MEMP_SNMP_VALUE); - if (vb->value != NULL) - { - en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); - snmp_varbind_tail_add(&msg_ps->outvb, vb); - /* search again (if vb_idx < msg_ps->invb.count) */ - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - en->get_value_pc(request_id, &msg_ps->ext_object_def); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); - msg_ps->vb_ptr->ident = vb->ident; - msg_ps->vb_ptr->ident_len = vb->ident_len; - memp_free(MEMP_SNMP_VARBIND, vb); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - else - { - /* vb->value_len == 0, empty value (e.g. empty string) */ - en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL); - vb->value = NULL; - snmp_varbind_tail_add(&msg_ps->outvb, vb); - /* search again (if vb_idx < msg_ps->invb.count) */ - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - } - else - { - en->get_value_pc(request_id, &msg_ps->ext_object_def); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n")); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - - while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx < msg_ps->invb.count)) - { - struct mib_node *mn; - struct snmp_name_ptr np; - - if (msg_ps->vb_idx == 0) - { - msg_ps->vb_ptr = msg_ps->invb.head; - } - else - { - msg_ps->vb_ptr = msg_ps->vb_ptr->next; - } - /** test object identifier for .iso.org.dod.internet prefix */ - if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) - { - mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, - msg_ps->vb_ptr->ident + 4, &np); - if (mn != NULL) - { - if (mn->node_type == MIB_NODE_EX) - { - /* external object */ - struct mib_external_node *en = (struct mib_external_node*)mn; - - msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; - /* save en && args in msg_ps!! */ - msg_ps->ext_mib_node = en; - msg_ps->ext_name_ptr = np; - - en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); - } - else - { - /* internal object */ - struct obj_def object_def; - - msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; - mn->get_object_def(np.ident_len, np.ident, &object_def); - if ((object_def.instance != MIB_OBJECT_NONE) && - (object_def.access & MIB_ACCESS_READ)) - { - mn = mn; - } - else - { - /* search failed, object id points to unknown object (nosuchname) */ - mn = NULL; - } - if (mn != NULL) - { - struct snmp_varbind *vb; - - msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; - /* allocate output varbind */ - vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); - if (vb != NULL) - { - vb->next = NULL; - vb->prev = NULL; - - /* move name from invb to outvb */ - vb->ident = msg_ps->vb_ptr->ident; - vb->ident_len = msg_ps->vb_ptr->ident_len; - /* ensure this memory is refereced once only */ - msg_ps->vb_ptr->ident = NULL; - msg_ps->vb_ptr->ident_len = 0; - - vb->value_type = object_def.asn_type; - LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); - vb->value_len = (u8_t)object_def.v_len; - if (vb->value_len > 0) - { - LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", - vb->value_len <= SNMP_MAX_VALUE_SIZE); - vb->value = memp_malloc(MEMP_SNMP_VALUE); - if (vb->value != NULL) - { - mn->get_value(&object_def, vb->value_len, vb->value); - snmp_varbind_tail_add(&msg_ps->outvb, vb); - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); - msg_ps->vb_ptr->ident = vb->ident; - msg_ps->vb_ptr->ident_len = vb->ident_len; - vb->ident = NULL; - vb->ident_len = 0; - memp_free(MEMP_SNMP_VARBIND, vb); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - else - { - /* vb->value_len == 0, empty value (e.g. empty string) */ - vb->value = NULL; - snmp_varbind_tail_add(&msg_ps->outvb, vb); - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - } - else - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n")); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - } - } - } - else - { - mn = NULL; - } - if (mn == NULL) - { - /* mn == NULL, noSuchName */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx == msg_ps->invb.count)) - { - snmp_ok_response(msg_ps); - } -} - -/** - * Service an internal or external event for SNMP GETNEXT. - * - * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) - * @param msg_ps points to the assosicated message process state - */ -static void -snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) -{ - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); - - if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) - { - struct mib_external_node *en; - - /* get_object_def() answer*/ - en = msg_ps->ext_mib_node; - - /* translate answer into a known lifeform */ - en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def); - if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) - { - msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; - en->get_value_q(request_id, &msg_ps->ext_object_def); - } - else - { - en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]); - /* search failed, object id points to unknown object (nosuchname) */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE) - { - struct mib_external_node *en; - struct snmp_varbind *vb; - - /* get_value() answer */ - en = msg_ps->ext_mib_node; - - LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); - vb = snmp_varbind_alloc(&msg_ps->ext_oid, - msg_ps->ext_object_def.asn_type, - (u8_t)msg_ps->ext_object_def.v_len); - if (vb != NULL) - { - en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); - snmp_varbind_tail_add(&msg_ps->outvb, vb); - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - en->get_value_pc(request_id, &msg_ps->ext_object_def); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n")); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - - while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx < msg_ps->invb.count)) - { - struct mib_node *mn; - struct snmp_obj_id oid; - - if (msg_ps->vb_idx == 0) - { - msg_ps->vb_ptr = msg_ps->invb.head; - } - else - { - msg_ps->vb_ptr = msg_ps->vb_ptr->next; - } - if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid)) - { - if (msg_ps->vb_ptr->ident_len > 3) - { - /* can offset ident_len and ident */ - mn = snmp_expand_tree((struct mib_node*)&internet, - msg_ps->vb_ptr->ident_len - 4, - msg_ps->vb_ptr->ident + 4, &oid); - } - else - { - /* can't offset ident_len -4, ident + 4 */ - mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid); - } - } - else - { - mn = NULL; - } - if (mn != NULL) - { - if (mn->node_type == MIB_NODE_EX) - { - /* external object */ - struct mib_external_node *en = (struct mib_external_node*)mn; - - msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; - /* save en && args in msg_ps!! */ - msg_ps->ext_mib_node = en; - msg_ps->ext_oid = oid; - - en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]); - } - else - { - /* internal object */ - struct obj_def object_def; - struct snmp_varbind *vb; - - msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; - mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); - - LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); - vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len); - if (vb != NULL) - { - msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; - mn->get_value(&object_def, object_def.v_len, vb->value); - snmp_varbind_tail_add(&msg_ps->outvb, vb); - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n")); - snmp_error_response(msg_ps,SNMP_ES_TOOBIG); - } - } - } - if (mn == NULL) - { - /* mn == NULL, noSuchName */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx == msg_ps->invb.count)) - { - snmp_ok_response(msg_ps); - } -} - -/** - * Service an internal or external event for SNMP SET. - * - * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) - * @param msg_ps points to the assosicated message process state - */ -static void -snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) -{ - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state)); - - if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF) - { - struct mib_external_node *en; - struct snmp_name_ptr np; - - /* get_object_def() answer*/ - en = msg_ps->ext_mib_node; - np = msg_ps->ext_name_ptr; - - /* translate answer into a known lifeform */ - en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); - if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) - { - msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST; - en->set_test_q(request_id, &msg_ps->ext_object_def); - } - else - { - en->get_object_def_pc(request_id, np.ident_len, np.ident); - /* search failed, object id points to unknown object (nosuchname) */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST) - { - struct mib_external_node *en; - - /* set_test() answer*/ - en = msg_ps->ext_mib_node; - - if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE) - { - if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && - (en->set_test_a(request_id,&msg_ps->ext_object_def, - msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) - { - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - en->set_test_pc(request_id,&msg_ps->ext_object_def); - /* bad value */ - snmp_error_response(msg_ps,SNMP_ES_BADVALUE); - } - } - else - { - en->set_test_pc(request_id,&msg_ps->ext_object_def); - /* object not available for set */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S) - { - struct mib_external_node *en; - struct snmp_name_ptr np; - - /* get_object_def() answer*/ - en = msg_ps->ext_mib_node; - np = msg_ps->ext_name_ptr; - - /* translate answer into a known lifeform */ - en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); - if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) - { - msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE; - en->set_value_q(request_id, &msg_ps->ext_object_def, - msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); - } - else - { - en->get_object_def_pc(request_id, np.ident_len, np.ident); - /* set_value failed, object has disappeared for some odd reason?? */ - snmp_error_response(msg_ps,SNMP_ES_GENERROR); - } - } - else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE) - { - struct mib_external_node *en; - - /** set_value_a() */ - en = msg_ps->ext_mib_node; - en->set_value_a(request_id, &msg_ps->ext_object_def, - msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value); - - /** @todo use set_value_pc() if toobig */ - msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; - msg_ps->vb_idx += 1; - } - - /* test all values before setting */ - while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx < msg_ps->invb.count)) - { - struct mib_node *mn; - struct snmp_name_ptr np; - - if (msg_ps->vb_idx == 0) - { - msg_ps->vb_ptr = msg_ps->invb.head; - } - else - { - msg_ps->vb_ptr = msg_ps->vb_ptr->next; - } - /** test object identifier for .iso.org.dod.internet prefix */ - if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident)) - { - mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, - msg_ps->vb_ptr->ident + 4, &np); - if (mn != NULL) - { - if (mn->node_type == MIB_NODE_EX) - { - /* external object */ - struct mib_external_node *en = (struct mib_external_node*)mn; - - msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF; - /* save en && args in msg_ps!! */ - msg_ps->ext_mib_node = en; - msg_ps->ext_name_ptr = np; - - en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); - } - else - { - /* internal object */ - struct obj_def object_def; - - msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; - mn->get_object_def(np.ident_len, np.ident, &object_def); - if (object_def.instance != MIB_OBJECT_NONE) - { - mn = mn; - } - else - { - /* search failed, object id points to unknown object (nosuchname) */ - mn = NULL; - } - if (mn != NULL) - { - msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; - - if (object_def.access & MIB_ACCESS_WRITE) - { - if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && - (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) - { - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - msg_ps->vb_idx += 1; - } - else - { - /* bad value */ - snmp_error_response(msg_ps,SNMP_ES_BADVALUE); - } - } - else - { - /* object not available for set */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - } - } - } - else - { - mn = NULL; - } - if (mn == NULL) - { - /* mn == NULL, noSuchName */ - snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME); - } - } - - if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) && - (msg_ps->vb_idx == msg_ps->invb.count)) - { - msg_ps->vb_idx = 0; - msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; - } - - /* set all values "atomically" (be as "atomic" as possible) */ - while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && - (msg_ps->vb_idx < msg_ps->invb.count)) - { - struct mib_node *mn; - struct snmp_name_ptr np; - - if (msg_ps->vb_idx == 0) - { - msg_ps->vb_ptr = msg_ps->invb.head; - } - else - { - msg_ps->vb_ptr = msg_ps->vb_ptr->next; - } - /* skip iso prefix test, was done previously while settesting() */ - mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4, - msg_ps->vb_ptr->ident + 4, &np); - /* check if object is still available - (e.g. external hot-plug thingy present?) */ - if (mn != NULL) - { - if (mn->node_type == MIB_NODE_EX) - { - /* external object */ - struct mib_external_node *en = (struct mib_external_node*)mn; - - msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S; - /* save en && args in msg_ps!! */ - msg_ps->ext_mib_node = en; - msg_ps->ext_name_ptr = np; - - en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident); - } - else - { - /* internal object */ - struct obj_def object_def; - - msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S; - mn->get_object_def(np.ident_len, np.ident, &object_def); - msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE; - mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value); - msg_ps->vb_idx += 1; - } - } - } - if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) && - (msg_ps->vb_idx == msg_ps->invb.count)) - { - /* simply echo the input if we can set it - @todo do we need to return the actual value? - e.g. if value is silently modified or behaves sticky? */ - msg_ps->outvb = msg_ps->invb; - msg_ps->invb.head = NULL; - msg_ps->invb.tail = NULL; - msg_ps->invb.count = 0; - snmp_ok_response(msg_ps); - } -} - - -/** - * Handle one internal or external event. - * Called for one async event. (recv external/private answer) - * - * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1) - */ -void -snmp_msg_event(u8_t request_id) -{ - struct snmp_msg_pstat *msg_ps; - - if (request_id < SNMP_CONCURRENT_REQUESTS) - { - msg_ps = &msg_input_list[request_id]; - if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) - { - snmp_msg_getnext_event(request_id, msg_ps); - } - else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) - { - snmp_msg_get_event(request_id, msg_ps); - } - else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ) - { - snmp_msg_set_event(request_id, msg_ps); - } - } -} - - -/* lwIP UDP receive callback function */ -static void -snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) -{ - struct snmp_msg_pstat *msg_ps; - u8_t req_idx; - err_t err_ret; - u16_t payload_len = p->tot_len; - u16_t payload_ofs = 0; - u16_t varbind_ofs = 0; - - /* suppress unused argument warning */ - LWIP_UNUSED_ARG(arg); - - /* traverse input message process list, look for SNMP_MSG_EMPTY */ - msg_ps = &msg_input_list[0]; - req_idx = 0; - while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) - { - req_idx++; - msg_ps++; - } - if (req_idx == SNMP_CONCURRENT_REQUESTS) - { - /* exceeding number of concurrent requests */ - pbuf_free(p); - return; - } - - /* accepting request */ - snmp_inc_snmpinpkts(); - /* record used 'protocol control block' */ - msg_ps->pcb = pcb; - /* source address (network order) */ - msg_ps->sip = *addr; - /* source port (host order (lwIP oddity)) */ - msg_ps->sp = port; - - /* check total length, version, community, pdu type */ - err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); - /* Only accept requests and requests without error (be robust) */ - /* Reject response and trap headers or error requests as input! */ - if ((err_ret != ERR_OK) || - ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && - (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && - (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || - ((msg_ps->error_status != SNMP_ES_NOERROR) || - (msg_ps->error_index != 0)) ) - { - /* header check failed drop request silently, do not return error! */ - pbuf_free(p); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); - return; - } - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); - - /* Builds a list of variable bindings. Copy the varbinds from the pbuf - chain to glue them when these are divided over two or more pbuf's. */ - err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); - /* we've decoded the incoming message, release input msg now */ - pbuf_free(p); - if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) - { - /* varbind-list decode failed, or varbind list empty. - drop request silently, do not return error! - (errors are only returned for a specific varbind failure) */ - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); - return; - } - - msg_ps->error_status = SNMP_ES_NOERROR; - msg_ps->error_index = 0; - /* find object for each variable binding */ - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - /* first variable binding from list to inspect */ - msg_ps->vb_idx = 0; - - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); - - /* handle input event and as much objects as possible in one go */ - snmp_msg_event(req_idx); -} - -/** - * Checks and decodes incoming SNMP message header, logs header errors. - * - * @param p points to pbuf chain of SNMP message (UDP payload) - * @param ofs points to first octet of SNMP message - * @param pdu_len the length of the UDP payload - * @param ofs_ret returns the ofset of the variable bindings - * @param m_stat points to the current message request state return - * @return - * - ERR_OK SNMP header is sane and accepted - * - ERR_ARG SNMP header is either malformed or rejected - */ -static err_t -snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) -{ - err_t derr; - u16_t len, ofs_base; - u8_t len_octets; - u8_t type; - s32_t version; - - ofs_base = ofs; - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || - (pdu_len != (1 + len_octets + len)) || - (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) - { - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - ofs += (1 + len_octets); - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) - { - /* can't decode or no integer (version) */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version); - if (derr != ERR_OK) - { - /* can't decode */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - if (version != 0) - { - /* not version 1 */ - snmp_inc_snmpinbadversions(); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR))) - { - /* can't decode or no octet string (community) */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community); - if (derr != ERR_OK) - { - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - /* add zero terminator */ - len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); - m_stat->community[len] = 0; - m_stat->com_strlen = (u8_t)len; - if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) - { - /** @todo: move this if we need to check more names */ - snmp_inc_snmpinbadcommunitynames(); - snmp_authfail_trap(); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if (derr != ERR_OK) - { - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - switch(type) - { - case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ): - /* GetRequest PDU */ - snmp_inc_snmpingetrequests(); - derr = ERR_OK; - break; - case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ): - /* GetNextRequest PDU */ - snmp_inc_snmpingetnexts(); - derr = ERR_OK; - break; - case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP): - /* GetResponse PDU */ - snmp_inc_snmpingetresponses(); - derr = ERR_ARG; - break; - case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ): - /* SetRequest PDU */ - snmp_inc_snmpinsetrequests(); - derr = ERR_OK; - break; - case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP): - /* Trap PDU */ - snmp_inc_snmpintraps(); - derr = ERR_ARG; - break; - default: - snmp_inc_snmpinasnparseerrs(); - derr = ERR_ARG; - break; - } - if (derr != ERR_OK) - { - /* unsupported input PDU for this agent (no parse error) */ - return ERR_ARG; - } - m_stat->rt = type & 0x1F; - ofs += (1 + len_octets); - if (len != (pdu_len - (ofs - ofs_base))) - { - /* decoded PDU length does not equal actual payload length */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) - { - /* can't decode or no integer (request ID) */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid); - if (derr != ERR_OK) - { - /* can't decode */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) - { - /* can't decode or no integer (error-status) */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - /* must be noError (0) for incoming requests. - log errors for mib-2 completeness and for debug purposes */ - derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status); - if (derr != ERR_OK) - { - /* can't decode */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - switch (m_stat->error_status) - { - case SNMP_ES_TOOBIG: - snmp_inc_snmpintoobigs(); - break; - case SNMP_ES_NOSUCHNAME: - snmp_inc_snmpinnosuchnames(); - break; - case SNMP_ES_BADVALUE: - snmp_inc_snmpinbadvalues(); - break; - case SNMP_ES_READONLY: - snmp_inc_snmpinreadonlys(); - break; - case SNMP_ES_GENERROR: - snmp_inc_snmpingenerrs(); - break; - } - ofs += (1 + len_octets + len); - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG))) - { - /* can't decode or no integer (error-index) */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - /* must be 0 for incoming requests. - decode anyway to catch bad integers (and dirty tricks) */ - derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index); - if (derr != ERR_OK) - { - /* can't decode */ - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - *ofs_ret = ofs; - return ERR_OK; -} - -static err_t -snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat) -{ - err_t derr; - u16_t len, vb_len; - u8_t len_octets; - u8_t type; - - /* variable binding list */ - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len); - if ((derr != ERR_OK) || - (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ))) - { - snmp_inc_snmpinasnparseerrs(); - return ERR_ARG; - } - ofs += (1 + len_octets); - - /* start with empty list */ - m_stat->invb.count = 0; - m_stat->invb.head = NULL; - m_stat->invb.tail = NULL; - - while (vb_len > 0) - { - struct snmp_obj_id oid, oid_value; - struct snmp_varbind *vb; - - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || - (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) || - (len == 0) || (len > vb_len)) - { - snmp_inc_snmpinasnparseerrs(); - /* free varbinds (if available) */ - snmp_varbind_list_free(&m_stat->invb); - return ERR_ARG; - } - ofs += (1 + len_octets); - vb_len -= (1 + len_octets); - - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID))) - { - /* can't decode object name length */ - snmp_inc_snmpinasnparseerrs(); - /* free varbinds (if available) */ - snmp_varbind_list_free(&m_stat->invb); - return ERR_ARG; - } - derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid); - if (derr != ERR_OK) - { - /* can't decode object name */ - snmp_inc_snmpinasnparseerrs(); - /* free varbinds (if available) */ - snmp_varbind_list_free(&m_stat->invb); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - vb_len -= (1 + len_octets + len); - - snmp_asn1_dec_type(p, ofs, &type); - derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len); - if (derr != ERR_OK) - { - /* can't decode object value length */ - snmp_inc_snmpinasnparseerrs(); - /* free varbinds (if available) */ - snmp_varbind_list_free(&m_stat->invb); - return ERR_ARG; - } - - switch (type) - { - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): - vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); - if (vb != NULL) - { - s32_t *vptr = (s32_t*)vb->value; - - derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); - snmp_varbind_tail_add(&m_stat->invb, vb); - } - else - { - derr = ERR_ARG; - } - break; - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): - vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); - if (vb != NULL) - { - u32_t *vptr = (u32_t*)vb->value; - - derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); - snmp_varbind_tail_add(&m_stat->invb, vb); - } - else - { - derr = ERR_ARG; - } - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): - LWIP_ASSERT("invalid length", len <= 0xff); - vb = snmp_varbind_alloc(&oid, type, (u8_t)len); - if (vb != NULL) - { - derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); - snmp_varbind_tail_add(&m_stat->invb, vb); - } - else - { - derr = ERR_ARG; - } - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): - vb = snmp_varbind_alloc(&oid, type, 0); - if (vb != NULL) - { - snmp_varbind_tail_add(&m_stat->invb, vb); - derr = ERR_OK; - } - else - { - derr = ERR_ARG; - } - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): - derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value); - if (derr == ERR_OK) - { - vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t)); - if (vb != NULL) - { - u8_t i = oid_value.len; - s32_t *vptr = (s32_t*)vb->value; - - while(i > 0) - { - i--; - vptr[i] = oid_value.id[i]; - } - snmp_varbind_tail_add(&m_stat->invb, vb); - derr = ERR_OK; - } - else - { - derr = ERR_ARG; - } - } - break; - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): - if (len == 4) - { - /* must be exactly 4 octets! */ - vb = snmp_varbind_alloc(&oid, type, 4); - if (vb != NULL) - { - derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); - snmp_varbind_tail_add(&m_stat->invb, vb); - } - else - { - derr = ERR_ARG; - } - } - else - { - derr = ERR_ARG; - } - break; - default: - derr = ERR_ARG; - break; - } - if (derr != ERR_OK) - { - snmp_inc_snmpinasnparseerrs(); - /* free varbinds (if available) */ - snmp_varbind_list_free(&m_stat->invb); - return ERR_ARG; - } - ofs += (1 + len_octets + len); - vb_len -= (1 + len_octets + len); - } - - if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ) - { - snmp_add_snmpintotalsetvars(m_stat->invb.count); - } - else - { - snmp_add_snmpintotalreqvars(m_stat->invb.count); - } - - *ofs_ret = ofs; - return ERR_OK; -} - -struct snmp_varbind* -snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) -{ - struct snmp_varbind *vb; - - vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); - if (vb != NULL) - { - u8_t i; - - vb->next = NULL; - vb->prev = NULL; - i = oid->len; - vb->ident_len = i; - if (i > 0) - { - LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH); - /* allocate array of s32_t for our object identifier */ - vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE); - if (vb->ident == NULL) - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate ident value space\n")); - memp_free(MEMP_SNMP_VARBIND, vb); - return NULL; - } - while(i > 0) - { - i--; - vb->ident[i] = oid->id[i]; - } - } - else - { - /* i == 0, pass zero length object identifier */ - vb->ident = NULL; - } - vb->value_type = type; - vb->value_len = len; - if (len > 0) - { - LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); - /* allocate raw bytes for our object value */ - vb->value = memp_malloc(MEMP_SNMP_VALUE); - if (vb->value == NULL) - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate value space\n")); - if (vb->ident != NULL) - { - memp_free(MEMP_SNMP_VALUE, vb->ident); - } - memp_free(MEMP_SNMP_VARBIND, vb); - return NULL; - } - } - else - { - /* ASN1_NUL type, or zero length ASN1_OC_STR */ - vb->value = NULL; - } - } - else - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_varbind_alloc: couldn't allocate varbind space\n")); - } - return vb; -} - -void -snmp_varbind_free(struct snmp_varbind *vb) -{ - if (vb->value != NULL ) - { - memp_free(MEMP_SNMP_VALUE, vb->value); - } - if (vb->ident != NULL ) - { - memp_free(MEMP_SNMP_VALUE, vb->ident); - } - memp_free(MEMP_SNMP_VARBIND, vb); -} - -void -snmp_varbind_list_free(struct snmp_varbind_root *root) -{ - struct snmp_varbind *vb, *prev; - - vb = root->tail; - while ( vb != NULL ) - { - prev = vb->prev; - snmp_varbind_free(vb); - vb = prev; - } - root->count = 0; - root->head = NULL; - root->tail = NULL; -} - -void -snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb) -{ - if (root->count == 0) - { - /* add first varbind to list */ - root->head = vb; - root->tail = vb; - } - else - { - /* add nth varbind to list tail */ - root->tail->next = vb; - vb->prev = root->tail; - root->tail = vb; - } - root->count += 1; -} - -struct snmp_varbind* -snmp_varbind_tail_remove(struct snmp_varbind_root *root) -{ - struct snmp_varbind* vb; - - if (root->count > 0) - { - /* remove tail varbind */ - vb = root->tail; - root->tail = vb->prev; - vb->prev->next = NULL; - root->count -= 1; - } - else - { - /* nothing to remove */ - vb = NULL; - } - return vb; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/snmp/msg_out.c b/ext/lwip/src/core/snmp/msg_out.c deleted file mode 100644 index 485f076a..00000000 --- a/ext/lwip/src/core/snmp/msg_out.c +++ /dev/null @@ -1,674 +0,0 @@ -/** - * @file - * SNMP output message processing (RFC1157). - * - * Output responses and traps are build in two passes: - * - * Pass 0: iterate over the output message backwards to determine encoding lengths - * Pass 1: the actual forward encoding of internal form into ASN1 - * - * The single-pass encoding method described by Comer & Stevens - * requires extra buffer space and copying for reversal of the packet. - * The buffer requirement can be prohibitively large for big payloads - * (>= 484) therefore we use the two encoding passes. - */ - -/* - * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * Author: Christiaan Simons <christiaan.simons@axon.tv> - */ - -#include "lwip/opt.h" - -#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/netif.h" -#include "lwip/snmp.h" -#include "lwip/snmp_asn1.h" -#include "lwip/snmp_msg.h" - -struct snmp_trap_dst -{ - /* destination IP address in network order */ - ip_addr_t dip; - /* set to 0 when disabled, >0 when enabled */ - u8_t enable; -}; -struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS]; - -/** TRAP message structure */ -struct snmp_msg_trap trap_msg; - -static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len); -static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len); -static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root); - -static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p); -static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p); -static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs); - -/** - * Sets enable switch for this trap destination. - * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 - * @param enable switch if 0 destination is disabled >0 enabled. - */ -void -snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) -{ - if (dst_idx < SNMP_TRAP_DESTINATIONS) - { - trap_dst[dst_idx].enable = enable; - } -} - -/** - * Sets IPv4 address for this trap destination. - * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1 - * @param dst IPv4 address in host order. - */ -void -snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst) -{ - if (dst_idx < SNMP_TRAP_DESTINATIONS) - { - ip_addr_set(&trap_dst[dst_idx].dip, dst); - } -} - -/** - * Sends a 'getresponse' message to the request originator. - * - * @param m_stat points to the current message request state source - * @return ERR_OK when success, ERR_MEM if we're out of memory - * - * @note the caller is responsible for filling in outvb in the m_stat - * and provide error-status and index (except for tooBig errors) ... - */ -err_t -snmp_send_response(struct snmp_msg_pstat *m_stat) -{ - struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0}; - struct pbuf *p; - u16_t tot_len; - err_t err; - - /* pass 0, calculate length fields */ - tot_len = snmp_varbind_list_sum(&m_stat->outvb); - tot_len = snmp_resp_header_sum(m_stat, tot_len); - - /* try allocating pbuf(s) for complete response */ - p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); - if (p == NULL) - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n")); - - /* can't construct reply, return error-status tooBig */ - m_stat->error_status = SNMP_ES_TOOBIG; - m_stat->error_index = 0; - /* pass 0, recalculate lengths, for empty varbind-list */ - tot_len = snmp_varbind_list_sum(&emptyvb); - tot_len = snmp_resp_header_sum(m_stat, tot_len); - /* retry allocation once for header and empty varbind-list */ - p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); - } - if (p != NULL) - { - /* first pbuf alloc try or retry alloc success */ - u16_t ofs; - - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n")); - - /* pass 1, size error, encode packet ino the pbuf(s) */ - ofs = snmp_resp_header_enc(m_stat, p); - snmp_varbind_list_enc(&m_stat->outvb, p, ofs); - - switch (m_stat->error_status) - { - case SNMP_ES_TOOBIG: - snmp_inc_snmpouttoobigs(); - break; - case SNMP_ES_NOSUCHNAME: - snmp_inc_snmpoutnosuchnames(); - break; - case SNMP_ES_BADVALUE: - snmp_inc_snmpoutbadvalues(); - break; - case SNMP_ES_GENERROR: - snmp_inc_snmpoutgenerrs(); - break; - } - snmp_inc_snmpoutgetresponses(); - snmp_inc_snmpoutpkts(); - - /** @todo do we need separate rx and tx pcbs for threaded case? */ - /** connect to the originating source */ - udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp); - err = udp_send(m_stat->pcb, p); - if (err == ERR_MEM) - { - /** @todo release some memory, retry and return tooBig? tooMuchHassle? */ - err = ERR_MEM; - } - else - { - err = ERR_OK; - } - /** disassociate remote address and port with this pcb */ - udp_disconnect(m_stat->pcb); - - pbuf_free(p); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n")); - return err; - } - else - { - /* first pbuf alloc try or retry alloc failed - very low on memory, couldn't return tooBig */ - return ERR_MEM; - } -} - - -/** - * Sends an generic or enterprise specific trap message. - * - * @param generic_trap is the trap code - * @param eoid points to enterprise object identifier - * @param specific_trap used for enterprise traps when generic_trap == 6 - * @return ERR_OK when success, ERR_MEM if we're out of memory - * - * @note the caller is responsible for filling in outvb in the trap_msg - * @note the use of the enterpise identifier field - * is per RFC1215. - * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps - * and .iso.org.dod.internet.private.enterprises.yourenterprise - * (sysObjectID) for specific traps. - */ -err_t -snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) -{ - struct snmp_trap_dst *td; - struct netif *dst_if; - ip_addr_t dst_ip; - struct pbuf *p; - u16_t i,tot_len; - - for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++) - { - if ((td->enable != 0) && !ip_addr_isany(&td->dip)) - { - /* network order trap destination */ - ip_addr_copy(trap_msg.dip, td->dip); - /* lookup current source address for this dst */ - dst_if = ip_route(&td->dip); - ip_addr_copy(dst_ip, dst_if->ip_addr); - /* @todo: what about IPv6? */ - trap_msg.sip_raw[0] = ip4_addr1(&dst_ip); - trap_msg.sip_raw[1] = ip4_addr2(&dst_ip); - trap_msg.sip_raw[2] = ip4_addr3(&dst_ip); - trap_msg.sip_raw[3] = ip4_addr4(&dst_ip); - trap_msg.gen_trap = generic_trap; - trap_msg.spc_trap = specific_trap; - if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) - { - /* enterprise-Specific trap */ - trap_msg.enterprise = eoid; - } - else - { - /* generic (MIB-II) trap */ - snmp_get_snmpgrpid_ptr(&trap_msg.enterprise); - } - snmp_get_sysuptime(&trap_msg.ts); - - /* pass 0, calculate length fields */ - tot_len = snmp_varbind_list_sum(&trap_msg.outvb); - tot_len = snmp_trap_header_sum(&trap_msg, tot_len); - - /* allocate pbuf(s) */ - p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL); - if (p != NULL) - { - u16_t ofs; - - /* pass 1, encode packet ino the pbuf(s) */ - ofs = snmp_trap_header_enc(&trap_msg, p); - snmp_varbind_list_enc(&trap_msg.outvb, p, ofs); - - snmp_inc_snmpouttraps(); - snmp_inc_snmpoutpkts(); - - /** send to the TRAP destination */ - udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT); - - pbuf_free(p); - } - else - { - return ERR_MEM; - } - } - } - return ERR_OK; -} - -void -snmp_coldstart_trap(void) -{ - trap_msg.outvb.head = NULL; - trap_msg.outvb.tail = NULL; - trap_msg.outvb.count = 0; - snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0); -} - -void -snmp_authfail_trap(void) -{ - u8_t enable; - snmp_get_snmpenableauthentraps(&enable); - if (enable == 1) - { - trap_msg.outvb.head = NULL; - trap_msg.outvb.tail = NULL; - trap_msg.outvb.count = 0; - snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0); - } -} - -/** - * Sums response header field lengths from tail to head and - * returns resp_header_lengths for second encoding pass. - * - * @param vb_len varbind-list length - * @param rhl points to returned header lengths - * @return the required lenght for encoding the response header - */ -static u16_t -snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len) -{ - u16_t tot_len; - struct snmp_resp_header_lengths *rhl; - - rhl = &m_stat->rhl; - tot_len = vb_len; - snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen); - snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen); - tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen; - - snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen); - snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen); - tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen; - - snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen); - snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen); - tot_len += 1 + rhl->ridlenlen + rhl->ridlen; - - rhl->pdulen = tot_len; - snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen); - tot_len += 1 + rhl->pdulenlen; - - rhl->comlen = m_stat->com_strlen; - snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen); - tot_len += 1 + rhl->comlenlen + rhl->comlen; - - snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen); - snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen); - tot_len += 1 + rhl->verlen + rhl->verlenlen; - - rhl->seqlen = tot_len; - snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen); - tot_len += 1 + rhl->seqlenlen; - - return tot_len; -} - -/** - * Sums trap header field lengths from tail to head and - * returns trap_header_lengths for second encoding pass. - * - * @param vb_len varbind-list length - * @param thl points to returned header lengths - * @return the required lenght for encoding the trap header - */ -static u16_t -snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len) -{ - u16_t tot_len; - struct snmp_trap_header_lengths *thl; - - thl = &m_trap->thl; - tot_len = vb_len; - - snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen); - snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen); - tot_len += 1 + thl->tslen + thl->tslenlen; - - snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen); - snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen); - tot_len += 1 + thl->strplen + thl->strplenlen; - - snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen); - snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen); - tot_len += 1 + thl->gtrplen + thl->gtrplenlen; - - thl->aaddrlen = 4; - snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen); - tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen; - - snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen); - snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen); - tot_len += 1 + thl->eidlen + thl->eidlenlen; - - thl->pdulen = tot_len; - snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen); - tot_len += 1 + thl->pdulenlen; - - thl->comlen = sizeof(snmp_publiccommunity) - 1; - snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen); - tot_len += 1 + thl->comlenlen + thl->comlen; - - snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen); - snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen); - tot_len += 1 + thl->verlen + thl->verlenlen; - - thl->seqlen = tot_len; - snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen); - tot_len += 1 + thl->seqlenlen; - - return tot_len; -} - -/** - * Sums varbind lengths from tail to head and - * annotates lengths in varbind for second encoding pass. - * - * @param root points to the root of the variable binding list - * @return the required lenght for encoding the variable bindings - */ -static u16_t -snmp_varbind_list_sum(struct snmp_varbind_root *root) -{ - struct snmp_varbind *vb; - u32_t *uint_ptr; - s32_t *sint_ptr; - u16_t tot_len; - - tot_len = 0; - vb = root->tail; - while ( vb != NULL ) - { - /* encoded value lenght depends on type */ - switch (vb->value_type) - { - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): - sint_ptr = (s32_t*)vb->value; - snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); - break; - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): - uint_ptr = (u32_t*)vb->value; - snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen); - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): - vb->vlen = vb->value_len; - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): - sint_ptr = (s32_t*)vb->value; - snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); - break; - default: - /* unsupported type */ - vb->vlen = 0; - break; - }; - /* encoding length of value length field */ - snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen); - snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen); - snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen); - - vb->seqlen = 1 + vb->vlenlen + vb->vlen; - vb->seqlen += 1 + vb->olenlen + vb->olen; - snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen); - - /* varbind seq */ - tot_len += 1 + vb->seqlenlen + vb->seqlen; - - vb = vb->prev; - } - - /* varbind-list seq */ - root->seqlen = tot_len; - snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen); - tot_len += 1 + root->seqlenlen; - - return tot_len; -} - -/** - * Encodes response header from head to tail. - */ -static u16_t -snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p) -{ - u16_t ofs; - - ofs = 0; - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen); - ofs += m_stat->rhl.seqlenlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen); - ofs += m_stat->rhl.verlenlen; - snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version); - ofs += m_stat->rhl.verlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen); - ofs += m_stat->rhl.comlenlen; - snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community); - ofs += m_stat->rhl.comlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen); - ofs += m_stat->rhl.pdulenlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen); - ofs += m_stat->rhl.ridlenlen; - snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid); - ofs += m_stat->rhl.ridlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen); - ofs += m_stat->rhl.errstatlenlen; - snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status); - ofs += m_stat->rhl.errstatlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen); - ofs += m_stat->rhl.erridxlenlen; - snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index); - ofs += m_stat->rhl.erridxlen; - - return ofs; -} - -/** - * Encodes trap header from head to tail. - */ -static u16_t -snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p) -{ - u16_t ofs; - - ofs = 0; - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen); - ofs += m_trap->thl.seqlenlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen); - ofs += m_trap->thl.verlenlen; - snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version); - ofs += m_trap->thl.verlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen); - ofs += m_trap->thl.comlenlen; - snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]); - ofs += m_trap->thl.comlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen); - ofs += m_trap->thl.pdulenlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen); - ofs += m_trap->thl.eidlenlen; - snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]); - ofs += m_trap->thl.eidlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen); - ofs += m_trap->thl.aaddrlenlen; - snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]); - ofs += m_trap->thl.aaddrlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen); - ofs += m_trap->thl.gtrplenlen; - snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap); - ofs += m_trap->thl.gtrplen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen); - ofs += m_trap->thl.strplenlen; - snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap); - ofs += m_trap->thl.strplen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen); - ofs += m_trap->thl.tslenlen; - snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts); - ofs += m_trap->thl.tslen; - - return ofs; -} - -/** - * Encodes varbind list from head to tail. - */ -static u16_t -snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) -{ - struct snmp_varbind *vb; - s32_t *sint_ptr; - u32_t *uint_ptr; - u8_t *raw_ptr; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, root->seqlen); - ofs += root->seqlenlen; - - vb = root->head; - while ( vb != NULL ) - { - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, vb->seqlen); - ofs += vb->seqlenlen; - - snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)); - ofs += 1; - snmp_asn1_enc_length(p, ofs, vb->olen); - ofs += vb->olenlen; - snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]); - ofs += vb->olen; - - snmp_asn1_enc_type(p, ofs, vb->value_type); - ofs += 1; - snmp_asn1_enc_length(p, ofs, vb->vlen); - ofs += vb->vlenlen; - - switch (vb->value_type) - { - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): - sint_ptr = (s32_t*)vb->value; - snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); - break; - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): - uint_ptr = (u32_t*)vb->value; - snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): - case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): - raw_ptr = (u8_t*)vb->value; - snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): - break; - case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): - sint_ptr = (s32_t*)vb->value; - snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); - break; - default: - /* unsupported type */ - break; - }; - ofs += vb->vlen; - vb = vb->next; - } - return ofs; -} - -#endif /* LWIP_SNMP */ diff --git a/ext/lwip/src/core/stats.c b/ext/lwip/src/core/stats.c deleted file mode 100644 index 8ea82497..00000000 --- a/ext/lwip/src/core/stats.c +++ /dev/null @@ -1,176 +0,0 @@ -/** - * @file - * Statistics module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/stats.h" -#include "lwip/mem.h" - -#include <string.h> - -struct stats_ lwip_stats; - -void stats_init(void) -{ -#ifdef LWIP_DEBUG -#if MEMP_STATS - const char * memp_names[] = { -#define LWIP_MEMPOOL(name,num,size,desc) desc, -#include "lwip/memp_std.h" - }; - int i; - for (i = 0; i < MEMP_MAX; i++) { - lwip_stats.memp[i].name = memp_names[i]; - } -#endif /* MEMP_STATS */ -#if MEM_STATS - lwip_stats.mem.name = "MEM"; -#endif /* MEM_STATS */ -#endif /* LWIP_DEBUG */ -} - -#if LWIP_STATS_DISPLAY -void -stats_display_proto(struct stats_proto *proto, const char *name) -{ - LWIP_PLATFORM_DIAG(("\n%s\n\t", name)); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit)); - LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv)); - LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw)); - LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop)); - LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr)); - LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr)); - LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr)); - LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr)); - LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr)); - LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr)); - LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err)); - LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit)); -} - -#if IGMP_STATS -void -stats_display_igmp(struct stats_igmp *igmp) -{ - LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); - LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); - LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); - LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); - LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); - LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); - LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); - LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); - LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); - LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group)); - LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general)); - LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); - LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); - LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); - LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); -} -#endif /* IGMP_STATS */ - -#if MEM_STATS || MEMP_STATS -void -stats_display_mem(struct stats_mem *mem, const char *name) -{ - LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name)); - LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail)); - LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used)); - LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max)); - LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err)); -} - -#if MEMP_STATS -void -stats_display_memp(struct stats_mem *mem, int index) -{ - char * memp_names[] = { -#define LWIP_MEMPOOL(name,num,size,desc) desc, -#include "lwip/memp_std.h" - }; - if(index < MEMP_MAX) { - stats_display_mem(mem, memp_names[index]); - } -} -#endif /* MEMP_STATS */ -#endif /* MEM_STATS || MEMP_STATS */ - -#if SYS_STATS -void -stats_display_sys(struct stats_sys *sys) -{ - LWIP_PLATFORM_DIAG(("\nSYS\n\t")); - LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); - LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); - LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); - LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); - LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); - LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); - LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); - LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); - LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); -} -#endif /* SYS_STATS */ - -void -stats_display(void) -{ - s16_t i; - - LINK_STATS_DISPLAY(); - ETHARP_STATS_DISPLAY(); - IPFRAG_STATS_DISPLAY(); - IP_STATS_DISPLAY(); - IGMP_STATS_DISPLAY(); - ICMP_STATS_DISPLAY(); - UDP_STATS_DISPLAY(); - TCP_STATS_DISPLAY(); - MEM_STATS_DISPLAY(); - for (i = 0; i < MEMP_MAX; i++) { - MEMP_STATS_DISPLAY(i); - } - SYS_STATS_DISPLAY(); -} -#endif /* LWIP_STATS_DISPLAY */ - -#endif /* LWIP_STATS */ - diff --git a/ext/lwip/src/core/sys.c b/ext/lwip/src/core/sys.c deleted file mode 100644 index f1777372..00000000 --- a/ext/lwip/src/core/sys.c +++ /dev/null @@ -1,68 +0,0 @@ -/** - * @file - * lwIP Operating System abstraction - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#include "lwip/sys.h" - -/* Most of the functions defined in sys.h must be implemented in the - * architecture-dependent file sys_arch.c */ - -#if !NO_SYS - -#ifndef sys_msleep -/** - * Sleep for some ms. Timeouts are NOT processed while sleeping. - * - * @param ms number of milliseconds to sleep - */ -void -sys_msleep(u32_t ms) -{ - if (ms > 0) { - sys_sem_t delaysem; - err_t err = sys_sem_new(&delaysem, 0); - if (err == ERR_OK) { - sys_arch_sem_wait(&delaysem, ms); - sys_sem_free(&delaysem); - } - } -} -#endif /* sys_msleep */ - -#endif /* !NO_SYS */ diff --git a/ext/lwip/src/core/tcp.c b/ext/lwip/src/core/tcp.c deleted file mode 100644 index 105b68e7..00000000 --- a/ext/lwip/src/core/tcp.c +++ /dev/null @@ -1,1742 +0,0 @@ -/** - * @file - * Transmission Control Protocol for IP - * - * This file contains common functions for the TCP implementation, such as functinos - * for manipulating the data structures and the TCP timer functions. TCP functions - * related to input and output is found in tcp_in.c and tcp_out.c respectively. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/snmp.h" -#include "lwip/tcp.h" -#include "lwip/tcp_impl.h" -#include "lwip/debug.h" -#include "lwip/stats.h" - -#include <string.h> - -#ifndef TCP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define TCP_LOCAL_PORT_RANGE_START 0xc000 -#define TCP_LOCAL_PORT_RANGE_END 0xffff -#define TCP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~TCP_LOCAL_PORT_RANGE_START) + TCP_LOCAL_PORT_RANGE_START) -#endif - -#if LWIP_TCP_KEEPALIVE -#define TCP_KEEP_DUR(pcb) ((pcb)->keep_cnt * (pcb)->keep_intvl) -#define TCP_KEEP_INTVL(pcb) ((pcb)->keep_intvl) -#else /* LWIP_TCP_KEEPALIVE */ -#define TCP_KEEP_DUR(pcb) TCP_MAXIDLE -#define TCP_KEEP_INTVL(pcb) TCP_KEEPINTVL_DEFAULT -#endif /* LWIP_TCP_KEEPALIVE */ - -const char * const tcp_state_str[] = { - "CLOSED", - "LISTEN", - "SYN_SENT", - "SYN_RCVD", - "ESTABLISHED", - "FIN_WAIT_1", - "FIN_WAIT_2", - "CLOSE_WAIT", - "CLOSING", - "LAST_ACK", - "TIME_WAIT" -}; - -/* last local TCP port */ -static u16_t tcp_port = TCP_LOCAL_PORT_RANGE_START; - -/* Incremented every coarse grained timer shot (typically every 500 ms). */ -u32_t tcp_ticks; -const u8_t tcp_backoff[13] = - { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7}; - /* Times per slowtmr hits */ -const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; - -/* The TCP PCB lists. */ - -/** List of all TCP PCBs bound but not yet (connected || listening) */ -struct tcp_pcb *tcp_bound_pcbs; -/** List of all TCP PCBs in LISTEN state */ -union tcp_listen_pcbs_t tcp_listen_pcbs; -/** List of all TCP PCBs that are in a state in which - * they accept or send data. */ -struct tcp_pcb *tcp_active_pcbs; -/** List of all TCP PCBs in TIME-WAIT state */ -struct tcp_pcb *tcp_tw_pcbs; - -#define NUM_TCP_PCB_LISTS 4 -#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 -/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ -struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, - &tcp_active_pcbs, &tcp_tw_pcbs}; - -/** Only used for temporary storage. */ -struct tcp_pcb *tcp_tmp_pcb; - -u8_t tcp_active_pcbs_changed; - -/** Timer counter to handle calling slow-timer from tcp_tmr() */ -static u8_t tcp_timer; -static u8_t tcp_timer_ctr; -static u16_t tcp_new_port(void); - -/** - * Initialize this module. - */ -void -tcp_init(void) -{ -#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) - tcp_port = TCP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ -} - -/** - * Called periodically to dispatch TCP timers. - */ -void -tcp_tmr(void) -{ - /* Call tcp_fasttmr() every 250 ms */ - tcp_fasttmr(); - - if (++tcp_timer & 1) { - /* Call tcp_tmr() every 500 ms, i.e., every other timer - tcp_tmr() is called. */ - tcp_slowtmr(); - } -} - -/** - * Closes the TX side of a connection held by the PCB. - * For tcp_close(), a RST is sent if the application didn't receive all data - * (tcp_recved() not called for all data passed to recv callback). - * - * Listening pcbs are freed and may not be referenced any more. - * Connection pcbs are freed if not yet connected and may not be referenced - * any more. If a connection is established (at least SYN received or in - * a closing state), the connection is closed, and put in a closing state. - * The pcb is then automatically freed in tcp_slowtmr(). It is therefore - * unsafe to reference it. - * - * @param pcb the tcp_pcb to close - * @return ERR_OK if connection has been closed - * another err_t if closing failed and pcb is not freed - */ -static err_t -tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) -{ - err_t err; - - if (rst_on_unacked_data && ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { - if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { - /* Not all data received by application, send RST to tell the remote - side about this. */ - LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); - - /* don't call tcp_abort here: we must not deallocate the pcb since - that might not be expected when calling tcp_close */ - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - - tcp_pcb_purge(pcb); - TCP_RMV_ACTIVE(pcb); - if (pcb->state == ESTABLISHED) { - /* move to TIME_WAIT since we close actively */ - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } else { - /* CLOSE_WAIT: deallocate the pcb since we already sent a RST for it */ - memp_free(MEMP_TCP_PCB, pcb); - } - return ERR_OK; - } - } - - switch (pcb->state) { - case CLOSED: - /* Closing a pcb in the CLOSED state might seem erroneous, - * however, it is in this state once allocated and as yet unused - * and the user needs some way to free it should the need arise. - * Calling tcp_close() with a pcb that has already been closed, (i.e. twice) - * or for a pcb that has been used and then entered the CLOSED state - * is erroneous, but this should never happen as the pcb has in those cases - * been freed, and so any remaining handles are bogus. */ - err = ERR_OK; - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - memp_free(MEMP_TCP_PCB, pcb); - pcb = NULL; - break; - case LISTEN: - err = ERR_OK; - tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); - memp_free(MEMP_TCP_PCB_LISTEN, pcb); - pcb = NULL; - break; - case SYN_SENT: - err = ERR_OK; - TCP_PCB_REMOVE_ACTIVE(pcb); - memp_free(MEMP_TCP_PCB, pcb); - pcb = NULL; - snmp_inc_tcpattemptfails(); - break; - case SYN_RCVD: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - snmp_inc_tcpattemptfails(); - pcb->state = FIN_WAIT_1; - } - break; - case ESTABLISHED: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - snmp_inc_tcpestabresets(); - pcb->state = FIN_WAIT_1; - } - break; - case CLOSE_WAIT: - err = tcp_send_fin(pcb); - if (err == ERR_OK) { - snmp_inc_tcpestabresets(); - pcb->state = LAST_ACK; - } - break; - default: - /* Has already been closed, do nothing. */ - err = ERR_OK; - pcb = NULL; - break; - } - - if (pcb != NULL && err == ERR_OK) { - /* To ensure all data has been sent when tcp_close returns, we have - to make sure tcp_output doesn't fail. - Since we don't really have to ensure all data has been sent when tcp_close - returns (unsent data is sent from tcp timer functions, also), we don't care - for the return value of tcp_output for now. */ - /* @todo: When implementing SO_LINGER, this must be changed somehow: - If SOF_LINGER is set, the data should be sent and acked before close returns. - This can only be valid for sequential APIs, not for the raw API. */ - tcp_output(pcb); - } - return err; -} - -/** - * Closes the connection held by the PCB. - * - * Listening pcbs are freed and may not be referenced any more. - * Connection pcbs are freed if not yet connected and may not be referenced - * any more. If a connection is established (at least SYN received or in - * a closing state), the connection is closed, and put in a closing state. - * The pcb is then automatically freed in tcp_slowtmr(). It is therefore - * unsafe to reference it (unless an error is returned). - * - * @param pcb the tcp_pcb to close - * @return ERR_OK if connection has been closed - * another err_t if closing failed and pcb is not freed - */ -err_t -tcp_close(struct tcp_pcb *pcb) -{ -#if TCP_DEBUG - LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ - - if (pcb->state != LISTEN) { - /* Set a flag not to receive any more data... */ - pcb->flags |= TF_RXCLOSED; - } - /* ... and close */ - return tcp_close_shutdown(pcb, 1); -} - -/** - * Causes all or part of a full-duplex connection of this PCB to be shut down. - * This doesn't deallocate the PCB unless shutting down both sides! - * Shutting down both sides is the same as calling tcp_close, so if it succeds, - * the PCB should not be referenced any more. - * - * @param pcb PCB to shutdown - * @param shut_rx shut down receive side if this is != 0 - * @param shut_tx shut down send side if this is != 0 - * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) - * another err_t on error. - */ -err_t -tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) -{ - if (pcb->state == LISTEN) { - return ERR_CONN; - } - if (shut_rx) { - /* shut down the receive side: set a flag not to receive any more data... */ - pcb->flags |= TF_RXCLOSED; - if (shut_tx) { - /* shutting down the tx AND rx side is the same as closing for the raw API */ - return tcp_close_shutdown(pcb, 1); - } - /* ... and free buffered data */ - if (pcb->refused_data != NULL) { - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - } - if (shut_tx) { - /* This can't happen twice since if it succeeds, the pcb's state is changed. - Only close in these states as the others directly deallocate the PCB */ - switch (pcb->state) { - case SYN_RCVD: - case ESTABLISHED: - case CLOSE_WAIT: - return tcp_close_shutdown(pcb, shut_rx); - default: - /* Not (yet?) connected, cannot shutdown the TX side as that would bring us - into CLOSED state, where the PCB is deallocated. */ - return ERR_CONN; - } - } - return ERR_OK; -} - -/** - * Abandons a connection and optionally sends a RST to the remote - * host. Deletes the local protocol control block. This is done when - * a connection is killed because of shortage of memory. - * - * @param pcb the tcp_pcb to abort - * @param reset boolean to indicate whether a reset should be sent - */ -void -tcp_abandon(struct tcp_pcb *pcb, int reset) -{ - u32_t seqno, ackno; -#if LWIP_CALLBACK_API - tcp_err_fn errf; -#endif /* LWIP_CALLBACK_API */ - void *errf_arg; - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", - pcb->state != LISTEN); - /* Figure out on which TCP PCB list we are, and remove us. If we - are in an active state, call the receive function associated with - the PCB with a NULL argument, and send an RST to the remote end. */ - if (pcb->state == TIME_WAIT) { - tcp_pcb_remove(&tcp_tw_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - seqno = pcb->snd_nxt; - ackno = pcb->rcv_nxt; -#if LWIP_CALLBACK_API - errf = pcb->errf; -#endif /* LWIP_CALLBACK_API */ - errf_arg = pcb->callback_arg; - TCP_PCB_REMOVE_ACTIVE(pcb); - if (pcb->unacked != NULL) { - tcp_segs_free(pcb->unacked); - } - if (pcb->unsent != NULL) { - tcp_segs_free(pcb->unsent); - } -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL) { - tcp_segs_free(pcb->ooseq); - } -#endif /* TCP_QUEUE_OOSEQ */ - if (reset) { - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); - tcp_rst(seqno, ackno, &pcb->local_ip, &pcb->remote_ip, pcb->local_port, pcb->remote_port); - } - memp_free(MEMP_TCP_PCB, pcb); - TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); - } -} - -/** - * Aborts the connection by sending a RST (reset) segment to the remote - * host. The pcb is deallocated. This function never fails. - * - * ATTENTION: When calling this from one of the TCP callbacks, make - * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise - * or you will risk accessing deallocated memory or memory leaks! - * - * @param pcb the tcp pcb to abort - */ -void -tcp_abort(struct tcp_pcb *pcb) -{ - tcp_abandon(pcb, 1); -} - -/** - * Binds the connection to a local portnumber and IP address. If the - * IP address is not given (i.e., ipaddr == NULL), the IP address of - * the outgoing network interface is used instead. - * - * @param pcb the tcp_pcb to bind (no check is done whether this pcb is - * already bound!) - * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind - * to any local address - * @param port the local port to bind to - * @return ERR_USE if the port is already in use - * ERR_VAL if bind failed because the PCB is not in a valid state - * ERR_OK if bound - */ -err_t -tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - int i; - int max_pcb_list = NUM_TCP_PCB_LISTS; - struct tcp_pcb *cpcb; - - LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); - -#if SO_REUSE - /* Unless the REUSEADDR flag is set, - we have to check the pcbs in TIME-WAIT state, also. - We do not dump TIME_WAIT pcb's; they can still be matched by incoming - packets using both local and remote IP addresses and ports to distinguish. - */ - if (ip_get_option(pcb, SOF_REUSEADDR)) { - max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; - } -#endif /* SO_REUSE */ - - if (port == 0) { - port = tcp_new_port(); - if (port == 0) { - return ERR_BUF; - } - } - - /* Check if the address already is in use (on all lists) */ - for (i = 0; i < max_pcb_list; i++) { - for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { -#if SO_REUSE - /* Omit checking for the same port if both pcbs have REUSEADDR set. - For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in - tcp_connect. */ - if (!ip_get_option(pcb, SOF_REUSEADDR) || - !ip_get_option(cpcb, SOF_REUSEADDR)) -#endif /* SO_REUSE */ - { - if (ip_addr_isany(&(cpcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - return ERR_USE; - } - } - } - } - } - - if (!ip_addr_isany(ipaddr)) { - pcb->local_ip = *ipaddr; - } - pcb->local_port = port; - TCP_REG(&tcp_bound_pcbs, pcb); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port)); - return ERR_OK; -} -#if LWIP_CALLBACK_API -/** - * Default accept callback if no accept callback is specified by the user. - */ -static err_t -tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err) -{ - LWIP_UNUSED_ARG(arg); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(err); - - return ERR_ABRT; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * Set the state of the connection to be LISTEN, which means that it - * is able to accept incoming connections. The protocol control block - * is reallocated in order to consume less memory. Setting the - * connection to LISTEN is an irreversible process. - * - * @param pcb the original tcp_pcb - * @param backlog the incoming connections queue limit - * @return tcp_pcb used for listening, consumes less memory. - * - * @note The original tcp_pcb is freed. This function therefore has to be - * called like this: - * tpcb = tcp_listen(tpcb); - */ -struct tcp_pcb * -tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) -{ - struct tcp_pcb_listen *lpcb; - - LWIP_UNUSED_ARG(backlog); - LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL); - - /* already listening? */ - if (pcb->state == LISTEN) { - return pcb; - } -#if SO_REUSE - if (ip_get_option(pcb, SOF_REUSEADDR)) { - /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage - is declared (listen-/connection-pcb), we have to make sure now that - this port is only used once for every local IP. */ - for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if (lpcb->local_port == pcb->local_port) { - if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { - /* this address/port is already used */ - return NULL; - } - } - } - } -#endif /* SO_REUSE */ - lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); - if (lpcb == NULL) { - return NULL; - } - lpcb->callback_arg = pcb->callback_arg; - lpcb->local_port = pcb->local_port; - lpcb->state = LISTEN; - lpcb->prio = pcb->prio; - lpcb->so_options = pcb->so_options; - ip_set_option(lpcb, SOF_ACCEPTCONN); - lpcb->ttl = pcb->ttl; - lpcb->tos = pcb->tos; - ip_addr_copy(lpcb->local_ip, pcb->local_ip); - if (pcb->local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - memp_free(MEMP_TCP_PCB, pcb); -#if LWIP_CALLBACK_API - lpcb->accept = tcp_accept_null; -#endif /* LWIP_CALLBACK_API */ -#if TCP_LISTEN_BACKLOG - lpcb->accepts_pending = 0; - lpcb->backlog = (backlog ? backlog : 1); -#endif /* TCP_LISTEN_BACKLOG */ - TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); - return (struct tcp_pcb *)lpcb; -} - -/** - * Update the state that tracks the available window space to advertise. - * - * Returns how much extra window would be advertised if we sent an - * update now. - */ -u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) -{ - u32_t new_right_edge = pcb->rcv_nxt + pcb->rcv_wnd; - - if (TCP_SEQ_GEQ(new_right_edge, pcb->rcv_ann_right_edge + LWIP_MIN((TCP_WND / 2), pcb->mss))) { - /* we can advertise more window */ - pcb->rcv_ann_wnd = pcb->rcv_wnd; - return new_right_edge - pcb->rcv_ann_right_edge; - } else { - if (TCP_SEQ_GT(pcb->rcv_nxt, pcb->rcv_ann_right_edge)) { - /* Can happen due to other end sending out of advertised window, - * but within actual available (but not yet advertised) window */ - pcb->rcv_ann_wnd = 0; - } else { - /* keep the right edge of window constant */ - u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; - LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); - pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd; - } - return 0; - } -} - -/** - * This function should be called by the application when it has - * processed the data. The purpose is to advertise a larger window - * when the data has been processed. - * - * @param pcb the tcp_pcb for which data is read - * @param len the amount of bytes that have been read by the application - */ -void -tcp_recved(struct tcp_pcb *pcb, u16_t len) -{ - int wnd_inflation; - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_recved for listen-pcbs", - pcb->state != LISTEN); - LWIP_ASSERT("tcp_recved: len would wrap rcv_wnd\n", - len <= 0xffff - pcb->rcv_wnd ); - - pcb->rcv_wnd += len; - if (pcb->rcv_wnd > TCP_WND) { - pcb->rcv_wnd = TCP_WND; - } - - wnd_inflation = tcp_update_rcv_ann_wnd(pcb); - - /* If the change in the right edge of window is significant (default - * watermark is TCP_WND/4), then send an explicit update now. - * Otherwise wait for a packet to be sent in the normal course of - * events (or more window to be available later) */ - if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { - tcp_ack_now(pcb); - tcp_output(pcb); - } - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", - len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); -} - -/** - * Allocate a new local TCP port. - * - * @return a new (free) local TCP port number - */ -static u16_t -tcp_new_port(void) -{ - u8_t i; - u16_t n = 0; - struct tcp_pcb *pcb; - -again: - if (tcp_port++ == TCP_LOCAL_PORT_RANGE_END) { - tcp_port = TCP_LOCAL_PORT_RANGE_START; - } - /* Check all PCB lists. */ - for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { - for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == tcp_port) { - if (++n > (TCP_LOCAL_PORT_RANGE_END - TCP_LOCAL_PORT_RANGE_START)) { - return 0; - } - goto again; - } - } - } - return tcp_port; -} - -/** - * Connects to another host. The function given as the "connected" - * argument will be called when the connection has been established. - * - * @param pcb the tcp_pcb used to establish the connection - * @param ipaddr the remote ip address to connect to - * @param port the remote tcp port to connect to - * @param connected callback function to call when connected (or on error) - * @return ERR_VAL if invalid arguments are given - * ERR_OK if connect request has been sent - * other err_t values if connect request couldn't be sent - */ -err_t -tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, - tcp_connected_fn connected) -{ - err_t ret; - u32_t iss; - u16_t old_local_port; - - LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); - if (ipaddr != NULL) { - pcb->remote_ip = *ipaddr; - } else { - return ERR_VAL; - } - pcb->remote_port = port; - - /* check if we have a route to the remote host */ - if (ip_addr_isany(&(pcb->local_ip))) { - /* no local IP address set, yet. */ - struct netif *netif = ip_route(&(pcb->remote_ip)); - if (netif == NULL) { - /* Don't even try to send a SYN packet if we have no route - since that will fail. */ - return ERR_RTE; - } - /* Use the netif's IP address as local address. */ - ip_addr_copy(pcb->local_ip, netif->ip_addr); - } - - old_local_port = pcb->local_port; - if (pcb->local_port == 0) { - pcb->local_port = tcp_new_port(); - if (pcb->local_port == 0) { - return ERR_BUF; - } - } -#if SO_REUSE - if (ip_get_option(pcb, SOF_REUSEADDR)) { - /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure - now that the 5-tuple is unique. */ - struct tcp_pcb *cpcb; - int i; - /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ - for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { - for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { - if ((cpcb->local_port == pcb->local_port) && - (cpcb->remote_port == port) && - ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && - ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { - /* linux returns EISCONN here, but ERR_USE should be OK for us */ - return ERR_USE; - } - } - } - } -#endif /* SO_REUSE */ - iss = tcp_next_iss(); - pcb->rcv_nxt = 0; - pcb->snd_nxt = iss; - pcb->lastack = iss - 1; - pcb->snd_lbb = iss - 1; - pcb->rcv_wnd = TCP_WND; - pcb->rcv_ann_wnd = TCP_WND; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->snd_wnd = TCP_WND; - /* As initial send MSS, we use TCP_MSS but limit it to 536. - The send MSS is updated when an MSS option is received. */ - pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; -#if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - pcb->cwnd = 1; - pcb->ssthresh = pcb->mss * 10; -#if LWIP_CALLBACK_API - pcb->connected = connected; -#else /* LWIP_CALLBACK_API */ - LWIP_UNUSED_ARG(connected); -#endif /* LWIP_CALLBACK_API */ - - /* Send a SYN together with the MSS option. */ - ret = tcp_enqueue_flags(pcb, TCP_SYN); - if (ret == ERR_OK) { - /* SYN segment was enqueued, changed the pcbs state now */ - pcb->state = SYN_SENT; - if (old_local_port != 0) { - TCP_RMV(&tcp_bound_pcbs, pcb); - } - TCP_REG_ACTIVE(pcb); - snmp_inc_tcpactiveopens(); - - tcp_output(pcb); - } - return ret; -} - -/** - * Called every 500 ms and implements the retransmission timer and the timer that - * removes PCBs that have been in TIME-WAIT for enough time. It also increments - * various timers such as the inactivity timer in each PCB. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_slowtmr(void) -{ - struct tcp_pcb *pcb, *prev; - u16_t eff_wnd; - u8_t pcb_remove; /* flag if a PCB should be removed */ - u8_t pcb_reset; /* flag if a RST should be sent when removing */ - err_t err; - - err = ERR_OK; - - ++tcp_ticks; - ++tcp_timer_ctr; - -tcp_slowtmr_start: - /* Steps through all of the active PCBs. */ - prev = NULL; - pcb = tcp_active_pcbs; - if (pcb == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n")); - } - while (pcb != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n")); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN); - LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT); - if (pcb->last_timer == tcp_timer_ctr) { - /* skip this pcb, we have already processed it */ - pcb = pcb->next; - continue; - } - pcb->last_timer = tcp_timer_ctr; - - pcb_remove = 0; - pcb_reset = 0; - - if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n")); - } - else if (pcb->nrtx == TCP_MAXRTX) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); - } else { - if (pcb->persist_backoff > 0) { - /* If snd_wnd is zero, use persist timer to send 1 byte probes - * instead of using the standard retransmission mechanism. */ - pcb->persist_cnt++; - if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) { - pcb->persist_cnt = 0; - if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) { - pcb->persist_backoff++; - } - tcp_zero_window_probe(pcb); - } - } else { - /* Increase the retransmission timer if it is running */ - if(pcb->rtime >= 0) { - ++pcb->rtime; - } - - if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { - /* Time for a retransmission. */ - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F - " pcb->rto %"S16_F"\n", - pcb->rtime, pcb->rto)); - - /* Double retransmission time-out unless we are trying to - * connect to somebody (i.e., we are in SYN_SENT). */ - if (pcb->state != SYN_SENT) { - pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; - } - - /* Reset the retransmission timer. */ - pcb->rtime = 0; - - /* Reduce congestion window and ssthresh. */ - eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); - pcb->ssthresh = eff_wnd >> 1; - if (pcb->ssthresh < (pcb->mss << 1)) { - pcb->ssthresh = (pcb->mss << 1); - } - pcb->cwnd = pcb->mss; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F - " ssthresh %"U16_F"\n", - pcb->cwnd, pcb->ssthresh)); - - /* The following needs to be called AFTER cwnd is set to one - mss - STJ */ - tcp_rexmit_rto(pcb); - } - } - } - /* Check if this PCB has stayed too long in FIN-WAIT-2 */ - if (pcb->state == FIN_WAIT_2) { - /* If this PCB is in FIN_WAIT_2 because of SHUT_WR don't let it time out. */ - if (pcb->flags & TF_RXCLOSED) { - /* PCB was fully closed (either through close() or SHUT_RDWR): - normal FIN-WAIT timeout handling. */ - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n")); - } - } - } - - /* Check if KEEPALIVE should be sent */ - if(ip_get_option(pcb, SOF_KEEPALIVE) && - ((pcb->state == ESTABLISHED) || - (pcb->state == CLOSE_WAIT))) { - if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + TCP_KEEP_DUR(pcb)) / TCP_SLOW_INTERVAL) - { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - ++pcb_remove; - ++pcb_reset; - } - else if((u32_t)(tcp_ticks - pcb->tmr) > - (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEP_INTVL(pcb)) - / TCP_SLOW_INTERVAL) - { - tcp_keepalive(pcb); - pcb->keep_cnt_sent++; - } - } - - /* If this PCB has queued out of sequence data, but has been - inactive for too long, will drop the data (it will eventually - be retransmitted). */ -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL && - (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n")); - } -#endif /* TCP_QUEUE_OOSEQ */ - - /* Check if this PCB has stayed too long in SYN-RCVD */ - if (pcb->state == SYN_RCVD) { - if ((u32_t)(tcp_ticks - pcb->tmr) > - TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n")); - } - } - - /* Check if this PCB has stayed too long in LAST-ACK */ - if (pcb->state == LAST_ACK) { - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n")); - } - } - - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *pcb2; - tcp_err_fn err_fn; - void *err_arg; - tcp_pcb_purge(pcb); - /* Remove PCB from tcp_active_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); - prev->next = pcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb); - tcp_active_pcbs = pcb->next; - } - - if (pcb_reset) { - tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, - pcb->local_port, pcb->remote_port); - } - - err_fn = pcb->errf; - err_arg = pcb->callback_arg; - pcb2 = pcb; - pcb = pcb->next; - memp_free(MEMP_TCP_PCB, pcb2); - - tcp_active_pcbs_changed = 0; - TCP_EVENT_ERR(err_fn, err_arg, ERR_ABRT); - if (tcp_active_pcbs_changed) { - goto tcp_slowtmr_start; - } - } else { - /* get the 'next' element now and work with 'prev' below (in case of abort) */ - prev = pcb; - pcb = pcb->next; - - /* We check if we should poll the connection. */ - ++prev->polltmr; - if (prev->polltmr >= prev->pollinterval) { - prev->polltmr = 0; - LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); - tcp_active_pcbs_changed = 0; - TCP_EVENT_POLL(prev, err); - if (tcp_active_pcbs_changed) { - goto tcp_slowtmr_start; - } - /* if err == ERR_ABRT, 'prev' is already deallocated */ - if (err == ERR_OK) { - tcp_output(prev); - } - } - } - } - - - /* Steps through all of the TIME-WAIT PCBs. */ - prev = NULL; - pcb = tcp_tw_pcbs; - while (pcb != NULL) { - LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - pcb_remove = 0; - - /* Check if this PCB has stayed long enough in TIME-WAIT */ - if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) { - ++pcb_remove; - } - - - - /* If the PCB should be removed, do it. */ - if (pcb_remove) { - struct tcp_pcb *pcb2; - tcp_pcb_purge(pcb); - /* Remove PCB from tcp_tw_pcbs list. */ - if (prev != NULL) { - LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); - prev->next = pcb->next; - } else { - /* This PCB was the first. */ - LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); - tcp_tw_pcbs = pcb->next; - } - pcb2 = pcb; - pcb = pcb->next; - memp_free(MEMP_TCP_PCB, pcb2); - } else { - prev = pcb; - pcb = pcb->next; - } - } -} - -/** - * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously - * "refused" by upper layer (application) and sends delayed ACKs. - * - * Automatically called from tcp_tmr(). - */ -void -tcp_fasttmr(void) -{ - struct tcp_pcb *pcb; - - ++tcp_timer_ctr; - -tcp_fasttmr_start: - pcb = tcp_active_pcbs; - - while(pcb != NULL) { - if (pcb->last_timer != tcp_timer_ctr) { - struct tcp_pcb *next; - pcb->last_timer = tcp_timer_ctr; - /* send delayed ACKs */ - if (pcb->flags & TF_ACK_DELAY) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); - tcp_ack_now(pcb); - tcp_output(pcb); - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - - next = pcb->next; - - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - tcp_active_pcbs_changed = 0; - tcp_process_refused_data(pcb); - if (tcp_active_pcbs_changed) { - /* application callback has changed the pcb list: restart the loop */ - goto tcp_fasttmr_start; - } - } - pcb = next; - } - } -} - -/** Pass pcb->refused_data to the recv callback */ -err_t -tcp_process_refused_data(struct tcp_pcb *pcb) -{ - err_t err; - u8_t refused_flags = pcb->refused_data->flags; - /* set pcb->refused_data to NULL in case the callback frees it and then - closes the pcb */ - struct pbuf *refused_data = pcb->refused_data; - pcb->refused_data = NULL; - /* Notify again application with data previously received. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n")); - TCP_EVENT_RECV(pcb, refused_data, ERR_OK, err); - if (err == ERR_OK) { - /* did refused_data include a FIN? */ - if (refused_flags & PBUF_FLAG_TCP_FIN) { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - return ERR_ABRT; - } - } - } else if (err == ERR_ABRT) { - /* if err == ERR_ABRT, 'pcb' is already deallocated */ - /* Drop incoming packets because pcb is "full" (only if the incoming - segment contains data). */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); - return ERR_ABRT; - } else { - /* data is still refused, pbuf is still valid (go on for ACK-only packets) */ - pcb->refused_data = refused_data; - } - return ERR_OK; -} - -/** - * Deallocates a list of TCP segments (tcp_seg structures). - * - * @param seg tcp_seg list of TCP segments to free - */ -void -tcp_segs_free(struct tcp_seg *seg) -{ - while (seg != NULL) { - struct tcp_seg *next = seg->next; - tcp_seg_free(seg); - seg = next; - } -} - -/** - * Frees a TCP segment (tcp_seg structure). - * - * @param seg single tcp_seg to free - */ -void -tcp_seg_free(struct tcp_seg *seg) -{ - if (seg != NULL) { - if (seg->p != NULL) { - pbuf_free(seg->p); -#if TCP_DEBUG - seg->p = NULL; -#endif /* TCP_DEBUG */ - } - memp_free(MEMP_TCP_SEG, seg); - } -} - -/** - * Sets the priority of a connection. - * - * @param pcb the tcp_pcb to manipulate - * @param prio new priority - */ -void -tcp_setprio(struct tcp_pcb *pcb, u8_t prio) -{ - pcb->prio = prio; -} - -#if TCP_QUEUE_OOSEQ -/** - * Returns a copy of the given TCP segment. - * The pbuf and data are not copied, only the pointers - * - * @param seg the old tcp_seg - * @return a copy of seg - */ -struct tcp_seg * -tcp_seg_copy(struct tcp_seg *seg) -{ - struct tcp_seg *cseg; - - cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); - if (cseg == NULL) { - return NULL; - } - SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg)); - pbuf_ref(cseg->p); - return cseg; -} -#endif /* TCP_QUEUE_OOSEQ */ - -#if LWIP_CALLBACK_API -/** - * Default receive callback that is called if the user didn't register - * a recv callback for the pcb. - */ -err_t -tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) -{ - LWIP_UNUSED_ARG(arg); - if (p != NULL) { - tcp_recved(pcb, p->tot_len); - pbuf_free(p); - } else if (err == ERR_OK) { - return tcp_close(pcb); - } - return ERR_OK; -} -#endif /* LWIP_CALLBACK_API */ - -/** - * Kills the oldest active connection that has the same or lower priority than - * 'prio'. - * - * @param prio minimum priority - */ -static void -tcp_kill_prio(u8_t prio) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - u8_t mprio; - - - mprio = TCP_PRIO_MAX; - - /* We kill the oldest active connection that has lower priority than prio. */ - inactivity = 0; - inactive = NULL; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->prio <= prio && - pcb->prio <= mprio && - (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - mprio = pcb->prio; - } - } - if (inactive != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", - (void *)inactive, inactivity)); - tcp_abort(inactive); - } -} - -/** - * Kills the oldest connection that is in TIME_WAIT state. - * Called from tcp_alloc() if no more connections are available. - */ -static void -tcp_kill_timewait(void) -{ - struct tcp_pcb *pcb, *inactive; - u32_t inactivity; - - inactivity = 0; - inactive = NULL; - /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */ - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) { - inactivity = tcp_ticks - pcb->tmr; - inactive = pcb; - } - } - if (inactive != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", - (void *)inactive, inactivity)); - tcp_abort(inactive); - } -} - -/** - * Allocate a new tcp_pcb structure. - * - * @param prio priority for the new pcb - * @return a new tcp_pcb that initially is in state CLOSED - */ -struct tcp_pcb * -tcp_alloc(u8_t prio) -{ - struct tcp_pcb *pcb; - u32_t iss; - - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing oldest connection in TIME-WAIT. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); - tcp_kill_timewait(); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb == NULL) { - /* Try killing active connections with lower priority than the new one. */ - LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); - tcp_kill_prio(prio); - /* Try to allocate a tcp_pcb again. */ - pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); - if (pcb != NULL) { - /* adjust err stats: memp_malloc failed twice before */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - /* adjust err stats: timewait PCB was freed above */ - MEMP_STATS_DEC(err, MEMP_TCP_PCB); - } - } - if (pcb != NULL) { - memset(pcb, 0, sizeof(struct tcp_pcb)); - pcb->prio = prio; - pcb->snd_buf = TCP_SND_BUF; - pcb->snd_queuelen = 0; - pcb->rcv_wnd = TCP_WND; - pcb->rcv_ann_wnd = TCP_WND; - pcb->tos = 0; - pcb->ttl = TCP_TTL; - /* As initial send MSS, we use TCP_MSS but limit it to 536. - The send MSS is updated when an MSS option is received. */ - pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS; - pcb->rto = 3000 / TCP_SLOW_INTERVAL; - pcb->sa = 0; - pcb->sv = 3000 / TCP_SLOW_INTERVAL; - pcb->rtime = -1; - pcb->cwnd = 1; - iss = tcp_next_iss(); - pcb->snd_wl2 = iss; - pcb->snd_nxt = iss; - pcb->lastack = iss; - pcb->snd_lbb = iss; - pcb->tmr = tcp_ticks; - pcb->last_timer = tcp_timer_ctr; - - pcb->polltmr = 0; - -#if LWIP_CALLBACK_API - pcb->recv = tcp_recv_null; -#endif /* LWIP_CALLBACK_API */ - - /* Init KEEPALIVE timer */ - pcb->keep_idle = TCP_KEEPIDLE_DEFAULT; - -#if LWIP_TCP_KEEPALIVE - pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT; - pcb->keep_cnt = TCP_KEEPCNT_DEFAULT; -#endif /* LWIP_TCP_KEEPALIVE */ - - pcb->keep_cnt_sent = 0; - } - return pcb; -} - -/** - * Creates a new TCP protocol control block but doesn't place it on - * any of the TCP PCB lists. - * The pcb is not put on any list until binding using tcp_bind(). - * - * @internal: Maybe there should be a idle TCP PCB list where these - * PCBs are put on. Port reservation using tcp_bind() is implemented but - * allocated pcbs that are not bound can't be killed automatically if wanting - * to allocate a pcb with higher prio (@see tcp_kill_prio()) - * - * @return a new tcp_pcb that initially is in state CLOSED - */ -struct tcp_pcb * -tcp_new(void) -{ - return tcp_alloc(TCP_PRIO_NORMAL); -} - -/** - * Used to specify the argument that should be passed callback - * functions. - * - * @param pcb tcp_pcb to set the callback argument - * @param arg void pointer argument to pass to callback functions - */ -void -tcp_arg(struct tcp_pcb *pcb, void *arg) -{ - /* This function is allowed to be called for both listen pcbs and - connection pcbs. */ - pcb->callback_arg = arg; -} -#if LWIP_CALLBACK_API - -/** - * Used to specify the function that should be called when a TCP - * connection receives data. - * - * @param pcb tcp_pcb to set the recv callback - * @param recv callback function to call for this pcb when data is received - */ -void -tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) -{ - LWIP_ASSERT("invalid socket state for recv callback", pcb->state != LISTEN); - pcb->recv = recv; -} - -/** - * Used to specify the function that should be called when TCP data - * has been successfully delivered to the remote host. - * - * @param pcb tcp_pcb to set the sent callback - * @param sent callback function to call for this pcb when data is successfully sent - */ -void -tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) -{ - LWIP_ASSERT("invalid socket state for sent callback", pcb->state != LISTEN); - pcb->sent = sent; -} - -/** - * Used to specify the function that should be called when a fatal error - * has occured on the connection. - * - * @param pcb tcp_pcb to set the err callback - * @param err callback function to call for this pcb when a fatal error - * has occured on the connection - */ -void -tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) -{ - LWIP_ASSERT("invalid socket state for err callback", pcb->state != LISTEN); - pcb->errf = err; -} - -/** - * Used for specifying the function that should be called when a - * LISTENing connection has been connected to another host. - * - * @param pcb tcp_pcb to set the accept callback - * @param accept callback function to call for this pcb when LISTENing - * connection has been connected to another host - */ -void -tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) -{ - /* This function is allowed to be called for both listen pcbs and - connection pcbs. */ - pcb->accept = accept; -} -#endif /* LWIP_CALLBACK_API */ - - -/** - * Used to specify the function that should be called periodically - * from TCP. The interval is specified in terms of the TCP coarse - * timer interval, which is called twice a second. - * - */ -void -tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) -{ - LWIP_ASSERT("invalid socket state for poll", pcb->state != LISTEN); -#if LWIP_CALLBACK_API - pcb->poll = poll; -#else /* LWIP_CALLBACK_API */ - LWIP_UNUSED_ARG(poll); -#endif /* LWIP_CALLBACK_API */ - pcb->pollinterval = interval; -} - -/** - * Purges a TCP PCB. Removes any buffered data and frees the buffer memory - * (pcb->ooseq, pcb->unsent and pcb->unacked are freed). - * - * @param pcb tcp_pcb to purge. The pcb itself is not deallocated! - */ -void -tcp_pcb_purge(struct tcp_pcb *pcb) -{ - if (pcb->state != CLOSED && - pcb->state != TIME_WAIT && - pcb->state != LISTEN) { - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n")); - -#if TCP_LISTEN_BACKLOG - if (pcb->state == SYN_RCVD) { - /* Need to find the corresponding listen_pcb and decrease its accepts_pending */ - struct tcp_pcb_listen *lpcb; - LWIP_ASSERT("tcp_pcb_purge: pcb->state == SYN_RCVD but tcp_listen_pcbs is NULL", - tcp_listen_pcbs.listen_pcbs != NULL); - for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if ((lpcb->local_port == pcb->local_port) && - (ip_addr_isany(&lpcb->local_ip) || - ip_addr_cmp(&pcb->local_ip, &lpcb->local_ip))) { - /* port and address of the listen pcb match the timed-out pcb */ - LWIP_ASSERT("tcp_pcb_purge: listen pcb does not have accepts pending", - lpcb->accepts_pending > 0); - lpcb->accepts_pending--; - break; - } - } - } -#endif /* TCP_LISTEN_BACKLOG */ - - - if (pcb->refused_data != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n")); - pbuf_free(pcb->refused_data); - pcb->refused_data = NULL; - } - if (pcb->unsent != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n")); - } - if (pcb->unacked != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); - } -#if TCP_QUEUE_OOSEQ - if (pcb->ooseq != NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); - } - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; -#endif /* TCP_QUEUE_OOSEQ */ - - /* Stop the retransmission timer as it will expect data on unacked - queue if it fires */ - pcb->rtime = -1; - - tcp_segs_free(pcb->unsent); - tcp_segs_free(pcb->unacked); - pcb->unacked = pcb->unsent = NULL; -#if TCP_OVERSIZE - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - } -} - -/** - * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first. - * - * @param pcblist PCB list to purge. - * @param pcb tcp_pcb to purge. The pcb itself is NOT deallocated! - */ -void -tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb) -{ - TCP_RMV(pcblist, pcb); - - tcp_pcb_purge(pcb); - - /* if there is an outstanding delayed ACKs, send it */ - if (pcb->state != TIME_WAIT && - pcb->state != LISTEN && - pcb->flags & TF_ACK_DELAY) { - pcb->flags |= TF_ACK_NOW; - tcp_output(pcb); - } - - if (pcb->state != LISTEN) { - LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL); - LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL); -#if TCP_QUEUE_OOSEQ - LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL); -#endif /* TCP_QUEUE_OOSEQ */ - } - - pcb->state = CLOSED; - - LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane()); -} - -/** - * Calculates a new initial sequence number for new connections. - * - * @return u32_t pseudo random sequence number - */ -u32_t -tcp_next_iss(void) -{ - static u32_t iss = 6510; - - iss += tcp_ticks; /* XXX */ - return iss; -} - -#if TCP_CALCULATE_EFF_SEND_MSS -/** - * Calcluates the effective send mss that can be used for a specific IP address - * by using ip_route to determin the netif used to send to the address and - * calculating the minimum of TCP_MSS and that netif's mtu (if set). - */ -u16_t -tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) -{ - u16_t mss_s; - struct netif *outif; - - outif = ip_route(addr); - if ((outif != NULL) && (outif->mtu != 0)) { - mss_s = outif->mtu - IP_HLEN - TCP_HLEN; - /* RFC 1122, chap 4.2.2.6: - * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * We correct for TCP options in tcp_write(), and don't support IP options. - */ - sendmss = LWIP_MIN(sendmss, mss_s); - } - return sendmss; -} -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - -const char* -tcp_debug_state_str(enum tcp_state s) -{ - return tcp_state_str[s]; -} - -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -/** - * Print a tcp header for debugging purposes. - * - * @param tcphdr pointer to a struct tcp_hdr - */ -void -tcp_debug_print(struct tcp_hdr *tcphdr) -{ - LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", - ntohs(tcphdr->src), ntohs(tcphdr->dest))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (seq no)\n", - ntohl(tcphdr->seqno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %010"U32_F" | (ack no)\n", - ntohl(tcphdr->ackno))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" | |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"| %5"U16_F" | (hdrlen, flags (", - TCPH_HDRLEN(tcphdr), - TCPH_FLAGS(tcphdr) >> 5 & 1, - TCPH_FLAGS(tcphdr) >> 4 & 1, - TCPH_FLAGS(tcphdr) >> 3 & 1, - TCPH_FLAGS(tcphdr) >> 2 & 1, - TCPH_FLAGS(tcphdr) >> 1 & 1, - TCPH_FLAGS(tcphdr) & 1, - ntohs(tcphdr->wnd))); - tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); - LWIP_DEBUGF(TCP_DEBUG, ("), win)\n")); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(TCP_DEBUG, ("| 0x%04"X16_F" | %5"U16_F" | (chksum, urgp)\n", - ntohs(tcphdr->chksum), ntohs(tcphdr->urgp))); - LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n")); -} - -/** - * Print a tcp state for debugging purposes. - * - * @param s enum tcp_state to print - */ -void -tcp_debug_print_state(enum tcp_state s) -{ - LWIP_DEBUGF(TCP_DEBUG, ("State: %s\n", tcp_state_str[s])); -} - -/** - * Print tcp flags for debugging purposes. - * - * @param flags tcp flags, all active flags are printed - */ -void -tcp_debug_print_flags(u8_t flags) -{ - if (flags & TCP_FIN) { - LWIP_DEBUGF(TCP_DEBUG, ("FIN ")); - } - if (flags & TCP_SYN) { - LWIP_DEBUGF(TCP_DEBUG, ("SYN ")); - } - if (flags & TCP_RST) { - LWIP_DEBUGF(TCP_DEBUG, ("RST ")); - } - if (flags & TCP_PSH) { - LWIP_DEBUGF(TCP_DEBUG, ("PSH ")); - } - if (flags & TCP_ACK) { - LWIP_DEBUGF(TCP_DEBUG, ("ACK ")); - } - if (flags & TCP_URG) { - LWIP_DEBUGF(TCP_DEBUG, ("URG ")); - } - if (flags & TCP_ECE) { - LWIP_DEBUGF(TCP_DEBUG, ("ECE ")); - } - if (flags & TCP_CWR) { - LWIP_DEBUGF(TCP_DEBUG, ("CWR ")); - } - LWIP_DEBUGF(TCP_DEBUG, ("\n")); -} - -/** - * Print all tcp_pcbs in every list for debugging purposes. - */ -void -tcp_debug_print_pcbs(void) -{ - struct tcp_pcb *pcb; - LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n")); - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } - LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n")); - for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } - LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n")); - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ", - pcb->local_port, pcb->remote_port, - pcb->snd_nxt, pcb->rcv_nxt)); - tcp_debug_print_state(pcb->state); - } -} - -/** - * Check state consistency of the tcp_pcb lists. - */ -s16_t -tcp_pcbs_sane(void) -{ - struct tcp_pcb *pcb; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN); - LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - } - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - } - return 1; -} -#endif /* TCP_DEBUG */ - -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/core/tcp_in.c b/ext/lwip/src/core/tcp_in.c deleted file mode 100644 index 051869ff..00000000 --- a/ext/lwip/src/core/tcp_in.c +++ /dev/null @@ -1,1619 +0,0 @@ -/** - * @file - * Transmission Control Protocol, incoming traffic - * - * The input processing functions of the TCP layer. - * - * These functions are generally called in the order (ip_input() ->) - * tcp_input() -> * tcp_process() -> tcp_receive() (-> application). - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp_impl.h" -#include "lwip/def.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/inet_chksum.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "arch/perf.h" - -/* These variables are global to all functions involved in the input - processing of TCP segments. They are set by the tcp_input() - function. */ -static struct tcp_seg inseg; -static struct tcp_hdr *tcphdr; -static struct ip_hdr *iphdr; -static u32_t seqno, ackno; -static u8_t flags; -static u16_t tcplen; - -static u8_t recv_flags; -static struct pbuf *recv_data; - -struct tcp_pcb *tcp_input_pcb; - -/* Forward declarations. */ -static err_t tcp_process(struct tcp_pcb *pcb); -static void tcp_receive(struct tcp_pcb *pcb); -static void tcp_parseopt(struct tcp_pcb *pcb); - -static err_t tcp_listen_input(struct tcp_pcb_listen *pcb); -static err_t tcp_timewait_input(struct tcp_pcb *pcb); - -/** - * The initial input processing of TCP. It verifies the TCP header, demultiplexes - * the segment between the PCBs and passes it on to tcp_process(), which implements - * the TCP finite state machine. This function is called by the IP layer (in - * ip_input()). - * - * @param p received TCP segment to process (p->payload pointing to the IP header) - * @param inp network interface on which this segment was received - */ -void -tcp_input(struct pbuf *p, struct netif *inp) -{ - struct tcp_pcb *pcb, *prev; - struct tcp_pcb_listen *lpcb; -#if SO_REUSE - struct tcp_pcb *lpcb_prev = NULL; - struct tcp_pcb_listen *lpcb_any = NULL; -#endif /* SO_REUSE */ - u8_t hdrlen; - err_t err; - - PERF_START; - - TCP_STATS_INC(tcp.recv); - snmp_inc_tcpinsegs(); - - iphdr = (struct ip_hdr *)p->payload; - tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); - -#if TCP_INPUT_DEBUG - tcp_debug_print(tcphdr); -#endif - - /* remove header from payload */ - if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) { - /* drop short packets */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len)); - TCP_STATS_INC(tcp.lenerr); - goto dropped; - } - - /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || - ip_addr_ismulticast(¤t_iphdr_dest)) { - TCP_STATS_INC(tcp.proterr); - goto dropped; - } - -#if CHECKSUM_CHECK_TCP - /* Verify TCP checksum. */ - if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_TCP, p->tot_len) != 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_TCP, p->tot_len))); -#if TCP_DEBUG - tcp_debug_print(tcphdr); -#endif /* TCP_DEBUG */ - TCP_STATS_INC(tcp.chkerr); - goto dropped; - } -#endif - - /* Move the payload pointer in the pbuf so that it points to the - TCP data instead of the TCP header. */ - hdrlen = TCPH_HDRLEN(tcphdr); - if(pbuf_header(p, -(hdrlen * 4))){ - /* drop short packets */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n")); - TCP_STATS_INC(tcp.lenerr); - goto dropped; - } - - /* Convert fields in TCP header to host byte order. */ - tcphdr->src = ntohs(tcphdr->src); - tcphdr->dest = ntohs(tcphdr->dest); - seqno = tcphdr->seqno = ntohl(tcphdr->seqno); - ackno = tcphdr->ackno = ntohl(tcphdr->ackno); - tcphdr->wnd = ntohs(tcphdr->wnd); - - flags = TCPH_FLAGS(tcphdr); - tcplen = p->tot_len + ((flags & (TCP_FIN | TCP_SYN)) ? 1 : 0); - - /* Demultiplex an incoming segment. First, we check if it is destined - for an active connection. */ - prev = NULL; - - - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED); - LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT); - LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { - - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ - LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb); - if (prev != NULL) { - prev->next = pcb->next; - pcb->next = tcp_active_pcbs; - tcp_active_pcbs = pcb; - } - LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb); - break; - } - prev = pcb; - } - - if (pcb == NULL) { - /* If it did not go to an active connection, we check the connections - in the TIME-WAIT state. */ - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); - if (pcb->remote_port == tcphdr->src && - pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { - /* We don't really care enough to move this PCB to the front - of the list since we are not very likely to receive that - many segments for connections in TIME-WAIT. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n")); - tcp_timewait_input(pcb); - pbuf_free(p); - return; - } - } - - /* Finally, if we still did not get a match, we check all PCBs that - are LISTENing for incoming connections. */ - prev = NULL; - for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if (lpcb->local_port == tcphdr->dest) { -#if SO_REUSE - if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { - /* found an exact match */ - break; - } else if(ip_addr_isany(&(lpcb->local_ip))) { - /* found an ANY-match */ - lpcb_any = lpcb; - lpcb_prev = prev; - } -#else /* SO_REUSE */ - if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || - ip_addr_isany(&(lpcb->local_ip))) { - /* found a match */ - break; - } -#endif /* SO_REUSE */ - } - prev = (struct tcp_pcb *)lpcb; - } -#if SO_REUSE - /* first try specific local IP */ - if (lpcb == NULL) { - /* only pass to ANY if no specific local IP has been found */ - lpcb = lpcb_any; - prev = lpcb_prev; - } -#endif /* SO_REUSE */ - if (lpcb != NULL) { - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ - if (prev != NULL) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; - /* put this listening pcb at the head of the listening list */ - tcp_listen_pcbs.listen_pcbs = lpcb; - } - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); - tcp_listen_input(lpcb); - pbuf_free(p); - return; - } - } - -#if TCP_INPUT_DEBUG - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags ")); - tcp_debug_print_flags(TCPH_FLAGS(tcphdr)); - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n")); -#endif /* TCP_INPUT_DEBUG */ - - - if (pcb != NULL) { - /* The incoming segment belongs to a connection. */ -#if TCP_INPUT_DEBUG -#if TCP_DEBUG - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ -#endif /* TCP_INPUT_DEBUG */ - - /* Set up a tcp_seg structure. */ - inseg.next = NULL; - inseg.len = p->tot_len; - inseg.p = p; - inseg.tcphdr = tcphdr; - - recv_data = NULL; - recv_flags = 0; - - if (flags & TCP_PSH) { - p->flags |= PBUF_FLAG_PUSH; - } - - /* If there is data which was previously "refused" by upper layer */ - if (pcb->refused_data != NULL) { - if ((tcp_process_refused_data(pcb) == ERR_ABRT) || - ((pcb->refused_data != NULL) && (tcplen > 0))) { - /* pcb has been aborted or refused data is still refused and the new - segment contains data */ - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - goto aborted; - } - } - tcp_input_pcb = pcb; - err = tcp_process(pcb); - /* A return value of ERR_ABRT means that tcp_abort() was called - and that the pcb has been freed. If so, we don't do anything. */ - if (err != ERR_ABRT) { - if (recv_flags & TF_RESET) { - /* TF_RESET means that the connection was reset by the other - end. We then call the error callback to inform the - application that the connection is dead before we - deallocate the PCB. */ - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else if (recv_flags & TF_CLOSED) { - /* The connection has been closed and we will deallocate the - PCB. */ - if (!(pcb->flags & TF_RXCLOSED)) { - /* Connection closed although the application has only shut down the - tx side: call the PCB's err callback and indicate the closure to - ensure the application doesn't continue using the PCB. */ - TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_CLSD); - } - tcp_pcb_remove(&tcp_active_pcbs, pcb); - memp_free(MEMP_TCP_PCB, pcb); - } else { - err = ERR_OK; - /* If the application has registered a "sent" function to be - called when new send buffer space is available, we call it - now. */ - if (pcb->acked > 0) { - TCP_EVENT_SENT(pcb, pcb->acked, err); - if (err == ERR_ABRT) { - goto aborted; - } - } - - if (recv_data != NULL) { - LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); - if (pcb->flags & TF_RXCLOSED) { - /* received data although already closed -> abort (send RST) to - notify the remote host that not all data has been processed */ - pbuf_free(recv_data); - tcp_abort(pcb); - goto aborted; - } - - /* Notify application that data has been received. */ - TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); - if (err == ERR_ABRT) { - goto aborted; - } - - /* If the upper layer can't receive this data, store it */ - if (err != ERR_OK) { - pcb->refused_data = recv_data; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n")); - } - } - - /* If a FIN segment was received, we call the callback - function with a NULL buffer to indicate EOF. */ - if (recv_flags & TF_GOT_FIN) { - if (pcb->refused_data != NULL) { - /* Delay this if we have refused data. */ - pcb->refused_data->flags |= PBUF_FLAG_TCP_FIN; - } else { - /* correct rcv_wnd as the application won't call tcp_recved() - for the FIN's seqno */ - if (pcb->rcv_wnd != TCP_WND) { - pcb->rcv_wnd++; - } - TCP_EVENT_CLOSED(pcb, err); - if (err == ERR_ABRT) { - goto aborted; - } - } - } - - tcp_input_pcb = NULL; - /* Try to send something out. */ - tcp_output(pcb); -#if TCP_INPUT_DEBUG -#if TCP_DEBUG - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ -#endif /* TCP_INPUT_DEBUG */ - } - } - /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). - Below this line, 'pcb' may not be dereferenced! */ -aborted: - tcp_input_pcb = NULL; - recv_data = NULL; - - /* give up our reference to inseg.p */ - if (inseg.p != NULL) - { - pbuf_free(inseg.p); - inseg.p = NULL; - } - } else { - - /* If no matching PCB was found, send a TCP RST (reset) to the - sender. */ - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n")); - if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) { - TCP_STATS_INC(tcp.proterr); - TCP_STATS_INC(tcp.drop); - tcp_rst(ackno, seqno + tcplen, - ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } - pbuf_free(p); - } - - LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); - PERF_STOP("tcp_input"); - return; -dropped: - TCP_STATS_INC(tcp.drop); - snmp_inc_tcpinerrs(); - pbuf_free(p); -} - -/** - * Called by tcp_input() when a segment arrives for a listening - * connection (from tcp_input()). - * - * @param pcb the tcp_pcb_listen for which a segment arrived - * @return ERR_OK if the segment was processed - * another err_t on error - * - * @note the return value is not (yet?) used in tcp_input() - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static err_t -tcp_listen_input(struct tcp_pcb_listen *pcb) -{ - struct tcp_pcb *npcb; - err_t rc; - - if (flags & TCP_RST) { - /* An incoming RST should be ignored. Return. */ - return ERR_OK; - } - - /* In the LISTEN state, we check for incoming SYN segments, - creates a new PCB, and responds with a SYN|ACK. */ - if (flags & TCP_ACK) { - /* For incoming segments with the ACK flag set, respond with a - RST. */ - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), - ip_current_src_addr(), tcphdr->dest, tcphdr->src); - } else if (flags & TCP_SYN) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); -#if TCP_LISTEN_BACKLOG - if (pcb->accepts_pending >= pcb->backlog) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: listen backlog exceeded for port %"U16_F"\n", tcphdr->dest)); - return ERR_ABRT; - } -#endif /* TCP_LISTEN_BACKLOG */ - npcb = tcp_alloc(pcb->prio); - /* If a new PCB could not be created (probably due to lack of memory), - we don't do anything, but rely on the sender will retransmit the - SYN at a time when we have more memory available. */ - if (npcb == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n")); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } -#if TCP_LISTEN_BACKLOG - pcb->accepts_pending++; -#endif /* TCP_LISTEN_BACKLOG */ - /* Set up the new PCB. */ - ip_addr_copy(npcb->local_ip, current_iphdr_dest); - npcb->local_port = pcb->local_port; - ip_addr_copy(npcb->remote_ip, current_iphdr_src); - npcb->remote_port = tcphdr->src; - npcb->state = SYN_RCVD; - npcb->rcv_nxt = seqno + 1; - npcb->rcv_ann_right_edge = npcb->rcv_nxt; - npcb->snd_wnd = tcphdr->wnd; - npcb->snd_wnd_max = tcphdr->wnd; - npcb->ssthresh = npcb->snd_wnd; - npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */ - npcb->callback_arg = pcb->callback_arg; -#if LWIP_CALLBACK_API - npcb->accept = pcb->accept; -#endif /* LWIP_CALLBACK_API */ - /* inherit socket options */ - npcb->so_options = pcb->so_options & SOF_INHERITED; - /* Register the new PCB so that we can begin receiving segments - for it. */ - TCP_REG_ACTIVE(npcb); - - /* Parse any options in the SYN. */ - tcp_parseopt(npcb); -#if TCP_CALCULATE_EFF_SEND_MSS - npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip)); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - snmp_inc_tcppassiveopens(); - - /* Send a SYN|ACK together with the MSS option. */ - rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); - if (rc != ERR_OK) { - tcp_abandon(npcb, 0); - return rc; - } - return tcp_output(npcb); - } - return ERR_OK; -} - -/** - * Called by tcp_input() when a segment arrives for a connection in - * TIME_WAIT. - * - * @param pcb the tcp_pcb for which a segment arrived - * - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static err_t -tcp_timewait_input(struct tcp_pcb *pcb) -{ - /* RFC 1337: in TIME_WAIT, ignore RST and ACK FINs + any 'acceptable' segments */ - /* RFC 793 3.9 Event Processing - Segment Arrives: - * - first check sequence number - we skip that one in TIME_WAIT (always - * acceptable since we only send ACKs) - * - second check the RST bit (... return) */ - if (flags & TCP_RST) { - return ERR_OK; - } - /* - fourth, check the SYN bit, */ - if (flags & TCP_SYN) { - /* If an incoming segment is not acceptable, an acknowledgment - should be sent in reply */ - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { - /* If the SYN is in the window it is an error, send a reset */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - return ERR_OK; - } - } else if (flags & TCP_FIN) { - /* - eighth, check the FIN bit: Remain in the TIME-WAIT state. - Restart the 2 MSL time-wait timeout.*/ - pcb->tmr = tcp_ticks; - } - - if ((tcplen > 0)) { - /* Acknowledge data, FIN or out-of-window SYN */ - pcb->flags |= TF_ACK_NOW; - return tcp_output(pcb); - } - return ERR_OK; -} - -/** - * Implements the TCP state machine. Called by tcp_input. In some - * states tcp_receive() is called to receive data. The tcp_seg - * argument will be freed by the caller (tcp_input()) unless the - * recv_data pointer in the pcb is set. - * - * @param pcb the tcp_pcb for which a segment arrived - * - * @note the segment which arrived is saved in global variables, therefore only the pcb - * involved is passed as a parameter to this function - */ -static err_t -tcp_process(struct tcp_pcb *pcb) -{ - struct tcp_seg *rseg; - u8_t acceptable = 0; - err_t err; - - err = ERR_OK; - - /* Process incoming RST segments. */ - if (flags & TCP_RST) { - /* First, determine if the reset is acceptable. */ - if (pcb->state == SYN_SENT) { - if (ackno == pcb->snd_nxt) { - acceptable = 1; - } - } else { - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt+pcb->rcv_wnd)) { - acceptable = 1; - } - } - - if (acceptable) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n")); - LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED); - recv_flags |= TF_RESET; - pcb->flags &= ~TF_ACK_DELAY; - return ERR_RST; - } else { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n", - seqno, pcb->rcv_nxt)); - return ERR_OK; - } - } - - if ((flags & TCP_SYN) && (pcb->state != SYN_SENT && pcb->state != SYN_RCVD)) { - /* Cope with new connection attempt after remote end crashed */ - tcp_ack_now(pcb); - return ERR_OK; - } - - if ((pcb->flags & TF_RXCLOSED) == 0) { - /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ - pcb->tmr = tcp_ticks; - } - pcb->keep_cnt_sent = 0; - - tcp_parseopt(pcb); - - /* Do different things depending on the TCP state. */ - switch (pcb->state) { - case SYN_SENT: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno, - pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno))); - /* received SYN ACK with expected sequence number? */ - if ((flags & TCP_ACK) && (flags & TCP_SYN) - && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) { - pcb->snd_buf++; - pcb->rcv_nxt = seqno + 1; - pcb->rcv_ann_right_edge = pcb->rcv_nxt; - pcb->lastack = ackno; - pcb->snd_wnd = tcphdr->wnd; - pcb->snd_wnd_max = tcphdr->wnd; - pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */ - pcb->state = ESTABLISHED; - -#if TCP_CALCULATE_EFF_SEND_MSS - pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip)); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - - /* Set ssthresh again after changing pcb->mss (already set in tcp_connect - * but for the default value of pcb->mss) */ - pcb->ssthresh = pcb->mss * 10; - - pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss); - LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0)); - --pcb->snd_queuelen; - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - rseg = pcb->unacked; - pcb->unacked = rseg->next; - tcp_seg_free(rseg); - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ - if(pcb->unacked == NULL) - pcb->rtime = -1; - else { - pcb->rtime = 0; - pcb->nrtx = 0; - } - - /* Call the user specified function to call when sucessfully - * connected. */ - TCP_EVENT_CONNECTED(pcb, ERR_OK, err); - if (err == ERR_ABRT) { - return ERR_ABRT; - } - tcp_ack_now(pcb); - } - /* received ACK? possibly a half-open connection */ - else if (flags & TCP_ACK) { - /* send a RST to bring the other side in a non-synchronized state. */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } - break; - case SYN_RCVD: - if (flags & TCP_ACK) { - /* expected ACK number? */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) { - u16_t old_cwnd; - pcb->state = ESTABLISHED; - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); -#if LWIP_CALLBACK_API - LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL); -#endif - /* Call the accept function. */ - TCP_EVENT_ACCEPT(pcb, ERR_OK, err); - if (err != ERR_OK) { - /* If the accept function returns with an error, we abort - * the connection. */ - /* Already aborted? */ - if (err != ERR_ABRT) { - tcp_abort(pcb); - } - return ERR_ABRT; - } - old_cwnd = pcb->cwnd; - /* If there was any data contained within this ACK, - * we'd better pass it on to the application as well. */ - tcp_receive(pcb); - - /* Prevent ACK for SYN to generate a sent event */ - if (pcb->acked != 0) { - pcb->acked--; - } - - pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); - - if (recv_flags & TF_GOT_FIN) { - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - } else { - /* incorrect ACK number, send RST */ - tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), - tcphdr->dest, tcphdr->src); - } - } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { - /* Looks like another copy of the SYN - retransmit our SYN-ACK */ - tcp_rexmit(pcb); - } - break; - case CLOSE_WAIT: - /* FALLTHROUGH */ - case ESTABLISHED: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { /* passive close */ - tcp_ack_now(pcb); - pcb->state = CLOSE_WAIT; - } - break; - case FIN_WAIT_1: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { - if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_DEBUG, - ("TCP connection closed: FIN_WAIT_1 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } else { - tcp_ack_now(pcb); - pcb->state = CLOSING; - } - } else if ((flags & TCP_ACK) && (ackno == pcb->snd_nxt)) { - pcb->state = FIN_WAIT_2; - } - break; - case FIN_WAIT_2: - tcp_receive(pcb); - if (recv_flags & TF_GOT_FIN) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: FIN_WAIT_2 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_ack_now(pcb); - tcp_pcb_purge(pcb); - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } - break; - case CLOSING: - tcp_receive(pcb); - if (flags & TCP_ACK && ackno == pcb->snd_nxt) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: CLOSING %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - tcp_pcb_purge(pcb); - TCP_RMV_ACTIVE(pcb); - pcb->state = TIME_WAIT; - TCP_REG(&tcp_tw_pcbs, pcb); - } - break; - case LAST_ACK: - tcp_receive(pcb); - if (flags & TCP_ACK && ackno == pcb->snd_nxt) { - LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed: LAST_ACK %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); - /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */ - recv_flags |= TF_CLOSED; - } - break; - default: - break; - } - return ERR_OK; -} - -#if TCP_QUEUE_OOSEQ -/** - * Insert segment into the list (segments covered with new one will be deleted) - * - * Called from tcp_receive() - */ -static void -tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) -{ - struct tcp_seg *old_seg; - - if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { - /* received segment overlaps all following segments */ - tcp_segs_free(next); - next = NULL; - } - else { - /* delete some following segments - oos queue may have segments with FIN flag */ - while (next && - TCP_SEQ_GEQ((seqno + cseg->len), - (next->tcphdr->seqno + next->len))) { - /* cseg with FIN already processed */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); - } - old_seg = next; - next = next->next; - tcp_seg_free(old_seg); - } - if (next && - TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) { - /* We need to trim the incoming segment. */ - cseg->len = (u16_t)(next->tcphdr->seqno - seqno); - pbuf_realloc(cseg->p, cseg->len); - } - } - cseg->next = next; -} -#endif /* TCP_QUEUE_OOSEQ */ - -/** - * Called by tcp_process. Checks if the given segment is an ACK for outstanding - * data, and if so frees the memory of the buffered data. Next, is places the - * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment - * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until - * it has been removed from the buffer. - * - * If the incoming segment constitutes an ACK for a segment that was used for RTT - * estimation, the RTT is estimated here as well. - * - * Called from tcp_process(). - */ -static void -tcp_receive(struct tcp_pcb *pcb) -{ - struct tcp_seg *next; -#if TCP_QUEUE_OOSEQ - struct tcp_seg *prev, *cseg; -#endif /* TCP_QUEUE_OOSEQ */ - struct pbuf *p; - s32_t off; - s16_t m; - u32_t right_wnd_edge; - u16_t new_tot_len; - int found_dupack = 0; -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - u32_t ooseq_blen; - u16_t ooseq_qlen; -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ - - LWIP_ASSERT("tcp_receive: wrong state", pcb->state >= ESTABLISHED); - - if (flags & TCP_ACK) { - right_wnd_edge = pcb->snd_wnd + pcb->snd_wl2; - - /* Update window. */ - if (TCP_SEQ_LT(pcb->snd_wl1, seqno) || - (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) || - (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) { - pcb->snd_wnd = tcphdr->wnd; - /* keep track of the biggest window announced by the remote host to calculate - the maximum segment size */ - if (pcb->snd_wnd_max < tcphdr->wnd) { - pcb->snd_wnd_max = tcphdr->wnd; - } - pcb->snd_wl1 = seqno; - pcb->snd_wl2 = ackno; - if (pcb->snd_wnd == 0) { - if (pcb->persist_backoff == 0) { - /* start persist timer */ - pcb->persist_cnt = 0; - pcb->persist_backoff = 1; - } - } else if (pcb->persist_backoff > 0) { - /* stop persist timer */ - pcb->persist_backoff = 0; - } - LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd)); -#if TCP_WND_DEBUG - } else { - if (pcb->snd_wnd != tcphdr->wnd) { - LWIP_DEBUGF(TCP_WND_DEBUG, - ("tcp_receive: no window update lastack %"U32_F" ackno %" - U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n", - pcb->lastack, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2)); - } -#endif /* TCP_WND_DEBUG */ - } - - /* (From Stevens TCP/IP Illustrated Vol II, p970.) Its only a - * duplicate ack if: - * 1) It doesn't ACK new data - * 2) length of received packet is zero (i.e. no payload) - * 3) the advertised window hasn't changed - * 4) There is outstanding unacknowledged data (retransmission timer running) - * 5) The ACK is == biggest ACK sequence number so far seen (snd_una) - * - * If it passes all five, should process as a dupack: - * a) dupacks < 3: do nothing - * b) dupacks == 3: fast retransmit - * c) dupacks > 3: increase cwnd - * - * If it only passes 1-3, should reset dupack counter (and add to - * stats, which we don't do in lwIP) - * - * If it only passes 1, should reset dupack counter - * - */ - - /* Clause 1 */ - if (TCP_SEQ_LEQ(ackno, pcb->lastack)) { - pcb->acked = 0; - /* Clause 2 */ - if (tcplen == 0) { - /* Clause 3 */ - if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ - /* Clause 4 */ - if (pcb->rtime >= 0) { - /* Clause 5 */ - if (pcb->lastack == ackno) { - found_dupack = 1; - if ((u8_t)(pcb->dupacks + 1) > pcb->dupacks) { - ++pcb->dupacks; - } - if (pcb->dupacks > 3) { - /* Inflate the congestion window, but not if it means that - the value overflows. */ - if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - } else if (pcb->dupacks == 3) { - /* Do fast retransmit */ - tcp_rexmit_fast(pcb); - } - } - } - } - } - /* If Clause (1) or more is true, but not a duplicate ack, reset - * count of consecutive duplicate acks */ - if (!found_dupack) { - pcb->dupacks = 0; - } - } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)){ - /* We come here when the ACK acknowledges new data. */ - - /* Reset the "IN Fast Retransmit" flag, since we are no longer - in fast retransmit. Also reset the congestion window to the - slow start threshold. */ - if (pcb->flags & TF_INFR) { - pcb->flags &= ~TF_INFR; - pcb->cwnd = pcb->ssthresh; - } - - /* Reset the number of retransmissions. */ - pcb->nrtx = 0; - - /* Reset the retransmission time-out. */ - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - /* Update the send buffer space. Diff between the two can never exceed 64K? */ - pcb->acked = (u16_t)(ackno - pcb->lastack); - - pcb->snd_buf += pcb->acked; - - /* Reset the fast retransmit variables. */ - pcb->dupacks = 0; - pcb->lastack = ackno; - - /* Update the congestion control variables (cwnd and - ssthresh). */ - if (pcb->state >= ESTABLISHED) { - if (pcb->cwnd < pcb->ssthresh) { - if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) { - pcb->cwnd += pcb->mss; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd)); - } else { - u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd); - if (new_cwnd > pcb->cwnd) { - pcb->cwnd = new_cwnd; - } - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd)); - } - } - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n", - ackno, - pcb->unacked != NULL? - ntohl(pcb->unacked->tcphdr->seqno): 0, - pcb->unacked != NULL? - ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0)); - - /* Remove segment from the unacknowledged list if the incoming - ACK acknowlegdes them. */ - while (pcb->unacked != NULL && - TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked), ackno)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", - ntohl(pcb->unacked->tcphdr->seqno), - ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked))); - - next = pcb->unacked; - pcb->unacked = pcb->unacked->next; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); - LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - pcb->acked--; - } - - pcb->snd_queuelen -= pbuf_clen(next->p); - tcp_seg_free(next); - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - } - - /* If there's nothing left to acknowledge, stop the retransmit - timer, otherwise reset it to start again */ - if(pcb->unacked == NULL) - pcb->rtime = -1; - else - pcb->rtime = 0; - - pcb->polltmr = 0; - } else { - /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */ - pcb->acked = 0; - } - - /* We go through the ->unsent list to see if any of the segments - on the list are acknowledged by the ACK. This may seem - strange since an "unsent" segment shouldn't be acked. The - rationale is that lwIP puts all outstanding segments on the - ->unsent list after a retransmission, so these segments may - in fact have been sent once. */ - while (pcb->unsent != NULL && - TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent), pcb->snd_nxt)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n", - ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) + - TCP_TCPLEN(pcb->unsent))); - - next = pcb->unsent; - pcb->unsent = pcb->unsent->next; -#if TCP_OVERSIZE - if (pcb->unsent == NULL) { - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen)); - LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p))); - /* Prevent ACK for FIN to generate a sent event */ - if ((pcb->acked != 0) && ((TCPH_FLAGS(next->tcphdr) & TCP_FIN) != 0)) { - pcb->acked--; - } - pcb->snd_queuelen -= pbuf_clen(next->p); - tcp_seg_free(next); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_receive: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - } - /* End of ACK for new data processing. */ - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n", - pcb->rttest, pcb->rtseq, ackno)); - - /* RTT estimation calculations. This is done by checking if the - incoming segment acknowledges the segment we use to take a - round-trip time measurement. */ - if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) { - /* diff between this shouldn't exceed 32K since this are tcp timer ticks - and a round-trip shouldn't be that long... */ - m = (s16_t)(tcp_ticks - pcb->rttest); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n", - m, m * TCP_SLOW_INTERVAL)); - - /* This is taken directly from VJs original code in his paper */ - m = m - (pcb->sa >> 3); - pcb->sa += m; - if (m < 0) { - m = -m; - } - m = m - (pcb->sv >> 2); - pcb->sv += m; - pcb->rto = (pcb->sa >> 3) + pcb->sv; - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n", - pcb->rto, pcb->rto * TCP_SLOW_INTERVAL)); - - pcb->rttest = 0; - } - } - - /* If the incoming segment contains data, we must process it - further unless the pcb already received a FIN. - (RFC 793, chapeter 3.9, "SEGMENT ARRIVES" in states CLOSE-WAIT, CLOSING, - LAST-ACK and TIME-WAIT: "Ignore the segment text.") */ - if ((tcplen > 0) && (pcb->state < CLOSE_WAIT)) { - /* This code basically does three things: - - +) If the incoming segment contains data that is the next - in-sequence data, this data is passed to the application. This - might involve trimming the first edge of the data. The rcv_nxt - variable and the advertised window are adjusted. - - +) If the incoming segment has data that is above the next - sequence number expected (->rcv_nxt), the segment is placed on - the ->ooseq queue. This is done by finding the appropriate - place in the ->ooseq queue (which is ordered by sequence - number) and trim the segment in both ends if needed. An - immediate ACK is sent to indicate that we received an - out-of-sequence segment. - - +) Finally, we check if the first segment on the ->ooseq queue - now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If - rcv_nxt > ooseq->seqno, we must trim the first edge of the - segment on ->ooseq before we adjust rcv_nxt. The data in the - segments that are now on sequence are chained onto the - incoming segment so that we only need to call the application - once. - */ - - /* First, we check if we must trim the first edge. We have to do - this if the sequence number of the incoming segment is less - than rcv_nxt, and the sequence number plus the length of the - segment is larger than rcv_nxt. */ - /* if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ - if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/ - if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){ - /* Trimming the first edge is done by pushing the payload - pointer in the pbuf downwards. This is somewhat tricky since - we do not want to discard the full contents of the pbuf up to - the new starting point of the data since we have to keep the - TCP header which is present in the first pbuf in the chain. - - What is done is really quite a nasty hack: the first pbuf in - the pbuf chain is pointed to by inseg.p. Since we need to be - able to deallocate the whole pbuf, we cannot change this - inseg.p pointer to point to any of the later pbufs in the - chain. Instead, we point the ->payload pointer in the first - pbuf to data in one of the later pbufs. We also set the - inseg.data pointer to point to the right place. This way, the - ->p pointer will still point to the first pbuf, but the - ->p->payload pointer will point to data in another pbuf. - - After we are done with adjusting the pbuf pointers we must - adjust the ->data pointer in the seg and the segment - length.*/ - - off = pcb->rcv_nxt - seqno; - p = inseg.p; - LWIP_ASSERT("inseg.p != NULL", inseg.p); - LWIP_ASSERT("insane offset!", (off < 0x7fff)); - if (inseg.p->len < off) { - LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off)); - new_tot_len = (u16_t)(inseg.p->tot_len - off); - while (p->len < off) { - off -= p->len; - /* KJM following line changed (with addition of new_tot_len var) - to fix bug #9076 - inseg.p->tot_len -= p->len; */ - p->tot_len = new_tot_len; - p->len = 0; - p = p->next; - } - if(pbuf_header(p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } else { - if(pbuf_header(inseg.p, (s16_t)-off)) { - /* Do we need to cope with this failing? Assert for now */ - LWIP_ASSERT("pbuf_header failed", 0); - } - } - inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); - inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; - } - else { - if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){ - /* the whole segment is < rcv_nxt */ - /* must be a duplicate of a packet that has already been correctly handled */ - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno)); - tcp_ack_now(pcb); - } - } - - /* The sequence number must be within the window (above rcv_nxt - and below rcv_nxt + rcv_wnd) in order to be further - processed. */ - if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, - pcb->rcv_nxt + pcb->rcv_wnd - 1)){ - if (pcb->rcv_nxt == seqno) { - /* The incoming segment is the next in sequence. We check if - we have to trim the end of the segment and update rcv_nxt - and pass the data to the application. */ - tcplen = TCP_TCPLEN(&inseg); - - if (tcplen > pcb->rcv_wnd) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: other end overran receive window" - "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", - seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - /* Must remove the FIN from the header as we're trimming - * that byte of sequence-space from the packet */ - TCPH_FLAGS_SET(inseg.tcphdr, TCPH_FLAGS(inseg.tcphdr) &~ TCP_FIN); - } - /* Adjust length of segment to fit in the window. */ - inseg.len = pcb->rcv_wnd; - if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { - inseg.len -= 1; - } - pbuf_realloc(inseg.p, inseg.len); - tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", - (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); - } -#if TCP_QUEUE_OOSEQ - /* Received in-sequence data, adjust ooseq data if: - - FIN has been received or - - inseq overlaps with ooseq */ - if (pcb->ooseq != NULL) { - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: received in-order FIN, binning ooseq queue\n")); - /* Received in-order FIN means anything that was received - * out of order must now have been received in-order, so - * bin the ooseq queue */ - while (pcb->ooseq != NULL) { - struct tcp_seg *old_ooseq = pcb->ooseq; - pcb->ooseq = pcb->ooseq->next; - tcp_seg_free(old_ooseq); - } - } else { - next = pcb->ooseq; - /* Remove all segments on ooseq that are covered by inseg already. - * FIN is copied from ooseq to inseg if present. */ - while (next && - TCP_SEQ_GEQ(seqno + tcplen, - next->tcphdr->seqno + next->len)) { - /* inseg cannot have FIN here (already processed above) */ - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && - (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { - TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); - tcplen = TCP_TCPLEN(&inseg); - } - prev = next; - next = next->next; - tcp_seg_free(prev); - } - /* Now trim right side of inseg if it overlaps with the first - * segment on ooseq */ - if (next && - TCP_SEQ_GT(seqno + tcplen, - next->tcphdr->seqno)) { - /* inseg cannot have FIN here (already processed above) */ - inseg.len = (u16_t)(next->tcphdr->seqno - seqno); - if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { - inseg.len -= 1; - } - pbuf_realloc(inseg.p, inseg.len); - tcplen = TCP_TCPLEN(&inseg); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", - (seqno + tcplen) == next->tcphdr->seqno); - } - pcb->ooseq = next; - } - } -#endif /* TCP_QUEUE_OOSEQ */ - - pcb->rcv_nxt = seqno + tcplen; - - /* Update the receiver's (our) window. */ - LWIP_ASSERT("tcp_receive: tcplen > rcv_wnd\n", pcb->rcv_wnd >= tcplen); - pcb->rcv_wnd -= tcplen; - - tcp_update_rcv_ann_wnd(pcb); - - /* If there is data in the segment, we make preparations to - pass this up to the application. The ->recv_data variable - is used for holding the pbuf that goes to the - application. The code for reassembling out-of-sequence data - chains its data on this pbuf as well. - - If the segment was a FIN, we set the TF_GOT_FIN flag that will - be used to indicate to the application that the remote side has - closed its end of the connection. */ - if (inseg.p->tot_len > 0) { - recv_data = inseg.p; - /* Since this pbuf now is the responsibility of the - application, we delete our reference to it so that we won't - (mistakingly) deallocate it. */ - inseg.p = NULL; - } - if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n")); - recv_flags |= TF_GOT_FIN; - } - -#if TCP_QUEUE_OOSEQ - /* We now check if we have segments on the ->ooseq queue that - are now in sequence. */ - while (pcb->ooseq != NULL && - pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { - - cseg = pcb->ooseq; - seqno = pcb->ooseq->tcphdr->seqno; - - pcb->rcv_nxt += TCP_TCPLEN(cseg); - LWIP_ASSERT("tcp_receive: ooseq tcplen > rcv_wnd\n", - pcb->rcv_wnd >= TCP_TCPLEN(cseg)); - pcb->rcv_wnd -= TCP_TCPLEN(cseg); - - tcp_update_rcv_ann_wnd(pcb); - - if (cseg->p->tot_len > 0) { - /* Chain this pbuf onto the pbuf that we will pass to - the application. */ - if (recv_data) { - pbuf_cat(recv_data, cseg->p); - } else { - recv_data = cseg->p; - } - cseg->p = NULL; - } - if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n")); - recv_flags |= TF_GOT_FIN; - if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */ - pcb->state = CLOSE_WAIT; - } - } - - pcb->ooseq = cseg->next; - tcp_seg_free(cseg); - } -#endif /* TCP_QUEUE_OOSEQ */ - - - /* Acknowledge the segment(s). */ - tcp_ack(pcb); - - } else { - /* We get here if the incoming segment is out-of-sequence. */ - tcp_send_empty_ack(pcb); -#if TCP_QUEUE_OOSEQ - /* We queue the segment on the ->ooseq queue. */ - if (pcb->ooseq == NULL) { - pcb->ooseq = tcp_seg_copy(&inseg); - } else { - /* If the queue is not empty, we walk through the queue and - try to find a place where the sequence number of the - incoming segment is between the sequence numbers of the - previous and the next segment on the ->ooseq queue. That is - the place where we put the incoming segment. If needed, we - trim the second edges of the previous and the incoming - segment so that it will fit into the sequence. - - If the incoming segment has the same sequence number as a - segment on the ->ooseq queue, we discard the segment that - contains less data. */ - - prev = NULL; - for(next = pcb->ooseq; next != NULL; next = next->next) { - if (seqno == next->tcphdr->seqno) { - /* The sequence number of the incoming segment is the - same as the sequence number of the segment on - ->ooseq. We check the lengths to see which one to - discard. */ - if (inseg.len > next->len) { - /* The incoming segment is larger than the old - segment. We replace some segments with the new - one. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - if (prev != NULL) { - prev->next = cseg; - } else { - pcb->ooseq = cseg; - } - tcp_oos_insert_segment(cseg, next); - } - break; - } else { - /* Either the lenghts are the same or the incoming - segment was smaller than the old one; in either - case, we ditch the incoming segment. */ - break; - } - } else { - if (prev == NULL) { - if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) { - /* The sequence number of the incoming segment is lower - than the sequence number of the first segment on the - queue. We put the incoming segment first on the - queue. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - pcb->ooseq = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } else { - /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) && - TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/ - if (TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)) { - /* The sequence number of the incoming segment is in - between the sequence numbers of the previous and - the next segment on ->ooseq. We trim trim the previous - segment, delete next segments that included in received segment - and trim received, if needed. */ - cseg = tcp_seg_copy(&inseg); - if (cseg != NULL) { - if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) { - /* We need to trim the prev segment. */ - prev->len = (u16_t)(seqno - prev->tcphdr->seqno); - pbuf_realloc(prev->p, prev->len); - } - prev->next = cseg; - tcp_oos_insert_segment(cseg, next); - } - break; - } - } - /* If the "next" segment is the last segment on the - ooseq queue, we add the incoming segment to the end - of the list. */ - if (next->next == NULL && - TCP_SEQ_GT(seqno, next->tcphdr->seqno)) { - if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - /* segment "next" already contains all data */ - break; - } - next->next = tcp_seg_copy(&inseg); - if (next->next != NULL) { - if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) { - /* We need to trim the last segment. */ - next->len = (u16_t)(seqno - next->tcphdr->seqno); - pbuf_realloc(next->p, next->len); - } - /* check if the remote side overruns our receive window */ - if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, - ("tcp_receive: other end overran receive window" - "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", - seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); - if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { - /* Must remove the FIN from the header as we're trimming - * that byte of sequence-space from the packet */ - TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); - } - /* Adjust length of segment to fit in the window. */ - next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; - pbuf_realloc(next->next->p, next->next->len); - tcplen = TCP_TCPLEN(next->next); - LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", - (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); - } - } - break; - } - } - prev = next; - } - } -#if TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS - /* Check that the data on ooseq doesn't exceed one of the limits - and throw away everything above that limit. */ - ooseq_blen = 0; - ooseq_qlen = 0; - prev = NULL; - for(next = pcb->ooseq; next != NULL; prev = next, next = next->next) { - struct pbuf *p = next->p; - ooseq_blen += p->tot_len; - ooseq_qlen += pbuf_clen(p); - if ((ooseq_blen > TCP_OOSEQ_MAX_BYTES) || - (ooseq_qlen > TCP_OOSEQ_MAX_PBUFS)) { - /* too much ooseq data, dump this and everything after it */ - tcp_segs_free(next); - if (prev == NULL) { - /* first ooseq segment is too much, dump the whole queue */ - pcb->ooseq = NULL; - } else { - /* just dump 'next' and everything after it */ - prev->next = NULL; - } - break; - } - } -#endif /* TCP_OOSEQ_MAX_BYTES || TCP_OOSEQ_MAX_PBUFS */ -#endif /* TCP_QUEUE_OOSEQ */ - } - } else { - /* The incoming segment is not withing the window. */ - tcp_send_empty_ack(pcb); - } - } else { - /* Segments with length 0 is taken care of here. Segments that - fall out of the window are ACKed. */ - /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) || - TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/ - if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){ - tcp_ack_now(pcb); - } - } -} - -/** - * Parses the options contained in the incoming segment. - * - * Called from tcp_listen_input() and tcp_process(). - * Currently, only the MSS option is supported! - * - * @param pcb the tcp_pcb for which a segment arrived - */ -static void -tcp_parseopt(struct tcp_pcb *pcb) -{ - u16_t c, max_c; - u16_t mss; - u8_t *opts, opt; -#if LWIP_TCP_TIMESTAMPS - u32_t tsval; -#endif - - opts = (u8_t *)tcphdr + TCP_HLEN; - - /* Parse the TCP MSS option, if present. */ - if(TCPH_HDRLEN(tcphdr) > 0x5) { - max_c = (TCPH_HDRLEN(tcphdr) - 5) << 2; - for (c = 0; c < max_c; ) { - opt = opts[c]; - switch (opt) { - case 0x00: - /* End of options. */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: EOL\n")); - return; - case 0x01: - /* NOP option. */ - ++c; - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: NOP\n")); - break; - case 0x02: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: MSS\n")); - if (opts[c + 1] != 0x04 || c + 0x04 > max_c) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* An MSS option with the right option length. */ - mss = (opts[c + 2] << 8) | opts[c + 3]; - /* Limit the mss to the configured TCP_MSS and prevent division by zero */ - pcb->mss = ((mss > TCP_MSS) || (mss == 0)) ? TCP_MSS : mss; - /* Advance to next option */ - c += 0x04; - break; -#if LWIP_TCP_TIMESTAMPS - case 0x08: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: TS\n")); - if (opts[c + 1] != 0x0A || c + 0x0A > max_c) { - /* Bad length */ - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - return; - } - /* TCP timestamp option with valid length */ - tsval = (opts[c+2]) | (opts[c+3] << 8) | - (opts[c+4] << 16) | (opts[c+5] << 24); - if (flags & TCP_SYN) { - pcb->ts_recent = ntohl(tsval); - pcb->flags |= TF_TIMESTAMP; - } else if (TCP_SEQ_BETWEEN(pcb->ts_lastacksent, seqno, seqno+tcplen)) { - pcb->ts_recent = ntohl(tsval); - } - /* Advance to next option */ - c += 0x0A; - break; -#endif - default: - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: other\n")); - if (opts[c + 1] == 0) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_parseopt: bad length\n")); - /* If the length field is zero, the options are malformed - and we don't process them further. */ - return; - } - /* All other options have a length field, so that we easily - can skip past them. */ - c += opts[c + 1]; - } - } - } -} - -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/core/tcp_out.c b/ext/lwip/src/core/tcp_out.c deleted file mode 100644 index 94395e25..00000000 --- a/ext/lwip/src/core/tcp_out.c +++ /dev/null @@ -1,1485 +0,0 @@ -/** - * @file - * Transmission Control Protocol, outgoing traffic - * - * The output functions of TCP. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - -#include "lwip/opt.h" - -#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/tcp_impl.h" -#include "lwip/def.h" -#include "lwip/mem.h" -#include "lwip/memp.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/inet_chksum.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#if LWIP_TCP_TIMESTAMPS -#include "lwip/sys.h" -#endif - -#include <string.h> - -/* Define some copy-macros for checksum-on-copy so that the code looks - nicer by preventing too many ifdef's. */ -#if TCP_CHECKSUM_ON_COPY -#define TCP_DATA_COPY(dst, src, len, seg) do { \ - tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ - len, &seg->chksum, &seg->chksum_swapped); \ - seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) -#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ - tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); -#else /* TCP_CHECKSUM_ON_COPY*/ -#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) -#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) -#endif /* TCP_CHECKSUM_ON_COPY*/ - -/** Define this to 1 for an extra check that the output checksum is valid - * (usefule when the checksum is generated by the application, not the stack) */ -#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK -#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 -#endif - -/* Forward declarations.*/ -static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); - -/** Allocate a pbuf and create a tcphdr at p->payload, used for output - * functions other than the default tcp_output -> tcp_output_segment - * (e.g. tcp_send_empty_ack, etc.) - * - * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) - * @param optlen length of header-options - * @param datalen length of tcp data to reserve in pbuf - * @param seqno_be seqno in network byte order (big-endian) - * @return pbuf with p->payload being the tcp_hdr - */ -static struct pbuf * -tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, - u32_t seqno_be /* already in network byte order */) -{ - struct tcp_hdr *tcphdr; - struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); - if (p != NULL) { - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= TCP_HLEN + optlen)); - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = seqno_be; - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - - /* If we're sending a packet, update the announced right window edge */ - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - } - return p; -} - -/** - * Called by tcp_close() to send a segment including FIN flag but not data. - * - * @param pcb the tcp_pcb over which to send a segment - * @return ERR_OK if sent, another err_t otherwise - */ -err_t -tcp_send_fin(struct tcp_pcb *pcb) -{ - /* first, try to add the fin to the last unsent segment */ - if (pcb->unsent != NULL) { - struct tcp_seg *last_unsent; - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { - /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ - TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); - pcb->flags |= TF_FIN; - return ERR_OK; - } - } - /* no data, no length, flags, copy=1, no optdata */ - return tcp_enqueue_flags(pcb, TCP_FIN); -} - -/** - * Create a TCP segment with prefilled header. - * - * Called by tcp_write and tcp_enqueue_flags. - * - * @param pcb Protocol control block for the TCP connection. - * @param p pbuf that is used to hold the TCP header. - * @param flags TCP flags for header. - * @param seqno TCP sequence number of this packet - * @param optflags options to include in TCP header - * @return a new tcp_seg pointing to p, or NULL. - * The TCP header is filled in except ackno and wnd. - * p is freed on failure. - */ -static struct tcp_seg * -tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) -{ - struct tcp_seg *seg; - u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); - - if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); - pbuf_free(p); - return NULL; - } - seg->flags = optflags; - seg->next = NULL; - seg->p = p; - seg->len = p->tot_len - optlen; -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = 0; -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - seg->chksum = 0; - seg->chksum_swapped = 0; - /* check optflags */ - LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", - (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* build TCP header */ - if (pbuf_header(p, TCP_HLEN)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); - TCP_STATS_INC(tcp.err); - tcp_seg_free(seg); - return NULL; - } - seg->tcphdr = (struct tcp_hdr *)seg->p->payload; - seg->tcphdr->src = htons(pcb->local_port); - seg->tcphdr->dest = htons(pcb->remote_port); - seg->tcphdr->seqno = htonl(seqno); - /* ackno is set in tcp_output */ - TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); - /* wnd and chksum are set in tcp_output */ - seg->tcphdr->urgp = 0; - return seg; -} - -/** - * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. - * - * This function is like pbuf_alloc(layer, length, PBUF_RAM) except - * there may be extra bytes available at the end. - * - * @param layer flag to define header size. - * @param length size of the pbuf's payload. - * @param max_length maximum usable size of payload+oversize. - * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. - * @param pcb The TCP connection that willo enqueue the pbuf. - * @param apiflags API flags given to tcp_write. - * @param first_seg true when this pbuf will be used in the first enqueued segment. - * @param - */ -#if TCP_OVERSIZE -static struct pbuf * -tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, - u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, - u8_t first_seg) -{ - struct pbuf *p; - u16_t alloc = length; - -#if LWIP_NETIF_TX_SINGLE_PBUF - LWIP_UNUSED_ARG(max_length); - LWIP_UNUSED_ARG(pcb); - LWIP_UNUSED_ARG(apiflags); - LWIP_UNUSED_ARG(first_seg); - /* always create MSS-sized pbufs */ - alloc = max_length; -#else /* LWIP_NETIF_TX_SINGLE_PBUF */ - if (length < max_length) { - /* Should we allocate an oversized pbuf, or just the minimum - * length required? If tcp_write is going to be called again - * before this segment is transmitted, we want the oversized - * buffer. If the segment will be transmitted immediately, we can - * save memory by allocating only length. We use a simple - * heuristic based on the following information: - * - * Did the user set TCP_WRITE_FLAG_MORE? - * - * Will the Nagle algorithm defer transmission of this segment? - */ - if ((apiflags & TCP_WRITE_FLAG_MORE) || - (!(pcb->flags & TF_NODELAY) && - (!first_seg || - pcb->unsent != NULL || - pcb->unacked != NULL))) { - alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE)); - } - } -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - p = pbuf_alloc(layer, alloc, PBUF_RAM); - if (p == NULL) { - return NULL; - } - LWIP_ASSERT("need unchained pbuf", p->next == NULL); - *oversize = p->len - length; - /* trim p->len to the currently used size */ - p->len = p->tot_len = length; - return p; -} -#else /* TCP_OVERSIZE */ -#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) -#endif /* TCP_OVERSIZE */ - -#if TCP_CHECKSUM_ON_COPY -/** Add a checksum of newly added data to the segment */ -static void -tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, - u8_t *seg_chksum_swapped) -{ - u32_t helper; - /* add chksum to old chksum and fold to u16_t */ - helper = chksum + *seg_chksum; - chksum = FOLD_U32T(helper); - if ((len & 1) != 0) { - *seg_chksum_swapped = 1 - *seg_chksum_swapped; - chksum = SWAP_BYTES_IN_WORD(chksum); - } - *seg_chksum = chksum; -} -#endif /* TCP_CHECKSUM_ON_COPY */ - -/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). - * - * @param pcb the tcp pcb to check for - * @param len length of data to send (checked agains snd_buf) - * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise - */ -static err_t -tcp_write_checks(struct tcp_pcb *pcb, u16_t len) -{ - /* connection is in invalid state for data transmission? */ - if ((pcb->state != ESTABLISHED) && - (pcb->state != CLOSE_WAIT) && - (pcb->state != SYN_SENT) && - (pcb->state != SYN_RCVD)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); - return ERR_CONN; - } else if (len == 0) { - return ERR_OK; - } - - /* fail on too much data */ - if (len > pcb->snd_buf) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", - len, pcb->snd_buf)); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - - /* If total number of pbufs on the unsent/unacked queues exceeds the - * configured maximum, return an error */ - /* check for configured max queuelen and possible overflow */ - if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", - pcb->unacked != NULL || pcb->unsent != NULL); - } else { - LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", - pcb->unacked == NULL && pcb->unsent == NULL); - } - return ERR_OK; -} - -/** - * Write data for sending (but does not send it immediately). - * - * It waits in the expectation of more data being sent soon (as - * it can send them more efficiently by combining them together). - * To prompt the system to send data now, call tcp_output() after - * calling tcp_write(). - * - * @param pcb Protocol control block for the TCP connection to enqueue data for. - * @param arg Pointer to the data to be enqueued for sending. - * @param len Data length in bytes - * @param apiflags combination of following flags : - * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack - * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, - * @return ERR_OK if enqueued, another err_t on error - */ -err_t -tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) -{ - struct pbuf *concat_p = NULL; - struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; - u16_t pos = 0; /* position in 'arg' data */ - u16_t queuelen; - u8_t optlen = 0; - u8_t optflags = 0; -#if TCP_OVERSIZE - u16_t oversize = 0; - u16_t oversize_used = 0; -#endif /* TCP_OVERSIZE */ -#if TCP_CHECKSUM_ON_COPY - u16_t concat_chksum = 0; - u8_t concat_chksum_swapped = 0; - u16_t concat_chksummed = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - err_t err; - /* don't allocate segments bigger than half the maximum window we ever received */ - u16_t mss_local = LWIP_MIN(pcb->mss, pcb->snd_wnd_max/2); - -#if LWIP_NETIF_TX_SINGLE_PBUF - /* Always copy to try to create single pbufs for TX */ - apiflags |= TCP_WRITE_FLAG_COPY; -#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", - (void *)pcb, arg, len, (u16_t)apiflags)); - LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", - arg != NULL, return ERR_ARG;); - - err = tcp_write_checks(pcb, len); - if (err != ERR_OK) { - return err; - } - queuelen = pcb->snd_queuelen; - -#if LWIP_TCP_TIMESTAMPS - if ((pcb->flags & TF_TIMESTAMP)) { - optflags = TF_SEG_OPTS_TS; - optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); - } -#endif /* LWIP_TCP_TIMESTAMPS */ - - - /* - * TCP segmentation is done in three phases with increasing complexity: - * - * 1. Copy data directly into an oversized pbuf. - * 2. Chain a new pbuf to the end of pcb->unsent. - * 3. Create new segments. - * - * We may run out of memory at any point. In that case we must - * return ERR_MEM and not change anything in pcb. Therefore, all - * changes are recorded in local variables and committed at the end - * of the function. Some pcb fields are maintained in local copies: - * - * queuelen = pcb->snd_queuelen - * oversize = pcb->unsent_oversize - * - * These variables are set consistently by the phases: - * - * seg points to the last segment tampered with. - * - * pos records progress as data is segmented. - */ - - /* Find the tail of the unsent queue. */ - if (pcb->unsent != NULL) { - u16_t space; - u16_t unsent_optlen; - - /* @todo: this could be sped up by keeping last_unsent in the pcb */ - for (last_unsent = pcb->unsent; last_unsent->next != NULL; - last_unsent = last_unsent->next); - - /* Usable space at the end of the last unsent segment */ - unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); - space = mss_local - (last_unsent->len + unsent_optlen); - - /* - * Phase 1: Copy data directly into an oversized pbuf. - * - * The number of bytes copied is recorded in the oversize_used - * variable. The actual copying is done at the bottom of the - * function. - */ -#if TCP_OVERSIZE -#if TCP_OVERSIZE_DBGCHECK - /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ - LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", - pcb->unsent_oversize == last_unsent->oversize_left); -#endif /* TCP_OVERSIZE_DBGCHECK */ - oversize = pcb->unsent_oversize; - if (oversize > 0) { - LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); - seg = last_unsent; - oversize_used = oversize < len ? oversize : len; - pos += oversize_used; - oversize -= oversize_used; - space -= oversize_used; - } - /* now we are either finished or oversize is zero */ - LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); -#endif /* TCP_OVERSIZE */ - - /* - * Phase 2: Chain a new pbuf to the end of pcb->unsent. - * - * We don't extend segments containing SYN/FIN flags or options - * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at - * the end. - */ - if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { - u16_t seglen = space < len - pos ? space : len - pos; - seg = last_unsent; - - /* Create a pbuf with a copy or reference to seglen bytes. We - * can use PBUF_RAW here since the data appears in the middle of - * a segment. A header will never be prepended. */ - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* Data is copied */ - if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, - ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", - seglen)); - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - last_unsent->oversize_left += oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ - TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); -#if TCP_CHECKSUM_ON_COPY - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - } else { - /* Data is not copied */ - if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, - ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum of nocopy-data */ - tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, - &concat_chksum, &concat_chksum_swapped); - concat_chksummed += seglen; -#endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - concat_p->payload = (u8_t*)arg + pos; - } - - pos += seglen; - queuelen += pbuf_clen(concat_p); - } - } else { -#if TCP_OVERSIZE - LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", - pcb->unsent_oversize == 0); -#endif /* TCP_OVERSIZE */ - } - - /* - * Phase 3: Create new segments. - * - * The new segments are chained together in the local 'queue' - * variable, ready to be appended to pcb->unsent. - */ - while (pos < len) { - struct pbuf *p; - u16_t left = len - pos; - u16_t max_len = mss_local - optlen; - u16_t seglen = left > max_len ? max_len : left; -#if TCP_CHECKSUM_ON_COPY - u16_t chksum = 0; - u8_t chksum_swapped = 0; -#endif /* TCP_CHECKSUM_ON_COPY */ - - if (apiflags & TCP_WRITE_FLAG_COPY) { - /* If copy is set, memory should be allocated and data copied - * into pbuf */ - if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, mss_local, &oversize, pcb, apiflags, queue == NULL)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); - goto memerr; - } - LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", - (p->len >= seglen)); - TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); - } else { - /* Copy is not set: First allocate a pbuf for holding the data. - * Since the referenced data is available at least until it is - * sent out on the link (as it has to be ACKed by the remote - * party) we can safely use PBUF_ROM instead of PBUF_REF here. - */ - struct pbuf *p2; -#if TCP_OVERSIZE - LWIP_ASSERT("oversize == 0", oversize == 0); -#endif /* TCP_OVERSIZE */ - if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } -#if TCP_CHECKSUM_ON_COPY - /* calculate the checksum of nocopy-data */ - chksum = ~inet_chksum((u8_t*)arg + pos, seglen); -#endif /* TCP_CHECKSUM_ON_COPY */ - /* reference the non-volatile payload data */ - p2->payload = (u8_t*)arg + pos; - - /* Second, allocate a pbuf for the headers. */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - /* If allocation fails, we have to deallocate the data pbuf as - * well. */ - pbuf_free(p2); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n")); - goto memerr; - } - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(p/*header*/, p2/*data*/); - } - - queuelen += pbuf_clen(p); - - /* Now that there are more segments queued, we check again if the - * length of the queue exceeds the configured maximum or - * overflows. */ - if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); - pbuf_free(p); - goto memerr; - } - - if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { - goto memerr; - } -#if TCP_OVERSIZE_DBGCHECK - seg->oversize_left = oversize; -#endif /* TCP_OVERSIZE_DBGCHECK */ -#if TCP_CHECKSUM_ON_COPY - seg->chksum = chksum; - seg->chksum_swapped = chksum_swapped; - seg->flags |= TF_SEG_DATA_CHECKSUMMED; -#endif /* TCP_CHECKSUM_ON_COPY */ - - /* first segment of to-be-queued data? */ - if (queue == NULL) { - queue = seg; - } else { - /* Attach the segment to the end of the queued segments */ - LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); - prev_seg->next = seg; - } - /* remember last segment of to-be-queued data for next iteration */ - prev_seg = seg; - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - - pos += seglen; - } - - /* - * All three segmentation phases were successful. We can commit the - * transaction. - */ - - /* - * Phase 1: If data has been added to the preallocated tail of - * last_unsent, we update the length fields of the pbuf chain. - */ -#if TCP_OVERSIZE - if (oversize_used > 0) { - struct pbuf *p; - /* Bump tot_len of whole chain, len of tail */ - for (p = last_unsent->p; p; p = p->next) { - p->tot_len += oversize_used; - if (p->next == NULL) { - TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); - p->len += oversize_used; - } - } - last_unsent->len += oversize_used; -#if TCP_OVERSIZE_DBGCHECK - LWIP_ASSERT("last_unsent->oversize_left >= oversize_used", - last_unsent->oversize_left >= oversize_used); - last_unsent->oversize_left -= oversize_used; -#endif /* TCP_OVERSIZE_DBGCHECK */ - } - pcb->unsent_oversize = oversize; -#endif /* TCP_OVERSIZE */ - - /* - * Phase 2: concat_p can be concatenated onto last_unsent->p - */ - if (concat_p != NULL) { - LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", - (last_unsent != NULL)); - pbuf_cat(last_unsent->p, concat_p); - last_unsent->len += concat_p->tot_len; -#if TCP_CHECKSUM_ON_COPY - if (concat_chksummed) { - tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, - &last_unsent->chksum_swapped); - last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; - } -#endif /* TCP_CHECKSUM_ON_COPY */ - } - - /* - * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that - * is harmless - */ - if (last_unsent == NULL) { - pcb->unsent = queue; - } else { - last_unsent->next = queue; - } - - /* - * Finally update the pcb state. - */ - pcb->snd_lbb += len; - pcb->snd_buf -= len; - pcb->snd_queuelen = queuelen; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", - pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - - /* Set the PSH flag in the last segment that we enqueued. */ - if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { - TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); - } - - return ERR_OK; -memerr: - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - - if (concat_p != NULL) { - pbuf_free(concat_p); - } - if (queue != NULL) { - tcp_segs_free(queue); - } - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || - pcb->unsent != NULL); - } - LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); - return ERR_MEM; -} - -/** - * Enqueue TCP options for transmission. - * - * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). - * - * @param pcb Protocol control block for the TCP connection. - * @param flags TCP header flags to set in the outgoing segment. - * @param optdata pointer to TCP options, or NULL. - * @param optlen length of TCP options in bytes. - */ -err_t -tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) -{ - struct pbuf *p; - struct tcp_seg *seg; - u8_t optflags = 0; - u8_t optlen = 0; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); - - LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", - (flags & (TCP_SYN | TCP_FIN)) != 0); - - /* check for configured max queuelen and possible overflow */ - if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", - pcb->snd_queuelen, TCP_SND_QUEUELEN)); - TCP_STATS_INC(tcp.memerr); - pcb->flags |= TF_NAGLEMEMERR; - return ERR_MEM; - } - - if (flags & TCP_SYN) { - optflags = TF_SEG_OPTS_MSS; - } -#if LWIP_TCP_TIMESTAMPS - if ((pcb->flags & TF_TIMESTAMP)) { - optflags |= TF_SEG_OPTS_TS; - } -#endif /* LWIP_TCP_TIMESTAMPS */ - optlen = LWIP_TCP_OPT_LENGTH(optflags); - - /* tcp_enqueue_flags is always called with either SYN or FIN in flags. - * We need one available snd_buf byte to do that. - * This means we can't send FIN while snd_buf==0. A better fix would be to - * not include SYN and FIN sequence numbers in the snd_buf count. */ - if (pcb->snd_buf == 0) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n")); - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - - /* Allocate pbuf with room for TCP header + options */ - if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", - (p->len >= optlen)); - - /* Allocate memory for tcp_seg, and fill in fields. */ - if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { - pcb->flags |= TF_NAGLEMEMERR; - TCP_STATS_INC(tcp.memerr); - return ERR_MEM; - } - LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); - LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); - - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, - ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", - ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), - (u16_t)flags)); - - /* Now append seg to pcb->unsent queue */ - if (pcb->unsent == NULL) { - pcb->unsent = seg; - } else { - struct tcp_seg *useg; - for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); - useg->next = seg; - } -#if TCP_OVERSIZE - /* The new unsent tail has no space */ - pcb->unsent_oversize = 0; -#endif /* TCP_OVERSIZE */ - - /* SYN and FIN bump the sequence number */ - if ((flags & TCP_SYN) || (flags & TCP_FIN)) { - pcb->snd_lbb++; - /* optlen does not influence snd_buf */ - pcb->snd_buf--; - } - if (flags & TCP_FIN) { - pcb->flags |= TF_FIN; - } - - /* update number of segments on the queues */ - pcb->snd_queuelen += pbuf_clen(seg->p); - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); - if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); - } - - return ERR_OK; -} - -#if LWIP_TCP_TIMESTAMPS -/* Build a timestamp option (12 bytes long) at the specified options pointer) - * - * @param pcb tcp_pcb - * @param opts option pointer where to store the timestamp option - */ -static void -tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) -{ - /* Pad with two NOP options to make everything nicely aligned */ - opts[0] = PP_HTONL(0x0101080A); - opts[1] = htonl(sys_now()); - opts[2] = htonl(pcb->ts_recent); -} -#endif - -/** Send an ACK without data. - * - * @param pcb Protocol control block for the TCP connection to send the ACK - */ -err_t -tcp_send_empty_ack(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - u8_t optlen = 0; - -#if LWIP_TCP_TIMESTAMPS - if (pcb->flags & TF_TIMESTAMP) { - optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); - } -#endif - - p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); - if (p == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); - return ERR_BUF; - } - tcphdr = (struct tcp_hdr *)p->payload; - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, - ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); - /* remove ACK flags from the PCB, as we send an empty ACK now */ - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - - /* NB. MSS option is only sent on SYNs, so ignore it here */ -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; - - if (pcb->flags & TF_TIMESTAMP) { - tcp_build_timestamp_option(pcb, (u32_t *)(tcphdr + 1)); - } -#endif - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip), - IP_PROTO_TCP, p->tot_len); -#endif -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - pbuf_free(p); - - return ERR_OK; -} - -/** - * Find out what we can send and send it - * - * @param pcb Protocol control block for the TCP connection to send data - * @return ERR_OK if data has been sent or nothing to send - * another err_t on error - */ -err_t -tcp_output(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg, *useg; - u32_t wnd, snd_nxt; -#if TCP_CWND_DEBUG - s16_t i = 0; -#endif /* TCP_CWND_DEBUG */ - - /* pcb->state LISTEN not allowed here */ - LWIP_ASSERT("don't call tcp_output for listen-pcbs", - pcb->state != LISTEN); - - /* First, check if we are invoked by the TCP input processing - code. If so, we do not output anything. Instead, we rely on the - input processing code to call us when input processing is done - with. */ - if (tcp_input_pcb == pcb) { - return ERR_OK; - } - - wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd); - - seg = pcb->unsent; - - /* If the TF_ACK_NOW flag is set and no data will be sent (either - * because the ->unsent queue is empty or because the window does - * not allow it), construct an empty ACK segment and send it. - * - * If data is to be sent, we will just piggyback the ACK (see below). - */ - if (pcb->flags & TF_ACK_NOW && - (seg == NULL || - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) { - return tcp_send_empty_ack(pcb); - } - - /* useg should point to last segment on unacked queue */ - useg = pcb->unacked; - if (useg != NULL) { - for (; useg->next != NULL; useg = useg->next); - } - -#if TCP_OUTPUT_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", - (void*)pcb->unsent)); - } -#endif /* TCP_OUTPUT_DEBUG */ -#if TCP_CWND_DEBUG - if (seg == NULL) { - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F - ", cwnd %"U16_F", wnd %"U32_F - ", seg == NULL, ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack)); - } else { - LWIP_DEBUGF(TCP_CWND_DEBUG, - ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F - ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len, - ntohl(seg->tcphdr->seqno), pcb->lastack)); - } -#endif /* TCP_CWND_DEBUG */ - /* data available and window allows it to be sent? */ - while (seg != NULL && - ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) { - LWIP_ASSERT("RST not expected here!", - (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); - /* Stop sending if the nagle algorithm would prevent it - * Don't stop: - * - if tcp_write had a memory error before (prevent delayed ACK timeout) or - * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - - * either seg->next != NULL or pcb->unacked == NULL; - * RST is no sent using tcp_write/tcp_output. - */ - if((tcp_do_output_nagle(pcb) == 0) && - ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ - break; - } -#if TCP_CWND_DEBUG - LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F", i %"S16_F"\n", - pcb->snd_wnd, pcb->cwnd, wnd, - ntohl(seg->tcphdr->seqno) + seg->len - - pcb->lastack, - ntohl(seg->tcphdr->seqno), pcb->lastack, i)); - ++i; -#endif /* TCP_CWND_DEBUG */ - - pcb->unsent = seg->next; - - if (pcb->state != SYN_SENT) { - TCPH_SET_FLAG(seg->tcphdr, TCP_ACK); - pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - } - - tcp_output_segment(seg, pcb); - snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg); - if (TCP_SEQ_LT(pcb->snd_nxt, snd_nxt)) { - pcb->snd_nxt = snd_nxt; - } - /* put segment on unacknowledged list if length > 0 */ - if (TCP_TCPLEN(seg) > 0) { - seg->next = NULL; - /* unacked list is empty? */ - if (pcb->unacked == NULL) { - pcb->unacked = seg; - useg = seg; - /* unacked list is not empty? */ - } else { - /* In the case of fast retransmit, the packet should not go to the tail - * of the unacked queue, but rather somewhere before it. We need to check for - * this case. -STJ Jul 27, 2004 */ - if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { - /* add segment to before tail of unacked list, keeping the list sorted */ - struct tcp_seg **cur_seg = &(pcb->unacked); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = (*cur_seg); - (*cur_seg) = seg; - } else { - /* add segment to tail of unacked list */ - useg->next = seg; - useg = useg->next; - } - } - /* do not queue empty segments on the unacked list */ - } else { - tcp_seg_free(seg); - } - seg = pcb->unsent; - } -#if TCP_OVERSIZE - if (pcb->unsent == NULL) { - /* last unsent has been removed, reset unsent_oversize */ - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - - pcb->flags &= ~TF_NAGLEMEMERR; - return ERR_OK; -} - -/** - * Called by tcp_output() to actually send a TCP segment over IP. - * - * @param seg the tcp_seg to send - * @param pcb the tcp_pcb for the TCP connection used to send the segment - */ -static void -tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) -{ - u16_t len; - struct netif *netif; - u32_t *opts; - - /** @bug Exclude retransmitted segments from this count. */ - snmp_inc_tcpoutsegs(); - - /* The TCP header has already been constructed, but the ackno and - wnd fields remain. */ - seg->tcphdr->ackno = htonl(pcb->rcv_nxt); - - /* advertise our receive window size in this TCP segment */ - seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd); - - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - - /* Add any requested options. NB MSS option is only set on SYN - packets, so ignore it here */ - opts = (u32_t *)(void *)(seg->tcphdr + 1); - if (seg->flags & TF_SEG_OPTS_MSS) { - u16_t mss; -#if TCP_CALCULATE_EFF_SEND_MSS - mss = tcp_eff_send_mss(TCP_MSS, &pcb->remote_ip); -#else /* TCP_CALCULATE_EFF_SEND_MSS */ - mss = TCP_MSS; -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ - *opts = TCP_BUILD_MSS_OPTION(mss); - opts += 1; - } -#if LWIP_TCP_TIMESTAMPS - pcb->ts_lastacksent = pcb->rcv_nxt; - - if (seg->flags & TF_SEG_OPTS_TS) { - tcp_build_timestamp_option(pcb, opts); - opts += 3; - } -#endif - - /* Set retransmission timer running if it is not currently enabled - This must be set before checking the route. */ - if (pcb->rtime == -1) { - pcb->rtime = 0; - } - - /* If we don't have a local IP address, we get one by - calling ip_route(). */ - if (ip_addr_isany(&(pcb->local_ip))) { - netif = ip_route(&(pcb->remote_ip)); - if (netif == NULL) { - return; - } - ip_addr_copy(pcb->local_ip, netif->ip_addr); - } - - if (pcb->rttest == 0) { - pcb->rttest = tcp_ticks; - pcb->rtseq = ntohl(seg->tcphdr->seqno); - - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq)); - } - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n", - htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) + - seg->len)); - - len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload); - - seg->p->len -= len; - seg->p->tot_len -= len; - - seg->p->payload = seg->tcphdr; - - seg->tcphdr->chksum = 0; -#if CHECKSUM_GEN_TCP -#if TCP_CHECKSUM_ON_COPY - { - u32_t acc; -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ - if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { - LWIP_ASSERT("data included but not checksummed", - seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); - } - - /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ - acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); - /* add payload checksum */ - if (seg->chksum_swapped) { - seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); - seg->chksum_swapped = 0; - } - acc += (u16_t)~(seg->chksum); - seg->tcphdr->chksum = FOLD_U32T(acc); -#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK - if (chksum_slow != seg->tcphdr->chksum) { - LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", - seg->tcphdr->chksum, chksum_slow)); - seg->tcphdr->chksum = chksum_slow; - } -#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ - } -#else /* TCP_CHECKSUM_ON_COPY */ - seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), - &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif /* TCP_CHECKSUM_ON_COPY */ -#endif /* CHECKSUM_GEN_TCP */ - TCP_STATS_INC(tcp.xmit); - -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP, &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos, - IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ -} - -/** - * Send a TCP RESET packet (empty segment with RST flag set) either to - * abort a connection or to show that there is no matching local connection - * for a received segment. - * - * Called by tcp_abort() (to abort a local connection), tcp_input() (if no - * matching local pcb was found), tcp_listen_input() (if incoming segment - * has ACK flag set) and tcp_process() (received segment in the wrong state) - * - * Since a RST segment is in most cases not sent for an active connection, - * tcp_rst() has a number of arguments that are taken from a tcp_pcb for - * most other segment output functions. - * - * @param seqno the sequence number to use for the outgoing segment - * @param ackno the acknowledge number to use for the outgoing segment - * @param local_ip the local IP address to send the segment from - * @param remote_ip the remote IP address to send the segment to - * @param local_port the local TCP port to send the segment from - * @param remote_port the remote TCP port to send the segment to - */ -void -tcp_rst(u32_t seqno, u32_t ackno, - ip_addr_t *local_ip, ip_addr_t *remote_ip, - u16_t local_port, u16_t remote_port) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); - if (p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n")); - return; - } - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= sizeof(struct tcp_hdr))); - - tcphdr = (struct tcp_hdr *)p->payload; - tcphdr->src = htons(local_port); - tcphdr->dest = htons(remote_port); - tcphdr->seqno = htonl(seqno); - tcphdr->ackno = htonl(ackno); - TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); - tcphdr->wnd = PP_HTONS(TCP_WND); - tcphdr->chksum = 0; - tcphdr->urgp = 0; - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - snmp_inc_tcpoutrsts(); - /* Send output with hardcoded TTL since we have no access to the pcb */ - ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP); - pbuf_free(p); - LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno)); -} - -/** - * Requeue all unacked segments for retransmission - * - * Called by tcp_slowtmr() for slow retransmission. - * - * @param pcb the tcp_pcb for which to re-enqueue all unacked segments - */ -void -tcp_rexmit_rto(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - - if (pcb->unacked == NULL) { - return; - } - - /* Move all unacked segments to the head of the unsent queue */ - for (seg = pcb->unacked; seg->next != NULL; seg = seg->next); - /* concatenate unsent queue after unacked queue */ - seg->next = pcb->unsent; - /* unsent queue is the concatenated queue (of unacked, unsent) */ - pcb->unsent = pcb->unacked; - /* unacked queue is now empty */ - pcb->unacked = NULL; - /* last unsent hasn't changed, no need to reset unsent_oversize */ - - /* increment number of retransmissions */ - ++pcb->nrtx; - - /* Don't take any RTT measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission */ - tcp_output(pcb); -} - -/** - * Requeue the first unacked segment for retransmission - * - * Called by tcp_receive() for fast retramsmit. - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit(struct tcp_pcb *pcb) -{ - struct tcp_seg *seg; - struct tcp_seg **cur_seg; - - if (pcb->unacked == NULL) { - return; - } - - /* Move the first unacked segment to the unsent queue */ - /* Keep the unsent queue sorted. */ - seg = pcb->unacked; - pcb->unacked = seg->next; - - cur_seg = &(pcb->unsent); - while (*cur_seg && - TCP_SEQ_LT(ntohl((*cur_seg)->tcphdr->seqno), ntohl(seg->tcphdr->seqno))) { - cur_seg = &((*cur_seg)->next ); - } - seg->next = *cur_seg; - *cur_seg = seg; -#if TCP_OVERSIZE - if (seg->next == NULL) { - /* the retransmitted segment is last in unsent, so reset unsent_oversize */ - pcb->unsent_oversize = 0; - } -#endif /* TCP_OVERSIZE */ - - ++pcb->nrtx; - - /* Don't take any rtt measurements after retransmitting. */ - pcb->rttest = 0; - - /* Do the actual retransmission. */ - snmp_inc_tcpretranssegs(); - /* No need to call tcp_output: we are always called from tcp_input() - and thus tcp_output directly returns. */ -} - - -/** - * Handle retransmission after three dupacks received - * - * @param pcb the tcp_pcb for which to retransmit the first unacked segment - */ -void -tcp_rexmit_fast(struct tcp_pcb *pcb) -{ - if (pcb->unacked != NULL && !(pcb->flags & TF_INFR)) { - /* This is fast retransmit. Retransmit the first unacked segment. */ - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: dupacks %"U16_F" (%"U32_F - "), fast retransmit %"U32_F"\n", - (u16_t)pcb->dupacks, pcb->lastack, - ntohl(pcb->unacked->tcphdr->seqno))); - tcp_rexmit(pcb); - - /* Set ssthresh to half of the minimum of the current - * cwnd and the advertised window */ - if (pcb->cwnd > pcb->snd_wnd) { - pcb->ssthresh = pcb->snd_wnd / 2; - } else { - pcb->ssthresh = pcb->cwnd / 2; - } - - /* The minimum value for ssthresh should be 2 MSS */ - if (pcb->ssthresh < 2*pcb->mss) { - LWIP_DEBUGF(TCP_FR_DEBUG, - ("tcp_receive: The minimum value for ssthresh %"U16_F - " should be min 2 mss %"U16_F"...\n", - pcb->ssthresh, 2*pcb->mss)); - pcb->ssthresh = 2*pcb->mss; - } - - pcb->cwnd = pcb->ssthresh + 3 * pcb->mss; - pcb->flags |= TF_INFR; - } -} - - -/** - * Send keepalive packets to keep a connection active although - * no data is sent over it. - * - * Called by tcp_slowtmr() - * - * @param pcb the tcp_pcb for which to send a keepalive packet - */ -void -tcp_keepalive(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", - tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); - - p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1)); - if(p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_keepalive: could not allocate memory for pbuf\n")); - return; - } - tcphdr = (struct tcp_hdr *)p->payload; - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - - pbuf_free(p); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n", - pcb->snd_nxt - 1, pcb->rcv_nxt)); -} - - -/** - * Send persist timer zero-window probes to keep a connection active - * when a window update is lost. - * - * Called by tcp_slowtmr() - * - * @param pcb the tcp_pcb for which to send a zero-window probe packet - */ -void -tcp_zero_window_probe(struct tcp_pcb *pcb) -{ - struct pbuf *p; - struct tcp_hdr *tcphdr; - struct tcp_seg *seg; - u16_t len; - u8_t is_fin; - - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" - U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); - - LWIP_DEBUGF(TCP_DEBUG, - ("tcp_zero_window_probe: tcp_ticks %"U32_F - " pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", - tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); - - seg = pcb->unacked; - - if(seg == NULL) { - seg = pcb->unsent; - } - if(seg == NULL) { - return; - } - - is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); - /* we want to send one seqno: either FIN or data (no options) */ - len = is_fin ? 0 : 1; - - p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); - if(p == NULL) { - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); - return; - } - tcphdr = (struct tcp_hdr *)p->payload; - - if (is_fin) { - /* FIN segment, no data */ - TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); - } else { - /* Data segment, copy in one byte from the head of the unacked queue */ - char *d = ((char *)p->payload + TCP_HLEN); - /* Depending on whether the segment has already been sent (unacked) or not - (unsent), seg->p->payload points to the IP header or TCP header. - Ensure we copy the first TCP data byte: */ - pbuf_copy_partial(seg->p, d, 1, seg->p->tot_len - seg->len); - } - -#if CHECKSUM_GEN_TCP - tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, - IP_PROTO_TCP, p->tot_len); -#endif - TCP_STATS_INC(tcp.xmit); - - /* Send output to IP */ -#if LWIP_NETIF_HWADDRHINT - ip_output_hinted(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP, - &(pcb->addr_hint)); -#else /* LWIP_NETIF_HWADDRHINT*/ - ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP); -#endif /* LWIP_NETIF_HWADDRHINT*/ - - pbuf_free(p); - - LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F - " ackno %"U32_F".\n", - pcb->snd_nxt - 1, pcb->rcv_nxt)); -} -#endif /* LWIP_TCP */ diff --git a/ext/lwip/src/core/timers.c b/ext/lwip/src/core/timers.c deleted file mode 100644 index e3084666..00000000 --- a/ext/lwip/src/core/timers.c +++ /dev/null @@ -1,487 +0,0 @@ -/** - * @file - * Stack-internal timers implementation. - * This file includes timer callbacks for stack-internal timers as well as - * functions to set up or stop timers and check for expired timers. - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * Simon Goldschmidt - * - */ - -#include "lwip/opt.h" - -#include "lwip/timers.h" -#include "lwip/tcp_impl.h" - -#if LWIP_TIMERS - -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/tcpip.h" - -#include "lwip/ip_frag.h" -#include "netif/etharp.h" -#include "lwip/dhcp.h" -#include "lwip/autoip.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" -#include "lwip/sys.h" -#include "lwip/pbuf.h" - - -/** The one and only timeout list */ -static struct sys_timeo *next_timeout; -#if NO_SYS -static u32_t timeouts_last_time; -#endif /* NO_SYS */ - -#if LWIP_TCP -/** global variable that shows if the tcp timer is currently scheduled or not */ -static int tcpip_tcp_timer_active; - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -tcpip_tcp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - - /* call TCP timer handler */ - tcp_tmr(); - /* timer still needed? */ - if (tcp_active_pcbs || tcp_tw_pcbs) { - /* restart timer */ - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } else { - /* disable timer */ - tcpip_tcp_timer_active = 0; - } -} - -/** - * Called from TCP_REG when registering a new PCB: - * the reason is to have the TCP timer only running when - * there are active (or time-wait) PCBs. - */ -void -tcp_timer_needed(void) -{ - /* timer is off but needed again? */ - if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { - /* enable and start timer */ - tcpip_tcp_timer_active = 1; - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } -} -#endif /* LWIP_TCP */ - -#if IP_REASSEMBLY -/** - * Timer callback function that calls ip_reass_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -ip_reass_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); - ip_reass_tmr(); - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -} -#endif /* IP_REASSEMBLY */ - -#if LWIP_ARP -/** - * Timer callback function that calls etharp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -arp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); - etharp_tmr(); - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -} -#endif /* LWIP_ARP */ - -#if LWIP_DHCP -/** - * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dhcp_timer_coarse(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); - dhcp_coarse_tmr(); - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); -} - -/** - * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dhcp_timer_fine(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); - dhcp_fine_tmr(); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -} -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP -/** - * Timer callback function that calls autoip_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -autoip_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); - autoip_tmr(); - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -} -#endif /* LWIP_AUTOIP */ - -#if LWIP_IGMP -/** - * Timer callback function that calls igmp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -igmp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); - igmp_tmr(); - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -} -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -/** - * Timer callback function that calls dns_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dns_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); - dns_tmr(); - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -} -#endif /* LWIP_DNS */ - -/** Initialize this module */ -void sys_timeouts_init(void) -{ -#if IP_REASSEMBLY - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -#endif /* IP_REASSEMBLY */ -#if LWIP_ARP - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -#endif /* LWIP_ARP */ -#if LWIP_DHCP - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -#endif /* LWIP_DNS */ - -#if NO_SYS - /* Initialise timestamp for sys_check_timeouts */ - timeouts_last_time = sys_now(); -#endif -} - -/** - * Create a one-shot timer (aka timeout). Timeouts are processed in the - * following cases: - * - while waiting for a message using sys_timeouts_mbox_fetch() - * - by calling sys_check_timeouts() (NO_SYS==1 only) - * - * @param msecs time in milliseconds after that the timer should expire - * @param handler callback function to call when msecs have elapsed - * @param arg argument to pass to the callback function - */ -#if LWIP_DEBUG_TIMERNAMES -void -sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) -#else /* LWIP_DEBUG_TIMERNAMES */ -void -sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) -#endif /* LWIP_DEBUG_TIMERNAMES */ -{ - struct sys_timeo *timeout, *t; - - timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); - if (timeout == NULL) { - LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); - return; - } - timeout->next = NULL; - timeout->h = handler; - timeout->arg = arg; - timeout->time = msecs; -#if LWIP_DEBUG_TIMERNAMES - timeout->handler_name = handler_name; - LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", - (void *)timeout, msecs, handler_name, (void *)arg)); -#endif /* LWIP_DEBUG_TIMERNAMES */ - - if (next_timeout == NULL) { - next_timeout = timeout; - return; - } - - if (next_timeout->time > msecs) { - next_timeout->time -= msecs; - timeout->next = next_timeout; - next_timeout = timeout; - } else { - for(t = next_timeout; t != NULL; t = t->next) { - timeout->time -= t->time; - if (t->next == NULL || t->next->time > timeout->time) { - if (t->next != NULL) { - t->next->time -= timeout->time; - } - timeout->next = t->next; - t->next = timeout; - break; - } - } - } -} - -/** - * Go through timeout list (for this task only) and remove the first matching - * entry, even though the timeout has not triggered yet. - * - * @note This function only works as expected if there is only one timeout - * calling 'handler' in the list of timeouts. - * - * @param handler callback function that would be called by the timeout - * @param arg callback argument that would be passed to handler -*/ -void -sys_untimeout(sys_timeout_handler handler, void *arg) -{ - struct sys_timeo *prev_t, *t; - - if (next_timeout == NULL) { - return; - } - - for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { - if ((t->h == handler) && (t->arg == arg)) { - /* We have a match */ - /* Unlink from previous in list */ - if (prev_t == NULL) { - next_timeout = t->next; - } else { - prev_t->next = t->next; - } - /* If not the last one, add time of this one back to next */ - if (t->next != NULL) { - t->next->time += t->time; - } - memp_free(MEMP_SYS_TIMEOUT, t); - return; - } - } - return; -} - -#if NO_SYS - -/** Handle timeouts for NO_SYS==1 (i.e. without using - * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout - * handler functions when timeouts expire. - * - * Must be called periodically from your main loop. - */ -void -sys_check_timeouts(void) -{ - if (next_timeout) { - struct sys_timeo *tmptimeout; - u32_t diff; - sys_timeout_handler handler; - void *arg; - u8_t had_one; - u32_t now; - - now = sys_now(); - /* this cares for wraparounds */ - diff = now - timeouts_last_time; - do - { -#if PBUF_POOL_FREE_OOSEQ - PBUF_CHECK_FREE_OOSEQ(); -#endif /* PBUF_POOL_FREE_OOSEQ */ - had_one = 0; - tmptimeout = next_timeout; - if (tmptimeout && (tmptimeout->time <= diff)) { - /* timeout has expired */ - had_one = 1; - timeouts_last_time = now; - diff -= tmptimeout->time; - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", - tmptimeout->handler_name, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { - handler(arg); - } - } - /* repeat until all expired timers have been called */ - }while(had_one); - } -} - -/** Set back the timestamp of the last call to sys_check_timeouts() - * This is necessary if sys_check_timeouts() hasn't been called for a long - * time (e.g. while saving energy) to prevent all timer functions of that - * period being called. - */ -void -sys_restart_timeouts(void) -{ - timeouts_last_time = sys_now(); -} - -#else /* NO_SYS */ - -/** - * Wait (forever) for a message to arrive in an mbox. - * While waiting, timeouts are processed. - * - * @param mbox the mbox to fetch the message from - * @param msg the place to store the message - */ -void -sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) -{ - u32_t time_needed; - struct sys_timeo *tmptimeout; - sys_timeout_handler handler; - void *arg; - - again: - if (!next_timeout) { - time_needed = sys_arch_mbox_fetch(mbox, msg, 0); - } else { - if (next_timeout->time > 0) { - time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); - } else { - time_needed = SYS_ARCH_TIMEOUT; - } - - if (time_needed == SYS_ARCH_TIMEOUT) { - /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message - could be fetched. We should now call the timeout handler and - deallocate the memory allocated for the timeout. */ - tmptimeout = next_timeout; - next_timeout = tmptimeout->next; - handler = tmptimeout->h; - arg = tmptimeout->arg; -#if LWIP_DEBUG_TIMERNAMES - if (handler != NULL) { - LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", - tmptimeout->handler_name, arg)); - } -#endif /* LWIP_DEBUG_TIMERNAMES */ - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (handler != NULL) { - /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the - timeout handler function. */ - LOCK_TCPIP_CORE(); - handler(arg); - UNLOCK_TCPIP_CORE(); - } - LWIP_TCPIP_THREAD_ALIVE(); - - /* We try again to fetch a message from the mbox. */ - goto again; - } else { - /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout - occured. The time variable is set to the number of - milliseconds we waited for the message. */ - if (time_needed < next_timeout->time) { - next_timeout->time -= time_needed; - } else { - next_timeout->time = 0; - } - } - } -} - -#endif /* NO_SYS */ - -#else /* LWIP_TIMERS */ -/* Satisfy the TCP code which calls this function */ -void -tcp_timer_needed(void) -{ -} -#endif /* LWIP_TIMERS */ diff --git a/ext/lwip/src/core/udp.c b/ext/lwip/src/core/udp.c deleted file mode 100644 index 32c7d384..00000000 --- a/ext/lwip/src/core/udp.c +++ /dev/null @@ -1,1013 +0,0 @@ -/** - * @file - * User Datagram Protocol module - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ - - -/* udp.c - * - * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828). - * - */ - -/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'! - */ - -#include "lwip/opt.h" - -#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ - -#include "lwip/udp.h" -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/inet_chksum.h" -#include "lwip/ip_addr.h" -#include "lwip/netif.h" -#include "lwip/icmp.h" -#include "lwip/stats.h" -#include "lwip/snmp.h" -#include "arch/perf.h" -#include "lwip/dhcp.h" - -#include <string.h> - -#ifndef UDP_LOCAL_PORT_RANGE_START -/* From http://www.iana.org/assignments/port-numbers: - "The Dynamic and/or Private Ports are those from 49152 through 65535" */ -#define UDP_LOCAL_PORT_RANGE_START 0xc000 -#define UDP_LOCAL_PORT_RANGE_END 0xffff -#define UDP_ENSURE_LOCAL_PORT_RANGE(port) (((port) & ~UDP_LOCAL_PORT_RANGE_START) + UDP_LOCAL_PORT_RANGE_START) -#endif - -/* last local UDP port */ -static u16_t udp_port = UDP_LOCAL_PORT_RANGE_START; - -/* The list of UDP PCBs */ -/* exported in udp.h (was static) */ -struct udp_pcb *udp_pcbs; - -/** - * Initialize this module. - */ -void -udp_init(void) -{ -#if LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) - udp_port = UDP_ENSURE_LOCAL_PORT_RANGE(LWIP_RAND()); -#endif /* LWIP_RANDOMIZE_INITIAL_LOCAL_PORTS && defined(LWIP_RAND) */ -} - -/** - * Allocate a new local UDP port. - * - * @return a new (free) local UDP port number - */ -static u16_t -udp_new_port(void) -{ - u16_t n = 0; - struct udp_pcb *pcb; - -again: - if (udp_port++ == UDP_LOCAL_PORT_RANGE_END) { - udp_port = UDP_LOCAL_PORT_RANGE_START; - } - /* Check all PCBs. */ - for(pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == udp_port) { - if (++n > (UDP_LOCAL_PORT_RANGE_END - UDP_LOCAL_PORT_RANGE_START)) { - return 0; - } - goto again; - } - } - return udp_port; -#if 0 - struct udp_pcb *ipcb = udp_pcbs; - while ((ipcb != NULL) && (udp_port != UDP_LOCAL_PORT_RANGE_END)) { - if (ipcb->local_port == udp_port) { - /* port is already used by another udp_pcb */ - udp_port++; - /* restart scanning all udp pcbs */ - ipcb = udp_pcbs; - } else { - /* go on with next udp pcb */ - ipcb = ipcb->next; - } - } - if (ipcb != NULL) { - return 0; - } - return udp_port; -#endif -} - -/** - * Process an incoming UDP datagram. - * - * Given an incoming UDP datagram (as a chain of pbufs) this function - * finds a corresponding UDP PCB and hands over the pbuf to the pcbs - * recv function. If no pcb is found or the datagram is incorrect, the - * pbuf is freed. - * - * @param p pbuf to be demultiplexed to a UDP PCB. - * @param inp network interface on which the datagram was received. - * - */ -void -udp_input(struct pbuf *p, struct netif *inp) -{ - struct udp_hdr *udphdr; - struct udp_pcb *pcb, *prev; - struct udp_pcb *uncon_pcb; - struct ip_hdr *iphdr; - u16_t src, dest; - u8_t local_match; - u8_t broadcast; - - PERF_START; - - UDP_STATS_INC(udp.recv); - - iphdr = (struct ip_hdr *)p->payload; - - /* Check minimum length (IP header + UDP header) - * and move payload pointer to UDP header */ - if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) { - /* drop short packets */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len)); - UDP_STATS_INC(udp.lenerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - - udphdr = (struct udp_hdr *)p->payload; - - /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); - - LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); - - /* convert src and dest ports to host byte order */ - src = ntohs(udphdr->src); - dest = ntohs(udphdr->dest); - - udp_debug_print(udphdr); - - /* print the UDP source and destination */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), - ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), - ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), - ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); - -#if LWIP_DHCP - pcb = NULL; - /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by - the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */ - if (dest == DHCP_CLIENT_PORT) { - /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */ - if (src == DHCP_SERVER_PORT) { - if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) { - /* accept the packe if - (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - - inp->dhcp->pcb->remote == ANY or iphdr->src */ - if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || - ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { - pcb = inp->dhcp->pcb; - } - } - } - } else -#endif /* LWIP_DHCP */ - { - prev = NULL; - local_match = 0; - uncon_pcb = NULL; - /* Iterate through the UDP pcb list for a matching pcb. - * 'Perfect match' pcbs (connected to the remote port & ip address) are - * preferred. If no perfect match is found, the first unconnected pcb that - * matches the local port and ip address gets the datagram. */ - for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) { - local_match = 0; - /* print the PCB local and remote address */ - LWIP_DEBUGF(UDP_DEBUG, - ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " - "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, - ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), - ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); - - /* compare PCB local addr+port to UDP destination addr+port */ - if (pcb->local_port == dest) { - if ( - (!broadcast && ip_addr_isany(&pcb->local_ip)) || - ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || -#if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || -#endif /* LWIP_IGMP */ -#if IP_SOF_BROADCAST_RECV - (broadcast && ip_get_option(pcb, SOF_BROADCAST) && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast && - (ip_addr_isany(&pcb->local_ip) || - ip_addr_netcmp(&pcb->local_ip, ip_current_dest_addr(), &inp->netmask)))) { -#endif /* IP_SOF_BROADCAST_RECV */ - local_match = 1; - if ((uncon_pcb == NULL) && - ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) { - /* the first unconnected matching PCB */ - uncon_pcb = pcb; - } - } - } - /* compare PCB remote addr+port to UDP source addr+port */ - if ((local_match != 0) && - (pcb->remote_port == src) && - (ip_addr_isany(&pcb->remote_ip) || - ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { - /* the first fully matching PCB */ - if (prev != NULL) { - /* move the pcb to the front of udp_pcbs so that is - found faster next time */ - prev->next = pcb->next; - pcb->next = udp_pcbs; - udp_pcbs = pcb; - } else { - UDP_STATS_INC(udp.cachehit); - } - break; - } - prev = pcb; - } - /* no fully matching pcb found? then look for an unconnected pcb */ - if (pcb == NULL) { - pcb = uncon_pcb; - } - } - - /* Check checksum if this is a match or if it was directed at us. */ - if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); -#if LWIP_UDPLITE - if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { - /* Do the UDP Lite checksum */ -#if CHECKSUM_CHECK_UDP - u16_t chklen = ntohs(udphdr->len); - if (chklen < sizeof(struct udp_hdr)) { - if (chklen == 0) { - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet (See RFC 3828 chap. 3.1) */ - chklen = p->tot_len; - } else { - /* At least the UDP-Lite header must be covered by the - checksum! (Again, see RFC 3828 chap. 3.1) */ - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - } - if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, - IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } -#endif /* CHECKSUM_CHECK_UDP */ - } else -#endif /* LWIP_UDPLITE */ - { -#if CHECKSUM_CHECK_UDP - if (udphdr->chksum != 0) { - if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), - IP_PROTO_UDP, p->tot_len) != 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_input: UDP datagram discarded due to failing checksum\n")); - UDP_STATS_INC(udp.chkerr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - } -#endif /* CHECKSUM_CHECK_UDP */ - } - if(pbuf_header(p, -UDP_HLEN)) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - UDP_STATS_INC(udp.drop); - snmp_inc_udpinerrors(); - pbuf_free(p); - goto end; - } - if (pcb != NULL) { - snmp_inc_udpindatagrams(); -#if SO_REUSE && SO_REUSE_RXTOALL - if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && - ip_get_option(pcb, SOF_REUSEADDR)) { - /* pass broadcast- or multicast packets to all multicast pcbs - if SOF_REUSEADDR is set on the first match */ - struct udp_pcb *mpcb; - u8_t p_header_changed = 0; - for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { - if (mpcb != pcb) { - /* compare PCB local addr+port to UDP destination addr+port */ - if ((mpcb->local_port == dest) && - ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || - ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || -#if LWIP_IGMP - ip_addr_ismulticast(¤t_iphdr_dest) || -#endif /* LWIP_IGMP */ -#if IP_SOF_BROADCAST_RECV - (broadcast && ip_get_option(mpcb, SOF_BROADCAST)))) { -#else /* IP_SOF_BROADCAST_RECV */ - (broadcast))) { -#endif /* IP_SOF_BROADCAST_RECV */ - /* pass a copy of the packet to all local matches */ - if (mpcb->recv != NULL) { - struct pbuf *q; - /* for that, move payload to IP header again */ - if (p_header_changed == 0) { - pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - p_header_changed = 1; - } - q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if (q != NULL) { - err_t err = pbuf_copy(q, p); - if (err == ERR_OK) { - /* move payload to UDP data */ - pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); - } - } - } - } - } - } - if (p_header_changed) { - /* and move payload to UDP data again */ - pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); - } - } -#endif /* SO_REUSE && SO_REUSE_RXTOALL */ - /* callback */ - if (pcb->recv != NULL) { - /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); - } else { - /* no recv function registered? then we have to free the pbuf! */ - pbuf_free(p); - goto end; - } - } else { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n")); - -#if LWIP_ICMP - /* No match was found, send ICMP destination port unreachable unless - destination address was broadcast/multicast. */ - if (!broadcast && - !ip_addr_ismulticast(¤t_iphdr_dest)) { - /* move payload pointer back to ip header */ - pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); - LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); - icmp_dest_unreach(p, ICMP_DUR_PORT); - } -#endif /* LWIP_ICMP */ - UDP_STATS_INC(udp.proterr); - UDP_STATS_INC(udp.drop); - snmp_inc_udpnoports(); - pbuf_free(p); - } - } else { - pbuf_free(p); - } -end: - PERF_STOP("udp_input"); -} - -/** - * Send data using UDP. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * - * The datagram will be sent to the current remote_ip & remote_port - * stored in pcb. If the pcb is not bound to a port, it will - * automatically be bound to a random port. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_MEM. Out of memory. - * - ERR_RTE. Could not find route to destination address. - * - More errors could be returned by lower protocol layers. - * - * @see udp_disconnect() udp_sendto() - */ -err_t -udp_send(struct udp_pcb *pcb, struct pbuf *p) -{ - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); -} - -#if LWIP_CHECKSUM_ON_COPY -/** Same as udp_send() but with checksum - */ -err_t -udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, - u8_t have_chksum, u16_t chksum) -{ - /* send to the packet using remote ip and port stored in the pcb */ - return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, - have_chksum, chksum); -} -#endif /* LWIP_CHECKSUM_ON_COPY */ - -/** - * Send data to a specified address using UDP. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * @param dst_ip Destination IP address. - * @param dst_port Destination UDP port. - * - * dst_ip & dst_port are expected to be in the same byte order as in the pcb. - * - * If the PCB already has a remote address association, it will - * be restored after the data is sent. - * - * @return lwIP error code (@see udp_send for possible error codes) - * - * @see udp_disconnect() udp_send() - */ -err_t -udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port) -{ -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); -} - -/** Same as udp_sendto(), but with checksum */ -err_t -udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, - u16_t dst_port, u8_t have_chksum, u16_t chksum) -{ -#endif /* LWIP_CHECKSUM_ON_COPY */ - struct netif *netif; - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); - - /* find the outgoing network interface for this packet */ -#if LWIP_IGMP - netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip)); -#else - netif = ip_route(dst_ip); -#endif /* LWIP_IGMP */ - - /* no outgoing network interface could be found? */ - if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); -#else /* LWIP_CHECKSUM_ON_COPY */ - return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); -#endif /* LWIP_CHECKSUM_ON_COPY */ -} - -/** - * Send data to a specified address using UDP. - * The netif used for sending can be specified. - * - * This function exists mainly for DHCP, to be able to send UDP packets - * on a netif that is still down. - * - * @param pcb UDP PCB used to send the data. - * @param p chain of pbuf's to be sent. - * @param dst_ip Destination IP address. - * @param dst_port Destination UDP port. - * @param netif the netif used for sending. - * - * dst_ip & dst_port are expected to be in the same byte order as in the pcb. - * - * @return lwIP error code (@see udp_send for possible error codes) - * - * @see udp_disconnect() udp_send() - */ -err_t -udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, - ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) -{ -#if LWIP_CHECKSUM_ON_COPY - return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); -} - -/** Same as udp_sendto_if(), but with checksum */ -err_t -udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, - u16_t dst_port, struct netif *netif, u8_t have_chksum, - u16_t chksum) -{ -#endif /* LWIP_CHECKSUM_ON_COPY */ - struct udp_hdr *udphdr; - ip_addr_t *src_ip; - err_t err; - struct pbuf *q; /* q will be sent down the stack */ - -#if IP_SOF_BROADCAST - /* broadcast filter? */ - if (!ip_get_option(pcb, SOF_BROADCAST) && ip_addr_isbroadcast(dst_ip, netif)) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); - return ERR_VAL; - } -#endif /* IP_SOF_BROADCAST */ - - /* if the PCB is not yet bound to a port, bind it here */ - if (pcb->local_port == 0) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n")); - err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); - if (err != ERR_OK) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n")); - return err; - } - } - - /* not enough space to add an UDP header to first pbuf in given p chain? */ - if (pbuf_header(p, UDP_HLEN)) { - /* allocate header in a separate new pbuf */ - q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM); - /* new header pbuf could not be allocated? */ - if (q == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); - return ERR_MEM; - } - if (p->tot_len != 0) { - /* chain header q in front of given pbuf p (only if p contains data) */ - pbuf_chain(q, p); - } - /* first pbuf q points to header pbuf */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); - } else { - /* adding space for header within p succeeded */ - /* first pbuf q equals given pbuf */ - q = p; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p)); - } - LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", - (q->len >= sizeof(struct udp_hdr))); - /* q now represents the packet to be sent */ - udphdr = (struct udp_hdr *)q->payload; - udphdr->src = htons(pcb->local_port); - udphdr->dest = htons(dst_port); - /* in UDP, 0 checksum means 'no checksum' */ - udphdr->chksum = 0x0000; - - /* Multicast Loop? */ -#if LWIP_IGMP - if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { - q->flags |= PBUF_FLAG_MCASTLOOP; - } -#endif /* LWIP_IGMP */ - - - /* PCB local address is IP_ANY_ADDR? */ - if (ip_addr_isany(&pcb->local_ip)) { - /* use outgoing network interface IP address as source address */ - src_ip = &(netif->ip_addr); - } else { - /* check if UDP PCB local IP address is correct - * this could be an old address if netif->ip_addr has changed */ - if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { - /* local_ip doesn't match, drop the packet */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; - /* p is still referenced by the caller, and will live on */ - } - return ERR_VAL; - } - /* use UDP PCB local IP address as source address */ - src_ip = &(pcb->local_ip); - } - - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len)); - -#if LWIP_UDPLITE - /* UDP Lite protocol? */ - if (pcb->flags & UDP_FLAGS_UDPLITE) { - u16_t chklen, chklen_hdr; - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len)); - /* set UDP message length in UDP header */ - chklen_hdr = chklen = pcb->chksum_len_tx; - if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) { - if (chklen != 0) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen)); - } - /* For UDP-Lite, checksum length of 0 means checksum - over the complete packet. (See RFC 3828 chap. 3.1) - At least the UDP-Lite header must be covered by the - checksum, therefore, if chksum_len has an illegal - value, we generate the checksum over the complete - packet to be safe. */ - chklen_hdr = 0; - chklen = q->tot_len; - } - udphdr->len = htons(chklen_hdr); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, -#if !LWIP_CHECKSUM_ON_COPY - chklen); -#else /* !LWIP_CHECKSUM_ON_COPY */ - (have_chksum ? UDP_HLEN : chklen)); - if (have_chksum) { - u32_t acc; - acc = udphdr->chksum + (u16_t)~(chksum); - udphdr->chksum = FOLD_U32T(acc); - } -#endif /* !LWIP_CHECKSUM_ON_COPY */ - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) { - udphdr->chksum = 0xffff; - } -#endif /* CHECKSUM_GEN_UDP */ - /* output to IP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); - NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - } else -#endif /* LWIP_UDPLITE */ - { /* UDP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len)); - udphdr->len = htons(q->tot_len); - /* calculate checksum */ -#if CHECKSUM_GEN_UDP - if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - u16_t udpchksum; -#if LWIP_CHECKSUM_ON_COPY - if (have_chksum) { - u32_t acc; - udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, - q->tot_len, UDP_HLEN); - acc = udpchksum + (u16_t)~(chksum); - udpchksum = FOLD_U32T(acc); - } else -#endif /* LWIP_CHECKSUM_ON_COPY */ - { - udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); - } - - /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udpchksum == 0x0000) { - udpchksum = 0xffff; - } - udphdr->chksum = udpchksum; - } -#endif /* CHECKSUM_GEN_UDP */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); - LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); - /* output to IP */ - NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint); - err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); - NETIF_SET_HWADDRHINT(netif, NULL); - } - /* TODO: must this be increased even if error occured? */ - snmp_inc_udpoutdatagrams(); - - /* did we chain a separate header pbuf earlier? */ - if (q != p) { - /* free the header pbuf */ - pbuf_free(q); - q = NULL; - /* p is still referenced by the caller, and will live on */ - } - - UDP_STATS_INC(udp.xmit); - return err; -} - -/** - * Bind an UDP PCB. - * - * @param pcb UDP PCB to be bound with a local address ipaddr and port. - * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to - * bind to all local interfaces. - * @param port local UDP port to bind with. Use 0 to automatically bind - * to a random port between UDP_LOCAL_PORT_RANGE_START and - * UDP_LOCAL_PORT_RANGE_END. - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * @return lwIP error code. - * - ERR_OK. Successful. No error occured. - * - ERR_USE. The specified ipaddr and port are already bound to by - * another UDP PCB. - * - * @see udp_disconnect() - */ -err_t -udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - u8_t rebind; - - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = ")); - ip_addr_debug_print(UDP_DEBUG, ipaddr); - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port)); - - rebind = 0; - /* Check for double bind and rebind of the same pcb */ - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - /* is this UDP PCB already on active list? */ - if (pcb == ipcb) { - /* pcb may occur at most once in active list */ - LWIP_ASSERT("rebind == 0", rebind == 0); - /* pcb already in list, just rebind */ - rebind = 1; - } - - /* By default, we don't allow to bind to a port that any other udp - PCB is alread bound to, unless *all* PCBs with that port have tha - REUSEADDR flag set. */ -#if SO_REUSE - else if (!ip_get_option(pcb, SOF_REUSEADDR) && - !ip_get_option(ipcb, SOF_REUSEADDR)) { -#else /* SO_REUSE */ - /* port matches that of PCB in list and REUSEADDR not set -> reject */ - else { -#endif /* SO_REUSE */ - if ((ipcb->local_port == port) && - /* IP address matches, or one is IP_ADDR_ANY? */ - (ip_addr_isany(&(ipcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(ipcb->local_ip), ipaddr))) { - /* other PCB already binds to this local IP and port */ - LWIP_DEBUGF(UDP_DEBUG, - ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); - return ERR_USE; - } - } - } - - ip_addr_set(&pcb->local_ip, ipaddr); - - /* no port specified? */ - if (port == 0) { - port = udp_new_port(); - if (port == 0) { - /* no more ports available in local range */ - LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n")); - return ERR_USE; - } - } - pcb->local_port = port; - snmp_insert_udpidx_tree(pcb); - /* pcb not active yet? */ - if (rebind == 0) { - /* place the PCB on the active list if not already there */ - pcb->next = udp_pcbs; - udp_pcbs = pcb; - } - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); - return ERR_OK; -} -/** - * Connect an UDP PCB. - * - * This will associate the UDP PCB with the remote address. - * - * @param pcb UDP PCB to be connected with remote address ipaddr and port. - * @param ipaddr remote IP address to connect with. - * @param port remote UDP port to connect with. - * - * @return lwIP error code - * - * ipaddr & port are expected to be in the same byte order as in the pcb. - * - * The udp pcb is bound to a random local port if not already bound. - * - * @see udp_disconnect() - */ -err_t -udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) -{ - struct udp_pcb *ipcb; - - if (pcb->local_port == 0) { - err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); - if (err != ERR_OK) { - return err; - } - } - - ip_addr_set(&pcb->remote_ip, ipaddr); - pcb->remote_port = port; - pcb->flags |= UDP_FLAGS_CONNECTED; -/** TODO: this functionality belongs in upper layers */ -#ifdef LWIP_UDP_TODO - /* Nail down local IP for netconn_addr()/getsockname() */ - if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) { - struct netif *netif; - - if ((netif = ip_route(&(pcb->remote_ip))) == NULL) { - LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr)); - UDP_STATS_INC(udp.rterr); - return ERR_RTE; - } - /** TODO: this will bind the udp pcb locally, to the interface which - is used to route output packets to the remote address. However, we - might want to accept incoming packets on any interface! */ - pcb->local_ip = netif->ip_addr; - } else if (ip_addr_isany(&pcb->remote_ip)) { - pcb->local_ip.addr = 0; - } -#endif - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", - ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), - ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), - pcb->local_port)); - - /* Insert UDP PCB into the list of active UDP PCBs. */ - for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { - if (pcb == ipcb) { - /* already on the list, just return */ - return ERR_OK; - } - } - /* PCB not yet on the list, add PCB now */ - pcb->next = udp_pcbs; - udp_pcbs = pcb; - return ERR_OK; -} - -/** - * Disconnect a UDP PCB - * - * @param pcb the udp pcb to disconnect. - */ -void -udp_disconnect(struct udp_pcb *pcb) -{ - /* reset remote address association */ - ip_addr_set_any(&pcb->remote_ip); - pcb->remote_port = 0; - /* mark PCB as unconnected */ - pcb->flags &= ~UDP_FLAGS_CONNECTED; -} - -/** - * Set a receive callback for a UDP PCB - * - * This callback will be called when receiving a datagram for the pcb. - * - * @param pcb the pcb for wich to set the recv callback - * @param recv function pointer of the callback function - * @param recv_arg additional argument to pass to the callback function - */ -void -udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) -{ - /* remember recv() callback and user data */ - pcb->recv = recv; - pcb->recv_arg = recv_arg; -} - -/** - * Remove an UDP PCB. - * - * @param pcb UDP PCB to be removed. The PCB is removed from the list of - * UDP PCB's and the data structure is freed from memory. - * - * @see udp_new() - */ -void -udp_remove(struct udp_pcb *pcb) -{ - struct udp_pcb *pcb2; - - snmp_delete_udpidx_tree(pcb); - /* pcb to be removed is first in list? */ - if (udp_pcbs == pcb) { - /* make list start at 2nd pcb */ - udp_pcbs = udp_pcbs->next; - /* pcb not 1st in list */ - } else { - for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { - /* find pcb in udp_pcbs list */ - if (pcb2->next != NULL && pcb2->next == pcb) { - /* remove pcb from list */ - pcb2->next = pcb->next; - } - } - } - memp_free(MEMP_UDP_PCB, pcb); -} - -/** - * Create a UDP PCB. - * - * @return The UDP PCB which was created. NULL if the PCB data structure - * could not be allocated. - * - * @see udp_remove() - */ -struct udp_pcb * -udp_new(void) -{ - struct udp_pcb *pcb; - pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); - /* could allocate UDP PCB? */ - if (pcb != NULL) { - /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 - * which means checksum is generated over the whole datagram per default - * (recommended as default by RFC 3828). */ - /* initialize PCB to all zeroes */ - memset(pcb, 0, sizeof(struct udp_pcb)); - pcb->ttl = UDP_TTL; - } - return pcb; -} - -#if UDP_DEBUG -/** - * Print UDP header information for debug purposes. - * - * @param udphdr pointer to the udp header in memory. - */ -void -udp_debug_print(struct udp_hdr *udphdr) -{ - LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n")); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | %5"U16_F" | (src port, dest port)\n", - ntohs(udphdr->src), ntohs(udphdr->dest))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); - LWIP_DEBUGF(UDP_DEBUG, ("| %5"U16_F" | 0x%04"X16_F" | (len, chksum)\n", - ntohs(udphdr->len), ntohs(udphdr->chksum))); - LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n")); -} -#endif /* UDP_DEBUG */ - -#endif /* LWIP_UDP */ |