diff options
Diffstat (limited to 'firmware/usrp3')
175 files changed, 63092 insertions, 0 deletions
diff --git a/firmware/usrp3/.gitignore b/firmware/usrp3/.gitignore new file mode 100644 index 000000000..796b96d1c --- /dev/null +++ b/firmware/usrp3/.gitignore @@ -0,0 +1 @@ +/build diff --git a/firmware/usrp3/CMakeLists.txt b/firmware/usrp3/CMakeLists.txt new file mode 100644 index 000000000..c25adb68a --- /dev/null +++ b/firmware/usrp3/CMakeLists.txt @@ -0,0 +1,118 @@ +# +# Copyright 2010-2014 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +# setup project and compiler +######################################################################## +CMAKE_MINIMUM_REQUIRED(VERSION 2.6) +#force the compiler because the check wont use the special flag below +INCLUDE(CMakeForceCompiler) +SET(CMAKE_SYSTEM_NAME Generic) +CMAKE_FORCE_C_COMPILER(zpu-elf-gcc GNU) +PROJECT(USRP3_FW C) + +INCLUDE_DIRECTORIES(include) + +find_package(PythonInterp) + +######################################################################## +# lwIP header include dirs +######################################################################## +SET(LWIPDIR ${CMAKE_SOURCE_DIR}/lwip/lwip-1.3.1) + +INCLUDE_DIRECTORIES( +    ${CMAKE_SOURCE_DIR}/lwip +    ${CMAKE_SOURCE_DIR}/lwip_port +    ${LWIPDIR}/src/include +    ${LWIPDIR}/src/include/ipv4 +) + +######################################################################## +# misc flags for the gcc compiler +######################################################################## +SET(CMAKE_C_FLAGS -phi) #always needed compile time and link time +ADD_DEFINITIONS(-Os) +ADD_DEFINITIONS(--std=gnu99) +ADD_DEFINITIONS(-Wall) +ADD_DEFINITIONS(-Werror-implicit-function-declaration) +ADD_DEFINITIONS(-ffunction-sections) +ADD_DEFINITIONS(-DPRINTF_LONG_SUPPORT) + +MACRO(ADD_LINKER_FLAGS flags) +    SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${flags}") +ENDMACRO(ADD_LINKER_FLAGS) + +ADD_LINKER_FLAGS("-Wl,--gc-sections") +ADD_LINKER_FLAGS("-Wl,--relax") + +######################################################################## +# setup programs for output files +######################################################################## +FIND_PROGRAM(LINKER zpu-elf-ld) +FIND_PROGRAM(OBJCOPY zpu-elf-objcopy) +FIND_PROGRAM(OBJDUMP zpu-elf-objdump) +FIND_PROGRAM(HEXDUMP hexdump) + +######################################################################## +# helper functions to build output formats +######################################################################## +SET(GEN_OUTPUTS_BIN_SIZE "bin_size_not_set") #set before calling +MACRO(GEN_OUTPUTS target pretty_name) +    GET_FILENAME_COMPONENT(name ${target} NAME_WE) +    #command to create a map from elf +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.map DEPENDS ${target} +        COMMAND ${LINKER} -Map ${name}.map ${target} +    ) +    #command to create a bin from elf +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.bin DEPENDS ${target} +        COMMAND ${OBJCOPY} -O binary ${target} ${name}.bin +        --pad-to ${GEN_OUTPUTS_BIN_SIZE} +    ) +    #command to create a ihx from elf +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.ihx DEPENDS ${target} +        COMMAND ${OBJCOPY} -O ihex ${target} ${name}.ihx +        --pad-to ${GEN_OUTPUTS_BIN_SIZE} +    ) +    #command to create a dump from elf +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.dump DEPENDS ${target} +        COMMAND ${OBJDUMP} -DSC ${target} > ${name}.dump +    ) +    #command to create a rom from bin +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.rom DEPENDS ${name}.bin +        COMMAND ${HEXDUMP} -v -e'1/1 \"%.2X\\n\"' ${name}.bin > ${name}.rom +    ) +    #command to create a coe from bin +    ADD_CUSTOM_COMMAND( +        OUTPUT ${name}.coe DEPENDS ${name}.bin +        COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/utils/bin_to_coe.py ${name}.bin ${name}.coe +    ) +    #add a top level target for output files +    ADD_CUSTOM_TARGET( +        ${pretty_name} ALL DEPENDS ${name}.map ${name}.bin ${name}.ihx ${name}.dump ${name}.rom ${name}.coe +    ) +ENDMACRO(GEN_OUTPUTS) + +######################################################################## +# Add the subdirectories +######################################################################## +ADD_SUBDIRECTORY(lib) +ADD_SUBDIRECTORY(x300) diff --git a/firmware/usrp3/include/chinch.h b/firmware/usrp3/include/chinch.h new file mode 100644 index 000000000..a3e70337a --- /dev/null +++ b/firmware/usrp3/include/chinch.h @@ -0,0 +1,109 @@ +// +// Copyright 2013 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// +#ifndef INCLUDED_CHINCH_H +#define INCLUDED_CHINCH_H + +#include <wb_utils.h> +#include <stdbool.h> +#include <printf.h> + +#define STATUS_CHAIN(x, status) if (status) status = (x) +#define STATUS_MERGE(x, status) status &= (x) +#define STATUS_CHAIN_DBG(x, status) STATUS_CHAIN(x, status); printf("%s: %s\n", #x, status?"succeeded":"failed!") + +//The unit for this timeout is somewhat arbitrary. We could use the counter reg to enforce this in +//terms of clock cycles but that is not worth the extra code +static const uint32_t CHINCH_DEFAULT_XACT_TIMEOUT   = 32768; +static const uint32_t CHINCH_FLASH_MAX_BUF_WRITES   = 32; + +//----------------------------------------------------- +// Peek-Poke interface for the Chinch +//----------------------------------------------------- +bool chinch_poke(const uint32_t addr, const uint32_t data, bool half_word, uint32_t timeout); +bool chinch_peek(const uint32_t addr, uint32_t* data, bool half_word, uint32_t timeout); + +static inline bool chinch_poke32(const uint32_t addr, const uint32_t data) { +    return chinch_poke(addr, data, false /*half word*/, CHINCH_DEFAULT_XACT_TIMEOUT); +} +static inline bool chinch_poke16(const uint32_t addr, const uint32_t data) { +    return chinch_poke(addr, data, true /*half word*/, CHINCH_DEFAULT_XACT_TIMEOUT); +} +static inline bool chinch_peek32(const uint32_t addr, uint32_t* data) { +    return chinch_peek(addr, data, false /*half word*/, CHINCH_DEFAULT_XACT_TIMEOUT); +} +static inline bool chinch_peek16(const uint32_t addr, uint32_t* data) { +    return chinch_peek(addr, data, true /*half word*/, CHINCH_DEFAULT_XACT_TIMEOUT); +} + +//----------------------------------------------------- +// Flash access +//----------------------------------------------------- +bool chinch_flash_init(); +void chinch_flash_cleanup(); +bool chinch_flash_select_sector(uint32_t sector); +bool chinch_flash_erase_sector(); +bool chinch_flash_read_buf(uint32_t offset, uint16_t* buf, uint32_t size); +bool chinch_flash_write_buf(uint32_t offset, uint16_t* buf, uint32_t size); + +static inline bool chinch_flash_read(uint32_t offset, uint16_t* data) { +    return chinch_flash_read_buf(offset, data, 1); +} +static inline bool chinch_flash_write(uint32_t offset, uint16_t data) { +    return chinch_flash_write_buf(offset, &data, 1); +} + +//----------------------------------------------------- +// FPGA Configuration +//----------------------------------------------------- +typedef uint8_t config_status_t; +static const config_status_t CHINCH_CONFIG_RUNNING   = 0; +static const config_status_t CHINCH_CONFIG_DISABLED  = 1; +static const config_status_t CHINCH_CONFIG_COMPLETED = 2; +static const config_status_t CHINCH_CONFIG_ERROR     = 3; + +void chinch_start_config();   //Caution: This operation will make the ZPU self-destruct! +config_status_t chinch_get_config_status(); + +//----------------------------------------------------- +// Read-back interface for user initiated +// PCIe register transactions +//----------------------------------------------------- +typedef uint8_t pcie_xact_size_t; +static const pcie_xact_size_t PCIE_XACT_32_BIT = 0; +static const pcie_xact_size_t PCIE_XACT_16_BIT = 1; + +typedef uint8_t pcie_xact_t; +static const pcie_xact_t PCIE_XACT_ERROR = 0; +static const pcie_xact_t PCIE_XACT_READ  = 1; +static const pcie_xact_t PCIE_XACT_WRITE = 2; + +typedef bool (*pcie_register_xact_responder_t)(uint32_t response, uint32_t timeout); + +typedef struct +{ +    pcie_xact_t                     type; +    uint32_t                        addr; +    uint32_t                        data; +    pcie_xact_size_t                size; +    pcie_register_xact_responder_t  respond; +} pcie_register_xact_t; + +bool check_pcie_user_regport(pcie_register_xact_t** xact_info_hdl); +bool forward_pcie_user_xact_to_wb(); + + +#endif /* INCLUDED_CHINCH_H */ diff --git a/firmware/usrp3/include/ethernet.h b/firmware/usrp3/include/ethernet.h new file mode 100644 index 000000000..52f14d05b --- /dev/null +++ b/firmware/usrp3/include/ethernet.h @@ -0,0 +1,53 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_ETHERNET_H +#define INCLUDED_ETHERNET_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +typedef void (*ethernet_link_changed_callback_t)(int ethnum, int speed); + +#define MDIO_PORT 4 + +/*! + * \brief one time call to initialize ethernet + */ +void xge_ethernet_init(const uint32_t eth); + +/*! + * \brief Return number of ethernet interfaces + */ +int ethernet_ninterfaces(void); + + +void dump_mdio_regs(const uint8_t eth, uint32_t mdio_port); + +/*! + * \brief Test status of SFP+ modules + */ +void +xge_poll_sfpp_status(const uint32_t eth); + +//! get the link status of eth (true for link up) +bool ethernet_get_link_up(const uint32_t eth); + +#endif /* INCLUDED_ETHERNET_H */ diff --git a/firmware/usrp3/include/ethertype.h b/firmware/usrp3/include/ethertype.h new file mode 100644 index 000000000..235981193 --- /dev/null +++ b/firmware/usrp3/include/ethertype.h @@ -0,0 +1,27 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009-2011 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ +#ifndef INCLUDED_ETHERTYPE_H +#define INCLUDED_ETHERTYPE_H + +// all we care about + +#define	ETHERTYPE_IPV4	0x0800 +#define	ETHERTYPE_ARP	0x0806 + + +#endif /* INCLUDED_ETHERTYPE_H */ diff --git a/firmware/usrp3/include/if_arp.h b/firmware/usrp3/include/if_arp.h new file mode 100644 index 000000000..63519c4be --- /dev/null +++ b/firmware/usrp3/include/if_arp.h @@ -0,0 +1,153 @@ +/* + * INET		An implementation of the TCP/IP protocol suite for the LINUX + *		operating system.  INET is implemented using the  BSD Socket + *		interface as the means of communication with the user level. + * + *		Global definitions for the ARP (RFC 826) protocol. + * + * Version:	@(#)if_arp.h	1.0.1	04/16/93 + * + * Authors:	Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + *		Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + *		Ross Biro + *		Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG> + *		Florian La Roche, + *		Jonathan Layes <layes@loran.com> + *		Arnaldo Carvalho de Melo <acme@conectiva.com.br> ARPHRD_HWX25 + * + *		This program is free software; you can redistribute it and/or + *		modify it under the terms of the GNU General Public License + *		as published by the Free Software Foundation; either version + *		2 of the License, or (at your option) any later version. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM	0		/* from KA9Q: NET/ROM pseudo	*/ +#define ARPHRD_ETHER 	1		/* Ethernet 10Mbps		*/ +#define	ARPHRD_EETHER	2		/* Experimental Ethernet	*/ +#define	ARPHRD_AX25	3		/* AX.25 Level 2		*/ +#define	ARPHRD_PRONET	4		/* PROnet token ring		*/ +#define	ARPHRD_CHAOS	5		/* Chaosnet			*/ +#define	ARPHRD_IEEE802	6		/* IEEE 802.2 Ethernet/TR/TB	*/ +#define	ARPHRD_ARCNET	7		/* ARCnet			*/ +#define	ARPHRD_APPLETLK	8		/* APPLEtalk			*/ +#define ARPHRD_DLCI	15		/* Frame Relay DLCI		*/ +#define ARPHRD_ATM	19		/* ATM 				*/ +#define ARPHRD_METRICOM	23		/* Metricom STRIP (new IANA id)	*/ +#define	ARPHRD_IEEE1394	24		/* IEEE 1394 IPv4 - RFC 2734	*/ +#define ARPHRD_EUI64	27		/* EUI-64                       */ +#define ARPHRD_INFINIBAND 32		/* InfiniBand			*/ + +/* Dummy types for non ARP hardware */ +#define ARPHRD_SLIP	256 +#define ARPHRD_CSLIP	257 +#define ARPHRD_SLIP6	258 +#define ARPHRD_CSLIP6	259 +#define ARPHRD_RSRVD	260		/* Notional KISS type 		*/ +#define ARPHRD_ADAPT	264 +#define ARPHRD_ROSE	270 +#define ARPHRD_X25	271		/* CCITT X.25			*/ +#define ARPHRD_HWX25	272		/* Boards with X.25 in firmware	*/ +#define ARPHRD_CAN	280		/* Controller Area Network      */ +#define ARPHRD_PPP	512 +#define ARPHRD_CISCO	513		/* Cisco HDLC	 		*/ +#define ARPHRD_HDLC	ARPHRD_CISCO +#define ARPHRD_LAPB	516		/* LAPB				*/ +#define ARPHRD_DDCMP    517		/* Digital's DDCMP protocol     */ +#define ARPHRD_RAWHDLC	518		/* Raw HDLC			*/ + +#define ARPHRD_TUNNEL	768		/* IPIP tunnel			*/ +#define ARPHRD_TUNNEL6	769		/* IP6IP6 tunnel       		*/ +#define ARPHRD_FRAD	770             /* Frame Relay Access Device    */ +#define ARPHRD_SKIP	771		/* SKIP vif			*/ +#define ARPHRD_LOOPBACK	772		/* Loopback device		*/ +#define ARPHRD_LOCALTLK 773		/* Localtalk device		*/ +#define ARPHRD_FDDI	774		/* Fiber Distributed Data Interface */ +#define ARPHRD_BIF      775             /* AP1000 BIF                   */ +#define ARPHRD_SIT	776		/* sit0 device - IPv6-in-IPv4	*/ +#define ARPHRD_IPDDP	777		/* IP over DDP tunneller	*/ +#define ARPHRD_IPGRE	778		/* GRE over IP			*/ +#define ARPHRD_PIMREG	779		/* PIMSM register interface	*/ +#define ARPHRD_HIPPI	780		/* High Performance Parallel Interface */ +#define ARPHRD_ASH	781		/* Nexus 64Mbps Ash		*/ +#define ARPHRD_ECONET	782		/* Acorn Econet			*/ +#define ARPHRD_IRDA 	783		/* Linux-IrDA			*/ +/* ARP works differently on different FC media .. so  */ +#define ARPHRD_FCPP	784		/* Point to point fibrechannel	*/ +#define ARPHRD_FCAL	785		/* Fibrechannel arbitrated loop */ +#define ARPHRD_FCPL	786		/* Fibrechannel public loop	*/ +#define ARPHRD_FCFABRIC	787		/* Fibrechannel fabric		*/ +	/* 787->799 reserved for fibrechannel media types */ +#define ARPHRD_IEEE802_TR 800		/* Magic type ident for TR	*/ +#define ARPHRD_IEEE80211 801		/* IEEE 802.11			*/ +#define ARPHRD_IEEE80211_PRISM 802	/* IEEE 802.11 + Prism2 header  */ +#define ARPHRD_IEEE80211_RADIOTAP 803	/* IEEE 802.11 + radiotap header */ + +#define ARPHRD_VOID	  0xFFFF	/* Void type, nothing is known */ +#define ARPHRD_NONE	  0xFFFE	/* zero header length */ + +/* ARP protocol opcodes. */ +#define	ARPOP_REQUEST	1		/* ARP request			*/ +#define	ARPOP_REPLY	2		/* ARP reply			*/ +#define	ARPOP_RREQUEST	3		/* RARP request			*/ +#define	ARPOP_RREPLY	4		/* RARP reply			*/ +#define	ARPOP_InREQUEST	8		/* InARP request		*/ +#define	ARPOP_InREPLY	9		/* InARP reply			*/ +#define	ARPOP_NAK	10		/* (ATM)ARP NAK			*/ + + +/* ARP Flag values. */ +#define ATF_COM		0x02		/* completed entry (ha valid)	*/ +#define	ATF_PERM	0x04		/* permanent entry		*/ +#define	ATF_PUBL	0x08		/* publish entry		*/ +#define	ATF_USETRAILERS	0x10		/* has requested trailers	*/ +#define ATF_NETMASK     0x20            /* want to use a netmask (only +					   for proxy entries) */ +#define ATF_DONTPUB	0x40		/* don't answer this addresses	*/ + +typedef unsigned short  __be16; + +/* + *	This structure defines an ethernet arp header. + */ +struct arphdr +{ +	__be16		ar_hrd;		/* format of hardware address	*/ +	__be16		ar_pro;		/* format of protocol address	*/ +	unsigned char	ar_hln;		/* length of hardware address	*/ +	unsigned char	ar_pln;		/* length of protocol address	*/ +	__be16		ar_op;		/* ARP opcode (command)		*/ + +#if 0 +	 /* +	  *	 Ethernet looks like this : This bit is variable sized however... +	  */ +	unsigned char		ar_sha[ETH_ALEN];	/* sender hardware address	*/ +	unsigned char		ar_sip[4];		/* sender IP address		*/ +	unsigned char		ar_tha[ETH_ALEN];	/* target hardware address	*/ +	unsigned char		ar_tip[4];		/* target IP address		*/ +#endif + +}; + +/* + *	This structure defines an ethernet arp header. + */ +struct arp_eth_ipv4 +{ +	__be16		ar_hrd;		/* format of hardware address	*/ +	__be16		ar_pro;		/* format of protocol address	*/ +	unsigned char	ar_hln;		/* length of hardware address	*/ +	unsigned char	ar_pln;		/* length of protocol address	*/ +	__be16		ar_op;		/* ARP opcode (command)		*/ + +	unsigned char	ar_sha[6];	/* sender hardware address	*/ +	unsigned char	ar_sip[4];	/* sender IP address		*/ +	unsigned char	ar_tha[6];	/* target hardware address	*/ +	unsigned char	ar_tip[4];	/* target IP address		*/ +}; + + +#endif	/* _LINUX_IF_ARP_H */ diff --git a/firmware/usrp3/include/link_state_route_proto.h b/firmware/usrp3/include/link_state_route_proto.h new file mode 100644 index 000000000..8feb3e717 --- /dev/null +++ b/firmware/usrp3/include/link_state_route_proto.h @@ -0,0 +1,56 @@ + +// Copyright 2013 Ettus Research LLC + +#ifndef INCLUDED_LINK_STATE_ROUTE_PROTO_H +#define INCLUDED_LINK_STATE_ROUTE_PROTO_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <lwip/ip_addr.h> + +//http://en.wikipedia.org/wiki/Link-state_routing_protocol + +//! Initialize internals and handler registration +void link_state_route_proto_init(void); + +/*! + * Advances the internal counter to determine expired entries. + * Call this periodically, along with the other periodic calls. + */ +void link_state_route_proto_tick(void); + +//! Initiate a periodic update to the neighbor table +void link_state_route_proto_update(const uint8_t ethno); + +//! Flood the network with information about routes +void link_state_route_proto_flood(const uint8_t ethno); + +/*! + * Updates the causes cycle cache for the given source ethno. + */ +void link_state_route_proto_update_cycle_cache(const uint8_t ethno); + +/*! + * Determine if the given link is the cause of a cycle (aka routing loop) + * This call does not run the algorithm, but rather checks the cache. + * This call also differs from the one below, takes the ethnos. + */ +bool link_state_route_proto_causes_cycle_cached(const uint8_t eth_src, const uint8_t eth_dst); + +//! Determine if the given link is the cause of a cycle (aka routing loop) +bool link_state_route_proto_causes_cycle(const struct ip_addr *src, const struct ip_addr *dst); + +typedef struct +{ +    struct ip_addr node; +    struct ip_addr nbor; +} ls_node_mapping_t; + +/*! + * Get a pointer to the node mapping table. + * The table length will be set to *length. + */ +const ls_node_mapping_t *link_state_route_get_node_mapping(size_t *length); + +#endif /* INCLUDED_LINK_STATE_ROUTE_PROTO_H */ diff --git a/firmware/usrp3/include/mdelay.h b/firmware/usrp3/include/mdelay.h new file mode 100644 index 000000000..226bbb3f7 --- /dev/null +++ b/firmware/usrp3/include/mdelay.h @@ -0,0 +1,29 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_MDELAY_H +#define INCLUDED_MDELAY_H + +/*! + * \brief Delay about ms milliseconds + * + * If simulating, _very_ short delay + */ +void mdelay(int ms); + +#endif /* INCLUDED_MDELAY_H */ diff --git a/firmware/usrp3/include/print_addrs.h b/firmware/usrp3/include/print_addrs.h new file mode 100644 index 000000000..1aa5d6888 --- /dev/null +++ b/firmware/usrp3/include/print_addrs.h @@ -0,0 +1,15 @@ +// Copyright 2013 Ettus Research LLC + +#ifndef INCLUDED_PRINT_ADDRS_H +#define INCLUDED_PRINT_ADDRS_H + +char *mac_addr_to_str_r(const void *addr, char *str); +char *ip_addr_to_str_r(const void *addr, char *str); + +char *mac_addr_to_str(const void *addr); +char *ip_addr_to_str(const void *addr); + +//void print_mac_addr(const void *addr); +//void print_ip_addr(const void *addr); + +#endif /* INCLUDED_PRINT_ADDRS_H */ diff --git a/firmware/usrp3/include/printf.h b/firmware/usrp3/include/printf.h new file mode 100644 index 000000000..6b3088dbe --- /dev/null +++ b/firmware/usrp3/include/printf.h @@ -0,0 +1,108 @@ +/* +File: printf.h + +Copyright (C) 2004  Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   +See the GNU Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +This library is realy just two files: 'printf.h' and 'printf.c'. + +They provide a simple and small (+200 loc) printf functionality to  +be used in embedded systems. + +I've found them so usefull in debugging that I do not bother with a  +debugger at all. + +They are distributed in source form, so to use them, just compile them  +into your project.  + +Two printf variants are provided: printf and sprintf.  + +The formats supported by this implementation are: 'd' 'u' 'c' 's' 'x' 'X'. + +Zero padding and field width are also supported. + +If the library is compiled with 'PRINTF_SUPPORT_LONG' defined then the  +long specifier is also +supported. Note that this will pull in some long math routines (pun intended!) +and thus make your executable noticably longer. + +The memory foot print of course depends on the target cpu, compiler and  +compiler options, but a rough guestimate (based on a H8S target) is about  +1.4 kB for code and some twenty 'int's and 'char's, say 60 bytes of stack space.  +Not too bad. Your milage may vary. By hacking the source code you can  +get rid of some hunred bytes, I'm sure, but personally I feel the balance of  +functionality and flexibility versus  code size is close to optimal for +many embedded systems. + +To use the printf you need to supply your own character output function,  +something like : + +	void putc ( void* p, char c) +		{ +		while (!SERIAL_PORT_EMPTY) ; +		SERIAL_PORT_TX_REGISTER = c; +		} + +Before you can call printf you need to initialize it to use your  +character output function with something like: + +	init_printf(NULL,putc); + +Notice the 'NULL' in 'init_printf' and the parameter 'void* p' in 'putc',  +the NULL (or any pointer) you pass into the 'init_printf' will eventually be  +passed to your 'putc' routine. This allows you to pass some storage space (or  +anything realy) to the character output function, if necessary.  +This is not often needed but it was implemented like that because it made  +implementing the sprintf function so neat (look at the source code). + +The code is re-entrant, except for the 'init_printf' function, so it  +is safe to call it from interupts too, although this may result in mixed output.  +If you rely on re-entrancy, take care that your 'putc' function is re-entrant! + +The printf and sprintf functions are actually macros that translate to  +'tfp_printf' and 'tfp_sprintf'. This makes it possible +to use them along with 'stdio.h' printf's in a single source file.  +You just need to undef the names before you include the 'stdio.h'. +Note that these are not function like macros, so if you have variables +or struct members with these names, things will explode in your face. +Without variadic macros this is the best we can do to wrap these +fucnction. If it is a problem just give up the macros and use the +functions directly or rename them. + +For further details see source code. + +regs Kusti, 23.10.2004 +*/ + + +#ifndef __TFP_PRINTF__ +#define __TFP_PRINTF__ + +#include <stdarg.h> + +void init_printf(void* putp,void (*putf) (void*,char)); + +void tfp_printf(char *fmt, ...); +void tfp_sprintf(char* s,char *fmt, ...); + +void tfp_format(void* putp,void (*putf) (void*,char),char *fmt, va_list va); + +#define printf tfp_printf  +#define sprintf tfp_sprintf  +#define PRINTF_LONG_SUPPORT 1 +//#define PRINTF_LONG_LONG_SUPPORT 1 //IJB gcc for ZPU long long appears to have bugs + +#endif diff --git a/firmware/usrp3/include/stdint.h b/firmware/usrp3/include/stdint.h new file mode 100644 index 000000000..b5a8611a9 --- /dev/null +++ b/firmware/usrp3/include/stdint.h @@ -0,0 +1,34 @@ +/* -*- c -*- */ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_STDINT_H +#define INCLUDED_STDINT_H + +typedef signed char	int8_t; +typedef unsigned char	uint8_t; +typedef short		int16_t; +typedef unsigned short	uint16_t; +typedef int		int32_t; +typedef unsigned int	uint32_t; +typedef long long int		int64_t; +typedef unsigned long long int	uint64_t; + +typedef int		intptr_t; +typedef unsigned int	uintptr_t; + +#endif /* INCLUDED_STDINT_H */ diff --git a/firmware/usrp3/include/u3_net_stack.h b/firmware/usrp3/include/u3_net_stack.h new file mode 100644 index 000000000..cbf714e20 --- /dev/null +++ b/firmware/usrp3/include/u3_net_stack.h @@ -0,0 +1,113 @@ + +// Copyright 2012-2013 Ettus Research LLC + +#ifndef INCLUDED_U3_NET_STACK_H +#define INCLUDED_U3_NET_STACK_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> +#include <wb_pkt_iface64.h> + +//---------------------------------------------------------------------- + +#include <lwip/ip_addr.h> +#include <lwip/ip.h> +#include <lwip/udp.h> +#include <lwip/icmp.h> +#include <if_arp.h> +#include <ethertype.h> + +typedef struct +{ +    uint8_t addr[6]; +} eth_mac_addr_t; + +typedef struct +{ +    uint8_t ethno; +    uint8_t pad[5]; +    eth_mac_addr_t dst; +    eth_mac_addr_t src; +    uint16_t ethertype; +} padded_eth_hdr_t; + +//------------------ init stuff ------------------------------------ + +void u3_net_stack_init(wb_pkt_iface64_config_t *config); + +void u3_net_stack_init_eth(const uint8_t ethno, const eth_mac_addr_t *mac, const struct ip_addr *ip, const struct ip_addr *subnet); + +const struct ip_addr *u3_net_stack_get_ip_addr(const uint8_t ethno); + +const struct ip_addr *u3_net_stack_get_subnet(const uint8_t ethno); + +const struct ip_addr *u3_net_stack_get_bcast(const uint8_t ethno); + +const eth_mac_addr_t *u3_net_stack_get_mac_addr(const uint8_t ethno); + +uint32_t u3_net_stack_get_stat_counts(const uint8_t ethno); + +//------------------ udp handling ------------------------------------ + +typedef void (*u3_net_stack_udp_handler_t)( +    const uint8_t, +    const struct ip_addr *, const struct ip_addr *, +    const uint16_t, const uint16_t, +    const void *, const size_t +); + +void u3_net_stack_register_udp_handler( +    const uint16_t port, +    const u3_net_stack_udp_handler_t handler +); + +void u3_net_stack_send_udp_pkt( +    const uint8_t ethno, +    const struct ip_addr *dst, +    const uint16_t src_port, +    const uint16_t dst_port, +    const void *buff, +    const size_t num_bytes +); + +//------------------ icmp handling ------------------------------------ + +typedef void (*u3_net_stack_icmp_handler_t)( +    const uint8_t, +    const struct ip_addr *, const struct ip_addr *, +    const uint16_t, const uint16_t, +    const void *, const size_t +); + +void u3_net_stack_register_icmp_handler( +    const uint8_t type, +    const uint8_t code, +    const u3_net_stack_icmp_handler_t handler +); + +void u3_net_stack_send_icmp_pkt( +    const uint8_t ethno, +    const uint8_t type, +    const uint8_t code, +    const uint16_t id, +    const uint16_t seq, +    const struct ip_addr *dst, +    const void *buff, +    const size_t num_bytes +); + +//------------------ entry point ------------------------------------ + +void u3_net_stack_handle_one(void); + +//------------------ arp handling ------------------------------------ + +void u3_net_stack_send_arp_request(const uint8_t ethno, const struct ip_addr *addr); + +//commented out to make private - do we need cache update outside this module? +//void u3_net_stack_arp_cache_update(const struct ip_addr *ip_addr, const eth_mac_addr_t *mac_addr, const uint8_t ethno); + +const eth_mac_addr_t *u3_net_stack_arp_cache_lookup(const struct ip_addr *ip_addr); + +#endif /* INCLUDED_U3_NET_STACK_H */ diff --git a/firmware/usrp3/include/udp_uart.h b/firmware/usrp3/include/udp_uart.h new file mode 100644 index 000000000..4a33a9299 --- /dev/null +++ b/firmware/usrp3/include/udp_uart.h @@ -0,0 +1,37 @@ +/* + * Copyright 2011-2013 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef INCLUDED_UDP_UART_H +#define INCLUDED_UDP_UART_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +/*! + * Initialize the UDP/UART module. + * Registers handler into the network. + */ +void udp_uart_init(const uint32_t uart_base, const uint16_t udp_port); + +/*! + * Polls the UART state machine, + * and sends messages over UDP. + */ +void udp_uart_poll(void); + +#endif /* INCLUDED_UDP_UART_H */ diff --git a/firmware/usrp3/include/wb_i2c.h b/firmware/usrp3/include/wb_i2c.h new file mode 100644 index 000000000..cb307f373 --- /dev/null +++ b/firmware/usrp3/include/wb_i2c.h @@ -0,0 +1,18 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_WB_I2C_H +#define INCLUDED_WB_I2C_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +void wb_i2c_init(const uint32_t base, const size_t clk_rate); + +bool wb_i2c_read(const uint32_t base, const uint8_t i2c_addr, uint8_t *buf, size_t len); + +bool wb_i2c_write(const uint32_t base, const uint8_t i2c_addr, const uint8_t *buf, size_t len); + + +#endif /* INCLUDED_WB_I2C_H */ diff --git a/firmware/usrp3/include/wb_pkt_iface64.h b/firmware/usrp3/include/wb_pkt_iface64.h new file mode 100644 index 000000000..aa3c174ed --- /dev/null +++ b/firmware/usrp3/include/wb_pkt_iface64.h @@ -0,0 +1,44 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_WB_PKT_IFACE64_H +#define INCLUDED_WB_PKT_IFACE64_H + +#include <stdint.h> +#include <stddef.h> +#include <stdbool.h> + +//! opaque, dont touch insides +typedef struct +{ +    uint32_t base; +    uint32_t ctrl; +    uint32_t config_addr; +} wb_pkt_iface64_config_t; + +//! Init the wb slave for packet interface +wb_pkt_iface64_config_t wb_pkt_iface64_init(const uint32_t base, const size_t ctrl_offset); + +/*! + * Poll if an packet has been received. + * If yes, return the pointer to the pkt, num_bytes is set. + * Otherwise, return null. + */ +const void *wb_pkt_iface64_rx_try_claim(wb_pkt_iface64_config_t *config, size_t *num_bytes); + +/*! + * Release the hold on a received packet. + */ +void wb_pkt_iface64_rx_release(wb_pkt_iface64_config_t *config); + +/*! + * Aquire the buffer for an outgoing packet. + */ +void *wb_pkt_iface64_tx_claim(wb_pkt_iface64_config_t *config); + +/*! + * Submit an outgoing packet from a filled the buffer. + */ +void wb_pkt_iface64_tx_submit(wb_pkt_iface64_config_t *config, const size_t num_bytes); + +#endif /* INCLUDED_WB_PKT_IFACE64_H */ diff --git a/firmware/usrp3/include/wb_uart.h b/firmware/usrp3/include/wb_uart.h new file mode 100644 index 000000000..46dd97441 --- /dev/null +++ b/firmware/usrp3/include/wb_uart.h @@ -0,0 +1,23 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_WB_UART_H +#define INCLUDED_WB_UART_H + +#include <stdint.h> +#include <stdbool.h> +#include <stddef.h> + +//! Init the uart in question +void wb_uart_init(const uint32_t base, const size_t div); + +//! Put character blocking +void wb_uart_putc(const uint32_t base, const int ch); + +//! Put character not blocking - false for fail +bool wb_uart_try_putc(const uint32_t base, const int ch); + +//! Get character non blocking, -1 for none +int wb_uart_getc(const uint32_t base); + +#endif /* INCLUDED_WB_UART_H */ diff --git a/firmware/usrp3/include/wb_utils.h b/firmware/usrp3/include/wb_utils.h new file mode 100644 index 000000000..34be51b8f --- /dev/null +++ b/firmware/usrp3/include/wb_utils.h @@ -0,0 +1,24 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_WB_UTILS_H +#define INCLUDED_WB_UTILS_H + +#include <stdint.h> + +#define localparam static const int + +static inline void wb_poke32(const uint32_t addr, const uint32_t data) +{ +    *((volatile uint32_t *)addr) = data; +} + +static inline uint32_t wb_peek32(const uint32_t addr) +{ +    const uint32_t data = *((volatile uint32_t *)addr); +    return data; +} + +#define SR_ADDR(base, offset) ((base) + (offset)*4) + +#endif /* INCLUDED_WB_UTILS_H */ diff --git a/firmware/usrp3/include/xge_mac.h b/firmware/usrp3/include/xge_mac.h new file mode 100644 index 000000000..d288bdd8d --- /dev/null +++ b/firmware/usrp3/include/xge_mac.h @@ -0,0 +1,37 @@ + +#ifndef INCLUDED_XGE_MAC_H +#define INCLUDED_XGE_MAC_H + +#define HAVE_OPENCORES_XGEMAC 1 + +#ifdef HAVE_OPENCORES_XGEMAC +#define XGE_TX_ENABLE    (1 << 0)         // Set to enable transmission. +// Interupt register bits. +#define XGE_RX_FRAG_ERR  (1 << 8) +#define XGE_RX_CRC_ERR   (1 << 7) +#define XGE_RX_PAUSE     (1 << 6) +#define XGE_REMOTE_FAULT (1 << 5) +#define XGE_LOCAL_FAULT  (1 << 4) +#define XGE_RX_UNDERFLOW (1 << 3) +#define XGE_RX_OVERFLOW  (1 << 2) +#define XGE_TX_UNDERFLOW (1 << 1) +#define XGE_TX_OVERFLOW  (1 << 0) +#endif + +// MDIO OP +#define XGE_MDIO_CLAUSE(n) ((n & 0x1) << 12) +#define CLAUSE45 1 +#define CLAUSE22 0 +#define XGE_MDIO_OP(n)     ((n & 0x3) << 10) +#define MDIO_ADDRESS 0 +#define MDIO_WRITE 1 +#define MDIO_READ 3 +#define MDIO_C22_WRITE 2 +#define MDIO_C22_READ 1 +#define MDIO_READ_POST 2 +#define XGE_MDIO_ADDR(n)   ((n & 0x1f) << 5) +#define XGE_MDIO_MMD(n)    ((n & 0x1f) << 0) + +#endif + + diff --git a/firmware/usrp3/include/xge_phy.h b/firmware/usrp3/include/xge_phy.h new file mode 100644 index 000000000..eeb94753e --- /dev/null +++ b/firmware/usrp3/include/xge_phy.h @@ -0,0 +1,78 @@ + +#ifndef INCLUDED_XGE_PHY_H +#define INCLUDED_XGE_PHY_H + +#define HAVE_AEL2005_PHY 1 + +// +// IEEE 802.3ae Clause 45 managable device types (DEVAD) +// +#define XGE_MDIO_DEVICE_PMA 1 +#define XGE_MDIO_DEVICE_WIS 2 +#define XGE_MDIO_DEVICE_PCS 3 +#define XGE_MDIO_DEVICE_PHY_XS 4 +#define XGE_MDIO_DEVICE_DTE_XS 5 +#define XGE_MDIO_DEVICE_TC 6 + +// +// IEEE 802.3ae Clause 45 register set for MDIO +// +#define XGE_MDIO_CONTROL1 0 +#define XGE_MDIO_STATUS1 1 +#define XGE_MDIO_DEVID1 2 +#define XGE_MDIO_DEVID2 3 +#define XGE_MDIO_SPEED 4 +#define XGE_MDIO_DEVICES1 5 +#define XGE_MDIO_DEVICES2 6 +#define XGE_MDIO_CONTROL2 7 +#define XGE_MDIO_STATUS2 8 +#define XGE_MDIO_LANESTATUS 24 +#define XGE_MDIO_TESTCTRL 25 +#define XILINX_CORE_VERSION 65535 + +// +// QR2 AEL2005 Phy address on MDIO (PORT ADDR) +// +#define XGE_MDIO_ADDR_PHY_A 0 + +// +// QR2 MDIO address of FPGA XAUI (DTE XS) (PORT ADDR) +// +#define XGE_MDIO_ADDR_XAUI_A 2 + +// +// ID's for all XGE interfaces +#define XGE_A 0 + +// PHY module types  +enum { +  SFFP_TYPE_NONE, +  SFFP_TYPE_SR, +  SFFP_TYPE_LR, +  SFFP_TYPE_LRM, +  SFFP_TYPE_TWINAX, +  SFFP_TYPE_TWINAX_LONG, +  SFFP_TYPE_UNKNOWN, +  SFFP_TYPE_1000BASE_SX, +  SFFP_TYPE_1000BASE_LX, +  SFFP_TYPE_1000BASE_T +}; + +// PHY module I2C device address  +// (I2C device driver shifts "7bit" address left 1 bit) +// SFF-8431 specifys the I2C address as 8 bits with lSB as X +enum { +  MODULE_DEV_ADDR = (0xa0 >> 1), +  SFF_DEV_ADDR    = (0xa2 >>1), +}; + +// SFPP module status +enum { +  SFFP_NO_CHANGE, +  SFFP_REMOVED, +  SFFP_INSERTED +}; + +#endif + + diff --git a/firmware/usrp3/lib/CMakeLists.txt b/firmware/usrp3/lib/CMakeLists.txt new file mode 100644 index 000000000..621b9b611 --- /dev/null +++ b/firmware/usrp3/lib/CMakeLists.txt @@ -0,0 +1,32 @@ +# +# Copyright 2010-2013 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## + +add_library(usrp3fw STATIC +    udp_uart.c +    wb_uart.c +    wb_i2c.c +    printf.c +    wb_pkt_iface64.c +    u3_net_stack.c +    ethernet.c +    mdelay.c +    chinch.c +    print_addrs.c +    link_state_route_proto.c +) diff --git a/firmware/usrp3/lib/chinch.c b/firmware/usrp3/lib/chinch.c new file mode 100644 index 000000000..e33378851 --- /dev/null +++ b/firmware/usrp3/lib/chinch.c @@ -0,0 +1,313 @@ +// +// Copyright 2013 Ettus Research LLC +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program.  If not, see <http://www.gnu.org/licenses/>. +// + +#include "chinch.h" + +#define PCIE_MSG_REG_BASE   0xFB00 +#define PCIE_MSG_DATA_REG   0 //Write: Data register for outbound requests and responses +                              //Read:  Latched data for inbound requests +#define PCIE_MSG_CTRL_REG   1 //Write: Control register for outbound requests and responses (Initiates xfer) +                              //Read:  Latched control word for inbound requests +#define PCIE_MSG_RESP_REG   2 //Read:  Latched response data for outbound requests +#define PCIE_MSG_STATUS_REG 3 //Read:  Status register for inbound and outbound transactions + +// Transaction Word Format +// +// -Control- --Data-- +// 63     32 31      0 +// |       | |       | +// FXXA AAAA DDDD DDDD +// +// where: +// D = Data/Payload +// A = Address +// X = Reserved +// F = Flags: {Read_Response, Write_Request, Read_Request, Half_Word_Cycle} + +#define PCIE_CTRL_REG_READ_RESP         (1<<31) +#define PCIE_CTRL_REG_WRITE             (1<<30) +#define PCIE_CTRL_REG_READ              (1<<29) +#define PCIE_CTRL_REG_HALF_WORD         (1<<28) +#define PCIE_CTRL_REG_ADDR_MASK         0x000FFFFF + +#define PCIE_STATUS_REG_READ_PENDING    (1<<0) +#define PCIE_STATUS_REG_REQ_PENDING     (1<<1) +#define PCIE_STATUS_REG_RESP_PENDING    (1<<2) +#define PCIE_STATUS_REG_BUSY            (1<<4) + +#define CHINCH_FPGA_CONFIG_REG          0x58 +#define CHINCH_FLASH_WINDOW_REG0        0xC0 +#define CHINCH_FLASH_WINDOW_REG1        0xE0 +#define CHINCH_FLASH_2AAA_REG           0x400 +#define CHINCH_FLASH_5555_REG           0x408 +#define CHINCH_FLASH_WINDOW_BASE        0x60000 +#define CHINCH_FLASH_WINDOW_SIZE        0x20000 +#define CHINCH_FLASH_WINDOW_CONF        0x91 + +//----------------------------------------------------- +// Peek-Poke interface +//----------------------------------------------------- + +bool chinch_poke( +    const uint32_t addr, +    const uint32_t data, +    bool half_word, +    uint32_t timeout +) +{ +    //Build transaction control word +    uint32_t ctrl_word = 0, i; +    ctrl_word |= (addr & PCIE_CTRL_REG_ADDR_MASK); +    if (half_word) ctrl_word |= PCIE_CTRL_REG_HALF_WORD; +    ctrl_word |= PCIE_CTRL_REG_WRITE; + +    //Wait for space in the transaction queue or timeout +    i = 0; +    while ((wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_STATUS_REG)) & PCIE_STATUS_REG_BUSY) != 0) { +        if (++i > timeout) return false; +    } + +    //Flush transaction control and data registers +    wb_poke32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_DATA_REG), data); +    wb_poke32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_CTRL_REG), ctrl_word); + +    return true; +} + +bool chinch_peek( +    const uint32_t addr, +    uint32_t* data, +    bool half_word, +    uint32_t timeout +) +{ +    //Build transaction control word +    uint32_t ctrl_word = 0, i; +    ctrl_word |= (addr & PCIE_CTRL_REG_ADDR_MASK); +    if (half_word) ctrl_word |= PCIE_CTRL_REG_HALF_WORD; +    ctrl_word |= PCIE_CTRL_REG_READ; + +    //Wait for space in the transaction queue or timeout +    i = 0; +    while ((wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_STATUS_REG)) & PCIE_STATUS_REG_BUSY) != 0) { +        if (++i > timeout) return false; +    } + +    //Flush transaction control register +    if (data) *data = 0; +    wb_poke32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_CTRL_REG), ctrl_word); + +    //Wait for read completion or timeout +    i = 0; +    while ((wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_STATUS_REG)) & PCIE_STATUS_REG_READ_PENDING) != 0) { +        if (++i > timeout) return false; +    } +    //Read transaction data register +    if (data) *data = wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_RESP_REG)); +    return true; +} + +//----------------------------------------------------- +// Flash access +//----------------------------------------------------- + +uint32_t    g_cached_win_reg0; +uint32_t    g_cached_win_reg1; + +bool chinch_flash_init() +{ +    chinch_peek32(CHINCH_FLASH_WINDOW_REG0, &g_cached_win_reg0); +    chinch_peek32(CHINCH_FLASH_WINDOW_REG1, &g_cached_win_reg1); + +    bool status = true, passed = true; +    STATUS_MERGE(chinch_poke32(CHINCH_FLASH_WINDOW_REG0, CHINCH_FLASH_WINDOW_BASE | CHINCH_FLASH_WINDOW_CONF), status); + +    //Run a loopback test to ensure that we will not corrupt the flash. +    STATUS_MERGE(chinch_poke32(0x200, 0xDEADBEEF), status); +    STATUS_MERGE(chinch_poke16(0x204, 0x5678), status); +    uint32_t reg_val; +    STATUS_MERGE(chinch_peek16(0x0, ®_val), status); +    STATUS_MERGE(chinch_poke16(0x206, reg_val), status); +    STATUS_MERGE(chinch_peek32(0x200, ®_val), status); +    passed &= (reg_val == 0xDEADBEEF); +    STATUS_MERGE(chinch_peek32(0x204, ®_val), status); +    passed &= (reg_val == 0x7AD05678); + +    return status && passed; +} + +void chinch_flash_cleanup() +{ +    chinch_poke32(CHINCH_FLASH_WINDOW_REG0, g_cached_win_reg0); +    chinch_poke32(CHINCH_FLASH_WINDOW_REG1, g_cached_win_reg1); +} + +bool chinch_flash_select_sector(uint32_t sector) +{ +    return chinch_poke32(CHINCH_FLASH_WINDOW_REG1, sector * CHINCH_FLASH_WINDOW_SIZE); +} + +bool chinch_flash_erase_sector() +{ +    bool status = true; +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_5555_REG,    0x00AA), status);    //Unlock #1 +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_2AAA_REG,    0x0055), status);    //Unlock #2 +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_5555_REG,    0x0080), status);    //Setup +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_5555_REG,    0x00AA), status);    //Unlock #1 +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_2AAA_REG,    0x0055), status);    //Unlock #2 +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_WINDOW_BASE, 0x0030), status);    //Erase + +    if (status) { +        uint32_t read_data; +        while (true) { +            status = chinch_peek16(CHINCH_FLASH_WINDOW_BASE, &read_data);    //Wait for sector to erase +            if (((read_data & 0xFFFF) == 0xFFFF) || !status) break; +        } +    } +    return status; +} + +bool chinch_flash_read_buf(uint32_t offset, uint16_t* buf, uint32_t size) +{ +    bool status = true; +    uint32_t base_addr = CHINCH_FLASH_WINDOW_BASE | (offset & 0x3FFFF); +    for (uint32_t i = 0; (i < size) && status; i++) { +        uint32_t word; +        STATUS_CHAIN(chinch_peek16(base_addr + (i * 2), &word), status); +        buf[i] = (uint16_t)word; +    } +    return status; +} + +bool chinch_flash_write_buf(uint32_t offset, uint16_t* buf, uint32_t size) +{ +    if (size > CHINCH_FLASH_MAX_BUF_WRITES || buf == 0) return false; +    bool status = true; + +    //Setup buffered write +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_5555_REG,    0x00AA), status);      //Unlock #1 +    STATUS_MERGE(chinch_poke16(CHINCH_FLASH_2AAA_REG,    0x0055), status);      //Unlock #2 +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_WINDOW_BASE, 0x0025), status);      //Setup write +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_WINDOW_BASE, size - 1), status);    //Num words + +    //Write the data +    uint32_t base_addr = CHINCH_FLASH_WINDOW_BASE | (offset & 0x3FFFF); +    for (uint32_t i = 0; i < size; i++) { +        STATUS_CHAIN(chinch_poke16(base_addr + (i * 2), buf[i]), status); +    } + +    //Commit write +    STATUS_CHAIN(chinch_poke16(CHINCH_FLASH_WINDOW_BASE, 0x0029), status); + +    //Poll for completion +    //Bit 7 of the data at the final address is the status bit. +    //It is set to the inverse of bit 7 of the final data to be +    //written until the final write is completed. +    uint32_t read_data; +    do { +        STATUS_MERGE(chinch_peek16(base_addr + ((size - 1) * 2), &read_data), status); +    } while (status && (((uint16_t)read_data ^ buf[size - 1]) & (1 << 7))); + +    return status; +} + +//----------------------------------------------------- +// FPGA Configuration +//----------------------------------------------------- +void chinch_start_config() +{ +    chinch_poke32(CHINCH_FPGA_CONFIG_REG, 0x1); +} + +config_status_t chinch_get_config_status() +{ +    bool status = true; +    uint32_t read_data; +    STATUS_MERGE(chinch_peek32(CHINCH_FPGA_CONFIG_REG, &read_data), status); +    return status ? (config_status_t)read_data : CHINCH_CONFIG_ERROR; +} + +//----------------------------------------------------- +// Read-back interface for the user initiated +// PCIe register transactions +//----------------------------------------------------- +pcie_register_xact_t    g_pcie_reg_xact_info; +uint32_t                g_pcie_res_timeout; + +bool _respond_to_pcie_xact_request(uint32_t response, uint32_t timeout) +{ +    //Wait for space in the transaction queue or timeout +    uint32_t i = 0; +    while ((wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_STATUS_REG)) & PCIE_STATUS_REG_BUSY) != 0) { +        if (++i > g_pcie_res_timeout) return false; +    } + +    //First write data and then the control register to ensure coherency +    wb_poke32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_DATA_REG), response); +    wb_poke32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_CTRL_REG), PCIE_CTRL_REG_READ_RESP); + +    return true; +} + +bool check_pcie_user_regport(pcie_register_xact_t** xact_info_hdl) +{ +    //Check for pending transaction requests +    if ((wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_STATUS_REG)) & PCIE_STATUS_REG_REQ_PENDING) != 0) { +        //Attach responder to transaction info +        g_pcie_reg_xact_info.respond = _respond_to_pcie_xact_request; + +        //First read data and then the control register to ensure coherency +        g_pcie_reg_xact_info.data = wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_DATA_REG)); +        uint32_t xact_control = wb_peek32(SR_ADDR(PCIE_MSG_REG_BASE, PCIE_MSG_CTRL_REG)); + +        g_pcie_reg_xact_info.addr = xact_control & PCIE_CTRL_REG_ADDR_MASK; +        g_pcie_reg_xact_info.size = +            (xact_control & PCIE_CTRL_REG_HALF_WORD) == 0 ? PCIE_XACT_32_BIT : PCIE_XACT_16_BIT; +        if ((xact_control & PCIE_CTRL_REG_READ) != 0) +            g_pcie_reg_xact_info.type = PCIE_XACT_READ; +        else if ((xact_control & PCIE_CTRL_REG_WRITE) != 0) +            g_pcie_reg_xact_info.type = PCIE_XACT_WRITE; +        else +            g_pcie_reg_xact_info.type = PCIE_XACT_ERROR; + +        *xact_info_hdl = &g_pcie_reg_xact_info; +        return true; +    } else { +        *xact_info_hdl = 0; +        return false; +    } +} + +bool forward_pcie_user_xact_to_wb() +{ +    pcie_register_xact_t* xact_info; +    if (check_pcie_user_regport(&xact_info)) { +        if (xact_info->size == PCIE_XACT_32_BIT) { +            //Only respond to 32-bit transactions because that is all the LVFPGA interface can send +            if (xact_info->type == PCIE_XACT_WRITE) { +                wb_poke32(xact_info->addr, xact_info->data); +                return true; +            } else if (xact_info->type == PCIE_XACT_READ) { +                return xact_info->respond(wb_peek32(xact_info->addr), CHINCH_DEFAULT_XACT_TIMEOUT); +            } +        } +    } +    return false; +} + + + diff --git a/firmware/usrp3/lib/ethernet.c b/firmware/usrp3/lib/ethernet.c new file mode 100644 index 000000000..7a86980c7 --- /dev/null +++ b/firmware/usrp3/lib/ethernet.c @@ -0,0 +1,644 @@ +/* + * Copyright 2007,2009 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#include "../x300/x300_defs.h" +#include "ethernet.h" +#include "mdelay.h" +#include "printf.h" +#include "wb_i2c.h" +#include "wb_utils.h" +//#include "memory_map.h" +//#include "eth_phy.h" +//#include "pic.h" +//#include "hal_io.h" +//#include "nonstdio.h" +#include <stdint.h> +#include <stdbool.h> +#include "xge_phy.h" +#include "xge_mac.h" +#include <u3_net_stack.h> + + + + +#define VERBOSE 0 + +#define	NETHS	2	// # of ethernet interfaces + +static bool links_up[NETHS] = {}; + +//////////////////////////////////////////////////////////////////////// +// +// 10 Gig Ethernet MAC. +// +typedef struct { +  volatile uint32_t config;             // WO +  volatile uint32_t int_pending;        // Clear-on-read +  volatile uint32_t int_status;         // RO +  volatile uint32_t int_mask;           // RW +  volatile uint32_t mdio_data; +  volatile uint32_t mdio_addr; +  volatile uint32_t mdio_op; +  volatile uint32_t mdio_control; +  volatile uint32_t gpio; +} xge_regs_t; + +#define xge_regs ((xge_regs_t *) base) + +#define SFPP_STATUS_MODABS_CHG     (1 << 5)    // Has MODABS changed since last read? +#define SFPP_STATUS_TXFAULT_CHG    (1 << 4)    // Has TXFAULT changed since last read? +#define SFPP_STATUS_RXLOS_CHG      (1 << 3)    // Has RXLOS changed since last read? +#define SFPP_STATUS_MODABS         (1 << 2)    // MODABS state +#define SFPP_STATUS_TXFAULT        (1 << 1)    // TXFAULT state +#define SFPP_STATUS_RXLOS          (1 << 0)    // RXLOS state + + +int +ethernet_ninterfaces(void) +{ +  return NETHS; +} + +//////////////////////////////////////////////////////////////////////// +// +// Clause 45 MDIO used for 10Gig Ethernet has two bus transactions to complete a transfer. +// An initial transaction sets up the address, and a subsequent one transfers the read or write data. +// +static uint32_t +xge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port) +{ +  // Set register address each iteration +  xge_regs->mdio_addr = address; +  // Its a clause 45 device. We want to ADDRESS +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_ADDRESS) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +  // Its a clause 45 device. We want to READ +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_READ) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +  // Read MDIO data +  return(xge_regs->mdio_data); +} + +static void +xge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t device, const uint32_t port, const uint32_t data) +{ +  // Set register address each iteration +  xge_regs->mdio_addr = address; +  // Its a clause 45 device. We want to ADDRESS +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_ADDRESS) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +  // Write new value to mdio_write_data reg. +  xge_regs->mdio_data = data; +  // Its a clause 45 device. We want to WRITE +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE45) | XGE_MDIO_OP(MDIO_WRITE) | XGE_MDIO_ADDR(port) | XGE_MDIO_MMD(device); +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +} + +//////////////////////////////////////////////////////////////////////// +// +// Clause 22 MDIO used for 1Gig Ethernet has one bus transaction to complete a transfer. +// +static uint32_t +ge_read_mdio(const uint32_t base, const uint32_t address, const uint32_t port) +{ +  // Its a clause 22 device. We want to READ +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE22) | XGE_MDIO_OP(MDIO_C22_READ) | XGE_MDIO_ADDR(port) | address; +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +  // Read MDIO data +  return(xge_regs->mdio_data); +} + +static void +ge_write_mdio(const uint32_t base, const uint32_t address, const uint32_t port, const uint32_t data) +{ +  // Write new value to mdio_write_data reg. +  xge_regs->mdio_data = data; +  // Its a clause 22 device. We want to WRITE +  xge_regs->mdio_op = XGE_MDIO_CLAUSE(CLAUSE22) | XGE_MDIO_OP(MDIO_C22_WRITE) | XGE_MDIO_ADDR(port) | address; +  // Start MDIO bus transaction +  xge_regs->mdio_control = 1; +  // Wait until bus transaction complete +  while (xge_regs->mdio_control == 1); +} + +//////////////////////////////////////////////////////////////////////// +// +// Read and write MDIO independent of type +// + +static uint32_t read_mdio(const uint8_t eth, const uint32_t address, const uint32_t device, const uint32_t port) +{ +    const uint32_t rb_addr = (eth==0) ? RB_ETH_TYPE0 : RB_ETH_TYPE1; +    const uint32_t base = (eth==0) ? XGE0_BASE : XGE1_BASE; +    if (wb_peek32(SR_ADDR(RB0_BASE, rb_addr)) != 0) +    { +        return xge_read_mdio(base, address, device, port); +    } +    else +    { +        return ge_read_mdio(base, address, port); +    } +} + +static void write_mdio(const uint8_t eth, const uint32_t address, const uint32_t device, const uint32_t port, const uint32_t data) +{ +    const uint32_t rb_addr = (eth==0) ? RB_ETH_TYPE0 : RB_ETH_TYPE1; +    const uint32_t base = (eth==0) ? XGE0_BASE : XGE1_BASE; +    if (wb_peek32(SR_ADDR(RB0_BASE, rb_addr)) != 0) +    { +        return xge_write_mdio(base, address, device, port, data); +    } +    else +    { +        return ge_write_mdio(base, address, port, data); +    } +} + +//////////////////////////////////////////////////////////////////////// +// +// Read an 8-bit word from a device attached to the PHY's i2c bus. +// +static int +xge_i2c_rd(const uint32_t base, const uint8_t i2c_dev_addr, const uint8_t i2c_word_addr) +{ +  uint8_t buf; +  // IJB. CHECK HERE FOR MODET. Bail immediately if no module + +  // SFF-8472 defines a hardcoded bus address of 0xA0, an 8bit internal address and a register map. +  // Write the random access address to the SPF module +  if (wb_i2c_write(base, i2c_dev_addr, &i2c_word_addr, 1) == false) +    return(-1); + +  // Now read back a byte of data +  if (wb_i2c_read(base, i2c_dev_addr, &buf, 1) == false) +    return(-1); + +  return((int) buf); +} + +//////////////////////////////////////////////////////////////////////// +// +// Read identity of SFP+ module for XGE PHY +// +// (base is i2c controller) +static int +xge_read_sfpp_type(const uint32_t base, const uint32_t delay_ms) +{ +  int x; + // Delay read of SFPP +  if (delay_ms) +    mdelay(delay_ms); +  // Read ID code from SFP +  x = xge_i2c_rd(base, MODULE_DEV_ADDR, 3); +  // I2C Error? +  if (x < 0) { +    printf("DEBUG: I2C error in SFPP_TYPE.\n"); +    return x; +    } +  // Decode module type. These registers and values are defined in SFF-8472 +  if (x & 0x01) // Active 1X Infinband Copper +    { +      goto twinax; +    } +  if (x & 0x10) +    { +      printf("DEBUG: SFFP_TYPE_SR.\n"); +      return SFFP_TYPE_SR; +    } +  if (x & 0x20) +    { +      printf("DEBUG: SFFP_TYPE_LR.\n"); +      return SFFP_TYPE_LR; +    } +  if (x & 0x40) +    { +      printf("DEBUG: SFFP_TYPE_LRM.\n"); +      return SFFP_TYPE_LRM; +    } +  // Search for legacy 1000-Base SFP types +  x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0x6); +  if (x < 0) { +    printf("DEBUG: I2C error in SFPP_TYPE.\n"); +    return x; +  } +  if (x & 0x01) { +    printf("DEBUG: SFFP_TYPE_1000BASE_SX.\n"); +    return SFFP_TYPE_1000BASE_SX; +  } +  if (x & 0x02) { +    printf("DEBUG: SFFP_TYPE_1000BASE_LX.\n"); +    return SFFP_TYPE_1000BASE_LX; +  } +  if (x & 0x08) { +    printf("DEBUG: SFFP_TYPE_1000BASE_T.\n"); +    return SFFP_TYPE_1000BASE_T; +  } +  // Not one of the standard optical types..now try to deduce if it's twinax aka 10GSFP+CU +  // which is not covered explicitly in SFF-8472 +  x = xge_i2c_rd(base, MODULE_DEV_ADDR, 8); +  if (x < 0) { +    printf("DEBUG: I2C error in SFPP_TYPE.\n"); +    return x; +  } +  if ((x & 4) == 0) // Passive SFP+ cable type +    goto unknown; +//  x = xge_i2c_rd(MODULE_DEV_ADDR, 6); +//   printf("SFP+ reg6 read as %x\n",x); +//  if (x < 0) +//    return x; +//  if (x != 0x04)  // Returns  1000Base-CX as Compliance code +//    goto unknown; +  x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0xA); +  if (x < 0) { +    printf("DEBUG: I2C error in SFPP_TYPE.\n"); +    return x; +  } +  if (x & 0x80) { +  twinax: +    // Reports 1200 MBytes/sec fibre channel speed..close enough to 10G ethernet! +    x = xge_i2c_rd(base, MODULE_DEV_ADDR, 0x12); + +    if (x < 0) { +      printf("DEBUG: I2C error in SFPP_TYPE.\n"); +      return x; +    } +    printf("DEBUG: TwinAx.\n"); +    // If cable length support is greater than 10M then pick correct type +    return x > 10 ? SFFP_TYPE_TWINAX_LONG : SFFP_TYPE_TWINAX; +  } +unknown: +  printf("DEBUG: Unknown SFP+ type.\n"); +  // Not a supported Module type +  return SFFP_TYPE_UNKNOWN; +} + + +// Pull  reset line low for 100ms then release and wait 100ms +static void +xge_hard_phy_reset(const uint32_t base) +{ +  wb_poke32(base, 1); +  mdelay(100); +  wb_poke32(base, 0); +  mdelay(100); + +} + +static void +xge_mac_init(const uint32_t base) +{ +  printf("INFO: Begining XGE MAC init sequence.\n"); +  xge_regs->config =  XGE_TX_ENABLE; +} + +// base is pointer to XGE MAC on Wishbone. +static void +xge_phy_init(const uint8_t eth, const uint32_t mdio_port) +{ +  int x; +  // Read LASI Ctrl register to capture state. +  //y = xge_read_mdio(0x9002,XGE_MDIO_DEVICE_PMA,XGE_MDIO_ADDR_PHY_A); +  printf("INFO: Begining XGE PHY init sequence.\n"); +  // Software reset +  x = read_mdio(eth, 0x0, XGE_MDIO_DEVICE_PMA,mdio_port); +  x = x | (1 << 15); +  write_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port,x); +  while(x&(1<<15)) +    x = read_mdio(eth, 0x0,XGE_MDIO_DEVICE_PMA,mdio_port); +} + +void +xge_poll_sfpp_status(const uint32_t eth) +{ +  uint32_t x; +  // Has MODDET/MODAbS changed since we last looked? +  x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); + +  if (x & SFPP_STATUS_RXLOS_CHG) +    printf("DEBUG: eth%1d RXLOS changed state: %d\n", eth, x & SFPP_STATUS_RXLOS); +  if (x & SFPP_STATUS_TXFAULT_CHG) +    printf("DEBUG: eth%1d TXFAULT changed state: %d\n", eth,(x & SFPP_STATUS_TXFAULT) >> 1 ); +  if (x & SFPP_STATUS_MODABS_CHG) +    printf("DEBUG: eth%1d MODABS changed state: %d\n", eth, (x & SFPP_STATUS_MODABS) >> 2); + +  if (x & (SFPP_STATUS_RXLOS_CHG|SFPP_STATUS_TXFAULT_CHG|SFPP_STATUS_MODABS_CHG)) +  { +    if (( x & (SFPP_STATUS_RXLOS|SFPP_STATUS_TXFAULT|SFPP_STATUS_MODABS)) == 0) +    { +      if (wb_peek32(SR_ADDR(RB0_BASE, eth == 0 ? RB_ETH_TYPE0 : RB_ETH_TYPE1)) == 1) +      { +        xge_ethernet_init(eth); +        dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); +        mdelay(100); +        dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); +        mdelay(100); +        dump_mdio_regs((eth==0) ? XGE0_BASE : XGE1_BASE,MDIO_PORT); +      } +    } +  } + +  if (x & SFPP_STATUS_MODABS_CHG) { +    // MODDET has changed state since last checked +    if (x & SFPP_STATUS_MODABS) { +      // MODDET is high, module currently removed. +      printf("INFO: An SFP+ module has been removed from eth port %d.\n", eth); +    } else { +      // MODDET is low, module currently inserted. +      // Return status. +      printf("INFO: A new SFP+ module has been inserted into eth port %d.\n", eth); +      xge_read_sfpp_type((eth==0) ? I2C0_BASE : I2C2_BASE,1); +    } +  } + +    //update the link up status +    const bool old_link_up = links_up[eth]; +    links_up[eth] = ((read_mdio(eth, XGE_MDIO_STATUS1,XGE_MDIO_DEVICE_PMA,MDIO_PORT)) & (1 << 2)) != 0; +    //The link became up, send a GARP so everyone knows our mac/ip association +    if (!old_link_up && links_up[eth]) u3_net_stack_send_arp_request(eth, u3_net_stack_get_ip_addr(eth)); +} + + +void +xge_ethernet_init(const uint32_t eth) +{ +  xge_mac_init((eth==0) ? XGE0_BASE : XGE1_BASE); + //xge_hard_phy_reset(); +  xge_phy_init(eth ,MDIO_PORT); +  uint32_t x = wb_peek32(SR_ADDR(RB0_BASE, (eth==0) ? RB_SFPP_STATUS0 : RB_SFPP_STATUS1 )); +  printf(" eth%1d SFP initial state: RXLOS: %d  TXFAULT: %d  MODABS: %d\n", +	 eth, +	 x & SFPP_STATUS_RXLOS, +	 (x & SFPP_STATUS_TXFAULT) >> 1, +	 (x & SFPP_STATUS_MODABS) >> 2); +} + +// +// Debug code to verbosely read XGE MDIO registers below here. +// + + +void decode_reg(uint32_t address, uint32_t device, uint32_t data) +{ +  int x; +  printf("Device: "); +  printf("%x",device); +  printf("  "); +  switch(address) { +  case XGE_MDIO_CONTROL1: +    printf("CONTROL1: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 15: printf("Reset,"); break; +	case 14: printf("Loopback,"); break; +	case 11: printf("Low Power Mode,"); break; +	case 5:case 4:case 3:case 2: printf("RESERVED speed value,"); break; +	case 0: printf("PMA loopback,"); break; +	} //else +	// Bits clear. +	//switch (x) { +	//case 13: case 6: printf(" None 10Gb/s speed set!"); break; +	//} +    printf(" \n"); +    break; +  case XGE_MDIO_STATUS1: +    printf("STATUS1: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 7: printf("Fault Detected,"); break; +	case 2: printf("Link is Up,"); break; +	case 1: printf("Supports Low Power,"); break; +	} else +	// Bits Clear +	switch(x) { +	case 2: printf("Link is Down,"); break; +	} +    printf(" \n"); +    break; +  case XGE_MDIO_SPEED: +    printf("SPEED ABILITY: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 15:case 14:case 13:case 12:case 11:case 10:case 9: +	case 8:case 7:case 6:case 5:case 4:case 3:case 2:case 1: printf("RESERVED bits set!,"); break; +	case 0: printf("Capable of 10Gb/s,"); +	} else +	// Bits clear. +	switch(x) { +	case 0: printf("Incapable of 10Gb/s,"); break; +	} +    printf(" \n"); +    break; +  case XGE_MDIO_DEVICES1: +    printf("DEVICES IN PACKAGE: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 7: printf("Auto-Negotiation,"); break; +	case 6: printf("TC,"); break; + 	case 5: printf("DTE XS,"); break; +	case 4: printf("PHY XS,"); break; +	case 3: printf("PCS,"); break; +	case 2: printf("WIS,"); break; +	case 1: printf("PMD/PMA,"); break; +	case 0: printf("Clause 22 registers,"); break; +	} +    printf(" \n"); +    break; +  case XGE_MDIO_DEVICES2: +    printf("DEVICES IN PACKAGE (cont): "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 15: printf("Vendor device 2,"); break; +	case 14: printf("Vendor device 1,"); break; +	case 13: printf("Clause 22 extension,"); break; +	} +    printf(" \n"); +    break; +  case XGE_MDIO_CONTROL2: +    printf("CONTROL2: "); +    printf("%x",data); printf("  "); +    // PMA/PMD +    if (device == XGE_MDIO_DEVICE_PMA) +      switch((data & 0xf)) { +      case 0xF: printf("10BASE-T,"); break; +      case 0xE: printf("100BASE-TX,"); break; +      case 0xD: printf("1000BASE-KX,"); break; +      case 0xC: printf("1000BASE-T,"); break; +      case 0xB: printf("10GBASE-KR,"); break; +      case 0xA: printf("10GBASE-KX4,"); break; +      case 0x9: printf("10GBASE-T,"); break; +      case 0x8: printf("10GBASE-LRM,"); break; +      case 0x7: printf("10GBASE-SR,"); break; +      case 0x6: printf("10GBASE-LR,"); break; +      case 0x5: printf("10GBASE-ER,"); break; +      case 0x4: printf("10GBASE-LX4,"); break; +	//     case 0x3: printf("10GBASE-SW,"); break; +	//      case 0x2: printf("10GBASE-LW,"); break; +	//     case 0x1: printf("10GBASE-EW,"); break; +      case 0x0: printf("10GBASE-CX4,"); break; +      } else if (device == XGE_MDIO_DEVICE_PCS) +      // PCS +      switch((data & 0x3)) { +      case 0x3: printf("10GBASE-T PCS,"); break; +      case 0x2: printf("10GBASE-W PCS,"); break; +      case 0x1: printf("10GBASE-X PCS,"); break; +      case 0x0: printf("10GBASE-R PCS,"); break; +      } +    printf(" \n"); +    break; +  case XGE_MDIO_STATUS2: +    printf("STATUS2: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 15: if ((data & (1 << 14)) == 0) printf("Device responding,"); break; +	case 13: if (device == XGE_MDIO_DEVICE_PMA) printf("Able detect a Tx fault,"); break; +	case 12: if (device == XGE_MDIO_DEVICE_PMA) printf("Able detect an Rx fault,"); break; +	case 11: printf("Fault on Tx path,"); break; +	case 10: printf("Fault on Rx path,"); break; +	case 9:  if (device == XGE_MDIO_DEVICE_PMA) printf("Extended abilities in Reg1.11,"); break; +	case 8:  if (device == XGE_MDIO_DEVICE_PMA) printf("Able to disable TX,"); break; +	case 7:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-SR,"); break; +	case 6:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LR,"); break; +	case 5:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-ER,"); break; +	case 4:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LX4,"); break; +	case 3:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-SW,"); break; +	case 2:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-LW,"); break; +	case 1:  if (device == XGE_MDIO_DEVICE_PMA) printf("10GBASE-EW,"); break; +	case 0:  if (device == XGE_MDIO_DEVICE_PMA) printf("loopback,"); break; +	} +    printf(" \n"); +    break; +  case XGE_MDIO_LANESTATUS: +    printf("LANE STATUS: "); +    printf("%x",data); printf("  "); +    for (x=15; x >= 0 ; x--) +      if ((data & (1 << x)) != 0) +	// Bits set. +	switch(x) { +	case 12: printf("Lanes aligned,"); break; +	case 11: printf("Able to generate test patterns,"); break; +	case 3:  printf("Lane 3 synced,"); break; +	case 2:  printf("Lane 2 synced,"); break; +	case 1:  printf("Lane 1 synced,"); break; +	case 0:  printf("Lane 0 synced,"); break; +	} else +	// Bits clear +	switch(x) { + 	case 3:  printf("Lane 3 not synced,"); break; +	case 2:  printf("Lane 2 not synced,"); break; +	case 1:  printf("Lane 1 not synced,"); break; +	case 0:  printf("Lane 0 not synced,"); break; +	} +    printf(" \n"); +    break; +  case XILINX_CORE_VERSION: +    printf("XILINX CORE VERSION: %x  ",data); +    printf("Version: %d.%d ",(data&0xf000)>>12,(data&0xf00)>>8); +    printf("Patch: %d ",(data&0xE)>>1); +    if (data&0x1) printf("Evaluation Version of core"); +    printf("\n"); +    break; +  default: +    printf("Register @ address: "); +    printf("%x",address); +    printf(" has value: "); +    printf("%x\n",data); +    break; +  } +} + +void +dump_mdio_regs(const uint8_t eth, uint32_t mdio_port) +{ +    volatile unsigned int x; +    int y; +    unsigned int regs_a[9] = {0,1,4,5,6,7,8,32,33}; +    unsigned int regs_b[10] = {0,1,4,5,6,7,8,10,11,65535}; + +    printf("\n"); + +    for (y = 0; y < 10; y++) +	{ +	  // Read MDIO data +	  x = read_mdio(eth,regs_b[y],XGE_MDIO_DEVICE_PMA,mdio_port); +	  decode_reg(regs_b[y],XGE_MDIO_DEVICE_PMA,x); +	} + +      for (y = 0; y < 9; y++) +	{ +	  // Read MDIO data +	  x = read_mdio(eth,regs_a[y],XGE_MDIO_DEVICE_PCS,mdio_port); +	  decode_reg(regs_a[y],XGE_MDIO_DEVICE_PCS,x); +	} + +     printf("\n"); + +      /* for (y = 0; y < 8; y++) */ +      /* 	{ */ +      /* 	  // Read MDIO data */ +      /* 	  x = xge_read_mdio(base,regs_a[y],XGE_MDIO_DEVICE_PHY_XS,mdio_port); */ +      /* 	  decode_reg(regs_a[y],XGE_MDIO_DEVICE_PHY_XS,x); */ +      /* 	}  */ + +      /* for (y = 0; y < 8; y++) */ +      /* 	{ */ +      /* 	  // Read MDIO data */ +      /* 	  x = xge_read_mdio(base,regs_a[y],XGE_MDIO_DEVICE_DTE_XS,mdio_port); */ +      /* 	  decode_reg(regs_a[y],XGE_MDIO_DEVICE_DTE_XS,x); */ +      /* 	} */ +} + +bool ethernet_get_link_up(const uint32_t eth) +{ +    return links_up[eth]; +} diff --git a/firmware/usrp3/lib/link_state_route_proto.c b/firmware/usrp3/lib/link_state_route_proto.c new file mode 100644 index 000000000..30cfd73cb --- /dev/null +++ b/firmware/usrp3/lib/link_state_route_proto.c @@ -0,0 +1,441 @@ + +// Copyright 2013 Ettus Research LLC + +#include <link_state_route_proto.h> +#include <u3_net_stack.h> +#include <ethernet.h> +#include <string.h> +#include <printf.h> +#include <print_addrs.h> + +#define lengthof(a) (sizeof(a)/sizeof(*(a))) + +/*********************************************************************** + * global constants + **********************************************************************/ +#define LS_PROTO_VERSION 6 + +//shift the proto version into the ID so only matching fw responds +#define LS_ID_DISCOVER  (0 | (8 << LS_PROTO_VERSION)) +#define LS_ID_INFORM    (1 | (8 << LS_PROTO_VERSION)) + +#define LS_PAYLOAD_MTU 1024 +#define LS_NUM_NBOR_ENTRIES 16 +#define LS_NUM_NODE_ENTRIES 64 +#define LS_NUM_MAP_ENTRIES 128 + +#define NETHS 4 //max eths supported in this file + +/*********************************************************************** + * wire format for table communication + **********************************************************************/ +typedef struct +{ +    uint32_t num_nbors; //number of entries in neighbors list +    uint32_t num_ports; //first few neighbors are local ports +    struct ip_addr node; +    struct ip_addr nbors[]; +} ls_data_t; + +static inline size_t sizeof_ls_data(const ls_data_t *ls_data) +{ +    return 0 +        + sizeof(uint32_t)/*num neighbors*/ +        + sizeof(uint32_t)/*num ports*/ +        + sizeof(struct ip_addr)/*source node*/ +        + sizeof(struct ip_addr)*ls_data->num_nbors; +} + +/*********************************************************************** + * sequence and tick counter monitor + **********************************************************************/ +static uint16_t ticker = 0; + +void link_state_route_proto_tick(void) +{ +    ticker++; +} + +static inline bool is_tick_expired(const uint16_t tick) +{ +    const uint16_t delta = ticker - tick; +    return delta > 2; //have not talked in a while, you are deaf to me +} + +static uint16_t current_seq = 0; + +static inline bool is_seq_newer(const uint16_t seq, const uint16_t entry_seq) +{ +    if (seq == entry_seq) return false; //not newer if equal +    const uint16_t delta = seq - entry_seq; +    return (delta & (1 << 15)) == 0; //newer when subtraction did not overflow +} + +/*********************************************************************** + * node entry api + **********************************************************************/ +typedef struct +{ +    uint16_t seq; +    uint16_t tick; +    uint8_t ethno; +    struct ip_addr ip_addr; +} ls_node_entry_t; + +static bool ls_node_entry_valid(const ls_node_entry_t *entry) +{ +    return entry->ip_addr.addr != 0 && !is_tick_expired(entry->tick); +} + +static void ls_node_entry_update(ls_node_entry_t *entry, const int8_t ethno, const uint16_t seq, const struct ip_addr *ip_addr) +{ +    entry->seq = seq; +    entry->tick = ticker; +    entry->ethno = ethno; +    entry->ip_addr.addr = ip_addr->addr; +} + +static bool ls_node_entries_update( +    ls_node_entry_t *entries, const size_t num_entries, +    const int8_t ethno, const uint16_t seq, const struct ip_addr *ip_addr +) +{ +    for (size_t i = 0; i < num_entries; i++) +    { +        if (!ls_node_entry_valid(&entries[i])) +        { +            ls_node_entry_update(entries+i, ethno, seq, ip_addr); +            return true; +        } + +        if (entries[i].ip_addr.addr == ip_addr->addr && entries[i].ethno == ethno) +        { +            if (is_seq_newer(seq, entries[i].seq)) +            { +                ls_node_entry_update(entries+i, ethno, seq, ip_addr); +                return true; +            } +            return false; +        } +    } + +    //no space, shift the table down and take entry 0 +    memmove(entries+1, entries, (num_entries-1)*sizeof(ls_node_entry_t)); +    ls_node_entry_update(entries+0, ethno, seq, ip_addr); +    return true; +} + +/*********************************************************************** + * storage for nodes in the network + **********************************************************************/ +static ls_node_entry_t ls_nbors[LS_NUM_NBOR_ENTRIES]; +static ls_node_entry_t ls_nodes[LS_NUM_NODE_ENTRIES]; + +/*********************************************************************** + * node table + **********************************************************************/ +static ls_node_mapping_t ls_node_maps[LS_NUM_MAP_ENTRIES]; + +const ls_node_mapping_t *link_state_route_get_node_mapping(size_t *length) +{ +    *length = lengthof(ls_node_maps); +    return ls_node_maps; +} + +static void add_node_mapping(const struct ip_addr *node, const struct ip_addr *nbor) +{ +    //printf("add_node_mapping: %s -> %s\n", ip_addr_to_str(node), ip_addr_to_str(nbor)); + +    //write into the first available slot +    for (size_t i = 0; i < lengthof(ls_node_maps); i++) +    { +        if (ls_node_maps[i].node.addr == 0) +        { +            ls_node_maps[i].node.addr = node->addr; +            ls_node_maps[i].nbor.addr = nbor->addr; +            return; +        } +    } + +    //otherwise, shift down the table and take slot0 +    memmove(ls_node_maps+1, ls_node_maps, sizeof(ls_node_maps) - sizeof(ls_node_mapping_t)); +    ls_node_maps[0].node.addr = node->addr; +    ls_node_maps[0].nbor.addr = nbor->addr; +} + +static void remove_node_matches(const struct ip_addr *node) +{ +    //printf("remove_node_matches: %s\n", ip_addr_to_str(node)); + +    for (size_t j = 0; j < lengthof(ls_node_maps); j++) +    { +        //if the address is a match, clear the entry +        if (ls_node_maps[j].node.addr == node->addr) +        { +            ls_node_maps[j].node.addr = 0; +            ls_node_maps[j].nbor.addr = 0; +        } +    } +} + +static void update_node_mappings(const ls_data_t *ls_data) +{ +    //printf("update_node_mappings: %s\n", ip_addr_to_str(&ls_data->node)); + +    //remove any expired entries +    for (size_t i = 0; i < lengthof(ls_nodes); i++) +    { +        if (ls_nodes[i].ip_addr.addr != 0 && is_tick_expired(ls_nodes[i].tick)) +        { +            remove_node_matches(&ls_nodes[i].ip_addr); +        } +    } + +    //remove any matches for the current node +    remove_node_matches(&ls_data->node); + +    //is this a local packet? +    bool is_local = false; +    for (size_t e = 0; e < ethernet_ninterfaces(); e++) +    { +        if (ls_data->node.addr == u3_net_stack_get_ip_addr(e)->addr) is_local = true; +    } + +    //load entries from ls data into array +    for (size_t i = 0; i < ls_data->num_nbors; i++) +    { +        if (is_local && i < ls_data->num_ports) continue; //ignore local ports +        add_node_mapping(&ls_data->node, &ls_data->nbors[i]); +    } +} + +/*********************************************************************** + * forward link state data onto all neighbors on the given port + **********************************************************************/ +static void send_link_state_data_to_all_neighbors( +    const uint8_t ethno, const uint16_t seq, const ls_data_t *ls_data +){ +    //exit and dont forward if the information is stale +    if (!ls_node_entries_update(ls_nodes, lengthof(ls_nodes), ethno, seq, &ls_data->node)) return; + +    //update the mappings with new info +    update_node_mappings(ls_data); + +    //forward to all neighbors +    for (size_t i = 0; i < lengthof(ls_nbors); i++) +    { +        if (ls_nbors[i].ip_addr.addr == ls_data->node.addr) continue; //dont forward to sender +        if (ls_node_entry_valid(&ls_nbors[i])) +        { +            if (ethernet_get_link_up(ls_nbors[i].ethno)) u3_net_stack_send_icmp_pkt( +                ls_nbors[i].ethno, ICMP_IRQ, 0, +                LS_ID_INFORM, seq, +                &(ls_nbors[i].ip_addr), ls_data, sizeof_ls_data(ls_data) +            ); +        } +    } + +    //a change may have occured, update the cache +    link_state_route_proto_update_cycle_cache(ethno); +} + +/*********************************************************************** + * handler for information reply + **********************************************************************/ +static void handle_icmp_ir( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t id, const uint16_t seq, +    const void *buff, const size_t num_bytes +){ +    switch (id) +    { +    //received a reply directly from the neighbor, add to neighbor list +    case LS_ID_DISCOVER: +        //printf("GOT LS_ID_DISCOVER REPLY - ID 0x%x - IP%u: %s\n", id, (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno))); +        if (ls_node_entries_update(ls_nbors, lengthof(ls_nbors), ethno, seq, src)) link_state_route_proto_flood(ethno); +        break; +    } +} + +/*********************************************************************** + * handler for information request + **********************************************************************/ +static void handle_icmp_irq( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t id, const uint16_t seq, +    const void *buff, const size_t num_bytes +){ +    switch (id) +    { +    //replies to discovery packets +    case LS_ID_DISCOVER: +        //printf("GOT LS_ID_DISCOVER REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno))); +        //printf("SEND LS_ID_DISCOVER REPLY - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno))); +        u3_net_stack_send_icmp_pkt(ethno, ICMP_IR, 0, id, seq, src, buff, num_bytes); +        break; + +    //handle and forward information +    case LS_ID_INFORM: +        //printf("GOT LS_ID_INFORM REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno))); +        send_link_state_data_to_all_neighbors(ethno, seq, (const ls_data_t *)buff); +        break; +    }; +} + +/*********************************************************************** + * initiate a periodic update to the table + **********************************************************************/ +void link_state_route_proto_update(const uint8_t ethno) +{ +    //send a discovery packet +    //printf("SEND LS_ID_DISCOVER REQ - IP%u: %s\n", (int)ethno, ip_addr_to_str(u3_net_stack_get_ip_addr(ethno))); +    u3_net_stack_send_icmp_pkt( +        ethno, ICMP_IRQ, 0, +        LS_ID_DISCOVER, current_seq++, +        u3_net_stack_get_bcast(ethno), NULL, 0 +    ); +} + +void link_state_route_proto_flood(const uint8_t ethno) +{ +    for (size_t e = 0; e < ethernet_ninterfaces(); e++) +    { +        //fill link state data buffer +        uint8_t buff[LS_PAYLOAD_MTU] = {}; +        ls_data_t *ls_data = (ls_data_t *)buff; +        ls_data->node.addr = u3_net_stack_get_ip_addr(e)->addr; +        ls_data->num_nbors = 0; +        ls_data->num_ports = 0; + +        //first the local port links +        for (size_t ej = 0; ej < ethernet_ninterfaces(); ej++) +        { +            if (e == ej) continue; //dont include our own port +            ls_data->nbors[ls_data->num_nbors++].addr = u3_net_stack_get_ip_addr(ej)->addr; +            ls_data->num_ports++; +        } + +        //now list the neighbors +        for (size_t i = 0; i < lengthof(ls_nbors); i++) +        { +            if ((sizeof_ls_data(ls_data) + 4) >= LS_PAYLOAD_MTU) break; +            if (ls_node_entry_valid(&ls_nbors[i]) && ls_nbors[i].ethno == e) +            { +                ls_data->nbors[ls_data->num_nbors++].addr = ls_nbors[i].ip_addr.addr; +            } +        } + +        //send this data to all neighbors +        send_link_state_data_to_all_neighbors(ethno, current_seq++, ls_data); +    } +} + +/*********************************************************************** + * cycle detection logic + **********************************************************************/ +static void follow_links(const size_t current, struct ip_addr *nodes, bool *visited, const size_t num_nodes) +{ +    if (visited[current]) return; //end the recursion +    visited[current] = true; + +    //follow all links where current node is the source +    for (size_t i = 0; i < lengthof(ls_node_maps); i++) +    { +        if (ls_node_maps[i].node.addr != nodes[current].addr) continue; + +        //find the index of the neighbor in the node list to recurse +        for (size_t j = 0; j < num_nodes; j++) +        { +            if (nodes[j].addr != ls_node_maps[i].nbor.addr) continue; +            follow_links(j, nodes, visited, num_nodes); +        } +    } +} + +bool link_state_route_proto_causes_cycle(const struct ip_addr *src, const struct ip_addr *dst) +{ +    //printf("is there a cycle? %s -> %s: \n", ip_addr_to_str(src), ip_addr_to_str(dst)); + +    //make a set of all nodes +    size_t num_nodes = 0; +    struct ip_addr nodes[LS_NUM_MAP_ENTRIES]; +    for (size_t i = 0; i < lengthof(ls_node_maps); i++) +    { +        if (ls_node_maps[i].node.addr == 0 || ls_node_maps[i].nbor.addr == 0) continue; +        //printf("  Link %s -> %s\n", ip_addr_to_str(&ls_node_maps[i].node), ip_addr_to_str(&ls_node_maps[i].nbor)); +        const struct ip_addr *node = &ls_node_maps[i].node; + +        //check if we have an entry +        for (size_t j = 0; j < num_nodes; j++) +        { +            if (nodes[j].addr == node->addr) goto skip_add; +        } + +        //otherwise, we add the node +        nodes[num_nodes++].addr = node->addr; +        //printf("  Add to node set: %s\n", ip_addr_to_str(node)); +        skip_add: continue; +    } + +    //and stateful tracking info for each node +    bool visited[LS_NUM_MAP_ENTRIES]; +    for (size_t i = 0; i < num_nodes; i++) visited[i] = false; + +    //find our src node in the set and follow +    for (size_t i = 0; i < num_nodes; i++) +    { +        if (nodes[i].addr == src->addr) follow_links(i, nodes, visited, num_nodes); +    } + +    //did we visit the destination? if so, there is a cycle +    for (size_t i = 0; i < num_nodes; i++) +    { +        if (nodes[i].addr == dst->addr && visited[i]) +        { +            //printf("CAUSES CYCLE!\n"); +            return true; +        } +    } + +    //printf("no cycle found.\n"); +    return false; +} + +static bool ls_causes_cycle[NETHS][NETHS]; + +void link_state_route_proto_update_cycle_cache(const uint8_t eth_src) +{ +    for (size_t eth_dst = 0; eth_dst < ethernet_ninterfaces(); eth_dst++) +    { +        if (eth_src == eth_dst) continue; +        ls_causes_cycle[eth_src][eth_dst] = link_state_route_proto_causes_cycle( +            u3_net_stack_get_ip_addr(eth_src), +            u3_net_stack_get_ip_addr(eth_dst) +        ); +    } +} + +bool link_state_route_proto_causes_cycle_cached(const uint8_t eth_src, const uint8_t eth_dst) +{ +    return ls_causes_cycle[eth_src][eth_dst]; +} + +/*********************************************************************** + * init and registration code + **********************************************************************/ +void link_state_route_proto_init(void) +{ +    u3_net_stack_register_icmp_handler(ICMP_IRQ, 0, &handle_icmp_irq); +    u3_net_stack_register_icmp_handler(ICMP_IR, 0, &handle_icmp_ir); + +    //default to causing a cycle, let the algorithm set this correctly +    for (size_t i = 0; i < NETHS; i++) +    { +        for (size_t j = 0; j < NETHS; j++) +        { +            ls_causes_cycle[i][j] = true; +        } +    } +} diff --git a/firmware/usrp3/lib/mdelay.c b/firmware/usrp3/lib/mdelay.c new file mode 100644 index 000000000..6d2742206 --- /dev/null +++ b/firmware/usrp3/lib/mdelay.c @@ -0,0 +1,36 @@ +/* -*- c -*- */ +/* + * Copyright 2007 Free Software Foundation, Inc. + * Copyright 2009 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "mdelay.h" +#include "wb_utils.h" +#include "printf.h" +#include <stdint.h> +//IJB FIXME. +#include "../x300/x300_defs.h" + +void mdelay(int ms){ +  for(int i = 0; i < ms; i++){ +    static const uint32_t num_ticks = CPU_CLOCK/1000; +    const uint32_t ticks_begin = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); +    //    printf("DEBUG: Counter is %d\n",ticks_begin); +    while((wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)) - ticks_begin) < num_ticks) { +      /*NOP*/ +    } +  } +} diff --git a/firmware/usrp3/lib/print_addrs.c b/firmware/usrp3/lib/print_addrs.c new file mode 100644 index 000000000..6a710f75c --- /dev/null +++ b/firmware/usrp3/lib/print_addrs.c @@ -0,0 +1,64 @@ +// Copyright 2013 Ettus Research LLC + +#include <print_addrs.h> +#include <stddef.h> +#include <stdint.h> +#include <printf.h> + +#define MAX_MAC_CHARS 24 +#define MAX_IP_CHARS 16 + +static const char hex[16] = "0123456789ABCDEF"; + +char *mac_addr_to_str_r(const void *addr, char *str) +{ +    uint8_t *p = (uint8_t *)addr; +    size_t j = 0; +    for(size_t i = 0; i < 6; i++) +    { +        if (i) str[j++] = ':'; +        str[j++] = hex[(p[i] >> 4) & 0xf]; +        str[j++] = hex[p[i] & 0xf]; +    } +    str[j++] = '\0'; +    return str; +} + +char *ip_addr_to_str_r(const void *addr, char *str) +{ +    uint8_t *p = (uint8_t *)addr; +    sprintf(str, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]); +    return str; +} + +char *mac_addr_to_str(const void *addr) +{ +    static size_t index = 0; +    index = (index + 1) % 4; +    static char str[4][MAX_MAC_CHARS]; +    return mac_addr_to_str_r(addr, str[index]); +} + +char *ip_addr_to_str(const void *addr) +{ +    static size_t index = 0; +    index = (index + 1) % 4; +    static char str[4][MAX_IP_CHARS]; +    return ip_addr_to_str_r(addr, str[index]); +} + +/* +void print_mac_addr(const void *addr) +{ +    char str[MAX_MAC_CHARS]; +    mac_addr_to_str_r(addr, str); +    printf("%s", str); +} + +void print_ip_addr(const void *addr) +{ +    char str[MAX_IP_CHARS]; +    ip_addr_to_str_r(addr, str); +    printf("%s", str); +} +*/ diff --git a/firmware/usrp3/lib/printf.c b/firmware/usrp3/lib/printf.c new file mode 100644 index 000000000..6d6a3e712 --- /dev/null +++ b/firmware/usrp3/lib/printf.c @@ -0,0 +1,287 @@ +/* +File: printf.c + +Copyright (C) 2004  Kustaa Nyholm + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA + +*/ + +#include "printf.h" + +typedef void (*putcf) (void*,char); +static putcf stdout_putf; +static void* stdout_putp; + +#ifdef PRINTF_LONG_LONG_SUPPORT + +static void ulli2a(unsigned long long int num, unsigned int base, int uc,char * bf) +    { +    int n=0; +    unsigned int d=1; +    while (num/d >= base) +        d*=base;          +    while (d!=0) { +        int dgt = num / d; +        num%=d; +        d/=base; +        if (n || dgt>0|| d==0) { +            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); +            ++n; +            } +        } +    *bf=0; +    } + +static void lli2a (long long num, char * bf) +    { +    if (num<0) { +        num=-num; +        *bf++ = '-'; +        } +    ulli2a(num,10,0,bf); +    } + +#endif + +#ifdef PRINTF_LONG_SUPPORT + +static void uli2a(unsigned long int num, unsigned int base, int uc,char * bf) +    { +    int n=0; +    unsigned int d=1; +    while (num/d >= base) +        d*=base;          +    while (d!=0) { +        int dgt = num / d; +        num%=d; +        d/=base; +        if (n || dgt>0|| d==0) { +            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); +            ++n; +            } +        } +    *bf=0; +    } + +static void li2a (long num, char * bf) +    { +    if (num<0) { +        num=-num; +        *bf++ = '-'; +        } +    uli2a(num,10,0,bf); +    } + +#endif + +static void ui2a(unsigned int num, unsigned int base, int uc,char * bf) +    { +    int n=0; +    unsigned int d=1; +    while (num/d >= base) +        d*=base;         +    while (d!=0) { +        int dgt = num / d; +        num%= d; +        d/=base; +        if (n || dgt>0 || d==0) { +            *bf++ = dgt+(dgt<10 ? '0' : (uc ? 'A' : 'a')-10); +            ++n; +            } +        } +    *bf=0; +    } + +static void i2a (int num, char * bf) +    { +    if (num<0) { +        num=-num; +        *bf++ = '-'; +        } +    ui2a(num,10,0,bf); +    } + +static int a2d(char ch) +    { +    if (ch>='0' && ch<='9')  +        return ch-'0'; +    else if (ch>='a' && ch<='f') +        return ch-'a'+10; +    else if (ch>='A' && ch<='F') +        return ch-'A'+10; +    else return -1; +    } + +static char a2i(char ch, char** src,int base,int* nump) +    { +    char* p= *src; +    int num=0; +    int digit; +    while ((digit=a2d(ch))>=0) { +        if (digit>base) break; +        num=num*base+digit; +        ch=*p++; +        } +    *src=p; +    *nump=num; +    return ch; +    } + +static void putchw(void* putp,putcf putf,int n, char z, char* bf) +    { +    char fc=z? '0' : ' '; +    char ch; +    char* p=bf; +    while (*p++ && n > 0) +        n--; +    while (n-- > 0)  +        putf(putp,fc); +    while ((ch= *bf++)) +        putf(putp,ch); +    } + +void tfp_format(void* putp,putcf putf,char *fmt, va_list va) +    { +    char bf[12]; +     +    char ch; + + +    while ((ch=*(fmt++))) { +        if (ch!='%')  +            putf(putp,ch); +        else { +            char lz=0; +#ifdef  PRINTF_LONG_SUPPORT +            char lng=0; +#endif +#ifdef  PRINTF_LONG_LONG_SUPPORT +            char lnglng=0; +#endif +            int w=0; +            ch=*(fmt++); +            if (ch=='0') { +                ch=*(fmt++); +                lz=1; +                } +            if (ch>='0' && ch<='9') { +                ch=a2i(ch,&fmt,10,&w); +                } +#ifdef  PRINTF_LONG_SUPPORT +            if (ch=='l') { +                ch=*(fmt++); +                lng=1; +            } +#endif +#ifdef  PRINTF_LONG_LONG_SUPPORT +	    if ((ch=='l')&&(lng==1)) { +                ch=*(fmt++); +                lnglng=1; +            } +#endif +            switch (ch) { +                case 0:  +                    goto abort; +                case 'u' : { +#ifdef  PRINTF_LONG_LONG_SUPPORT +                    if (lnglng) +                        ulli2a(va_arg(va, unsigned long long int),10,0,bf); +                    else +#endif +#ifdef  PRINTF_LONG_SUPPORT +                    if (lng) +                        uli2a(va_arg(va, unsigned long int),10,0,bf); +                    else +#endif +                    ui2a(va_arg(va, unsigned int),10,0,bf); +                    putchw(putp,putf,w,lz,bf); +                    break; +                    } +                case 'd' :  { +#ifdef  PRINTF_LONG_LONG_SUPPORT +                    if (lnglng) +                        lli2a(va_arg(va, long long int),bf); +                    else +#endif +#ifdef  PRINTF_LONG_SUPPORT +                    if (lng) +                        li2a(va_arg(va, long int),bf); +                    else +#endif +                    i2a(va_arg(va, int),bf); +                    putchw(putp,putf,w,lz,bf); +                    break; +                    } +                case 'x': case 'X' :  +#ifdef  PRINTF_LONG_LONG_SUPPORT +                    if (lnglng) +                        ulli2a(va_arg(va, unsigned long long int),16,(ch=='X'),bf); +                    else +#endif +#ifdef  PRINTF_LONG_SUPPORT +                    if (lng) +                        uli2a(va_arg(va, unsigned long int),16,(ch=='X'),bf); +                    else +#endif +                    ui2a(va_arg(va, unsigned int),16,(ch=='X'),bf); +                    putchw(putp,putf,w,lz,bf); +                    break; +                case 'c' :  +                    putf(putp,(char)(va_arg(va, int))); +                    break; +                case 's' :  +                    putchw(putp,putf,w,0,va_arg(va, char*)); +                    break; +                case '%' : +                    putf(putp,ch); +                default: +                    break; +                } +            } +        } +    abort:; +    } + + +void init_printf(void* putp,void (*putf) (void*,char)) +    { +    stdout_putf=putf; +    stdout_putp=putp; +    } + +void tfp_printf(char *fmt, ...) +    { +    va_list va; +    va_start(va,fmt); +    tfp_format(stdout_putp,stdout_putf,fmt,va); +    va_end(va); +    } + +static void putcp(void* p,char c) +    { +    *(*((char**)p))++ = c; +    } + + + +void tfp_sprintf(char* s,char *fmt, ...) +    { +    va_list va; +    va_start(va,fmt); +    tfp_format(&s,putcp,fmt,va); +    putcp(&s,0); +    va_end(va); +    } diff --git a/firmware/usrp3/lib/u3_net_stack.c b/firmware/usrp3/lib/u3_net_stack.c new file mode 100644 index 000000000..6b8ef096c --- /dev/null +++ b/firmware/usrp3/lib/u3_net_stack.c @@ -0,0 +1,589 @@ + +// Copyright 2012-2013 Ettus Research LLC + +#include <u3_net_stack.h> +#include <string.h> //memcmp +#include <printf.h> + +#define MAX_NETHS 4 + +typedef struct +{ +    padded_eth_hdr_t eth; +    struct arp_eth_ipv4 arp; +} padded_arp_t; + +typedef struct +{ +    padded_eth_hdr_t eth; +    struct ip_hdr ip; +    struct icmp_echo_hdr icmp; +} padded_icmp_t; + +typedef struct +{ +    padded_eth_hdr_t eth; +    struct ip_hdr ip; +    struct udp_hdr udp; +} padded_udp_t; + +/*********************************************************************** + * declares for internal handlers + **********************************************************************/ +static void handle_icmp_echo_packet( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t id, const uint16_t seq, +    const void *buff, const size_t num_bytes +){ +    u3_net_stack_send_icmp_pkt(ethno, ICMP_ER, 0, id, seq, src, buff, num_bytes); +} + +static void handle_icmp_dur_packet( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t id, const uint16_t seq, +    const void *buff, const size_t num_bytes +); + +/*********************************************************************** + * 16-bit one's complement sum + **********************************************************************/ +static uint32_t chksum_buffer( +    uint16_t *buf, size_t nshorts, +    uint32_t initial_chksum +){ +    uint32_t chksum = initial_chksum; +    for (size_t i = 0; i < nshorts; i++) chksum += buf[i]; + +    while (chksum >> 16) chksum = (chksum & 0xffff) + (chksum >> 16); + +    return chksum; +} + +/*********************************************************************** + * ARP Cache implementation + **********************************************************************/ +#define ARP_CACHE_NENTRIES 32 + +static size_t arp_cache_wr_index; + +static struct ip_addr arp_cache_ips[ARP_CACHE_NENTRIES]; +static eth_mac_addr_t arp_cache_macs[ARP_CACHE_NENTRIES]; +static uint8_t arp_cache_eths[ARP_CACHE_NENTRIES]; + +void u3_net_stack_arp_cache_update(const struct ip_addr *ip_addr, const eth_mac_addr_t *mac_addr, const uint8_t ethno) +{ +    for (size_t i = 0; i < ARP_CACHE_NENTRIES; i++) +    { +        if (memcmp(ip_addr, arp_cache_ips+i, sizeof(struct ip_addr)) == 0) +        { +            memcpy(arp_cache_macs+i, mac_addr, sizeof(eth_mac_addr_t)); +            arp_cache_eths[i] = ethno; +            return; +        } +    } +    if (arp_cache_wr_index >= ARP_CACHE_NENTRIES) arp_cache_wr_index = 0; +    memcpy(arp_cache_ips+arp_cache_wr_index, ip_addr, sizeof(struct ip_addr)); +    memcpy(arp_cache_macs+arp_cache_wr_index, mac_addr, sizeof(eth_mac_addr_t)); +    arp_cache_eths[arp_cache_wr_index] = ethno; +    arp_cache_wr_index++; +} + +const eth_mac_addr_t *u3_net_stack_arp_cache_lookup(const struct ip_addr *ip_addr) +{ +    //do a local look up on our own ports +    for (size_t e = 0; e < MAX_NETHS; e++) +    { +        if (memcmp(ip_addr, u3_net_stack_get_ip_addr(e), sizeof(struct ip_addr)) == 0) +        { +            return u3_net_stack_get_mac_addr(e); +        } +    } +    //now check the arp cache +    for (size_t i = 0; i < ARP_CACHE_NENTRIES; i++) +    { +        if (memcmp(ip_addr, arp_cache_ips+i, sizeof(struct ip_addr)) == 0) +        { +            return &arp_cache_macs[i]; +        } +    } +    return NULL; +} + +bool resolve_ip(const struct ip_addr *ip_addr, eth_mac_addr_t *mac_addr) +{ +    for (size_t e = 0; e < MAX_NETHS; e++) +    { +        if (memcmp(u3_net_stack_get_bcast(e), ip_addr, sizeof(struct ip_addr)) == 0) +        { +            memset(mac_addr, 0xff, sizeof(eth_mac_addr_t)); +            return true; +        } +    } +    const eth_mac_addr_t *r = u3_net_stack_arp_cache_lookup(ip_addr); +    if (r != NULL) +    { +        memcpy(mac_addr, r, sizeof(eth_mac_addr_t)); +        return true; +    } +    return false; +} + +/*********************************************************************** + * Net stack config + **********************************************************************/ +static wb_pkt_iface64_config_t *pkt_iface_config = NULL; + +void u3_net_stack_init(wb_pkt_iface64_config_t *config) +{ +    pkt_iface_config = config; +    u3_net_stack_register_icmp_handler(ICMP_ECHO, 0, &handle_icmp_echo_packet); +    u3_net_stack_register_icmp_handler(ICMP_DUR, ICMP_DUR_PORT, &handle_icmp_dur_packet); +} + +static struct ip_addr net_conf_ips[MAX_NETHS]; +static eth_mac_addr_t net_conf_macs[MAX_NETHS]; +static struct ip_addr net_conf_subnets[MAX_NETHS]; +static struct ip_addr net_conf_bcasts[MAX_NETHS]; +static uint32_t net_stat_counts[MAX_NETHS]; + +void u3_net_stack_init_eth( +    const uint8_t ethno, +    const eth_mac_addr_t *mac, +    const struct ip_addr *ip, +    const struct ip_addr *subnet +) +{ +    memcpy(&net_conf_macs[ethno], mac, sizeof(eth_mac_addr_t)); +    memcpy(&net_conf_ips[ethno], ip, sizeof(struct ip_addr)); +    memcpy(&net_conf_subnets[ethno], subnet, sizeof(struct ip_addr)); +    net_stat_counts[ethno] = 0; +} + +const struct ip_addr *u3_net_stack_get_ip_addr(const uint8_t ethno) +{ +    return &net_conf_ips[ethno]; +} + +const struct ip_addr *u3_net_stack_get_subnet(const uint8_t ethno) +{ +    return &net_conf_subnets[ethno]; +} + +const struct ip_addr *u3_net_stack_get_bcast(const uint8_t ethno) +{ +    const uint32_t ip = u3_net_stack_get_ip_addr(ethno)->addr; +    const uint32_t subnet = u3_net_stack_get_subnet(ethno)->addr; +    net_conf_bcasts[ethno].addr = ip | (~subnet); +    return &net_conf_bcasts[ethno]; +} + +const eth_mac_addr_t *u3_net_stack_get_mac_addr(const uint8_t ethno) +{ +    return &net_conf_macs[ethno]; +} + +/*********************************************************************** + * Ethernet activity stats + **********************************************************************/ +uint32_t u3_net_stack_get_stat_counts(const uint8_t ethno) +{ +    return net_stat_counts[ethno]; +} + +static void incr_stat_counts(const void *p) +{ +    const padded_eth_hdr_t *eth = (const padded_eth_hdr_t *)p; +    if (eth->ethno < MAX_NETHS) net_stat_counts[eth->ethno]++; +} + +/*********************************************************************** + * Ethernet handlers - send packet w/ payload + **********************************************************************/ +static void send_eth_pkt( +    const void *p0, const size_t l0, +    const void *p1, const size_t l1, +    const void *p2, const size_t l2 +) +{ +    incr_stat_counts(p0); +    void *ptr = wb_pkt_iface64_tx_claim(pkt_iface_config); +    size_t buff_i = 0; + +    uint32_t *buff32 = (uint32_t *)ptr; +    for (size_t i = 0; i < (l0+3)/4; i++) +    { +        buff32[buff_i++] = ((const uint32_t *)p0)[i]; +    } +    for (size_t i = 0; i < (l1+3)/4; i++) +    { +        buff32[buff_i++] = ((const uint32_t *)p1)[i]; +    } +    for (size_t i = 0; i < (l2+3)/4; i++) +    { +        buff32[buff_i++] = ((const uint32_t *)p2)[i]; +    } + +    // Fixes issue where we don't write an even number of 32bit words leaving last data stranded in H/W. +    if ((buff_i%2) == 1) buff32[buff_i++] = 0; + +    wb_pkt_iface64_tx_submit(pkt_iface_config, l0 + l1 + l2); +} + +/*********************************************************************** + * ARP handlers + **********************************************************************/ +static void send_arp_reply( +    const uint8_t ethno, +    const struct arp_eth_ipv4 *req, +    const eth_mac_addr_t *our_mac +){ +    padded_arp_t reply; +    reply.eth.ethno = ethno; +    memcpy(&reply.eth.dst, (eth_mac_addr_t *)req->ar_sha, sizeof(eth_mac_addr_t)); +    memcpy(&reply.eth.src, u3_net_stack_get_mac_addr(ethno), sizeof(eth_mac_addr_t)); +    reply.eth.ethertype = ETHERTYPE_ARP; + +    reply.arp.ar_hrd = req->ar_hrd; +    reply.arp.ar_pro = req->ar_pro; +    reply.arp.ar_hln = req->ar_hln; +    reply.arp.ar_pln = req->ar_pln; +    reply.arp.ar_op = ARPOP_REPLY; +    memcpy(reply.arp.ar_sha, our_mac,     sizeof(eth_mac_addr_t)); +    memcpy(reply.arp.ar_sip, req->ar_tip, sizeof(struct ip_addr)); +    memcpy(reply.arp.ar_tha, req->ar_sha, sizeof(eth_mac_addr_t)); +    memcpy(reply.arp.ar_tip, req->ar_sip, sizeof(struct ip_addr)); + +    send_eth_pkt(&reply, sizeof(reply), NULL, 0, NULL, 0); +} + +void u3_net_stack_send_arp_request(const uint8_t ethno, const struct ip_addr *addr) +{ +    padded_arp_t req; +    req.eth.ethno = ethno; +    memset(&req.eth.dst, 0xff, sizeof(eth_mac_addr_t)); //bcast +    memcpy(&req.eth.src, u3_net_stack_get_mac_addr(ethno), sizeof(eth_mac_addr_t)); +    req.eth.ethertype = ETHERTYPE_ARP; + +    req.arp.ar_hrd = ARPHRD_ETHER; +    req.arp.ar_pro = ETHERTYPE_IPV4; +    req.arp.ar_hln = sizeof(eth_mac_addr_t); +    req.arp.ar_pln = sizeof(struct ip_addr); +    req.arp.ar_op = ARPOP_REQUEST; +    memcpy(req.arp.ar_sha, u3_net_stack_get_mac_addr(ethno), sizeof(eth_mac_addr_t)); +    memcpy(req.arp.ar_sip, u3_net_stack_get_ip_addr(ethno), sizeof(struct ip_addr)); +    memset(req.arp.ar_tha, 0x00, sizeof(eth_mac_addr_t)); +    memcpy(req.arp.ar_tip, addr, sizeof(struct ip_addr)); + +    send_eth_pkt(&req, sizeof(req), NULL, 0, NULL, 0); +} + +static void handle_arp_packet(const uint8_t ethno, const struct arp_eth_ipv4 *p) +{ +    //printf("handle_arp_packet\n"); +    if (p->ar_hrd != ARPHRD_ETHER +      || p->ar_pro != ETHERTYPE_IPV4 +      || p->ar_hln != sizeof(eth_mac_addr_t) +      || p->ar_pln != sizeof(struct ip_addr)) +    return; + +    //got an arp reply -- injest it into the arp cache +    if (p->ar_op == ARPOP_REPLY) +    { +        //printf("ARPOP_REPLY\n"); +        struct ip_addr ip_addr; +        memcpy(&ip_addr, p->ar_sip, sizeof(ip_addr)); +        eth_mac_addr_t mac_addr; +        memcpy(&mac_addr, p->ar_sha, sizeof(mac_addr)); +        u3_net_stack_arp_cache_update(&ip_addr, &mac_addr, ethno); +    } + +    //got an arp request -- reply if its for our address +    if (p->ar_op == ARPOP_REQUEST) +    { +        //printf("ARPOP_REQUEST\n"); +        if (memcmp(p->ar_tip, u3_net_stack_get_ip_addr(ethno), sizeof(struct ip_addr)) == 0) +        { +            send_arp_reply(ethno, p, u3_net_stack_get_mac_addr(ethno)); +        } +    } +} + +/*********************************************************************** + * UDP handlers + **********************************************************************/ +#define UDP_NHANDLERS 16 + +static uint16_t udp_handler_ports[UDP_NHANDLERS]; +static u3_net_stack_udp_handler_t udp_handlers[UDP_NHANDLERS]; +static size_t udp_handlers_index = 0; + +void u3_net_stack_register_udp_handler( +    const uint16_t port, +    const u3_net_stack_udp_handler_t handler +) +{ +    if (udp_handlers_index < UDP_NHANDLERS) +    { +        udp_handler_ports[udp_handlers_index] = port; +        udp_handlers[udp_handlers_index] = handler; +        udp_handlers_index++; +    } +} + +void u3_net_stack_send_udp_pkt( +    const uint8_t ethno, +    const struct ip_addr *dst, +    const uint16_t src_port, +    const uint16_t dst_port, +    const void *buff, +    const size_t num_bytes +) +{ +    eth_mac_addr_t dst_mac_addr; +    if (!resolve_ip(dst, &dst_mac_addr)) +    { +        printf("u3_net_stack_send_udp_pkt arp_cache_lookup fail\n"); +        return; +    } + +    padded_udp_t pkt; + +    pkt.eth.ethno = ethno; +    memcpy(&pkt.eth.dst, &dst_mac_addr,                    sizeof(eth_mac_addr_t)); +    memcpy(&pkt.eth.src, u3_net_stack_get_mac_addr(ethno), sizeof(eth_mac_addr_t)); +    pkt.eth.ethertype = ETHERTYPE_IPV4; + +    IPH_VHLTOS_SET(&pkt.ip, 4, 5, 0); +    IPH_LEN_SET(&pkt.ip, IP_HLEN + UDP_HLEN + num_bytes); +    IPH_ID_SET(&pkt.ip, 0); +    IPH_OFFSET_SET(&pkt.ip, IP_DF);	/* don't fragment */ +    IPH_TTL_SET(&pkt.ip, 32); +    IPH_PROTO_SET(&pkt.ip, IP_PROTO_UDP); +    IPH_CHKSUM_SET(&pkt.ip, 0); +    memcpy(&pkt.ip.src, u3_net_stack_get_ip_addr(ethno), sizeof(struct ip_addr)); +    memcpy(&pkt.ip.dest, dst, sizeof(struct ip_addr)); + +    IPH_CHKSUM_SET(&pkt.ip, ~chksum_buffer( +        (unsigned short *) &pkt.ip, sizeof(pkt.ip)/sizeof(short), 0 +    )); + +    pkt.udp.src = src_port; +    pkt.udp.dest = dst_port; +    pkt.udp.len = UDP_HLEN + num_bytes; +    pkt.udp.chksum = 0; + +    send_eth_pkt(&pkt, sizeof(pkt), buff, num_bytes, NULL, 0); +} + +static void handle_udp_packet( +    const uint8_t ethno, +    const struct ip_addr *src, +    const struct ip_addr *dst, +    const struct udp_hdr *udp, +    const size_t num_bytes +){ +    for (size_t i = 0; i < udp_handlers_index; i++) +    { +        if (udp_handler_ports[i] == udp->dest) +        { +            udp_handlers[i]( +                ethno, src, u3_net_stack_get_ip_addr(ethno), udp->src, udp->dest, +                ((const uint8_t *)udp) + sizeof(struct udp_hdr), +                num_bytes - UDP_HLEN +            ); +            return; +        } +    } +    printf("Unhandled UDP packet src=%u, dest=%u\n", udp->src, udp->dest); +    //TODO send destination unreachable +} + +/*********************************************************************** + * ICMP handlers + **********************************************************************/ +#define ICMP_NHANDLERS 8 + +static uint8_t icmp_handler_types[ICMP_NHANDLERS]; +static uint8_t icmp_handler_codes[ICMP_NHANDLERS]; +static u3_net_stack_icmp_handler_t icmp_handlers[ICMP_NHANDLERS]; +static size_t icmp_handlers_index = 0; + +void u3_net_stack_register_icmp_handler( +    const uint8_t type, +    const uint8_t code, +    const u3_net_stack_icmp_handler_t handler +) +{ +    if (icmp_handlers_index < ICMP_NHANDLERS) +    { +        icmp_handler_types[icmp_handlers_index] = type; +        icmp_handler_codes[icmp_handlers_index] = code; +        icmp_handlers[icmp_handlers_index] = handler; +        icmp_handlers_index++; +    } +} + +static void handle_icmp_packet( +    const uint8_t ethno, +    const struct ip_addr *src, +    const struct ip_addr *dst, +    const struct icmp_echo_hdr *icmp, +    const size_t num_bytes +){ + +    for (size_t i = 0; i < icmp_handlers_index; i++) +    { +        if (icmp_handler_types[i] == icmp->type && icmp_handler_codes[i] == icmp->code) +        { +            icmp_handlers[i]( +                ethno, src, u3_net_stack_get_ip_addr(ethno), icmp->id, icmp->seqno, +                ((const uint8_t *)icmp) + sizeof(struct icmp_echo_hdr), +                num_bytes - sizeof(struct icmp_echo_hdr) +            ); +            return; +        } +    } +    printf("Unhandled ICMP packet type=%u\n", icmp->type); +} + +static void handle_icmp_dur_packet( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t id, const uint16_t seq, +    const void *buff, const size_t num_bytes +){ +    struct ip_hdr *ip = (struct ip_hdr *)buff; +    struct udp_hdr *udp = (struct udp_hdr *)(((char *)ip) + IP_HLEN); +    if (IPH_PROTO(ip) != IP_PROTO_UDP) return; +    for (size_t i = 0; i < udp_handlers_index; i++) +    { +        if (udp_handler_ports[i] == udp->src) +        { +            udp_handlers[i](ethno, +                src, u3_net_stack_get_ip_addr(ethno), +                udp->src, udp->dest, NULL, 0 +            ); +            return; +        } +    } +} + +void u3_net_stack_send_icmp_pkt( +    const uint8_t ethno, +    const uint8_t type, +    const uint8_t code, +    const uint16_t id, +    const uint16_t seq, +    const struct ip_addr *dst, +    const void *buff, +    const size_t num_bytes +) +{ +    eth_mac_addr_t dst_mac_addr; +    if (!resolve_ip(dst, &dst_mac_addr)) +    { +        printf("u3_net_stack_send_echo_request arp_cache_lookup fail\n"); +        return; +    } + +    padded_icmp_t pkt; + +    pkt.eth.ethno = ethno; +    memcpy(&pkt.eth.dst, &dst_mac_addr,                    sizeof(eth_mac_addr_t)); +    memcpy(&pkt.eth.src, u3_net_stack_get_mac_addr(ethno), sizeof(eth_mac_addr_t)); +    pkt.eth.ethertype = ETHERTYPE_IPV4; + +    IPH_VHLTOS_SET(&pkt.ip, 4, 5, 0); +    IPH_LEN_SET(&pkt.ip, IP_HLEN + sizeof(pkt.icmp) + num_bytes); +    IPH_ID_SET(&pkt.ip, 0); +    IPH_OFFSET_SET(&pkt.ip, IP_DF);	/* don't fragment */ +    IPH_TTL_SET(&pkt.ip, 32); +    IPH_PROTO_SET(&pkt.ip, IP_PROTO_ICMP); +    IPH_CHKSUM_SET(&pkt.ip, 0); +    memcpy(&pkt.ip.src, u3_net_stack_get_ip_addr(ethno), sizeof(struct ip_addr)); +    memcpy(&pkt.ip.dest, dst, sizeof(struct ip_addr)); + +    IPH_CHKSUM_SET(&pkt.ip, ~chksum_buffer( +        (unsigned short *) &pkt.ip, sizeof(pkt.ip)/sizeof(short), 0 +    )); + +    pkt.icmp.type = type; +    pkt.icmp.code = code; +    pkt.icmp.chksum = 0; +    pkt.icmp.id = id; +    pkt.icmp.seqno = seq; +    pkt.icmp.chksum = ~chksum_buffer( //data checksum +        (unsigned short *)buff, +        num_bytes/sizeof(short), +        chksum_buffer(                  //header checksum +            (unsigned short *)&pkt.icmp, +            sizeof(pkt.icmp)/sizeof(short), +        0) +    ); + +    send_eth_pkt(&pkt, sizeof(pkt), buff, num_bytes, NULL, 0); +} + +/*********************************************************************** + * Ethernet handlers + **********************************************************************/ +static void handle_eth_packet(const void *buff, const size_t num_bytes) +{ +    const padded_eth_hdr_t *eth_hdr = (padded_eth_hdr_t *)buff; +    const uint8_t *eth_body = ((const uint8_t *)buff) + sizeof(padded_eth_hdr_t); +    //printf("handle_eth_packet got ethertype 0x%x\n", (unsigned)eth_hdr->ethertype); + +    if (eth_hdr->ethertype == ETHERTYPE_ARP) +    { +        //printf("eth_hdr->ethertype == ETHERTYPE_ARP\n"); +        const struct arp_eth_ipv4 *arp = (const struct arp_eth_ipv4 *)eth_body; +        handle_arp_packet(eth_hdr->ethno, arp); +    } +    else if (eth_hdr->ethertype == ETHERTYPE_IPV4) +    { +        //printf("eth_hdr->ethertype == ETHERTYPE_IPV4\n"); +        const struct ip_hdr *ip = (const struct ip_hdr *)eth_body; +        const uint8_t *ip_body = eth_body + IP_HLEN; + +        if (IPH_V(ip) != 4 || IPH_HL(ip) != 5) return;// ignore pkts w/ bad version or options +        if (IPH_OFFSET(ip) & (IP_MF | IP_OFFMASK)) return;// ignore fragmented packets + +        //TODO -- only handle when the mac is bcast or IP is for us + +        u3_net_stack_arp_cache_update(&ip->src, ð_hdr->src, eth_hdr->ethno); + +        if (IPH_PROTO(ip) == IP_PROTO_UDP) +        { +            handle_udp_packet( +                eth_hdr->ethno, &ip->src, &ip->dest, +                (const struct udp_hdr *)ip_body, +                IPH_LEN(ip) - IP_HLEN +            ); +        } + +        if (IPH_PROTO(ip) == IP_PROTO_ICMP) +        { +            handle_icmp_packet( +                eth_hdr->ethno, &ip->src, &ip->dest, +                (const struct icmp_echo_hdr *)ip_body, +                IPH_LEN(ip) - IP_HLEN +            ); +        } +    } +    else return;	// Not ARP or IPV4, ignore +} + +void u3_net_stack_handle_one(void) +{ +    size_t num_bytes = 0; +    const void *ptr = wb_pkt_iface64_rx_try_claim(pkt_iface_config, &num_bytes); +    if (ptr != NULL) +    { +        //printf("u3_net_stack_handle_one got %u bytes\n", (unsigned)num_bytes); +        incr_stat_counts(ptr); +        handle_eth_packet(ptr, num_bytes); +        wb_pkt_iface64_rx_release(pkt_iface_config); +    } +} diff --git a/firmware/usrp3/lib/udp_uart.c b/firmware/usrp3/lib/udp_uart.c new file mode 100644 index 000000000..d078aa2c3 --- /dev/null +++ b/firmware/usrp3/lib/udp_uart.c @@ -0,0 +1,149 @@ +/* + * Copyright 2011-2013 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include <wb_uart.h> +#include <udp_uart.h> +#include <u3_net_stack.h> + +/*********************************************************************** + * Constants + **********************************************************************/ +#define MAX_NUM_UARTS 4 + +static const size_t num_idle_cyc_b4_flush = 22; + +/*********************************************************************** + * Globals + **********************************************************************/ +typedef struct +{ +    uint32_t uart_base; +    struct ip_addr host_addr; +    int host_ethno; +    uint16_t host_port; +    uint16_t local_port; +    __attribute__ ((aligned (16))) uint8_t buf[256]; +    size_t len; //length of buffer +    size_t cyc; //idle cycle count +} udp_uart_state_t; + +static udp_uart_state_t _states[MAX_NUM_UARTS]; + +static int udp_uart_lookup(const uint16_t port) +{ +    for (size_t i = 0; i < MAX_NUM_UARTS; i++) +    { +        if (_states[i].local_port == port) return i; +    } +    return -1; +} + +/*********************************************************************** + * UDP handler for UARTs + **********************************************************************/ +static void handle_uart_data_packet( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t src_port, const uint16_t dst_port, +    const void *buff, const size_t num_bytes +){ +    //handle ICMP destination unreachable +    if (buff == NULL) +    { +        const size_t which = udp_uart_lookup(src_port); +        if (which == -1) return; +        _states[which].host_port = 0; +    } + +    //handle a regular blocking UART write +    else +    { +        const size_t which = udp_uart_lookup(dst_port); +        if (which == -1) return; +        _states[which].host_ethno = ethno; +        _states[which].host_addr = *src; +        _states[which].host_port = src_port; +        for (size_t i = 0; i < num_bytes; i++) +        { +            const char ch = ((const char *)buff)[i]; +            if (ch == '\n') wb_uart_putc(_states[which].uart_base, (int)'\r'); +            wb_uart_putc(_states[which].uart_base, (int)ch); +            udp_uart_poll(); +        } +    } +} + +/*********************************************************************** + * Public init function + **********************************************************************/ +void udp_uart_init(const uint32_t uart_base, const uint16_t udp_port) +{ +    for (size_t i = 0; i < MAX_NUM_UARTS; i++) +    { +        if (_states[i].uart_base != 0) continue; +        _states[i].uart_base = uart_base; +        _states[i].local_port = udp_port; +        _states[i].host_port = 0; //reset to null port +        _states[i].len = 0; +        _states[i].cyc = 0; +        u3_net_stack_register_udp_handler(udp_port, &handle_uart_data_packet); +        return; +    } +} + +/*********************************************************************** + * Public poll function + **********************************************************************/ +void udp_uart_poll(void) +{ +    for (size_t i = 0; i < MAX_NUM_UARTS; i++) +    { +        if (_states[i].uart_base == 0) continue; + +        bool newline = false; +        udp_uart_state_t *state = &_states[i]; + +        //read all characters we can without blocking +        for (size_t j = state->len; j < sizeof(state->buf); j++) +        { +            int ret = wb_uart_getc(state->uart_base); +            if (ret == -1) break; +            char ch = (char) ret; +            if (ch == '\n' || ch == '\r') newline = true; +            state->buf[j] = ch; +            state->len++; +            state->cyc = 0; //reset idle cycles +        } + +        //nothing in buffer, continue to next uart +        if (state->len == 0) continue; + +        //send out a message if newline or forced flush +        if (newline || state->cyc++ > num_idle_cyc_b4_flush) +        { +            if (state->host_port != 0) u3_net_stack_send_udp_pkt( +                state->host_ethno, +                &state->host_addr, +                state->local_port, +                state->host_port, +                state->buf, state->len +            ); +            state->len = 0; +            state->cyc = 0; +        } +    } +} diff --git a/firmware/usrp3/lib/wb_i2c.c b/firmware/usrp3/lib/wb_i2c.c new file mode 100644 index 000000000..611908e18 --- /dev/null +++ b/firmware/usrp3/lib/wb_i2c.c @@ -0,0 +1,137 @@ + +// Copyright 2012 Ettus Research LLC +/* + * Copyright 2007 Free Software Foundation, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +// NOTE: this driver left shifts a "7bit" I2C address by one bit and puts a R/W bit as bit 0. +// Some devices may specify there I2C address assuming this R/W bit is already in place. + +#include <wb_i2c.h> + +typedef struct { +  volatile uint32_t  prescaler_lo;	// r/w +  volatile uint32_t  prescaler_hi;	// r/w +  volatile uint32_t  ctrl;		// r/w +  volatile uint32_t  data;		// wr = transmit reg; rd = receive reg +  volatile uint32_t  cmd_status;	// wr = command reg;  rd = status reg +} i2c_regs_t; + +#define i2c_regs ((i2c_regs_t *) base) + +#define	I2C_CTRL_EN	(1 << 7)	// core enable +#define	I2C_CTRL_IE	(1 << 6)	// interrupt enable + +// +// STA, STO, RD, WR, and IACK bits are cleared automatically +// +#define	I2C_CMD_START	(1 << 7)	// generate (repeated) start condition +#define I2C_CMD_STOP	(1 << 6)	// generate stop condition +#define	I2C_CMD_RD	(1 << 5)	// read from slave +#define I2C_CMD_WR	(1 << 4)	// write to slave +#define	I2C_CMD_NACK	(1 << 3)	// when a rcvr, send ACK (ACK=0) or NACK (ACK=1) +#define I2C_CMD_RSVD_2	(1 << 2)	// reserved +#define	I2C_CMD_RSVD_1	(1 << 1)	// reserved +#define I2C_CMD_IACK	(1 << 0)	// set to clear pending interrupt + +#define I2C_ST_RXACK	(1 << 7)	// Received acknowledgement from slave (1 = NAK, 0 = ACK) +#define	I2C_ST_BUSY	(1 << 6)	// 1 after START signal detected; 0 after STOP signal detected +#define	I2C_ST_AL	(1 << 5)	// Arbitration lost.  1 when core lost arbitration +#define	I2C_ST_RSVD_4	(1 << 4)	// reserved +#define	I2C_ST_RSVD_3	(1 << 3)	// reserved +#define	I2C_ST_RSVD_2	(1 << 2)	// reserved +#define I2C_ST_TIP	(1 << 1)	// Transfer-in-progress +#define	I2C_ST_IP	(1 << 0)	// Interrupt pending + +void wb_i2c_init(const uint32_t base, const size_t clk_rate) +{ +    // prescaler divisor values for 100 kHz I2C [uses 5 * SCLK internally] +    const uint16_t prescaler = (clk_rate/(5 * 400000)) - 1; +  i2c_regs->prescaler_lo = prescaler & 0xff; +  i2c_regs->prescaler_hi = (prescaler >> 8) & 0xff; + +  i2c_regs->ctrl = I2C_CTRL_EN; //| I2C_CTRL_IE;	// enable core +} + +static inline void +wait_for_xfer(const uint32_t base) +{ +  while (i2c_regs->cmd_status & I2C_ST_TIP)	// wait for xfer to complete +    ; +} + +static inline bool +wait_chk_ack(const uint32_t base) +{ +  wait_for_xfer(base); + +  if ((i2c_regs->cmd_status & I2C_ST_RXACK) != 0){	// target NAK'd +    return false; +  } +  return true; +} + +bool wb_i2c_read(const uint32_t base, const uint8_t i2c_addr, uint8_t *buf, size_t len) +{ +  if (len == 0)			// reading zero bytes always works +    return true; + +  while (i2c_regs->cmd_status & I2C_ST_BUSY) +    ; + +  i2c_regs->data = (i2c_addr << 1) | 1;	 // 7 bit address and read bit (1) +  // generate START and write addr +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START; +  if (!wait_chk_ack(base)) +    goto fail; + +  for (; len > 0; buf++, len--){ +    i2c_regs->cmd_status = I2C_CMD_RD | (len == 1 ? (I2C_CMD_NACK | I2C_CMD_STOP) : 0); +    wait_for_xfer(base); +    *buf = i2c_regs->data; +  } +  return true; + + fail: +  i2c_regs->cmd_status = I2C_CMD_STOP;  // generate STOP +  return false; +} + +bool wb_i2c_write(const uint32_t base, const uint8_t i2c_addr, const uint8_t *buf, size_t len) +{ +  while (i2c_regs->cmd_status & I2C_ST_BUSY) +    ; + +  i2c_regs->data = (i2c_addr << 1) | 0;	 // 7 bit address and write bit (0) + +  // generate START and write addr (and maybe STOP) +  i2c_regs->cmd_status = I2C_CMD_WR | I2C_CMD_START | (len == 0 ? I2C_CMD_STOP : 0); +  if (!wait_chk_ack(base)) +    goto fail; + +  for (; len > 0; buf++, len--){ +    i2c_regs->data = *buf; +    i2c_regs->cmd_status = I2C_CMD_WR | (len == 1 ? I2C_CMD_STOP : 0); +    if (!wait_chk_ack(base)) +      goto fail; +  } +  return true; + + fail: +  i2c_regs->cmd_status = I2C_CMD_STOP;  // generate STOP +  return false; +} + diff --git a/firmware/usrp3/lib/wb_pkt_iface64.c b/firmware/usrp3/lib/wb_pkt_iface64.c new file mode 100644 index 000000000..3c0774bdd --- /dev/null +++ b/firmware/usrp3/lib/wb_pkt_iface64.c @@ -0,0 +1,87 @@ +// Copyright 2012 Ettus Research LLC + +#include <wb_pkt_iface64.h> +#include <wb_utils.h> +#include <printf.h> + +#define NUM_BYTES_MASK 0x1fff + +static uint32_t get_status(wb_pkt_iface64_config_t *config) +{ +    return wb_peek32(config->config_addr); +} + +static void set_control(wb_pkt_iface64_config_t *config) +{ +    wb_poke32(config->config_addr, config->ctrl); +} + +wb_pkt_iface64_config_t wb_pkt_iface64_init(const uint32_t base, const size_t ctrl_offset) +{ +    wb_pkt_iface64_config_t config; +    config.base = base; +    config.ctrl = 0; +    config.config_addr = base + ctrl_offset; +    set_control(&config); +    wb_pkt_iface64_rx_release(&config); //always release, in case left in a filled state +    return config; +} + +const void *wb_pkt_iface64_rx_try_claim(wb_pkt_iface64_config_t *config, size_t *num_bytes) +{ +    const uint32_t status = get_status(config); +    const uint32_t rx_state_flag = (status >> 31) & 0x1; +    *num_bytes = (status & NUM_BYTES_MASK); +    //if (*num_bytes & 0x7) *num_bytes -= 8; //adjust for tuser +    if (rx_state_flag == 0) return NULL; +    return (void *)config->base; +} + +void wb_pkt_iface64_rx_release(wb_pkt_iface64_config_t *config) +{ +    config->ctrl |= 1ul << 31; //does a release +    set_control(config); +    while (true) +    { +        const uint32_t status = get_status(config); +        const uint32_t rx_state_flag = (status >> 31) & 0x1; +        if (rx_state_flag == 0) +        { +            config->ctrl &= ~(1ul << 31); //allows for next claim +            set_control(config); +            return; +        } +    } +} + +void *wb_pkt_iface64_tx_claim(wb_pkt_iface64_config_t *config) +{ +    while (true) +    { +        const uint32_t status = get_status(config); +        const uint32_t tx_state_flag = (status >> 30) & 0x1; +        if (tx_state_flag == 1) break; +    } +    return (void *)config->base; +} + +void wb_pkt_iface64_tx_submit(wb_pkt_iface64_config_t *config, size_t num_bytes) +{ +    config->ctrl |= (1ul << 30); //allows for next claim +    config->ctrl &= ~(NUM_BYTES_MASK); //clear num bytes +    if (num_bytes & 0x7) num_bytes += 8; //adjust for tuser +    config->ctrl |= num_bytes & NUM_BYTES_MASK; //set num bytes +    set_control(config); + +    //wait for state machine to transition +    while (true) +    { +        const uint32_t status = get_status(config); +        const uint32_t tx_state_flag = (status >> 30) & 0x1; +        if (tx_state_flag == 0) break; +    } + +    config->ctrl &= ~(1ul << 30); //release +    set_control(config); + +} diff --git a/firmware/usrp3/lib/wb_uart.c b/firmware/usrp3/lib/wb_uart.c new file mode 100644 index 000000000..368d0e150 --- /dev/null +++ b/firmware/usrp3/lib/wb_uart.c @@ -0,0 +1,34 @@ +// Copyright 2012 Ettus Research LLC + +#include <wb_uart.h> +#include <wb_utils.h> + +localparam SUART_CLKDIV = 0; +localparam SUART_TXLEVEL = 1; +localparam SUART_RXLEVEL = 2; +localparam SUART_TXCHAR = 3; +localparam SUART_RXCHAR = 4; + +void wb_uart_init(const uint32_t base, const size_t div) +{ +    wb_poke32(base + SUART_CLKDIV*4, div); +} + +void wb_uart_putc(const uint32_t base, const int ch) +{ +    while (wb_peek32(base + SUART_TXLEVEL*4) == 0); +    wb_poke32(base + SUART_TXCHAR*4, ch); +} + +bool wb_uart_try_putc(const uint32_t base, const int ch) +{ +    if (wb_peek32(base + SUART_TXLEVEL*4) == 0) return false; +    wb_poke32(base + SUART_TXCHAR*4, ch); +    return true; +} + +int wb_uart_getc(const uint32_t base) +{ +    if (wb_peek32(base + SUART_RXLEVEL*4) == 0) return -1; +    return wb_peek32(base + SUART_RXCHAR*4); +} diff --git a/firmware/usrp3/lwip/lwip-1.3.1/CHANGELOG b/firmware/usrp3/lwip/lwip-1.3.1/CHANGELOG new file mode 100644 index 000000000..a45765010 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/CHANGELOG @@ -0,0 +1,2248 @@ +FUTURE + +  * TODO: The lwIP source code makes some invalid assumptions on processor +    word-length, storage sizes and alignment. See the mailing lists for +    problems with exoteric (/DSP) architectures showing these problems. +    We still have to fix some of these issues neatly. + +  * TODO: the PPP code is broken in a few ways. There are namespace +    collisions on BSD systems and many assumptions on word-length +    (sizeof(int)). In ppp.c an assumption is made on the availability of +    a thread subsystem. Either PPP needs to be moved to contrib/ports/??? +    or rearranged to be more generic. + +HISTORY + +(CVS HEAD) + +  * [Enter new changes just after this line - do not remove this line] + +  ++ New features: + +  ++ Bugfixes: + + +(STABLE-1.3.1) + +  ++ New features: + +  2009-05-10 Simon Goldschmidt +  * opt.h, sockets.c, pbuf.c, netbuf.h, pbuf.h: task #7013: Added option +    LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only +    one pbuf to help MACs that don't support scatter-gather DMA. + +  2009-05-09 Simon Goldschmidt +  * icmp.h, icmp.c: Shrinked ICMP code, added option to NOT check icoming +    ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN + +  2009-05-05 Simon Goldschmidt, Jakob Stoklund Olesen +  * ip.h, ip.c: Added ip_current_netif() & ip_current_header() to receive +    extended info about the currently received packet. + +  2009-04-27 Simon Goldschmidt +  * sys.h: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 + +  2009-04-25 Simon Goldschmidt +  * mem.c, opt.h: Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next +    bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). + +  2009-04-21 Simon Goldschmidt +  * dns.c, init.c, dns.h, opt.h: task #7507, patch #6786: DNS supports static +    hosts table. New configuration options DNS_LOCAL_HOSTLIST and +    DNS_LOCAL_HOSTLIST_IS_DYNAMIC. Also, DNS_LOOKUP_LOCAL_EXTERN() can be defined +    as an external function for lookup. + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: patch #6763: Global DHCP XID can be redefined to something more unique + +  2009-03-31 Kieran Mansley +  * tcp.c, tcp_out.c, tcp_in.c, sys.h, tcp.h, opts.h: add support for +    TCP timestamp options, off by default.  Rework tcp_enqueue() to +    take option flags rather than specified option data + +  2009-02-18 Simon Goldschmidt +  * cc.h: Added printf formatter for size_t: SZT_F + +  2009-02-16 Simon Goldschmidt (patch by Rishi Khan) +  * icmp.c, opt.h: patch #6539: (configurable) response to broadcast- and multicast +    pings + +  2009-02-12 Simon Goldschmidt +  * init.h: Added LWIP_VERSION to get the current version of the stack + +  2009-02-11 Simon Goldschmidt (suggested by Gottfried Spitaler) +  * opt.h, memp.h/.c: added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead +    of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc +    is otherwise used) + +  2009-01-28 Jonathan Larmour (suggested by Bill Bauerbach) +  * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial() +  is only used by UDPLITE at present, so conditionalise it. + +  2008-12-03 Simon Goldschmidt (base on patch from Luca Ceresoli) +  * autoip.c: checked in (slightly modified) patch #6683: Customizable AUTOIP +    "seed" address. This should reduce AUTOIP conflicts if +    LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. + +  2008-10-02 Jonathan Larmour and Rishi Khan +  * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking +    socket. + +  2008-06-30 Simon Goldschmidt +  * mem.c, opt.h, stats.h: fixed bug #21433: Calling mem_free/pbuf_free from +    interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows +    mem_free to run between mem_malloc iterations. Added illegal counter for +    mem stats. + +  2008-06-27 Simon Goldschmidt +  * stats.h/.c, some other files: patch #6483: stats module improvement: +    Added defines to display each module's statistic individually, added stats +    defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. + +  2008-06-17 Simon Goldschmidt +  * err.h: patch #6459: Made err_t overridable to use a more efficient type +    (define LWIP_ERR_T in cc.h) + +  2008-06-17 Simon Goldschmidt +  * slipif.c: patch #6480: Added a configuration option for slipif for symmetry +    to loopif + +  2008-06-17 Simon Goldschmidt (patch by Luca Ceresoli) +  * netif.c, loopif.c, ip.c, netif.h, loopif.h, opt.h: Checked in slightly +    modified version of patch # 6370: Moved loopif code to netif.c so that +    loopback traffic is supported on all netifs (all local IPs). +    Added option to limit loopback packets for each netifs. + + +  ++ Bugfixes: +  2009-08-12 Kieran Mansley +  * tcp_in.c, tcp.c: Fix bug #27209: handle trimming of segments when +    out of window or out of order properly + +  2009-08-12 Kieran Mansley +  * tcp_in.c: Fix bug #27199: use snd_wl2 instead of snd_wl1 + +  2009-07-28 Simon Goldschmidt +  * mem.h: Fixed bug #27105: "realloc() cannot replace mem_realloc()"s + +  2009-07-27 Kieran Mansley +  * api.h api_msg.h netdb.h sockets.h: add missing #include directives + +  2009-07-09 Kieran Mansley +  * api_msg.c, sockets.c, api.h: BUG23240 use signed counters for +    recv_avail and don't increment counters until message successfully +    sent to mbox + +  2009-06-25 Kieran Mansley +  * api_msg.c api.h: BUG26722: initialise netconn write variables  +    in netconn_alloc + +  2009-06-25 Kieran Mansley +  * tcp.h: BUG26879: set ret value in TCP_EVENT macros when function is not set + +  2009-06-25 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: BUG26301 and BUG26267: correct +    simultaneous close behaviour, and make snd_nxt have the same meaning  +    as in the RFCs. + +  2009-05-12 Simon Goldschmidt +  * etharp.h, etharp.c, netif.c: fixed bug #26507: "Gratuitous ARP depends on +    arp_table / uses etharp_query" by adding etharp_gratuitous() + +  2009-05-12 Simon Goldschmidt +  * ip.h, ip.c, igmp.c: bug #26487: Added ip_output_if_opt that can add IP options +    to the IP header (used by igmp_ip_output_if) + +  2009-05-06 Simon Goldschmidt +  * inet_chksum.c: On little endian architectures, use LWIP_PLATFORM_HTONS (if +    defined) for SWAP_BYTES_IN_WORD to speed up checksumming. + +  2009-05-05 Simon Goldschmidt +  * sockets.c: bug #26405: Prematurely released semaphore causes lwip_select() +    to crash + +  2009-05-04 Simon Goldschmidt +  * init.c: snmp was not initialized in lwip_init() + +  2009-05-04 Frédéric Bernon +  * dhcp.c, netbios.c: Changes if IP_SOF_BROADCAST is enabled. + +  2009-05-03 Simon Goldschmidt +  * tcp.h: bug #26349: Nagle algorithm doesn't send although segment is full +    (and unsent->next == NULL) + +  2009-05-02 Simon Goldschmidt +  * tcpip.h, tcpip.c: fixed tcpip_untimeout (does not need the time, broken after +    1.3.0 in CVS only) - fixes compilation of ppp_oe.c + +  2009-05-02 Simon Goldschmidt +  * msg_in.c: fixed bug #25636: SNMPSET value is ignored for integer fields + +  2009-05-01 Simon Goldschmidt +  * pap.c: bug #21680: PPP upap_rauthnak() drops legal NAK packets + +  2009-05-01 Simon Goldschmidt +  * ppp.c: bug #24228: Memory corruption with PPP and DHCP + +  2009-04-29 Frédéric Bernon +  * raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the +    SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception +    of broadcast packets even when this option wasn't set. Port maintainers +    which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. +    If you want this option also filter broadcast on recv operations, you also +    have to set IP_SOF_BROADCAST_RECV=1 in opt.h. + +  2009-04-28 Simon Goldschmidt, Jakob Stoklund Olesen +  * dhcp.c: patch #6721, bugs #25575, #25576: Some small fixes to DHCP and +    DHCP/AUTOIP cooperation + +  2009-04-25 Simon Goldschmidt, Oleg Tyshev +  * tcp_out.c: bug #24212: Deadlocked tcp_retransmit due to exceeded pcb->cwnd +    Fixed by sorting the unsent and unacked queues (segments are inserted at the +    right place in tcp_output and tcp_rexmit). + +  2009-04-25 Simon Goldschmidt +  * memp.c, mem.c, memp.h, mem_std.h: bug #26213 "Problem with memory allocation +    when debugging": memp_sizes contained the wrong sizes (including sanity +    regions); memp pools for MEM_USE_POOLS were too small + +  2009-04-24 Simon Goldschmidt, Frédéric Bernon +  * inet.c: patch #6765: Fix a small problem with the last changes (incorrect +    behavior, with with ip address string not ended by a '\0', a space or a +    end of line) + +  2009-04-19 Simon Goldschmidt +  * rawapi.txt: Fixed bug #26069: Corrected documentation: if tcp_connect fails, +    pcb->err is called, not pcb->connected (with an error code). + +  2009-04-19 Simon Goldschmidt +  * tcp_out.c: Fixed bug #26236: "TCP options (timestamp) don't work with +    no-copy-tcpwrite": deallocate option data, only concat segments with same flags + +  2009-04-19 Simon Goldschmidt +  * tcp_out.c: Fixed bug #25094: "Zero-length pbuf" (options are now allocated +    in the header pbuf, not the data pbuf) + +  2009-04-18 Simon Goldschmidt +  * api_msg.c: fixed bug #25695: Segmentation fault in do_writemore() + +  2009-04-15 Simon Goldschmidt +  * sockets.c: tried to fix bug #23559: lwip_recvfrom problem with tcp + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: task #9192: mem_free of dhcp->options_in and dhcp->msg_in + +  2009-04-15 Simon Goldschmidt +  * ip.c, ip6.c, tcp_out.c, ip.h: patch #6808: Add a utility function +    ip_hinted_output() (for smaller code mainly) + +  2009-04-15 Simon Goldschmidt +  * inet.c: patch #6765: Supporting new line characters in inet_aton() + +  2009-04-15 Simon Goldschmidt +  * dhcp.c: patch #6764: DHCP rebind and renew did not send hostnam option; +    Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu +    is big enough in dhcp_start + +  2009-04-15 Simon Goldschmidt +  * netbuf.c: bug #26027: netbuf_chain resulted in pbuf memory leak + +  2009-04-15 Simon Goldschmidt +  * sockets.c, ppp.c: bug #25763: corrected 4 occurrences of SMEMCPY to MEMCPY + +  2009-04-15 Simon Goldschmidt +  * sockets.c: bug #26121: set_errno can be overridden + +  2009-04-09 Kieran Mansley (patch from Luca Ceresoli <lucaceresoli>) +  * init.c, opt.h: Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when +    LWIP_TCP==0 + +  2009-04-09 Kieran Mansley (patch from Roy Lee <roylee17>) +  * tcp.h: Patch#6802 Add do-while-clauses to those function like +    macros in tcp.h + +  2009-03-31 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h, opt.h: Rework the way window +    updates are calculated and sent (BUG20515) + +  * tcp_in.c: cope with SYN packets received during established states, +    and retransmission of initial SYN. + +  * tcp_out.c: set push bit correctly when tcp segments are merged + +  2009-03-27 Kieran Mansley +  * tcp_out.c set window correctly on probes (correcting change made +    yesterday) + +  2009-03-26 Kieran Mansley +  * tcp.c, tcp_in.c, tcp.h: add tcp_abandon() to cope with dropping +    connections where no reset required (bug #25622) + +  * tcp_out.c: set TCP_ACK flag on keepalive and zero window probes  +    (bug #20779) + +  2009-02-18 Simon Goldschmidt (Jonathan Larmour and Bill Auerbach) +  * ip_frag.c: patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be +    too small depending on MEM_ALIGNMENT + +  2009-02-16 Simon Goldschmidt +  * sockets.h/.c, api_*.h/.c: fixed arguments of socket functions to match the standard; +    converted size argument of netconn_write to 'size_t' + +  2009-02-16 Simon Goldschmidt +  * tcp.h, tcp.c: fixed bug #24440: TCP connection close problem on 64-bit host +    by moving accept callback function pointer to TCP_PCB_COMMON + +  2009-02-12 Simon Goldschmidt +  * dhcp.c: fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" +    option) + +  2009-02-11 Simon Goldschmidt +  * dhcp.c: fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) + +  2009-02-11 Simon Goldschmidt +  * opt.h, api_msg.c: added configurable default valud for netconn->recv_bufsize: +    RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) + +  2009-02-10 Simon Goldschmidt +  * tcp.c: fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: +    Accepts_pending is decrease on a corresponding listen pcb when a connection +    in state SYN_RCVD is close. + +  2009-01-28 Jonathan Larmour +  * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run +    out of pool pbufs. + +  2008-12-19 Simon Goldschmidt +  * many files: patch #6699: fixed some warnings on platform where sizeof(int) == 2  + +  2008-12-10 Tamas Somogyi, Frédéric Bernon +  * sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and +    port uses deleted netbuf. + +  2008-10-18 Simon Goldschmidt +  * tcp_in.c: fixed bug ##24596: Vulnerability on faulty TCP options length +    in tcp_parseopt + +  2008-10-15 Simon Goldschmidt +  * ip_frag.c: fixed bug #24517: IP reassembly crashes on unaligned IP headers +    by packing the struct ip_reass_helper. + +  2008-10-03 David Woodhouse, Jonathan Larmour +  * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. + +  2008-10-02 Jonathan Larmour +  * dns.c: Hard-code structure sizes, to avoid issues on some compilers where +    padding is included. + +  2008-09-30 Jonathan Larmour +  * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an +    assertion check that addrlen isn't NULL. + +  2008-09-30 Jonathan Larmour +  * tcp.c: Fix bug #24227, wrong error message in tcp_bind. + +  2008-08-26 Simon Goldschmidt +  * inet.h, ip_addr.h: fixed bug #24132: Cross-dependency between ip_addr.h and +    inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h + +  2008-08-14 Simon Goldschmidt +  * api_msg.c: fixed bug #23847: do_close_internal references freed memory (when +    tcp_close returns != ERR_OK) + +  2008-07-08 Frédéric Bernon +  * stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters +    in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). + +  2008-06-24 Jonathan Larmour +  * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused +    if tcp_seg_copy fails. + +  2008-06-17 Simon Goldschmidt +  * inet_chksum.c: Checked in some ideas of patch #6460 (loop optimizations) +    and created defines for swapping bytes and folding u32 to u16. + +  2008-05-30 Kieran Mansley +  * tcp_in.c Remove redundant "if" statement, and use real rcv_wnd +    rather than rcv_ann_wnd when deciding if packets are in-window. +    Contributed by <arasmussen@consultant.datasys.swri.edu> + +  2008-05-30 Kieran Mansley +  * mem.h: Fix BUG#23254.  Change macro definition of mem_* to allow +    passing as function pointers when MEM_LIBC_MALLOC is defined. + +  2008-05-09 Jonathan Larmour +  * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to +    stop it being treated as a fatal error. + +  2008-04-15 Simon Goldschmidt +  * dhcp.c: fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP +    (flag now cleared) + +  2008-03-27 Simon Goldschmidt +  * mem.c, tcpip.c, tcpip.h, opt.h: fixed bug #21433 (Calling mem_free/pbuf_free +    from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 +    in lwipopts.h or use pbuf_free_callback(p)/mem_free_callback(m) to free pbufs +    or heap memory from interrupt context + +  2008-03-26 Simon Goldschmidt +  * tcp_in.c, tcp.c: fixed bug #22249: division by zero could occur if a remote +    host sent a zero mss as TCP option. + + +(STABLE-1.3.0) + +  ++ New features: + +  2008-03-10 Jonathan Larmour +  * inet_chksum.c: Allow choice of one of the sample algorithms to be +    made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM. + +  2008-01-22 Frédéric Bernon +  * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in  +    TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names. + +  2008-01-14 Frédéric Bernon +  * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable +    to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the +    tcp_recv callback (see rawapi.txt). + +  2008-01-14 Frédéric Bernon, Marc Chaland +  * ip.c: Integrate patch #6369" ip_input : checking before realloc". +   +  2008-01-12 Frédéric Bernon +  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field +    netconn::sem per netconn::op_completed like suggested for the task #7490 +    "Add return value to sys_mbox_post". + +  2008-01-12 Frédéric Bernon +  * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE, +    DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues +    sizes), like suggested for the task #7490 "Add return value to sys_mbox_post". + +  2008-01-10 Frédéric Bernon +  * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490 +    "Add return value to sys_mbox_post". tcpip_callback is always defined as +    "blocking" ("block" parameter = 1). + +  2008-01-10 Frédéric Bernon +  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field +    netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490 +    "Add return value to sys_mbox_post". + +  2008-01-05 Frédéric Bernon +  * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h: +    Introduce changes for task #7490 "Add return value to sys_mbox_post" with some +    modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which +    indicate the number of pointers query by the mailbox. There is three defines +    in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the  +    netconn::acceptmbox. Port maintainers, you can decide to just add this new  +    parameter in your implementation, but to ignore it to keep the previous behavior. +    The new sys_mbox_trypost function return a value to know if the mailbox is +    full or if the message is posted. Take a look to sys_arch.txt for more details. +    This new function is used in tcpip_input (so, can be called in an interrupt +    context since the function is not blocking), and in recv_udp and recv_raw. + +  2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour +  * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c, +    tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the +    "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add +    documentation in the rawapi.txt file. + +  2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm) +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer + +  2007-12-31 Frédéric Bernon, Luca Ceresoli +  * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets +    in autoip". The change in etharp_raw could be removed, since all calls to +    etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be +    wrong in the future. + +  2007-12-30 Frédéric Bernon, Tom Evans +  * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address +    Filtering" reported by Tom Evans. + +  2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour +  * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c, +    sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API +    applications have to call 'tcp_accepted(pcb)' in their accept callback to +    keep accepting new connections. + +  2007-12-13 Frédéric Bernon +  * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result" +    by err_t type. Add a new err_t code "ERR_INPROGRESS". + +  2007-12-12 Frédéric Bernon +  * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles +    are the one which have ram usage. + +  2007-12-05 Frédéric Bernon +  * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static +    set of variables (=0) or a local one (=1). In this last case, your port should +    provide a function "struct hostent* sys_thread_hostent( struct hostent* h)" +    which have to do a copy of "h" and return a pointer ont the "per-thread" copy. + +  2007-12-03 Simon Goldschmidt +  * ip.c: ip_input: check if a packet is for inp first before checking all other +    netifs on netif_list (speeds up packet receiving in most cases) + +  2007-11-30 Simon Goldschmidt +  * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access +    UDP: move a (connected) pcb selected for input to the front of the list of +    pcbs so that it is found faster next time. Same for RAW pcbs that have eaten +    a packet. + +  2007-11-28 Simon Goldschmidt +  * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS + +  2007-11-25 Simon Goldschmidt +  * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy +    algorithm. + +  2007-11-24 Simon Goldschmidt +  * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c +    to the new file netdb.c; included lwip_getaddrinfo. + +  2007-11-21 Simon Goldschmidt +  * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss +    based on the MTU of the netif used to send. Enabled by default. Disable by +    setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492. + +  2007-11-19 Frédéric Bernon +  * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name +    received match the name query), implement DNS_USES_STATIC_BUF (the place where +    copy dns payload to parse the response), return an error if there is no place +    for a new query, and fix some minor problems. + +  2007-11-16 Simon Goldschmidt +  * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c +    removed files: core/inet.c, core/inet6.c +    Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into +    inet and chksum part; changed includes in all lwIP files as appropriate + +  2007-11-16 Simon Goldschmidt +  * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential +    dns resolver function for netconn api (netconn_gethostbyname) and socket api +    (gethostbyname/gethostbyname_r). + +  2007-11-15 Jim Pettinato, Frédéric Bernon +  * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name +    requests with RAW api interface. Initialization is done in lwip_init() with +    build time options. DNS timer is added in tcpip_thread context. DHCP can set +    DNS server ip addresses when options are received. You need to set LWIP_DNS=1 +    in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get +    some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo" +    list with points to improve. + +  2007-11-06 Simon Goldschmidt +  * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly +    enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status +    for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined. + +  2007-11-06 Simon Goldschmidt +  * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include +    core header files in api.h (ip/tcp/udp/raw.h) to hide the internal +    implementation from netconn api applications. + +  2007-11-03 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP & +    RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled +    by default). Netconn API users can use the netconn_recv_bufsize macro to access +    it. This is a first release which have to be improve for TCP. Note it used the +    netconn::recv_avail which need to be more "thread-safe" (note there is already +    the problem for FIONREAD with lwip_ioctl/ioctlsocket). + +  2007-11-01 Frédéric Bernon, Marc Chaland +  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c: +    Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api +    layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api +    layer. This option enable to delayed TCP PUSH flag on multiple "write" calls. +    Note that previous "copy" parameter for "write" APIs is now called "apiflags". + +  2007-10-24 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than  +    TCP_EVENT_xxx macros to get a code more readable. It could also help to remove +    some code (like we have talk in "patch #5919 : Create compile switch to remove +    select code"), but it could be done later. + +  2007-10-08 Simon Goldschmidt +  * many files: Changed initialization: many init functions are not needed any +    more since we now rely on the compiler initializing global and static +    variables to zero! + +  2007-10-06 Simon Goldschmidt +  * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY +    to enqueue the received pbufs so that multiple packets can be reassembled +    simultaneously and no static reassembly buffer is needed. + +  2007-10-05 Simon Goldschmidt +  * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so +    all netifs (or ports) can use it. + +  2007-10-05 Frédéric Bernon +  * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the  +    common function to reduce a little bit the footprint (for all functions using +    only the "netif" parameter). + +  2007-10-03 Frédéric Bernon +  * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down, +    netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce +    a little bit the footprint (for all functions using only the "netif" parameter). + +  2007-09-15 Frédéric Bernon +  * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF +    option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for +    netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for +    IP_MULTICAST_TTL and IP_MULTICAST_IF. + +  2007-09-10 Frédéric Bernon +  * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles +    even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime() +    each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can +    decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but +    call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime() +    or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. +    This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside +    snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only +    when it's queried (any direct call to "sysuptime" is changed by a call to  +    snmp_get_sysuptime). + +  2007-09-09 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP, +    and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags +    if you want IGMP on an interface. igmp_stop() is now called inside netif_remove(). +    igmp_report_groups() is now called inside netif_set_link_up() (need to have +    LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait +    the next query message to receive the matching multicast streams). + +  2007-09-08 Frédéric Bernon +  * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains +    IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change). +    Use this new field to access to common pcb fields (ttl, tos, so_options, etc...). +    Enable to access to these fields with LWIP_TCP=0. + +  2007-09-05 Frédéric Bernon +  * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h, +    ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option +    LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default). +    Be careful, disabling ICMP make your product non-compliant to RFC1122, but +    help to reduce footprint, and to reduce "visibility" on the Internet. + +  2007-09-05 Frédéric Bernon, Bill Florac +  * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list +    for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new +    parameters have to be provided: a task name, and a task stack size. For this +    one, since it's platform dependant, you could define the best one for you in +    your lwipopts.h. For port maintainers, you can just add these new parameters +    in your sys_arch.c file, and but it's not mandatory, use them in your OS +    specific functions. + +  2007-09-05 Frédéric Bernon +  * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings +    inside init.c for task #7142 "Sanity check user-configurable values". + +  2007-09-04 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by +    memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the +    value). It will avoid potential fragmentation problems, use a counter to know +    how many times a group is used on an netif, and free it when all applications +    leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity +    check if LWIP_IGMP!=0). + +  2007-09-03 Frédéric Bernon +  * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement". +    Initialize igmp_mac_filter to NULL in netif_add (this field should be set in +    the netif's "init" function). Use the "imr_interface" field (for socket layer) +    and/or the "interface" field (for netconn layer), for join/leave operations. +    The igmp_join/leavegroup first parameter change from a netif to an ipaddr. +    This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany). + +  2007-08-30 Frédéric Bernon +  * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions +    from api/api_lib". Now netbuf API is independant of netconn, and can be used +    with other API (application based on raw API, or future "socket2" API). Ports +    maintainers just have to add src/api/netbuf.c in their makefile/projects. + +  2007-08-30 Frédéric Bernon, Jonathan Larmour +  * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check +    user-configurable values". + +  2007-08-29 Frédéric Bernon +  * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start. +    igmp_start is call inside netif_add. Now, igmp initialization is in the same +    spirit than the others modules. Modify some IGMP debug traces. + +  2007-08-29 Frédéric Bernon +  * Add init.h, init.c, Change opt.h, tcpip.c: Task  #7213 "Add a lwip_init function" +    Add lwip_init function to regroup all modules initializations, and to provide +    a place to add code for task #7142 "Sanity check user-configurable values". +    Ports maintainers should remove direct initializations calls from their code, +    and add init.c in their makefiles. Note that lwip_init() function is called +    inside tcpip_init, but can also be used by raw api users since all calls are +    disabled when matching options are disabled. Also note that their is new options +    in opt.h, you should configure in your lwipopts.h (they are enabled per default). + +  2007-08-26 Marc Boucher +  * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL +    since they can under certain circumstances be called with an invalid conn +    pointer after the connection has been closed (and conn has been freed).  + +  2007-08-25 Frédéric Bernon (Artem Migaev's Patch) +  * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up". +    Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set. + +  2007-08-22 Frédéric Bernon +  * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK +    to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release. + +  2007-08-22 Frédéric Bernon +  * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT & +    ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the  +    name is tcpip_input (we keep the name of 1.2.0 function). + +  2007-08-17 Jared Grubb +  * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool  +    settings into new memp_std.h and optional user file lwippools.h. This adds +    more dynamic mempools, and allows the user to create an arbitrary number of +    mempools for mem_malloc. + +  2007-08-16 Marc Boucher +  * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function; +    otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely +    close the connection. + +  2007-08-16 Marc Boucher +  * sockets.c: lwip_accept(): check netconn_peer() error return. + +  2007-08-16 Marc Boucher +  * mem.c, mem.h: Added mem_calloc(). + +  2007-08-16 Marc Boucher +  * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT) +    for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG +    and starving other message types. +    Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API + +  2007-08-16 Marc Boucher +  * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf +    type and flgs (later renamed to flags). +    Use enum pbuf_flag as pbuf_type.  Renumber PBUF_FLAG_*. +    Improved lwip_recvfrom().  TCP push now propagated. + +  2007-08-16 Marc Boucher +  * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global +    provided by etharp. + +  2007-08-16 Marc Boucher +  * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h, +    etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c: +    Added PPPoE support and various PPP improvements. + +  2007-07-25 Simon Goldschmidt +  * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial, +    making netbuf_copy_partial use this function. + +  2007-07-25 Simon Goldschmidt +  * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with +    2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and +    other stacks. + +  2007-07-13 Jared Grubb (integrated by Frédéric Bernon) +  * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add +    a link callback in the netif struct, and functions to handle it. Be carefull +    for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c) +    if you want to be sure to be compatible with future changes... + +  2007-06-30 Frédéric Bernon +  * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions. + +  2007-06-21 Simon Goldschmidt +  * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both +    LWIP_AUTOIP =0 and =1 to remove redundant code. + +  2007-06-21 Simon Goldschmidt +  * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option +    MEM_USE_POOLS to use 4 pools with different sized elements instead of a +    heap. This both prevents memory fragmentation and gives a higher speed +    at the cost of more memory consumption. Turned off by default. + +  2007-06-21 Simon Goldschmidt +  * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of +    netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into +    int to be able to send a bigger buffer than 64K with one time (mainly +    used from lwip_send). + +  2007-06-21 Simon Goldschmidt +  * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write +    into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too. + +  2007-06-21 Simon Goldschmidt +  * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in +    netconn_write from api_lib.c to api_msg.c to also prevent multiple context- +    changes on low memory or empty send-buffer. + +  2007-06-18 Simon Goldschmidt +  * etharp.c, etharp.h: Changed etharp to use a defined hardware address length +    of 6 to avoid loading netif->hwaddr_len every time (since this file is only +    used for ethernet and struct eth_addr already had a defined length of 6). + +  2007-06-17 Simon Goldschmidt +  * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets +    to disable UDP checksum generation on transmit. + +  2007-06-13 Frédéric Bernon, Simon Goldschmidt +  * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid +    pointers or parameters, and let the possibility to redefined it in cc.h. Use +    this macro to check "conn" parameter in api_msg.c functions. + +  2007-06-11 Simon Goldschmidt +  * sockets.c, sockets.h: Added UDP lite support for sockets + +  2007-06-10 Simon Goldschmidt +  * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled +    by default) to switch off UDP-Lite support if not needed (reduces udp.c code +    size) + +  2007-06-09 Dominik Spies (integrated by Frédéric Bernon) +  * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h: +    AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and +    LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt +    (see TODO mark in the source code). + +  2007-06-09 Simon Goldschmidt +  * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for +    etharp_output() to match netif->output so etharp_output() can be used +    directly as netif->output to save one function call. + +  2007-06-08 Simon Goldschmidt +  * netif.h, ethernetif.c, slipif.c, loopif.c: Added define +    NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables, +    added initialization of those to ethernetif, slipif and loopif. + +  2007-05-18 Simon Goldschmidt +  * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF +    (defaulting to off for now) that can be set to 0 to send fragmented +    packets by passing PBUF_REFs down the stack. + +  2007-05-23 Frédéric Bernon +  * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP +    connections, such present in patch #5959. + +  2007-05-23 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx +    code in only one part... + +  2007-05-18 Simon Goldschmidt +  * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp +    elements to overflow. This is achieved by adding some bytes before and after +    each pool element (increasing their size, of course), filling them with a +    prominent value and checking them on freeing the element. +    Set it to 2 to also check every element in every pool each time memp_malloc() +    or memp_free() is called (slower but more helpful). + +  2007-05-10 Simon Goldschmidt +  * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for +    PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce +    code size. + +  2007-05-11 Frédéric Bernon +  * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c: +    Include a function pointer instead of a table index in the message to reduce +    footprint. Disable some part of lwip_send and lwip_sendto if some options are +    not set (LWIP_TCP, LWIP_UDP, LWIP_RAW). + +  2007-05-10 Simon Goldschmidt +  * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus +    \ extern "C" {' in all header files. Now you can write your application using +    the lwIP stack in C++ and simply #include the core files. Note I have left +    out the netif/ppp/*h header files for now, since I don't know which files are +    included by applications and which are for internal use only. + +  2007-05-09 Simon Goldschmidt +  * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library +    memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for +    situations where some compilers might inline the copy and save a function +    call. Also replaced all calls to memcpy() with calls to (S)MEMCPY(). + +  2007-05-08 Simon Goldschmidt +  * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc()) +    to be overriden in case the C-library malloc implementation is not protected +    against concurrent access. + +  2007-05-04 Simon Goldschmidt (Atte Kojo) +  * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending +    multiple packets to the same host. + +  2007-05-04 Frédéric Bernon, Jonathan Larmour +  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible +    to corrupt remote addr/port connection state". Reduce problems "not enought memory" with +    netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between +    sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function. +    Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct, +    these fields are now renamed "addr" & "port". + +  2007-04-11 Jonathan Larmour +  * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new +    sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return +    with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro +    by the port in sys_arch.h if desired. + +  2007-04-06 Frédéric Bernon, Simon Goldschmidt +  * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API +    allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp +    clients, using new functions from netifapi.h. Disable as default (no port change to do). + +  2007-04-05 Frédéric Bernon +  * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant. + +  2007-04-04 Simon Goldschmidt +  * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x) +    use this for and architecture-independent form to tell the compiler you intentionally +    are not using this variable. Can be overriden in cc.h. + +  2007-03-28 Frédéric Bernon +  * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to +    define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded +    string, point on one of your's ethernetif field, or alloc a string you will free yourself). +    It will be used by DHCP to register a client hostname, but can also be use when you call +    snmp_set_sysname. + +  2007-03-28 Frédéric Bernon +  * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to  +    initialize a network interface's flag with. It tell this interface is an ethernet +    device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility +    Support for IPv4" section 4.6) when interface is "up" with netif_set_up(). + +  2007-03-26 Frédéric Bernon, Jonathan Larmour +  * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build +    time if you only use PPP or SLIP. The default is enable. Note we don't have to call  +    etharp_init in your port's initilization sequence if you use tcpip.c, because this call +    is done in tcpip_init function. + +  2007-03-22 Frédéric Bernon +  * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the +    new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in +    your lwipopts.h. More, unused counters are not defined in the stats structs, and not  +    display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined +    but never used. Fix msg_in.c with the correct #if test for a stat display. + +  2007-03-21 Kieran Mansley +  * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com).  +    Provides callback on netif up/down state change. + +  2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds +  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c, +    ip.c, netif.h, tcpip.c, opt.h: +    New configuration option LWIP_IGMP to enable IGMP processing. Based on only one  +    filter per all network interfaces. Declare a new function in netif to enable to +    control the MAC filter (to reduce lwIP traffic processing). + +  2007-03-11 Frédéric Bernon +  * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can +    be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this +    unless you know what you're doing (default are RFC1122 compliant). Note +    that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds. + +  2007-03-08 Frédéric Bernon +  * tcp.h: Keepalive values can be configured at compile time, but don't change +    this unless you know what you're doing (default are RFC1122 compliant). + +  2007-03-08 Frédéric Bernon +  * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h: +    Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO +    on UDP sockets/netconn. + +  2007-03-08 Simon Goldschmidt +  * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time. + +  2007-03-06 Frédéric Bernon +  * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h:  +    Implement SO_RCVTIMEO on UDP sockets/netconn. + +  2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt) +  * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated +    on the stack and remove the API msg type from memp + +  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) +  * sockets.h, sockets.c: Move socket initialization to new +    lwip_socket_init() function. +    NOTE: this changes the API with ports. Ports will have to be +    updated to call lwip_socket_init() now. + +  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt) +  * api_lib.c: Use memcpy in netbuf_copy_partial. + + +  ++ Bug fixes: + +  2008-03-17 Frédéric Bernon, Ed Kerekes +  * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have +    some problems to fill the IP header on some targets, use now the +    ip.h macros to do it). + +  2008-03-13 Frédéric Bernon +  * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using +    (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a +    TCP connection caused a crash. Note that using (lwip_)recvfrom +    like this is a bit slow and that using (lwip)getpeername is the +    good lwip way to do it (so, using recv is faster on tcp sockets). + +  2008-03-12 Frédéric Bernon, Jonathan Larmour +  * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's +    recv_raw() does not consume data", and the ping sample (with +    LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom +    returned the IP payload, without the IP header). + +  2008-03-04 Jonathan Larmour +  * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors +  and/or warnings on some systems where mem_size_t and size_t differ. +  * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc. + +  2008-03-04 Kieran Mansley (contributions by others)  +  * Numerous small compiler error/warning fixes from contributions to +    mailing list after 1.3.0 release candidate made. + +  2008-01-25 Cui hengbin (integrated by Frédéric Bernon) +  * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures. + +  2008-01-15 Kieran Mansley +  * tcp_out.c: BUG20511.  Modify persist timer to start when we are +    prevented from sending by a small send window, not just a zero +    send window. + +  2008-01-09 Jonathan Larmour +  * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid +    conflict with Linux system headers. + +  2008-01-06 Jonathan Larmour +  * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP +    address entirely on receiving a DHCPNAK, and restarting discovery. + +  2007-12-21 Simon Goldschmidt +  * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail +    is not protected" by using new macros for interlocked access to modify/test +    netconn->recv_avail. + +  2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev) +  * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state) + +  2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm) +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling +    of silly window avoidance and prevent lwIP from shrinking the window) + +  2007-12-04 Simon Goldschmidt +  * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last +    data packet was lost): add assert that all segment lists are empty in +    tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED +    state from LAST_ACK in tcp_process + +  2007-12-02 Simon Goldschmidt +  * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET +    If including <sys/time.h> for system-struct timeval, LWIP_TIMEVAL_PRIVATE now +    has to be set to 0 in lwipopts.h + +  2007-12-02 Simon Goldschmidt +  * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always +    allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen +    netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox. +    This is a fix for thread-safety and allocates all items needed for a netconn +    when the netconn is created. + +  2007-11-30 Simon Goldschmidt +  * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple +    netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed +    to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same +    port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address) + +  2007-11-27 Simon Goldschmidt +  * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by +    letting ip_route only use netifs that are up. + +  2007-11-27 Simon Goldschmidt +  * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF +    and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and +    sockets block most operations once they have seen a fatal error. + +  2007-11-27 Simon Goldschmidt +  * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the +    netif to send as an argument (to be able to send on netifs that are down). + +  2007-11-26 Simon Goldschmidt +  * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs +    arrive out-of-order + +  2007-11-21 Simon Goldschmidt +  * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early +    Fixed the nagle algorithm; nagle now also works for all raw API applications +    and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY' + +  2007-11-12 Frédéric Bernon +  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most +    of the netconn_peer and netconn_addr processing is done inside tcpip_thread +    context in do_getaddr. + +  2007-11-10 Simon Goldschmidt +  * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can +    happen any time). Now the packet simply isn't enqueued when out of memory. + +  2007-11-01 Simon Goldschmidt +  * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or +    TCP_MSS if that is smaller) as long as no MSS option is received from the +    remote host. + +  2007-11-01 Simon Goldschmidt +  * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN) +    is now based on TCP_MSS instead of pcb->mss (on passive open now effectively +    sending our configured TCP_MSS instead of the one received). + +  2007-11-01 Simon Goldschmidt +  * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was +    calculated based on the configured TCP_MSS, not on the MSS option received +    with SYN+ACK. + +  2007-10-09 Simon Goldschmidt +  * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too +    short and also was generated wrong if checksum coverage != tot_len; +    receive: checksum was calculated wrong if checksum coverage != tot_len + +  2007-10-08 Simon Goldschmidt +  * mem.c: lfree was not updated in mem_realloc! + +  2007-10-07 Frédéric Bernon +  * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential +    crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT: +    this change cause an API breakage for netconn_addr, since a parameter +    type change. Any compiler should cause an error without any changes in +    yours netconn_peer calls (so, it can't be a "silent change"). It also +    reduce a little bit the footprint for socket layer (lwip_getpeername & +    lwip_getsockname use now a common lwip_getaddrname function since  +    netconn_peer & netconn_addr have the same parameters). + +  2007-09-20 Simon Goldschmidt +  * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state) +    by checking  tcp_tw_pcbs also + +  2007-09-19 Simon Goldschmidt +  * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies) + +  2007-09-15 Mike Kleshov +  * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used) + +  2007-09-06 Frédéric Bernon +  * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove +    it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which +    already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h" +    if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h. + +  2007-08-30 Frédéric Bernon +  * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces,  +    and fix some coding style. + +  2007-08-28 Frédéric Bernon +  * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any +    kind of packets. These packets are considered like Ethernet packets (payload  +    pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets  +    are considered like IP packets (payload pointing to iphdr). + +  2007-08-27 Frédéric Bernon +  * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error +    problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state +    and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT). + +  2007-08-24 Kieran Mansley +  * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy +    compiler (Paradigm C++) + +  2007-08-09 Frédéric Bernon, Bill Florac +  * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement. +    Introduce IGMP_STATS to centralize statistics management. + +  2007-08-09 Frédéric Bernon, Bill Florac +  * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast +    packet on a udp pcb binded on an netif's IP address, and not on "any". + +  2007-08-09 Frédéric Bernon, Bill Florac +  * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement. +    This is mainly on using lookup/lookfor, and some coding styles... + +  2007-07-26 Frédéric Bernon (and "thedoctor") +  * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages. + +  2007-07-25 Simon Goldschmidt +  * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if +    tcp_output fails in tcp_close, the code in do_close_internal gets simpler +    (tcp_output is called again later from tcp timers). + +  2007-07-25 Simon Goldschmidt +  * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old +    copy_from_pbuf, which illegally modified the given pbuf. + +  2007-07-25 Simon Goldschmidt +  * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs: +    changed snd_queuelen++ to snd_queuelen += pbuf_clen(p). + +  2007-07-24 Simon Goldschmidt +  * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the +    correct state (must be CLOSED). + +  2007-07-13 Thomas Taranowski (commited by Jared Grubb) +  * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed +    allocation. It now returns NULL. + +  2007-07-13 Frédéric Bernon +  * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in +    all error cases. + +  2007-07-13 Frédéric Bernon +  * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed, +    because current code doesn't follow rawapi.txt documentation. + +  2007-07-13 Kieran Mansley +  * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in +    out of sequence processing of received packets + +  2007-07-03 Simon Goldschmidt +  * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an +    assumption is made that this pbuf is in one piece (i.e. not chained). These +    assumptions clash with the possibility of converting to fully pool-based +    pbuf implementations, where PBUF_RAM pbufs might be chained. + +  2007-07-03 Simon Goldschmidt +  * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems +    when closing tcp netconns: removed conn->sem, less context switches when +    closing, both netconn_close and netconn_delete should safely close tcp +    connections. + +  2007-07-02 Simon Goldschmidt +  * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c, +    tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off) +    to cache ARP table indices with each pcb instead of single-entry cache for +    the complete stack. + +  2007-07-02 Simon Goldschmidt +  * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent +    warnings when assigning to smaller types. + +  2007-06-28 Simon Goldschmidt +  * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing. + +  2007-06-28 Simon Goldschmidt +  * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if +    a segment contained chained pbufs) + +  2007-06-28 Frédéric Bernon +  * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute +    a "pseudo-random" value based on netif's MAC and some autoip fields. It's always +    possible to define this macro in your own lwipopts.h to always use C library's +    rand(). Note that autoip_create_rand_addr doesn't use this macro. + +  2007-06-28 Frédéric Bernon +  * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option +    LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications +    in api_lib/api_msg (use pointers and not type with table, etc...)  + +  2007-06-26 Simon Goldschmidt +  * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines. + +  2007-06-25 Simon Goldschmidt +  * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload +    for udp packets with no matching pcb. + +  2007-06-25 Simon Goldschmidt +  * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match +    could get udp input packets if the remote side matched. + +  2007-06-13 Simon Goldschmidt +  * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get +    changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0. + +  2007-06-13 Simon Goldschmidt +  * api_msg.c: pcb_new sets conn->err if protocol is not implemented +    -> netconn_new_..() does not allocate a new connection for unsupported +    protocols. + +  2007-06-13 Frédéric Bernon, Simon Goldschmidt +  * api_lib.c: change return expression in netconn_addr and netconn_peer, because +    conn->err was reset to ERR_OK without any reasons (and error was lost)... + +  2007-06-13 Frédéric Bernon, Matthias Weisser +  * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename +    MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid +    some macro names collision with some OS macros. + +  2007-06-11 Simon Goldschmidt +  * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0, +    create checksum over the complete packet. On RX, if it's < 8 (and not 0), +    discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both +    UDP & UDP Lite. + +  2007-06-11 Srinivas Gollakota & Oleg Tyshev +  * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags" +    where TCP flags wasn't initialized in tcp_keepalive. + +  2007-06-03 Simon Goldschmidt +  * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function +    registered, p->payload was modified without modifying p->len if sending +    icmp_dest_unreach() (had no negative effect but was definitively wrong). + +  2007-06-03 Simon Goldschmidt +  * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp +    re-used the input pbuf even if that didn't have enough space to include the +    link headers. Now the space is tested and a new pbuf is allocated for the +    echo response packet if the echo request pbuf isn't big enough. + +  2007-06-01 Simon Goldschmidt +  * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread. + +  2007-05-23 Frédéric Bernon +  * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only +    allocated by do_listen if success) and netconn_accept errors handling. In +    most of api_lib functions, we replace some errors checkings like "if (conn==NULL)" +    by ASSERT, except for netconn_delete. + +  2007-05-23 Frédéric Bernon +  * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return +    an error code if it's impossible to fetch a pbuf on a TCP connection (and not +    directly close the recvmbox). + +  2007-05-22 Simon Goldschmidt +  * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of +    bound but unconnected (and non-listening) tcp_pcbs. + +  2007-05-22 Frédéric Bernon +  * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only +    used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of +    sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features +    like "sys_timeout" in their application threads. + +  2007-05-22 Frédéric Bernon +  * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see +    which parameters are used by which do_xxx function, and to avoid "misusing" +    parameters (patch #5938). + +  2007-05-22 Simon Goldschmidt +  * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938: +    changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto +    is only 8 bits wide. This affects the api, as there, the protocol was +    u16_t, too. + +  2007-05-18 Simon Goldschmidt +  * memp.c: addition to patch #5913: smaller pointer was returned but +    memp_memory was the same size -> did not save memory. + +  2007-05-16 Simon Goldschmidt +  * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns +    != ERR_OK. + +  2007-05-16 Simon Goldschmidt +  * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same +    as the one of the netif used for sending to prevent sending from old +    addresses after a netif address gets changed (partly fixes bug #3168). + +  2007-05-16 Frédéric Bernon +  * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work +    with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in  +    tcpip_init) because we have to be sure that network interfaces are already +    added (mac filter is updated only in igmp_init for the moment). + +  2007-05-16 Simon Goldschmidt +  * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls +    into sys_arch_sem_wait calls to prevent timers from running while waiting +    for the heap. This fixes bug #19167. + +  2007-05-13 Simon Goldschmidt +  * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines +    for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from +    tcp.h to sockets.h. + +  2007-05-07 Simon Goldschmidt +  * mem.c: Another attempt to fix bug #17922. + +  2007-05-04 Simon Goldschmidt +  * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy() +    implementation so that it can be reused (don't allocate the target +    pbuf inside pbuf_copy()). + +  2007-05-04 Simon Goldschmidt +  * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem +    to save a little RAM (next pointer of memp is not used while not in pool). + +  2007-05-03 "maq" +  * sockets.c: Fix ioctl FIONREAD when some data remains from last recv. +    (patch #3574). + +  2007-04-23 Simon Goldschmidt +  * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results +    in NULL reference for incoming TCP packets". Loopif has to be configured +    (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input() +    (multithreading environments, e.g. netif->input() = tcpip_input()) or +    putting packets on a list that is fed to the stack by calling loopif_poll() +    (single-thread / NO_SYS / polling environment where e.g. +    netif->input() = ip_input). + +  2007-04-17 Jonathan Larmour +  * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold +    the difference between two u16_t's. +  * sockets.h: FD_SETSIZE needs to match number of sockets, which is +    MEMP_NUM_NETCONN in sockets.c right now. + +  2007-04-12 Jonathan Larmour +  * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580). + +  2007-04-12 Kieran Mansley +  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission +    timer is reset to fix bug#19434, with help from Oleg Tyshev. + +  2007-04-11 Simon Goldschmidt +  * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than +    previously thought need to be copied (everything but PBUF_ROM!). Cleaned up +    pbuf.c: removed functions no needed any more (by etharp). + +  2007-04-11 Kieran Mansley +  * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix +    "Constant is long" warnings with 16bit compilers.  Contributed by +    avatar@mmlab.cse.yzu.edu.tw + +  2007-04-05 Frédéric Bernon, Jonathan Larmour +  * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on +    the mailbox is active". Now, the post is only done during a connect, and do_send, +    do_write and do_join_leave_group don't do anything if a previous error was signaled. + +  2007-04-03 Frédéric Bernon +  * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output +    packets. See patch #5834. + +  2007-03-30 Frédéric Bernon +  * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add +    missing  pcb allocations checking (in do_bind, and for each raw_new). Fix style. + +  2007-03-30 Frédéric Bernon +  * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with +    others environment defines (these were too "generic"). + +  2007-03-28 Frédéric Bernon +  * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call +    result and can cause a crash. lwip_send now check netbuf_ref result. + +  2007-03-28 Simon Goldschmidt +  * sockets.c Remove "#include <errno.h>" from sockets.c to avoid multiple +    definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is +    defined. This is the way it should have been already (looking at +    doc/sys_arch.txt) + +  2007-03-28 Kieran Mansley +  * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS + +    IP and TCP headers *and* physical link headers + +  2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov) +  * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause +    to send some garbage. It is not a definitive solution, but the patch does solve +    the problem for most cases. + +  2007-03-22 Frédéric Bernon +  * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used). + +  2007-03-22 Frédéric Bernon +  * api_lib.c: somes resources couldn't be freed if there was errors during +    netconn_new_with_proto_and_callback. + +  2007-03-22 Frédéric Bernon +  * ethernetif.c: update netif->input calls to check return value. In older ports, +    it's a good idea to upgrade them, even if before, there could be another problem +    (access to an uninitialized mailbox). + +  2007-03-21 Simon Goldschmidt +  * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed +    by casting to unsigned). + +  2007-03-21 Frédéric Bernon +  * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from +    api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a +    dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call. +    Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a +    faster and more reliable communication between api_lib and tcpip. + +  2007-03-21 Frédéric Bernon +  * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0. + +  2007-03-21 Frédéric Bernon +  * api_msg.c, igmp.c, igmp.h: Fix C++ style comments + +  2007-03-21 Kieran Mansley +  * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS + +    IP and TCP headers + +  2007-03-21 Kieran Mansley +  * Fix all uses of pbuf_header to check the return value.  In some +    cases just assert if it fails as I'm not sure how to fix them, but +    this is no worse than before when they would carry on regardless +    of the failure. + +  2007-03-21 Kieran Mansley +  * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and +    comment out missing header include in icmp.c + +  2007-03-20 Frédéric Bernon +  * memp.h, stats.c: Fix stats_display function where memp_names table wasn't +    synchronized with memp.h. + +  2007-03-20 Frédéric Bernon +  * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input, +    tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with  +    network interfaces. Also fix a compiler warning. + +  2007-03-20 Kieran Mansley +  * udp.c: Only try and use pbuf_header() to make space for headers if +    not a ROM or REF pbuf. + +  2007-03-19 Frédéric Bernon +  * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg() +    and api_msg_post(). + +  2007-03-19 Frédéric Bernon +  * Remove unimplemented "memp_realloc" function from memp.h. + +  2007-03-11 Simon Goldschmidt +  * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused +    memory corruption. + +  2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251 +    (missing `const' qualifier in socket functions), to get more compatible to +    standard POSIX sockets. + +  2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov) +  * sockets.c: Add asserts inside bind, connect and sendto to check input +    parameters. Remove excessive set_errno() calls after get_socket(), because +    errno is set inside of get_socket(). Move last sock_set_errno() inside +    lwip_close. + +  2007-03-09 Simon Goldschmidt +  * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory +    was allocated too small. + +  2007-03-06 Simon Goldschmidt +  * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect +    the stack from concurrent access. + +  2007-03-06 Frédéric Bernon, Dmitry Potapov +  * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy +    call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input(). + +  2007-03-06 Simon Goldschmidt +  * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files +    if IP_FRAG == 0 and IP_REASSEMBLY == 0 + +  2007-03-06 Frédéric Bernon, Simon Goldschmidt +  * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration +    option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput. +    Allow to do ARP processing for incoming packets inside tcpip_thread +    (protecting ARP layer against concurrent access). You can also disable +    old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0. +    Older ports have to use tcpip_ethinput. + +  2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * err.h, err.c: fixed compiler warning "initialization dircards qualifiers +    from pointer target type" + +  2007-03-05 Frédéric Bernon +  * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES, +    ETHARP_TRUST_IP_MAC, review SO_REUSE) + +  2007-03-04 Frédéric Bernon +  * api_msg.c: Remove some compiler warnings : parameter "pcb" was never +    referenced. + +  2007-03-04 Frédéric Bernon +  * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from +    Dmitry Potapov). +    The api_msg struct stay on the stack (not moved to netconn struct). + +  2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov) +  * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if +    SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available) +    Also fixed cast warning in pbuf_alloc() + +  2007-03-04 Simon Goldschmidt +  * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt +    existing pbuf chain when enqueuing multiple pbufs to a pending ARP request + +  2007-03-03 Frédéric Bernon +  * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;" +    It is static, and never used in udp.c except udp_init(). + +  2007-03-02 Simon Goldschmidt +  * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from +    tcpip_thread() to tcpip_init(). This way, raw API connections can be +    initialized before tcpip_thread is running (e.g. before OS is started) + +  2007-03-02 Frédéric Bernon +  * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call +    interval. + +  2007-02-28 Kieran Mansley  +  * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved +    outside the region of the pbuf by pbuf_header() + +  2007-02-28 Kieran Mansley  +  * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero +    when supplied timeout is also non-zero  + +(STABLE-1.2.0) + +  2006-12-05 Leon Woestenberg +  * CHANGELOG: Mention STABLE-1.2.0 release. + +  ++ New features: + +  2006-12-01 Christiaan Simons +  * mem.h, opt.h: Added MEM_LIBC_MALLOC option. +    Note this is a workaround. Currently I have no other options left. + +  2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour) +  * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define +    to include/lwip/opt.h. +  * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL. +    Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h. +  * opt.h: Add above new options. + +  2006-08-18 Christiaan Simons +  * tcp_{in,out}.c: added SNMP counters. +  * ipv4/ip.c: added SNMP counters. +  * ipv4/ip_frag.c: added SNMP counters. + +  2006-08-08 Christiaan Simons +  * etharp.{c,h}: added etharp_find_addr() to read +    (stable) ethernet/IP address pair from ARP table + +  2006-07-14 Christiaan Simons +  * mib_structs.c: added +  * include/lwip/snmp_structs.h: added +  * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct + +  2006-07-06 Christiaan Simons +  * snmp/asn1_{enc,dec}.c added +  * snmp/mib2.c added +  * snmp/msg_{in,out}.c added +  * include/lwip/snmp_asn1.h added +  * include/lwip/snmp_msg.h added +  * doc/snmp_agent.txt added + +  2006-03-29 Christiaan Simons +  * inet.c, inet.h: Added platform byteswap support. +    Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and +    optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros. + +  ++ Bug fixes: + +  2006-11-30 Christiaan Simons +  * dhcp.c: Fixed false triggers of request_timeout. + +  2006-11-28 Christiaan Simons +  * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags. + +  2006-10-11 Christiaan Simons +  * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h: +    Partially accepted patch #5449 for ANSI C compatibility / build fixes. +  * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol +    identifier from 170 to 136 (bug #17574). + +  2006-10-10 Christiaan Simons +  * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice. + +  2006-08-17 Christiaan Simons +  * udp.c: Fixed bug #17200, added check for broadcast +    destinations for PCBs bound to a unicast address. + +  2006-08-07 Christiaan Simons +  * api_msg.c: Flushing TCP output in do_close() (bug #15926). + +  2006-06-27 Christiaan Simons +  * api_msg.c: Applied patch for cold case (bug #11135). +    In accept_function() ensure newconn->callback is always initialized. + +  2006-06-15 Christiaan Simons +  * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748), +    facilitate printing of mem_size_t and u16_t statistics. + +  2006-06-14 Christiaan Simons +  * api_msg.c: Applied patch #5146 to handle allocation failures +    in accept() by Kevin Lawson. + +  2006-05-26 Christiaan Simons +  * api_lib.c: Removed conn->sem creation and destruction  +    from netconn_write() and added sys_sem_new to netconn_new_*. + +(STABLE-1_1_1) + +  2006-03-03  Christiaan Simons +  * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap +    access and added pbuf_alloc() return value checks. + +  2006-01-01  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is +    now handled by the checksum routine properly. + +  2006-02-27  Leon Woestenberg <leon.woestenberg@gmx.net> +   * pbuf.c: Fix alignment; pbuf_init() would not work unless +     pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.) + +  2005-12-20  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch +    submitted by Mitrani Hiroshi. + +  2005-12-15  Christiaan Simons +  * inet.c: Disabled the added summing routine to preserve code space. + +  2005-12-14  Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson. +    Added Curt McDowell's optimized checksumming routine for future +    inclusion. Need to create test case for unaliged, aligned, odd, +    even length combination of cases on various endianess machines. + +  2005-12-09  Christiaan Simons +  * inet.c: Rewrote standard checksum routine in proper portable C. + +  2005-11-25  Christiaan Simons +  * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only. +  * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t, +    u32_t, s32_t typedefs. This solves most debug word-length assumes. + +  2005-07-17 Leon Woestenberg <leon.woestenberg@gmx.net> +  * inet.c: Fixed unaligned 16-bit access in the standard checksum +    routine by Peter Jolasson. +  * slipif.c: Fixed implementation assumption of single-pbuf datagrams. + +  2005-02-04 Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch. +  * tcp_{out|in}.c: Applied patch fixing unaligned access. + +  2005-01-04 Leon Woestenberg <leon.woestenberg@gmx.net> +  * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement. + +  2005-01-03 Leon Woestenberg <leon.woestenberg@gmx.net> +  * udp.c: UDP pcb->recv() was called even when it was NULL. + +(STABLE-1_1_0) + +  2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.*: Disabled multiple packets on the ARP queue. +    This clashes with TCP queueing. + +  2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.*: Fixed race condition from ARP request to ARP timeout. +    Halved the ARP period, doubled the period counts. +    ETHARP_MAX_PENDING now should be at least 2. This prevents +    the counter from reaching 0 right away (which would allow +    too little time for ARP responses to be received). + +  2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net> +  * dhcp.c: Decline messages were not multicast but unicast. +  * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD. +    Do not try hard to insert arbitrary packet's source address, +    etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD.  +    etharp_query() now always DOES call ETHARP_TRY_HARD so that users +    querying an address will see it appear in the cache (DHCP could +    suffer from this when a server invalidly gave an in-use address.) +  * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are +    comparing network addresses (identifiers), not the network masks +    themselves. +  * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given +    IP address actually belongs to the network of the given interface. + +  2004-11-24 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state. + +(STABLE-1_1_0-RC1) + +  2004-10-16 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately, +    even if one is already pending, if the rcv_wnd is above a threshold +    (currently TCP_WND/2). This avoids waiting for a timer to expire to send a +    delayed ACK in order to open the window if the stack is only receiving data. + +  2004-09-12 Kieran Mansley <kjm25@cam.ac.uk> +  * tcp*.*: Retransmit time-out handling improvement by Sam Jansen. + +  2004-08-20 Tony Mountifield <tony@softins.co.uk> +  * etharp.c: Make sure the first pbuf queued on an ARP entry +    is properly ref counted. + +  2004-07-27 Tony Mountifield <tony@softins.co.uk> +  * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler +    warnings about comparison. +  * pbuf.c: Stopped compiler complaining of empty if statement +    when LWIP_DEBUGF() empty.  Closed an unclosed comment. +  * tcp.c: Stopped compiler complaining of empty if statement +    when LWIP_DEBUGF() empty. +  * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons(). +  * inet.c: Added a couple of casts to quiet the compiler. +    No need to test isascii(c) before isdigit(c) or isxdigit(c). + +  2004-07-22 Tony Mountifield <tony@softins.co.uk> +  * inet.c: Made data types consistent in inet_ntoa(). +    Added casts for return values of checksum routines, to pacify compiler. +  * ip_frag.c, tcp_out.c, sockets.c, pbuf.c +    Small corrections to some debugging statements, to pacify compiler. + +  2004-07-21 Tony Mountifield <tony@softins.co.uk> +  * etharp.c: Removed spurious semicolon and added missing end-of-comment. +  * ethernetif.c Updated low_level_output() to match prototype for +    netif->linkoutput and changed low_level_input() similarly for consistency. +  * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype +    of raw_recv() in raw.h and so avoid compiler error. +  * sockets.c: Added trivial (int) cast to keep compiler happier. +  * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros. + +(STABLE-1_0_0) + +  ++ Changes: + +  2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net> +  * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure +    your cc.h file defines this either 1 or 0. If non-defined, +    defaults to 1. +  * .c: Added <string.h> and <errno.h> includes where used. +  * etharp.c: Made some array indices unsigned. + +  2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net> +  * netif.*: Added netif_set_up()/down(). +  * dhcp.c: Changes to restart program flow. + +  2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.c: In find_entry(), instead of a list traversal per candidate, do a +    single-pass lookup for different candidates. Should exploit locality. + +  2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net> +  * tcp*.c: Cleaned up source comment documentation for Doxygen processing. +  * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC. +  * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by +    the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option. + +  ++ Bug fixes: + +  2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net> +  * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution +    suggested by Timmy Brolin. Fix for 32-bit processors that cannot access +    non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix +    is to prefix the 14-bit Ethernet headers with two padding bytes. + +  2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net> +  * ip_addr.c: Fix in the ip_addr_isbroadcast() check. +  * etharp.c: Fixed the case where the packet that initiates the ARP request +    is not queued, and gets lost. Fixed the case where the packets destination +    address is already known; we now always queue the packet and perform an ARP +    request. + +(STABLE-0_7_0) + +  ++ Bug fixes: + +  * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition. +  * Fixed TCP bug in dequeueing of FIN from out of order segment queue. +  * Fixed two possible NULL references in rare cases. + +(STABLE-0_6_6) + +  ++ Bug fixes: + +  * Fixed DHCP which did not include the IP address in DECLINE messages. + +  ++ Changes: + +  * etharp.c has been hauled over a bit. + +(STABLE-0_6_5) + +  ++ Bug fixes: + +  * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic. +  * Packets sent from ARP queue had invalid source hardware address. + +  ++ Changes: + +  * Pass-by ARP requests do now update the cache. + +  ++ New features: + +  * No longer dependent on ctype.h. +  * New socket options. +  * Raw IP pcb support. + +(STABLE-0_6_4) + +  ++ Bug fixes: + +  * Some debug formatters and casts fixed. +  * Numereous fixes in PPP. + +  ++ Changes: + +  * DEBUGF now is LWIP_DEBUGF +  * pbuf_dechain() has been re-enabled. +  * Mentioned the changed use of CVS branches in README. + +(STABLE-0_6_3) + +  ++ Bug fixes: + +  * Fixed pool pbuf memory leak in pbuf_alloc(). +    Occured if not enough PBUF_POOL pbufs for a packet pbuf chain. +    Reported by Savin Zlobec. + +  * PBUF_POOL chains had their tot_len field not set for non-first +    pbufs. Fixed in pbuf_alloc(). + +  ++ New features: + +  * Added PPP stack contributed by Marc Boucher + +  ++ Changes: + +  * Now drops short packets for ICMP/UDP/TCP protocols. More robust. + +  * ARP queueuing now queues the latest packet instead of the first. +    This is the RFC recommended behaviour, but can be overridden in +    lwipopts.h. + +(0.6.2) + +  ++ Bugfixes: + +  * TCP has been fixed to deal with the new use of the pbuf->ref +    counter. + +  * DHCP dhcp_inform() crash bug fixed. + +  ++ Changes: + +  * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed +    pbuf_refresh(). This has sped up pbuf pool operations considerably. +    Implemented by David Haas. + +(0.6.1) + +  ++ New features: + +  * The packet buffer implementation has been enhanced to support +    zero-copy and copy-on-demand for packet buffers which have their +    payloads in application-managed memory. +    Implemented by David Haas. + +    Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy +    if an outgoing packet can be directly sent on the link, or perform +    a copy-on-demand when necessary. + +    The application can safely assume the packet is sent, and the RAM +    is available to the application directly after calling udp_send() +    or similar function. + +  ++ Bugfixes: + +  * ARP_QUEUEING should now correctly work for all cases, including +    PBUF_REF. +    Implemented by Leon Woestenberg. + +  ++ Changes: + +  * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer +    to a '0.0.0.0' IP address. + +  * The packet buffer implementation is changed. The pbuf->ref counter +    meaning has changed, and several pbuf functions have been +    adapted accordingly. + +  * netif drivers have to be changed to set the hardware address length field +    that must be initialized correctly by the driver (hint: 6 for Ethernet MAC). +    See the contrib/ports/c16x cs8900 driver as a driver example. + +  * netif's have a dhcp field that must be initialized to NULL by the driver. +    See the contrib/ports/c16x cs8900 driver as a driver example. + +(0.5.x) This file has been unmaintained up to 0.6.1. All changes are +  logged in CVS but have not been explained here. + +(0.5.3) Changes since version 0.5.2 + +  ++ Bugfixes: + +  * memp_malloc(MEMP_API_MSG) could fail with multiple application +    threads because it wasn't protected by semaphores. + +  ++ Other changes: + +  * struct ip_addr now packed. + +  * The name of the time variable in arp.c has been changed to ctime +    to avoid conflicts with the time() function. + +(0.5.2) Changes since version 0.5.1 + +  ++ New features: + +  * A new TCP function, tcp_tmr(), now handles both TCP timers. + +  ++ Bugfixes: + +  * A bug in tcp_parseopt() could cause the stack to hang because of a +    malformed TCP option. + +  * The address of new connections in the accept() function in the BSD +    socket library was not handled correctly. + +  * pbuf_dechain() did not update the ->tot_len field of the tail. + +  * Aborted TCP connections were not handled correctly in all +    situations. + +  ++ Other changes: + +  * All protocol header structs are now packed. + +  * The ->len field in the tcp_seg structure now counts the actual +    amount of data, and does not add one for SYN and FIN segments. + +(0.5.1) Changes since version 0.5.0 + +  ++ New features: + +  * Possible to run as a user process under Linux. + +  * Preliminary support for cross platform packed structs. + +  * ARP timer now implemented. + +  ++ Bugfixes: + +  * TCP output queue length was badly initialized when opening +    connections. + +  * TCP delayed ACKs were not sent correctly. + +  * Explicit initialization of BSS segment variables. + +  * read() in BSD socket library could drop data. + +  * Problems with memory alignment. + +  * Situations when all TCP buffers were used could lead to +    starvation. + +  * TCP MSS option wasn't parsed correctly. + +  * Problems with UDP checksum calculation. + +  * IP multicast address tests had endianess problems. + +  * ARP requests had wrong destination hardware address. + +  ++ Other changes: + +  * struct eth_addr changed from u16_t[3] array to u8_t[6]. + +  * A ->linkoutput() member was added to struct netif. + +  * TCP and UDP ->dest_* struct members where changed to ->remote_*. + +  * ntoh* macros are now null definitions for big endian CPUs. + +(0.5.0) Changes since version 0.4.2 + +  ++ New features: + +  * Redesigned operating system emulation layer to make porting easier. + +  * Better control over TCP output buffers. + +  * Documenation added. + +  ++ Bugfixes: + +  * Locking issues in buffer management. + +  * Bugfixes in the sequential API. + +  * IP forwarding could cause memory leakage. This has been fixed. + +  ++ Other changes: + +  * Directory structure somewhat changed; the core/ tree has been +    collapsed. + +(0.4.2) Changes since version 0.4.1 + +  ++ New features: + +  * Experimental ARP implementation added. + +  * Skeleton Ethernet driver added. + +  * Experimental BSD socket API library added. + +  ++ Bugfixes: + +  * In very intense situations, memory leakage could occur. This has +    been fixed. + +  ++ Other changes: + +  * Variables named "data" and "code" have been renamed in order to +    avoid name conflicts in certain compilers. + +  * Variable++ have in appliciable cases been translated to ++variable +    since some compilers generate better code in the latter case. + +(0.4.1) Changes since version 0.4 + +  ++ New features: + +  * TCP: Connection attempts time out earlier than data +    transmissions. Nagle algorithm implemented. Push flag set on the +    last segment in a burst. + +  * UDP: experimental support for UDP-Lite extensions. + +  ++ Bugfixes: + +  * TCP: out of order segments were in some cases handled incorrectly, +    and this has now been fixed. Delayed acknowledgements was broken +    in 0.4, has now been fixed. Binding to an address that is in use +    now results in an error. Reset connections sometimes hung an +    application; this has been fixed. + +  * Checksum calculation sometimes failed for chained pbufs with odd +    lengths. This has been fixed. + +  * API: a lot of bug fixes in the API. The UDP API has been improved +    and tested. Error reporting and handling has been +    improved. Logical flaws and race conditions for incoming TCP +    connections has been found and removed. + +  * Memory manager: alignment issues. Reallocating memory sometimes +    failed, this has been fixed. + +  * Generic library: bcopy was flawed and has been fixed. + +  ++ Other changes: + +  * API: all datatypes has been changed from generic ones such as +    ints, to specified ones such as u16_t. Functions that return +    errors now have the correct type (err_t). + +  * General: A lot of code cleaned up and debugging code removed. Many +    portability issues have been fixed. + +  * The license was changed; the advertising clause was removed. + +  * C64 port added. + +  * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri +    Kosunen, Mikael Caleres, and Frits Wilmink for reporting and +    fixing bugs! + +(0.4) Changes since version 0.3.1 + +  * Memory management has been radically changed; instead of +    allocating memory from a shared heap, memory for objects that are +    rapidly allocated and deallocated is now kept in pools. Allocation +    and deallocation from those memory pools is very fast. The shared +    heap is still present but is used less frequently. + +  * The memory, memory pool, and packet buffer subsystems now support +    4-, 2-, or 1-byte alignment. + +  * "Out of memory" situations are handled in a more robust way. + +  * Stack usage has been reduced. + +  * Easier configuration of lwIP parameters such as memory usage, +    TTLs, statistics gathering, etc. All configuration parameters are +    now kept in a single header file "lwipopts.h". + +  * The directory structure has been changed slightly so that all +    architecture specific files are kept under the src/arch +    hierarchy. + +  * Error propagation has been improved, both in the protocol modules +    and in the API. + +  * The code for the RTXC architecture has been implemented, tested +    and put to use. + +  * Bugs have been found and corrected in the TCP, UDP, IP, API, and +    the Internet checksum modules. + +  * Bugs related to porting between a 32-bit and a 16-bit architecture +    have been found and corrected. + +  * The license has been changed slightly to conform more with the +    original BSD license, including the advertisement clause. + +(0.3.1) Changes since version 0.3 + +  * Fix of a fatal bug in the buffer management. Pbufs with allocated +    RAM never returned the RAM when the pbuf was deallocated. + +  * TCP congestion control, window updates and retransmissions did not +    work correctly. This has now been fixed. + +  * Bugfixes in the API. + +(0.3) Changes since version 0.2 + +  * New and improved directory structure. All include files are now +    kept in a dedicated include/ directory. + +  * The API now has proper error handling. A new function, +    netconn_err(), now returns an error code for the connection in +    case of errors. + +  * Improvements in the memory management subsystem. The system now +    keeps a pointer to the lowest free memory block. A new function, +    mem_malloc2() tries to allocate memory once, and if it fails tries +    to free some memory and retry the allocation. + +  * Much testing has been done with limited memory +    configurations. lwIP now does a better job when overloaded. + +  * Some bugfixes and improvements to the buffer (pbuf) subsystem. + +  * Many bugfixes in the TCP code: + +    - Fixed a bug in tcp_close(). + +    - The TCP receive window was incorrectly closed when out of +      sequence segments was received. This has been fixed. + +    - Connections are now timed-out of the FIN-WAIT-2 state. + +    - The initial congestion window could in some cases be too +      large. This has been fixed. + +    - The retransmission queue could in some cases be screwed up. This +      has been fixed. + +    - TCP RST flag now handled correctly. + +    - Out of sequence data was in some cases never delivered to the +      application. This has been fixed. + +    - Retransmitted segments now contain the correct acknowledgment +      number and advertised window. + +    - TCP retransmission timeout backoffs are not correctly computed +      (ala BSD). After a number of retransmissions, TCP now gives up +      the connection. + +  * TCP connections now are kept on three lists, one for active +    connections, one for listening connections, and one for +    connections that are in TIME-WAIT. This greatly speeds up the fast +    timeout processing for sending delayed ACKs. + +  * TCP now provides proper feedback to the application when a +    connection has been successfully set up. + +  * More comments have been added to the code. The code has also been +    somewhat cleaned up. + +(0.2) Initial public release. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/COPYING b/firmware/usrp3/lwip/lwip-1.3.1/COPYING new file mode 100644 index 000000000..e23898b5e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/COPYING @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2001, 2002 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> + * + */ + + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/FILES b/firmware/usrp3/lwip/lwip-1.3.1/FILES new file mode 100644 index 000000000..66253196f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/FILES @@ -0,0 +1,4 @@ +src/      - The source code for the lwIP TCP/IP stack. +doc/      - The documentation for lwIP. + +See also the FILES file in each subdirectory. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/README b/firmware/usrp3/lwip/lwip-1.3.1/README new file mode 100644 index 000000000..8dda4b468 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/README @@ -0,0 +1,89 @@ +INTRODUCTION + +lwIP is a small independent implementation of the TCP/IP protocol +suite that has been developed by Adam Dunkels at the Computer and +Networks Architectures (CNA) lab at the Swedish Institute of Computer +Science (SICS). + +The focus of the lwIP TCP/IP implementation is to reduce the RAM usage +while still having a full scale TCP. This making lwIP suitable for use +in embedded systems with tens of kilobytes of free RAM and room for +around 40 kilobytes of code ROM. + +FEATURES + +  * IP (Internet Protocol) including packet forwarding over multiple network +    interfaces +  * ICMP (Internet Control Message Protocol) for network maintenance and debugging +  * IGMP (Internet Group Management Protocol) for multicast traffic management +  * UDP (User Datagram Protocol) including experimental UDP-lite extensions +  * TCP (Transmission Control Protocol) with congestion control, RTT estimation +    and fast recovery/fast retransmit +  * Specialized raw/native API for enhanced performance +  * Optional Berkeley-like socket API +  * DNS (Domain names resolver) +  * SNMP (Simple Network Management Protocol) +  * DHCP (Dynamic Host Configuration Protocol) +  * AUTOIP (for IPv4, conform with RFC 3927) +  * PPP (Point-to-Point Protocol) +  * ARP (Address Resolution Protocol) for Ethernet + +LICENSE + +lwIP is freely available under a BSD license. + +DEVELOPMENT + +lwIP has grown into an excellent TCP/IP stack for embedded devices, +and developers using the stack often submit bug fixes, improvements, +and additions to the stack to further increase its usefulness. + +Development of lwIP is hosted on Savannah, a central point for +software development, maintenance and distribution. Everyone can +help improve lwIP by use of Savannah's interface, CVS and the +mailing list. A core team of developers will commit changes to the +CVS source tree. + +The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and +contributions (such as platform ports) are in the 'contrib' module. + +See doc/savannah.txt for details on CVS server access for users and +developers. + +Last night's CVS tar ball can be downloaded from: +  http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING] + +The current CVS trees are web-browsable: +  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/ +  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/ + +Submit patches and bugs via the lwIP project page: +  http://savannah.nongnu.org/projects/lwip/ + + +DOCUMENTATION + +The original out-dated homepage of lwIP and Adam Dunkels' papers on +lwIP are at the official lwIP home page: +  http://www.sics.se/~adam/lwip/ + +Self documentation of the source code is regularly extracted from the +current CVS sources and is available from this web page: +  http://www.nongnu.org/lwip/ + +There is now a constantly growin wiki about lwIP at +  http://lwip.scribblewiki.com/ + +Also, there are mailing lists you can subscribe at +  http://savannah.nongnu.org/mail/?group=lwip +plus searchable archives: +  http://lists.nongnu.org/archive/html/lwip-users/ +  http://lists.nongnu.org/archive/html/lwip-devel/ + +Reading Adam's papers, the files in docs/, browsing the source code +documentation and browsing the mailing list archives is a good way to +become familiar with the design of lwIP. + +Adam Dunkels <adam@sics.se> +Leon Woestenberg <leon.woestenberg@gmx.net> + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/FILES b/firmware/usrp3/lwip/lwip-1.3.1/doc/FILES new file mode 100644 index 000000000..05d356f4f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/FILES @@ -0,0 +1,6 @@ +savannah.txt   - How to obtain the current development source code. +contrib.txt    - How to contribute to lwIP as a developer. +rawapi.txt     - The documentation for the core API of lwIP. +                 Also provides an overview about the other APIs and multithreading. +snmp_agent.txt - The documentation for the lwIP SNMP agent. +sys_arch.txt   - The documentation for a system abstraction layer of lwIP. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/contrib.txt b/firmware/usrp3/lwip/lwip-1.3.1/doc/contrib.txt new file mode 100644 index 000000000..39596fca3 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/contrib.txt @@ -0,0 +1,63 @@ +1 Introduction + +This document describes some guidelines for people participating +in lwIP development. + +2 How to contribute to lwIP + +Here is a short list of suggestions to anybody working with lwIP and  +trying to contribute bug reports, fixes, enhancements, platform ports etc. +First of all as you may already know lwIP is a volunteer project so feedback +to fixes or questions might often come late. Hopefully the bug and patch tracking  +features of Savannah help us not lose users' input. + +2.1 Source code style: + +1. do not use tabs. +2. indentation is two spaces per level (i.e. per tab). +3. end debug messages with a trailing newline (\n). +4. one space between keyword and opening bracket. +5. no space between function and opening bracket. +6. one space and no newline before opening curly braces of a block. +7. closing curly brace on a single line. +8. spaces surrounding assignment and comparisons. +9. don't initialize static and/or global variables to zero, the compiler takes care of that. +10. use current source code style as further reference. + +2.2 Source code documentation style: + +1. JavaDoc compliant and Doxygen compatible. +2. Function documentation above functions in .c files, not .h files. +   (This forces you to synchronize documentation and implementation.) +3. Use current documentation style as further reference. +  +2.3 Bug reports and patches: + +1. Make sure you are reporting bugs or send patches against the latest +   sources. (From the latest release and/or the current CVS sources.) +2. If you think you found a bug make sure it's not already filed in the +   bugtracker at Savannah. +3. If you have a fix put the patch on Savannah. If it is a patch that affects +   both core and arch specific stuff please separate them so that the core can +   be applied separately while leaving the other patch 'open'. The prefered way +   is to NOT touch archs you can't test and let maintainers take care of them. +   This is a good way to see if they are used at all - the same goes for unix +   netifs except tapif. +4. Do not file a bug and post a fix to it to the patch area. Either a bug report +   or a patch will be enough. +   If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area. +5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two) +   can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded +   as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead +   for reporting a compiler warning fix. +6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other +   trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you +   change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than +   if it's not to the point and long :) so the chances for it to be applied are greater.  + +2.4 Platform porters: + +1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and +   you think it could benefit others[1] you might want discuss this on the mailing list. You +   can also ask for CVS access to submit and maintain your port in the contrib CVS module. +   
\ No newline at end of file diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/rawapi.txt b/firmware/usrp3/lwip/lwip-1.3.1/doc/rawapi.txt new file mode 100644 index 000000000..8eec6e786 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/rawapi.txt @@ -0,0 +1,478 @@ +Raw TCP/IP interface for lwIP + +Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons + +lwIP provides three Application Program's Interfaces (APIs) for programs +to use for communication with the TCP/IP code: +* low-level "core" / "callback" or "raw" API. +* higher-level "sequential" API. +* BSD-style socket API. + +The sequential API provides a way for ordinary, sequential, programs +to use the lwIP stack. It is quite similar to the BSD socket API. The +model of execution is based on the blocking open-read-write-close +paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP +code and the application program must reside in different execution +contexts (threads). + +The socket API is a compatibility API for existing applications, +currently it is built on top of the sequential API. It is meant to +provide all functions needed to run socket API applications running +on other platforms (e.g. unix / windows etc.). However, due to limitations +in the specification of this API, there might be incompatibilities +that require small modifications of existing programs. + +** Threading + +lwIP started targeting single-threaded environments. When adding multi- +threading support, instead of making the core thread-safe, another +approach was chosen: there is one main thread running the lwIP core +(also known as the "tcpip_thread"). The raw API may only be used from +this thread! Application threads using the sequential- or socket API +communicate with this main thread through message passing. + +      As such, the list of functions that may be called from +      other threads or an ISR is very limited! Only functions +      from these API header files are thread-safe: +      - api.h +      - netbuf.h +      - netdb.h +      - netifapi.h +      - sockets.h +      - sys.h + +      Additionaly, memory (de-)allocation functions may be +      called from multiple threads (not ISR!) with NO_SYS=0 +      since they are protected by SYS_LIGHTWEIGHT_PROT and/or +      semaphores. + +      Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1 +      and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1, +      pbuf_free() may also be called from another thread or +      an ISR (since only then, mem_free - for PBUF_RAM - may +      be called from an ISR: otherwise, the HEAP is only +      protected by semaphores). +       + +** The remainder of this document discusses the "raw" API. ** + +The raw TCP/IP interface allows the application program to integrate +better with the TCP/IP code. Program execution is event based by +having callback functions being called from within the TCP/IP +code. The TCP/IP code and the application program both run in the same +thread. The sequential API has a much higher overhead and is not very +well suited for small systems since it forces a multithreaded paradigm +on the application. + +The raw TCP/IP interface is not only faster in terms of code execution +time but is also less memory intensive. The drawback is that program +development is somewhat harder and application programs written for +the raw TCP/IP interface are more difficult to understand. Still, this +is the preferred way of writing applications that should be small in +code size and memory usage. + +Both APIs can be used simultaneously by different application +programs. In fact, the sequential API is implemented as an application +program using the raw TCP/IP interface. + +--- Callbacks + +Program execution is driven by callbacks. Each callback is an ordinary +C function that is called from within the TCP/IP code. Every callback +function is passed the current TCP or UDP connection state as an +argument. Also, in order to be able to keep program specific state, +the callback functions are called with a program specified argument +that is independent of the TCP/IP state. + +The function for setting the application connection state is: + +- void tcp_arg(struct tcp_pcb *pcb, void *arg) + +  Specifies the program specific state that should be passed to all +  other callback functions. The "pcb" argument is the current TCP +  connection control block, and the "arg" argument is the argument +  that will be passed to the callbacks. + +   +--- TCP connection setup + +The functions used for setting up connections is similar to that of +the sequential API and of the BSD socket API. A new TCP connection +identifier (i.e., a protocol control block - PCB) is created with the +tcp_new() function. This PCB can then be either set to listen for new +incoming connections or be explicitly connected to another host. + +- struct tcp_pcb *tcp_new(void) + +  Creates a new connection identifier (PCB). If memory is not +  available for creating the new pcb, NULL is returned. + +- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port) + +  Binds the pcb to a local IP address and port number. The IP address +  can be specified as IP_ADDR_ANY in order to bind the connection to +  all local IP addresses. + +  If another connection is bound to the same port, the function will +  return ERR_USE, otherwise ERR_OK is returned. + +- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb) + +  Commands a pcb to start listening for incoming connections. When an +  incoming connection is accepted, the function specified with the +  tcp_accept() function will be called. The pcb will have to be bound +  to a local port with the tcp_bind() function. + +  The tcp_listen() function returns a new connection identifier, and +  the one passed as an argument to the function will be +  deallocated. The reason for this behavior is that less memory is +  needed for a connection that is listening, so tcp_listen() will +  reclaim the memory needed for the original connection and allocate a +  new smaller memory block for the listening connection. + +  tcp_listen() may return NULL if no memory was available for the +  listening connection. If so, the memory associated with the pcb +  passed as an argument to tcp_listen() will not be deallocated. + +- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) + +  Same as tcp_listen, but limits the number of outstanding connections +  in the listen queue to the value specified by the backlog argument. +  To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h. + +- void tcp_accepted(struct tcp_pcb *pcb) + +  Inform lwIP that an incoming connection has been accepted. This would +  usually be called from the accept callback. This allows lwIP to perform +  housekeeping tasks, such as allowing further incoming connections to be +  queued in the listen backlog. + +- void tcp_accept(struct tcp_pcb *pcb, +                  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, +                                   err_t err)) + +  Specified the callback function that should be called when a new +  connection arrives on a listening connection. +       +- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                    u16_t port, err_t (* connected)(void *arg, +                                                    struct tcp_pcb *tpcb, +                                                    err_t err)); + +  Sets up the pcb to connect to the remote host and sends the +  initial SYN segment which opens the connection.  + +  The tcp_connect() function returns immediately; it does not wait for +  the connection to be properly setup. Instead, it will call the +  function specified as the fourth argument (the "connected" argument) +  when the connection is established. If the connection could not be +  properly established, either because the other host refused the +  connection or because the other host didn't answer, the "err" +  callback function of this pcb (registered with tcp_err, see below) +  will be called. + +  The tcp_connect() function can return ERR_MEM if no memory is +  available for enqueueing the SYN segment. If the SYN indeed was +  enqueued successfully, the tcp_connect() function returns ERR_OK. + +   +--- Sending TCP data + +TCP data is sent by enqueueing the data with a call to +tcp_write(). When the data is successfully transmitted to the remote +host, the application will be notified with a call to a specified +callback function. + +- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len, +                  u8_t copy) + +  Enqueues the data pointed to by the argument dataptr. The length of +  the data is passed as the len parameter. The copy argument is either +  0 or 1 and indicates whether the new memory should be allocated for +  the data to be copied into. If the argument is 0, no new memory +  should be allocated and the data should only be referenced by +  pointer. + +  The tcp_write() function will fail and return ERR_MEM if the length +  of the data exceeds the current send buffer size or if the length of +  the queue of outgoing segment is larger than the upper limit defined +  in lwipopts.h. The number of bytes available in the output queue can +  be retrieved with the tcp_sndbuf() function. + +  The proper way to use this function is to call the function with at +  most tcp_sndbuf() bytes of data. If the function returns ERR_MEM, +  the application should wait until some of the currently enqueued +  data has been successfully received by the other host and try again. + +- void tcp_sent(struct tcp_pcb *pcb, +                err_t (* sent)(void *arg, struct tcp_pcb *tpcb, +                u16_t len)) + +  Specifies the callback function that should be called when data has +  successfully been received (i.e., acknowledged) by the remote +  host. The len argument passed to the callback function gives the +  amount bytes that was acknowledged by the last acknowledgment. + +   +--- Receiving TCP data + +TCP data reception is callback based - an application specified +callback function is called when new data arrives. When the +application has taken the data, it has to call the tcp_recved() +function to indicate that TCP can advertise increase the receive +window. + +- void tcp_recv(struct tcp_pcb *pcb, +                err_t (* recv)(void *arg, struct tcp_pcb *tpcb, +                               struct pbuf *p, err_t err)) + +  Sets the callback function that will be called when new data +  arrives. The callback function will be passed a NULL pbuf to +  indicate that the remote host has closed the connection. If +  there are no errors and the callback function is to return +  ERR_OK, then it must free the pbuf. Otherwise, it must not +  free the pbuf so that lwIP core code can store it. + +- void tcp_recved(struct tcp_pcb *pcb, u16_t len) + +  Must be called when the application has received the data. The len +  argument indicates the length of the received data. +     + +--- Application polling + +When a connection is idle (i.e., no data is either transmitted or +received), lwIP will repeatedly poll the application by calling a +specified callback function. This can be used either as a watchdog +timer for killing connections that have stayed idle for too long, or +as a method of waiting for memory to become available. For instance, +if a call to tcp_write() has failed because memory wasn't available, +the application may use the polling functionality to call tcp_write() +again when the connection has been idle for a while. + +- void tcp_poll(struct tcp_pcb *pcb, u8_t interval, +                err_t (* poll)(void *arg, struct tcp_pcb *tpcb)) + +  Specifies the polling interval and the callback function that should +  be called to poll the application. The interval is specified in +  number of TCP coarse grained timer shots, which typically occurs +  twice a second. An interval of 10 means that the application would +  be polled every 5 seconds. + + +--- Closing and aborting connections + +- err_t tcp_close(struct tcp_pcb *pcb) + +  Closes the connection. The function may return ERR_MEM if no memory +  was available for closing the connection. If so, the application +  should wait and try again either by using the acknowledgment +  callback or the polling functionality. If the close succeeds, the +  function returns ERR_OK. + +  The pcb is deallocated by the TCP code after a call to tcp_close().  + +- void tcp_abort(struct tcp_pcb *pcb) + +  Aborts the connection by sending a RST (reset) segment to the remote +  host. The pcb is deallocated. This function never fails. + +If a connection is aborted because of an error, the application is +alerted of this event by the err callback. Errors that might abort a +connection are when there is a shortage of memory. The callback +function to be called is set using the tcp_err() function. + +- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg, +       err_t err)) + +  The error callback function does not get the pcb passed to it as a +  parameter since the pcb may already have been deallocated. + + +--- Lower layer TCP interface + +TCP provides a simple interface to the lower layers of the +system. During system initialization, the function tcp_init() has +to be called before any other TCP function is called. When the system +is running, the two timer functions tcp_fasttmr() and tcp_slowtmr() +must be called with regular intervals. The tcp_fasttmr() should be +called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and +tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds.  + + +--- UDP interface + +The UDP interface is similar to that of TCP, but due to the lower +level of complexity of UDP, the interface is significantly simpler. + +- struct udp_pcb *udp_new(void) + +  Creates a new UDP pcb which can be used for UDP communication. The +  pcb is not active until it has either been bound to a local address +  or connected to a remote address. + +- void udp_remove(struct udp_pcb *pcb) + +  Removes and deallocates the pcb.   +   +- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port) + +  Binds the pcb to a local address. The IP-address argument "ipaddr" +  can be IP_ADDR_ANY to indicate that it should listen to any local IP +  address. The function currently always return ERR_OK. + +- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, +                    u16_t port) + +  Sets the remote end of the pcb. This function does not generate any +  network traffic, but only set the remote address of the pcb. + +- err_t udp_disconnect(struct udp_pcb *pcb) + +  Remove the remote end of the pcb. This function does not generate +  any network traffic, but only removes the remote address of the pcb. + +- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p) + +  Sends the pbuf p. The pbuf is not deallocated. + +- void udp_recv(struct udp_pcb *pcb, +                void (* recv)(void *arg, struct udp_pcb *upcb, +                                         struct pbuf *p, +                                         struct ip_addr *addr, +                                         u16_t port), +                              void *recv_arg) + +  Specifies a callback function that should be called when a UDP +  datagram is received. +   + +--- System initalization + +A truly complete and generic sequence for initializing the lwip stack +cannot be given because it depends on the build configuration (lwipopts.h) +and additional initializations for your runtime environment (e.g. timers). + +We can give you some idea on how to proceed when using the raw API. +We assume a configuration using a single Ethernet netif and the +UDP and TCP transport layers, IPv4 and the DHCP client. + +Call these functions in the order of appearance: + +- stats_init() + +  Clears the structure where runtime statistics are gathered. + +- sys_init() +   +  Not of much use since we set the NO_SYS 1 option in lwipopts.h, +  to be called for easy configuration changes. + +- mem_init() + +  Initializes the dynamic memory heap defined by MEM_SIZE. + +- memp_init() + +  Initializes the memory pools defined by MEMP_NUM_x. + +- pbuf_init() + +  Initializes the pbuf memory pool defined by PBUF_POOL_SIZE. +   +- etharp_init() + +  Initializes the ARP table and queue. +  Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval +  after this initialization. + +- ip_init() + +  Doesn't do much, it should be called to handle future changes. + +- udp_init() + +  Clears the UDP PCB list. + +- tcp_init() + +  Clears the TCP PCB list and clears some internal TCP timers. +  Note: you must call tcp_fasttmr() and tcp_slowtmr() at the +  predefined regular intervals after this initialization.  +   +- netif_add(struct netif *netif, struct ip_addr *ipaddr, +            struct ip_addr *netmask, struct ip_addr *gw, +            void *state, err_t (* init)(struct netif *netif), +            err_t (* input)(struct pbuf *p, struct netif *netif)) + +  Adds your network interface to the netif_list. Allocate a struct +  netif and pass a pointer to this structure as the first argument. +  Give pointers to cleared ip_addr structures when using DHCP, +  or fill them with sane numbers otherwise. The state pointer may be NULL. + +  The init function pointer must point to a initialization function for +  your ethernet netif interface. The following code illustrates it's use. +   +  err_t netif_if_init(struct netif *netif) +  { +    u8_t i; +     +    for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i]; +    init_my_eth_device(); +    return ERR_OK; +  } +   +  For ethernet drivers, the input function pointer must point to the lwip +  function ethernet_input() declared in "netif/etharp.h". Other drivers +  must use ip_input() declared in "lwip/ip.h". +   +- netif_set_default(struct netif *netif) + +  Registers the default network interface. + +- netif_set_up(struct netif *netif) + +  When the netif is fully configured this function must be called. + +- dhcp_start(struct netif *netif) + +  Creates a new DHCP client for this interface on the first call. +  Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at +  the predefined regular intervals after starting the client. +   +  You can peek in the netif->dhcp struct for the actual DHCP status. + + +--- Optimalization hints + +The first thing you want to optimize is the lwip_standard_checksum() +routine from src/core/inet.c. You can override this standard +function with the #define LWIP_CHKSUM <your_checksum_routine>. + +There are C examples given in inet.c or you might want to +craft an assembly function for this. RFC1071 is a good +introduction to this subject. + +Other significant improvements can be made by supplying +assembly or inline replacements for htons() and htonl() +if you're using a little-endian architecture. +#define LWIP_PLATFORM_BYTESWAP 1 +#define LWIP_PLATFORM_HTONS(x) <your_htons> +#define LWIP_PLATFORM_HTONL(x) <your_htonl> + +Check your network interface driver if it reads at +a higher speed than the maximum wire-speed. If the +hardware isn't serviced frequently and fast enough +buffer overflows are likely to occur. + +E.g. when using the cs8900 driver, call cs8900if_service(ethif) +as frequently as possible. When using an RTOS let the cs8900 interrupt +wake a high priority task that services your driver using a binary +semaphore or event flag. Some drivers might allow additional tuning +to match your application and network. + +For a production release it is recommended to set LWIP_STATS to 0. +Note that speed performance isn't influenced much by simply setting +high values to the memory options. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/savannah.txt b/firmware/usrp3/lwip/lwip-1.3.1/doc/savannah.txt new file mode 100644 index 000000000..409905b10 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/savannah.txt @@ -0,0 +1,135 @@ +Daily Use Guide for using Savannah for lwIP + +Table of Contents: + +1 - Obtaining lwIP from the CVS repository +2 - Committers/developers CVS access using SSH (to be written) +3 - Merging from DEVEL branch to main trunk (stable branch) +4 - How to release lwIP + + + +1 Obtaining lwIP from the CVS repository +---------------------------------------- + +To perform an anonymous CVS checkout of the main trunk (this is where +bug fixes and incremental enhancements occur), do this: + +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip +  +Or, obtain a stable branch (updated with bug fixes only) as follows: +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_7 -d lwip-0.7 lwip + +Or, obtain a specific (fixed) release as follows: +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_7_0 -d lwip-0.7.0 lwip + +3 Committers/developers CVS access using SSH +-------------------------------------------- + +The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption. +As such, CVS commits to the server occur through a SSH tunnel for project members. +To create a SSH2 key pair in UNIX-like environments, do this: + +ssh-keygen -t dsa + +Under Windows, a recommended SSH client is "PuTTY", freely available with good +documentation and a graphic user interface. Use its key generator. + +Now paste the id_dsa.pub contents into your Savannah account public key list. Wait +a while so that Savannah can update its configuration (This can take minutes). + +Try to login using SSH: + +ssh -v your_login@cvs.sv.gnu.org + +If it tells you: + +Authenticating with public key "your_key_name"... +Server refused to allocate pty + +then you could login; Savannah refuses to give you a shell - which is OK, as we +are allowed to use SSH for CVS only. Now, you should be able to do this: + +export CVS_RSH=ssh +cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip +  +after which you can edit your local files with bug fixes or new features and +commit them. Make sure you know what you are doing when using CVS to make +changes on the repository. If in doubt, ask on the lwip-members mailing list. + +(If SSH asks about authenticity of the host, you can check the key + fingerprint against http://savannah.nongnu.org/cvs/?group=lwip) + + +3 Merging from DEVEL branch to main trunk (stable) +-------------------------------------------------- + +Merging is a delicate process in CVS and requires the +following disciplined steps in order to prevent conflicts +in the future. Conflicts can be hard to solve! + +Merging from branch A to branch B requires that the A branch +has a tag indicating the previous merger. This tag is called +'merged_from_A_to_B'. After merging, the tag is moved in the +A branch to remember this merger for future merge actions. + +IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE +REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE +MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME). + +Merge all changes in DEVEL since our last merge to main: + +In the working copy of the main trunk: +cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL  + +(This will apply the changes between 'merged_from_DEVEL_to_main' +and 'DEVEL' to your work set of files) + +We can now commit the merge result. +cvs commit -R -m "Merged from DEVEL to main."  + +If this worked out OK, we now move the tag in the DEVEL branch +to this merge point, so we can use this point for future merges: + +cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip  + +4 How to release lwIP +--------------------- + +First, checkout a clean copy of the branch to be released. Tag this set with +tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example). + +Login CVS using pserver authentication, then export a clean copy of the +tagged tree. Export is similar to a checkout, except that the CVS metadata +is not created locally.  + +export CVS_RSH=ssh +cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \ +  -r STABLE-0_6_3 -d lwip-0.6.3 lwip + +Archive this directory using tar, gzip'd, bzip2'd and zip'd. + +tar czvf lwip-0.6.3.tar.gz lwip-0.6.3 +tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3 +zip -r lwip-0.6.3.zip lwip-0.6.3 + +Now, sign the archives with a detached GPG binary signature as follows: + +gpg -b lwip-0.6.3.tar.gz +gpg -b lwip-0.6.3.tar.bz2 +gpg -b lwip-0.6.3.zip + +Upload these files using anonymous FTP: +ncftp ftp://savannah.gnu.org/incoming/savannah/lwip + +ncftp>mput *0.6.3.* + +Additionally, you may post a news item on Savannah, like this: + +A new 0.6.3 release is now available here: +http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3 + +You will have to submit this via the user News interface, then approve +this via the Administrator News interface.
\ No newline at end of file diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/snmp_agent.txt b/firmware/usrp3/lwip/lwip-1.3.1/doc/snmp_agent.txt new file mode 100644 index 000000000..9b58616a6 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/snmp_agent.txt @@ -0,0 +1,181 @@ +SNMPv1 agent for lwIP + +Author: Christiaan Simons + +This is a brief introduction how to use and configure the SNMP agent. +Note the agent uses the raw-API UDP interface so you may also want to +read rawapi.txt to gain a better understanding of the SNMP message handling. + +0 Agent Capabilities +==================== + +SNMPv1 per RFC1157 +  This is an old(er) standard but is still widely supported. +  For SNMPv2c and v3 have a greater complexity and need many +  more lines of code. IMHO this breaks the idea of "lightweight IP". + +  Note the S in SNMP stands for "Simple". Note that "Simple" is +  relative. SNMP is simple compared to the complex ISO network +  management protocols CMIP (Common Management Information Protocol) +  and CMOT (CMip Over Tcp). + +MIB II per RFC1213 +  The standard lwIP stack management information base. +  This is a required MIB, so this is always enabled. +  When builing lwIP without TCP, the mib-2.tcp group is omitted. +  The groups EGP, CMOT and transmission are disabled by default. +   +  Most mib-2 objects are not writable except: +  sysName, sysLocation, sysContact, snmpEnableAuthenTraps. +  Writing to or changing the ARP and IP address and route +  tables is not possible. +  +  Note lwIP has a very limited notion of IP routing. It currently +  doen't have a route table and doesn't have a notion of the U,G,H flags. +  Instead lwIP uses the interface list with only one default interface +  acting as a single gateway interface (G) for the default route. + +  The agent returns a "virtual table" with the default route 0.0.0.0 +  for the default interface and network routes (no H) for each +  network interface in the netif_list. +  All routes are considered to be up (U). + +Loading additional MIBs +  MIBs can only be added in compile-time, not in run-time. +  There is no MIB compiler thus additional MIBs must be hand coded. + +Large SNMP message support +  The packet decoding and encoding routines are designed +  to use pbuf-chains. Larger payloads then the minimum +  SNMP requirement of 484 octets are supported if the  +  PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your +  local requirement. + +1 Building the Agent +==================== + +First of all you'll need to add the following define +to your local lwipopts.h: + +#define LWIP_SNMP               1 + +and add the source files in lwip/src/core/snmp +and some snmp headers in lwip/src/include/lwip to your makefile. + +Note you'll might need to adapt you network driver to update +the mib2 variables for your interface. + +2 Running the Agent +=================== + +The following function calls must be made in your program to +actually get the SNMP agent running. + +Before starting the agent you should supply pointers +to non-volatile memory for sysContact, sysLocation, +and snmpEnableAuthenTraps. You can do this by calling + +snmp_set_syscontact() +snmp_set_syslocation() +snmp_set_snmpenableauthentraps() + +Additionally you may want to set + +snmp_set_sysdescr() +snmp_set_sysobjid() (if you have a private MIB) +snmp_set_sysname() + +Also before starting the agent you need to setup +one or more trap destinations using these calls: + +snmp_trap_dst_enable(); +snmp_trap_dst_ip_set(); + +In the lwIP initialisation sequence call snmp_init() just after +the call to udp_init(). + +Exactly every 10 msec the SNMP uptime timestamp must be updated with +snmp_inc_sysuptime(). You should call this from a timer interrupt +or a timer signal handler depending on your runtime environment. + +An alternative way to update the SNMP uptime timestamp is to do a call like +snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to +a lower frequency). Another one is to not call snmp_inc_sysuptime() or +snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro. +This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside +snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only +when it's queried (any function which need "sysuptime" have to call +snmp_get_sysuptime). + + +3 Private MIBs +============== + +If want to extend the agent with your own private MIB you'll need to +add the following define to your local lwipopts.h: + +#define SNMP_PRIVATE_MIB        1 + +You must provide the private_mib.h and associated files yourself. +Note we don't have a "MIB compiler" that generates C source from a MIB, +so you're required to do some serious coding if you enable this! + +Note the lwIP enterprise ID (26381) is assigned to the lwIP project, +ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP +MAINTAINERS! + +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  + +You can set it by passing a struct snmp_obj_id to the agent +using snmp_set_sysobjid(&my_object_id), just before snmp_init(). + +Note the object identifiers for thes MIB-2 and your private MIB +tree must be kept in sorted ascending (lexicographical) order. +This to ensure correct getnext operation. + +An example for a private MIB is part of the "minimal Unix" project: +contrib/ports/unix/proj/minimal/lwip_prvmib.c + +The next chapter gives a more detailed description of the +MIB-2 tree and the optional private MIB. + +4 The Gory Details +================== + +4.0 Object identifiers and the MIB tree. + +We have three distinct parts for all object identifiers: + +The prefix +  .iso.org.dod.internet + +the middle part  +  .mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress + +and the index part +  .1.192.168.0.1 + +Objects located above the .internet hierarchy aren't supported. +Currently only the .mgmt sub-tree is available and +when the SNMP_PRIVATE_MIB is enabled the .private tree +becomes available too. + +Object identifiers from incoming requests are checked +for a matching prefix, middle part and index part +or are expanded(*) for GetNext requests with short +or inexisting names in the request. +(* we call this "expansion" but this also +resembles the "auto-completion" operation) + +The middle part is usually located in ROM (const) +to preserve precious RAM on small microcontrollers. +However RAM location is possible for an dynamically +changing private tree. + +The index part is handled by functions which in +turn use dynamically allocated index trees from RAM. +These trees are updated by e.g. the etharp code +when new entries are made or removed form the ARP cache. + +/** @todo more gory details */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/doc/sys_arch.txt b/firmware/usrp3/lwip/lwip-1.3.1/doc/sys_arch.txt new file mode 100644 index 000000000..66310a91e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/doc/sys_arch.txt @@ -0,0 +1,228 @@ +sys_arch interface for lwIP 0.6++ + +Author: Adam Dunkels + +The operating system emulation layer provides a common interface +between the lwIP code and the underlying operating system kernel. The +general idea is that porting lwIP to new architectures requires only +small changes to a few header files and a new sys_arch +implementation. It is also possible to do a sys_arch implementation +that does not rely on any underlying operating system. + +The sys_arch provides semaphores and mailboxes to lwIP. For the full +lwIP functionality, multiple threads support can be implemented in the +sys_arch, but this is not required for the basic lwIP +functionality. Previous versions of lwIP required the sys_arch to +implement timer scheduling as well but as of lwIP 0.5 this is +implemented in a higher layer. + +In addition to the source file providing the functionality of sys_arch, +the OS emulation layer must provide several header files defining +macros used throughout lwip.  The files required and the macros they +must define are listed below the sys_arch description. + +Semaphores can be either counting or binary - lwIP works with both +kinds. Mailboxes are used for message passing and can be implemented +either as a queue which allows multiple messages to be posted to a +mailbox, or as a rendez-vous point where only one message can be +posted at a time. lwIP works with both kinds, but the former type will +be more efficient. A message in a mailbox is just a pointer, nothing +more.  + +Semaphores are represented by the type "sys_sem_t" which is typedef'd +in the sys_arch.h file. Mailboxes are equivalently represented by the +type "sys_mbox_t". lwIP does not place any restrictions on how +sys_sem_t or sys_mbox_t are represented internally. + +The following functions must be implemented by the sys_arch: + +- void sys_init(void) + +  Is called to initialize the sys_arch layer. + +- sys_sem_t sys_sem_new(u8_t count) + +  Creates and returns a new semaphore. The "count" argument specifies +  the initial state of the semaphore. + +- void sys_sem_free(sys_sem_t sem) + +  Deallocates a semaphore. + +- void sys_sem_signal(sys_sem_t sem) + +  Signals a semaphore. + +- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) + +  Blocks the thread while waiting for the semaphore to be +  signaled. If the "timeout" argument is non-zero, the thread should +  only be blocked for the specified time (measured in +  milliseconds). If the "timeout" argument is zero, the thread should be +  blocked until the semaphore is signalled. + +  If the timeout argument is non-zero, the return value is the number of +  milliseconds spent waiting for the semaphore to be signaled. If the +  semaphore wasn't signaled within the specified time, the return value is +  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore +  (i.e., it was already signaled), the function may return zero. + +  Notice that lwIP implements a function with a similar name, +  sys_sem_wait(), that uses the sys_arch_sem_wait() function. + +- sys_mbox_t sys_mbox_new(int size) + +  Creates an empty mailbox for maximum "size" elements. Elements stored +  in mailboxes are pointers. You have to define macros "_MBOX_SIZE" +  in your lwipopts.h, or ignore this parameter in your implementation +  and use a default size. + +- void sys_mbox_free(sys_mbox_t mbox) + +  Deallocates a mailbox. If there are messages still present in the +  mailbox when the mailbox is deallocated, it is an indication of a +  programming error in lwIP and the developer should be notified. + +- void sys_mbox_post(sys_mbox_t mbox, void *msg) + +  Posts the "msg" to the mailbox. This function have to block until +  the "msg" is really posted. + +- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg) + +  Try to post the "msg" to the mailbox. Returns ERR_MEM if this one +  is full, else, ERR_OK if the "msg" is posted. + +- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) + +  Blocks the thread until a message arrives in the mailbox, but does +  not block the thread longer than "timeout" milliseconds (similar to +  the sys_arch_sem_wait() function). If "timeout" is 0, the thread should +  be blocked until a message arrives. The "msg" argument is a result +  parameter that is set by the function (i.e., by doing "*msg = +  ptr"). The "msg" parameter maybe NULL to indicate that the message +  should be dropped. + +  The return values are the same as for the sys_arch_sem_wait() function: +  Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a +  timeout. + +  Note that a function with a similar name, sys_mbox_fetch(), is +  implemented by lwIP.  + +- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) + +  This is similar to sys_arch_mbox_fetch, however if a message is not +  present in the mailbox, it immediately returns with the code +  SYS_MBOX_EMPTY. On success 0 is returned. + +  To allow for efficient implementations, this can be defined as a +  function-like macro in sys_arch.h instead of a normal function. For +  example, a naive implementation could be: +    #define sys_arch_mbox_tryfetch(mbox,msg) \ +      sys_arch_mbox_fetch(mbox,msg,1) +  although this would introduce unnecessary delays. +   +- struct sys_timeouts *sys_arch_timeouts(void) + +  Returns a pointer to the per-thread sys_timeouts structure. In lwIP, +  each thread has a list of timeouts which is repressented as a linked +  list of sys_timeout structures. The sys_timeouts structure holds a +  pointer to a linked list of timeouts. This function is called by +  the lwIP timeout scheduler and must not return a NULL value.  + +  In a single thread sys_arch implementation, this function will +  simply return a pointer to a global sys_timeouts variable stored in +  the sys_arch module. +   +If threads are supported by the underlying operating system and if +such functionality is needed in lwIP, the following function will have +to be implemented as well: + +- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio) + +  Starts a new thread named "name" with priority "prio" that will begin its +  execution in the function "thread()". The "arg" argument will be passed as an +  argument to the thread() function. The stack size to used for this thread is +  the "stacksize" parameter. The id of the new thread is returned. Both the id +  and the priority are system dependent. + +- sys_prot_t sys_arch_protect(void) + +  This optional function does a "fast" critical region protection and returns +  the previous protection level. This function is only called during very short +  critical regions. An embedded system which supports ISR-based drivers might +  want to implement this function by disabling interrupts. Task-based systems +  might want to implement this by using a mutex or disabling tasking. This +  function should support recursive calls from the same task or interrupt. In +  other words, sys_arch_protect() could be called while already protected. In +  that case the return value indicates that it is already protected. + +  sys_arch_protect() is only required if your port is supporting an operating +  system. + +- void sys_arch_unprotect(sys_prot_t pval) + +  This optional function does a "fast" set of critical region protection to the +  value specified by pval. See the documentation for sys_arch_protect() for +  more information. This function is only required if your port is supporting +  an operating system. + +Note: + +Be carefull with using mem_malloc() in sys_arch. When malloc() refers to +mem_malloc() you can run into a circular function call problem. In mem.c +mem_init() tries to allcate a semaphore using mem_malloc, which of course +can't be performed when sys_arch uses mem_malloc. + +------------------------------------------------------------------------------- +Additional files required for the "OS support" emulation layer: +------------------------------------------------------------------------------- + +cc.h       - Architecture environment, some compiler specific, some +             environment specific (probably should move env stuff  +             to sys_arch.h.) + +  Typedefs for the types used by lwip - +    u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t + +  Compiler hints for packing lwip's structures - +    PACK_STRUCT_FIELD(x) +    PACK_STRUCT_STRUCT +    PACK_STRUCT_BEGIN +    PACK_STRUCT_END + +  Platform specific diagnostic output - +    LWIP_PLATFORM_DIAG(x)    - non-fatal, print a message. +    LWIP_PLATFORM_ASSERT(x)  - fatal, print message and abandon execution. +    Portability defines for printf formatters: +    U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F + +  "lightweight" synchronization mechanisms - +    SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable. +    SYS_ARCH_PROTECT(x)      - enter protection mode. +    SYS_ARCH_UNPROTECT(x)    - leave protection mode. + +  If the compiler does not provide memset() this file must include a +  definition of it, or include a file which defines it. + +  This file must either include a system-local <errno.h> which defines +  the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO +  to make lwip/arch.h define the codes which are used throughout. + + +perf.h     - Architecture specific performance measurement. +  Measurement calls made throughout lwip, these can be defined to nothing. +    PERF_START               - start measuring something. +    PERF_STOP(x)             - stop measuring something, and record the result. + +sys_arch.h - Tied to sys_arch.c + +  Arch dependent types for the following objects: +    sys_sem_t, sys_mbox_t, sys_thread_t, +  And, optionally: +    sys_prot_t + +  Defines to set vars of sys_mbox_t and sys_sem_t to NULL. +    SYS_MBOX_NULL NULL +    SYS_SEM_NULL NULL diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/.hgignore b/firmware/usrp3/lwip/lwip-1.3.1/src/.hgignore new file mode 100644 index 000000000..f88587df3 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/.hgignore @@ -0,0 +1,26 @@ +syntax: glob  +  +*.pyc  +*.orig  +*.rej  +*~  +TAGS  +Module.symvers  +*.ncb +*.suo +*.bak +*.orig +*.rej + +syntax: regexp +\.\#.+ +[\\/]CVS$ +^CVS$ +^build$ +^install$ +^logs.build_tree$ +[\\/]bin$ +^bin$ +[\\/]obj$ +^obj$ +\.cvsignore diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/FILES b/firmware/usrp3/lwip/lwip-1.3.1/src/FILES new file mode 100644 index 000000000..952aeabb4 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/FILES @@ -0,0 +1,13 @@ +api/      - The code for the high-level wrapper API. Not needed if +            you use the lowel-level call-back/raw API. + +core/     - The core of the TPC/IP stack; protocol implementations, +            memory and buffer management, and the low-level raw API. + +include/  - lwIP include files. + +netif/    - Generic network interface device drivers are kept here, +            as well as the ARP module. + +For more information on the various subdirectories, check the FILES +file in each directory. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_lib.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_lib.c new file mode 100644 index 000000000..86df911ea --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_lib.c @@ -0,0 +1,557 @@ +/** + * @file + * Sequential API External 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> + * + */ + +/* This is the part of the API that is linked with +   the application */ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api.h" +#include "lwip/tcpip.h" +#include "lwip/memp.h" + +#include "lwip/ip.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" + +#include <string.h> + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is also created. + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + *         NULL on memory error + */ +struct netconn* +netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback) +{ +  struct netconn *conn; +  struct api_msg msg; + +  conn = netconn_alloc(t, callback); +  if (conn != NULL ) { +    msg.function = do_newconn; +    msg.msg.msg.n.proto = proto; +    msg.msg.conn = conn; +    TCPIP_APIMSG(&msg); + +    if (conn->err != ERR_OK) { +      LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); +      LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL); +      LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL); +      LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL); +      sys_sem_free(conn->op_completed); +      sys_mbox_free(conn->recvmbox); +      memp_free(MEMP_NETCONN, conn); +      return NULL; +    } +  } +  return conn; +} + +/** + * Close a netconn 'connection' and free its resources. + * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate + * after this returns. + * + * @param conn the netconn to delete + * @return ERR_OK if the connection was deleted + */ +err_t +netconn_delete(struct netconn *conn) +{ +  struct api_msg msg; + +  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */ +  if (conn == NULL) { +    return ERR_OK; +  } + +  msg.function = do_delconn; +  msg.msg.conn = conn; +  tcpip_apimsg(&msg); + +  conn->pcb.tcp = NULL; +  netconn_free(conn); + +  return ERR_OK; +} + +/** + * Get the local or remote IP address and port of a netconn. + * For RAW netconns, this returns the protocol instead of a port! + * + * @param conn the netconn to query + * @param addr a pointer to which to save the IP address + * @param port a pointer to which to save the port (or protocol for RAW) + * @param local 1 to get the local IP address, 0 to get the remote one + * @return ERR_CONN for invalid connections + *         ERR_OK if the information was retrieved + */ +err_t +netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;); + +  msg.function = do_getaddr; +  msg.msg.conn = conn; +  msg.msg.msg.ad.ipaddr = addr; +  msg.msg.msg.ad.port = port; +  msg.msg.msg.ad.local = local; +  TCPIP_APIMSG(&msg); + +  return conn->err; +} + +/** + * Bind a netconn to a specific local IP address and port. + * Binding one netconn twice might not always be checked correctly! + * + * @param conn the netconn to bind + * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY + *             to bind to all addresses) + * @param port the local port to bind the netconn to (not used for RAW) + * @return ERR_OK if bound, any other err_t on failure + */ +err_t +netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_bind; +  msg.msg.conn = conn; +  msg.msg.msg.bc.ipaddr = addr; +  msg.msg.msg.bc.port = port; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Connect a netconn to a specific remote IP address and port. + * + * @param conn the netconn to connect + * @param addr the remote IP address to connect to + * @param port the remote port to connect to (no used for RAW) + * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise + */ +err_t +netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_connect; +  msg.msg.conn = conn; +  msg.msg.msg.bc.ipaddr = addr; +  msg.msg.msg.bc.port = port; +  /* This is the only function which need to not block tcpip_thread */ +  tcpip_apimsg(&msg); +  return conn->err; +} + +/** + * Disconnect a netconn from its current peer (only valid for UDP netconns). + * + * @param conn the netconn to disconnect + * @return TODO: return value is not set here... + */ +err_t +netconn_disconnect(struct netconn *conn) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_disconnect; +  msg.msg.conn = conn; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Set a TCP netconn into listen mode + * + * @param conn the tcp netconn to set to listen mode + * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1 + * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns + *         don't return any error (yet?)) + */ +err_t +netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) +{ +  struct api_msg msg; + +  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ +  LWIP_UNUSED_ARG(backlog); + +  LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;); + +  msg.function = do_listen; +  msg.msg.conn = conn; +#if TCP_LISTEN_BACKLOG +  msg.msg.msg.lb.backlog = backlog; +#endif /* TCP_LISTEN_BACKLOG */ +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Accept a new connection on a TCP listening netconn. + * + * @param conn the TCP listen netconn + * @return the newly accepted netconn or NULL on timeout + */ +struct netconn * +netconn_accept(struct netconn *conn) +{ +  struct netconn *newconn; + +  LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return NULL;); +  LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;); + +#if LWIP_SO_RCVTIMEO +  if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { +    newconn = NULL; +  } else +#else +  sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); +#endif /* LWIP_SO_RCVTIMEO*/ +  { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + +#if TCP_LISTEN_BACKLOG +    if (newconn != NULL) { +      /* Let the stack know that we have accepted the connection. */ +      struct api_msg msg; +      msg.function = do_recv; +      msg.msg.conn = conn; +      TCPIP_APIMSG(&msg); +    } +#endif /* TCP_LISTEN_BACKLOG */ +  } + +  return newconn; +} + +/** + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @return a new netbuf containing received data or NULL on memory error or timeout + */ +struct netbuf * +netconn_recv(struct netconn *conn) +{ +  struct api_msg msg; +  struct netbuf *buf = NULL; +  struct pbuf *p; +  u16_t len; + +  LWIP_ERROR("netconn_recv: invalid conn",  (conn != NULL), return NULL;); + +  if (conn->recvmbox == SYS_MBOX_NULL) { +    /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */ +    /* TCP listen conns don't have a recvmbox! */ +    conn->err = ERR_CONN; +    return NULL; +  } + +  if (ERR_IS_FATAL(conn->err)) { +    return NULL; +  } + +  if (conn->type == NETCONN_TCP) { +#if LWIP_TCP +    if (conn->state == NETCONN_LISTEN) { +      /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */ +      conn->err = ERR_CONN; +      return NULL; +    } + +    buf = memp_malloc(MEMP_NETBUF); + +    if (buf == NULL) { +      conn->err = ERR_MEM; +      return NULL; +    } + +#if LWIP_SO_RCVTIMEO +    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { +      conn->err = ERR_TIMEOUT; +      p = NULL; +    } +#else +    sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0); +#endif /* LWIP_SO_RCVTIMEO*/ + +    if (p != NULL) { +      len = p->tot_len; +      SYS_ARCH_DEC(conn->recv_avail, len); +    } else { +      len = 0; +    } + +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + +    /* If we are closed, we indicate that we no longer wish to use the socket */ +    if (p == NULL) { +      memp_free(MEMP_NETBUF, buf); +      /* Avoid to lose any previous error code */ +      if (conn->err == ERR_OK) { +        conn->err = ERR_CLSD; +      } +      return NULL; +    } + +    buf->p = p; +    buf->ptr = p; +    buf->port = 0; +    buf->addr = NULL; + +    /* Let the stack know that we have taken the data. */ +    msg.function = do_recv; +    msg.msg.conn = conn; +    if (buf != NULL) { +      msg.msg.msg.r.len = buf->p->tot_len; +    } else { +      msg.msg.msg.r.len = 1; +    } +    TCPIP_APIMSG(&msg); +#endif /* LWIP_TCP */ +  } else { +#if (LWIP_UDP || LWIP_RAW) +#if LWIP_SO_RCVTIMEO +    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { +      buf = NULL; +    } +#else +    sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ +    if (buf!=NULL) { +      SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len); +      /* Register event with callback */ +      API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); +    } +#endif /* (LWIP_UDP || LWIP_RAW) */ +  } + +  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); + +  return buf; +} + +/** + * Send data (in form of a netbuf) to a specific remote IP address and port. + * Only to be used for UDP and RAW netconns (not TCP). + * + * @param conn the netconn over which to send data + * @param buf a netbuf containing the data to send + * @param addr the remote IP address to which to send the data + * @param port the remote port to which to send the data + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port) +{ +  if (buf != NULL) { +    buf->addr = addr; +    buf->port = port; +    return netconn_send(conn, buf); +  } +  return ERR_VAL; +} + +/** + * Send data over a UDP or RAW netconn (that is already connected). + * + * @param conn the UDP or RAW netconn over which to send data + * @param buf a netbuf containing the data to send + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_send(struct netconn *conn, struct netbuf *buf) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;); + +  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len)); +  msg.function = do_send; +  msg.msg.conn = conn; +  msg.msg.msg.b = buf; +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Send data over a TCP netconn. + * + * @param conn the TCP netconn over which to send data + * @param dataptr pointer to the application buffer that contains the data to send + * @param size size of the application data to send + * @param apiflags combination of following flags : + * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack + * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent + * @return ERR_OK if data was sent, any other err_t on error + */ +err_t +netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;); + +  msg.function = do_write; +  msg.msg.conn = conn; +  msg.msg.msg.w.dataptr = dataptr; +  msg.msg.msg.w.apiflags = apiflags; +  msg.msg.msg.w.len = size; +  /* For locking the core: this _can_ be delayed on low memory/low send buffer, +     but if it is, this is done inside api_msg.c:do_write(), so we can use the +     non-blocking version here. */ +  TCPIP_APIMSG(&msg); +  return conn->err; +} + +/** + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;); + +  msg.function = do_close; +  msg.msg.conn = conn; +  tcpip_apimsg(&msg); +  return conn->err; +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * + * @param conn the UDP netconn for which to change multicast addresses + * @param multiaddr IP address of the multicast group to join or leave + * @param interface the IP address of the network interface on which to send + *                  the igmp message + * @param join_or_leave flag whether to send a join- or leave-message + * @return ERR_OK if the action was taken, any err_t on error + */ +err_t +netconn_join_leave_group(struct netconn *conn, +                         struct ip_addr *multiaddr, +                         struct ip_addr *interface, +                         enum netconn_igmp join_or_leave) +{ +  struct api_msg msg; + +  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;); + +  msg.function = do_join_leave_group; +  msg.msg.conn = conn; +  msg.msg.msg.jl.multiaddr = multiaddr; +  msg.msg.msg.jl.interface = interface; +  msg.msg.msg.jl.join_or_leave = join_or_leave; +  TCPIP_APIMSG(&msg); +  return conn->err; +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Execute a DNS query, only one IP address is returned + * + * @param name a string representation of the DNS host name to query + * @param addr a preallocated struct ip_addr where to store the resolved IP address + * @return ERR_OK: resolving succeeded + *         ERR_MEM: memory error, try again later + *         ERR_ARG: dns client not initialized or invalid hostname + *         ERR_VAL: dns server response was invalid + */ +err_t +netconn_gethostbyname(const char *name, struct ip_addr *addr) +{ +  struct dns_api_msg msg; +  err_t err; +  sys_sem_t sem; + +  LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); +  LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); + +  sem = sys_sem_new(0); +  if (sem == SYS_SEM_NULL) { +    return ERR_MEM; +  } + +  msg.name = name; +  msg.addr = addr; +  msg.err = &err; +  msg.sem = sem; + +  tcpip_callback(do_gethostbyname, &msg); +  sys_sem_wait(sem); +  sys_sem_free(sem); + +  return err; +} +#endif /* LWIP_DNS*/ + +#endif /* LWIP_NETCONN */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_msg.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_msg.c new file mode 100644 index 000000000..28d101019 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/api_msg.c @@ -0,0 +1,1232 @@ +/** + * @file + * Sequential API Internal 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_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" + +#include "lwip/ip.h" +#include "lwip/udp.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" + +#include "lwip/memp.h" +#include "lwip/tcpip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" + +#include <string.h> + +/* forward declarations */ +#if LWIP_TCP +static err_t do_writemore(struct netconn *conn); +static void do_close_internal(struct netconn *conn); +#endif + +#if LWIP_RAW +/** + * Receive callback function for RAW netconns. + * Doesn't 'eat' the packet, only references it and sends it to + * conn->recvmbox + * + * @see raw.h (struct raw_pcb.recv) for parameters and return value + */ +static u8_t +recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr) +{ +  struct pbuf *q; +  struct netbuf *buf; +  struct netconn *conn; +#if LWIP_SO_RCVBUF +  int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + +  LWIP_UNUSED_ARG(addr); +  conn = arg; + +#if LWIP_SO_RCVBUF +  SYS_ARCH_GET(conn->recv_avail, recv_avail); +  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && +      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { +#else  /* LWIP_SO_RCVBUF */ +  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { +#endif /* LWIP_SO_RCVBUF */ +    /* copy the whole packet into new pbufs */ +    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +    if(q != NULL) { +      if (pbuf_copy(q, p) != ERR_OK) { +        pbuf_free(q); +        q = NULL; +      } +    } + +    if(q != NULL) { +      buf = memp_malloc(MEMP_NETBUF); +      if (buf == NULL) { +        pbuf_free(q); +        return 0; +      } + +      buf->p = q; +      buf->ptr = q; +      buf->addr = &(((struct ip_hdr*)(q->payload))->src); +      buf->port = pcb->protocol; + +      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { +        netbuf_delete(buf); +        return 0; +      } else { +        SYS_ARCH_INC(conn->recv_avail, q->tot_len); +        /* Register event with callback */ +        API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); +      } +    } +  } + +  return 0; /* do not eat the packet */ +} +#endif /* LWIP_RAW*/ + +#if LWIP_UDP +/** + * Receive callback function for UDP netconns. + * Posts the packet to conn->recvmbox or deletes it on memory error. + * + * @see udp.h (struct udp_pcb.recv) for parameters + */ +static void +recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, +   struct ip_addr *addr, u16_t port) +{ +  struct netbuf *buf; +  struct netconn *conn; +#if LWIP_SO_RCVBUF +  int recv_avail; +#endif /* LWIP_SO_RCVBUF */ + +  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ +  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); +  LWIP_ASSERT("recv_udp must have an argument", arg != NULL); +  conn = arg; +  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); + +#if LWIP_SO_RCVBUF +  SYS_ARCH_GET(conn->recv_avail, recv_avail); +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || +      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { +#else  /* LWIP_SO_RCVBUF */ +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { +#endif /* LWIP_SO_RCVBUF */ +    pbuf_free(p); +    return; +  } + +  buf = memp_malloc(MEMP_NETBUF); +  if (buf == NULL) { +    pbuf_free(p); +    return; +  } else { +    buf->p = p; +    buf->ptr = p; +    buf->addr = addr; +    buf->port = port; +  } + +  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { +    netbuf_delete(buf); +    return; +  } else { +    SYS_ARCH_INC(conn->recv_avail, p->tot_len); +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); +  } +} +#endif /* LWIP_UDP */ + +#if LWIP_TCP +/** + * Receive callback function for TCP netconns. + * Posts the packet to conn->recvmbox, but doesn't delete it on errors. + * + * @see tcp.h (struct tcp_pcb.recv) for parameters and return value + */ +static err_t +recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ +  struct netconn *conn; +  u16_t len; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); +  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); +  conn = arg; +  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); + +  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { +    return ERR_VAL; +  } + +  conn->err = err; +  if (p != NULL) { +    len = p->tot_len; +    SYS_ARCH_INC(conn->recv_avail, len); +  } else { +    len = 0; +  } + +  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { +    return ERR_MEM; +  } else { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); +  } + +  return ERR_OK; +} + +/** + * Poll callback function for TCP netconns. + * Wakes up an application thread that waits for a connection to close + * or data to be sent. The application thread then takes the + * appropriate action to go on. + * + * Signals the conn->sem. + * netconn_close waits for conn->sem if closing failed. + * + * @see tcp.h (struct tcp_pcb.poll) for parameters and return value + */ +static err_t +poll_tcp(void *arg, struct tcp_pcb *pcb) +{ +  struct netconn *conn = arg; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  if (conn->state == NETCONN_WRITE) { +    do_writemore(conn); +  } else if (conn->state == NETCONN_CLOSE) { +    do_close_internal(conn); +  } + +  return ERR_OK; +} + +/** + * Sent callback function for TCP netconns. + * Signals the conn->sem and calls API_EVENT. + * netconn_write waits for conn->sem if send buffer is low. + * + * @see tcp.h (struct tcp_pcb.sent) for parameters and return value + */ +static err_t +sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) +{ +  struct netconn *conn = arg; + +  LWIP_UNUSED_ARG(pcb); +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  if (conn->state == NETCONN_WRITE) { +    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); +    do_writemore(conn); +  } else if (conn->state == NETCONN_CLOSE) { +    do_close_internal(conn); +  } + +  if (conn) { +    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) { +      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); +    } +  } +   +  return ERR_OK; +} + +/** + * Error callback function for TCP netconns. + * Signals conn->sem, posts to all conn mboxes and calls API_EVENT. + * The application thread has then to decide what to do. + * + * @see tcp.h (struct tcp_pcb.err) for parameters + */ +static void +err_tcp(void *arg, err_t err) +{ +  struct netconn *conn; + +  conn = arg; +  LWIP_ASSERT("conn != NULL", (conn != NULL)); + +  conn->pcb.tcp = NULL; + +  conn->err = err; +  if (conn->recvmbox != SYS_MBOX_NULL) { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    sys_mbox_post(conn->recvmbox, NULL); +  } +  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) { +    conn->state = NETCONN_NONE; +    sys_sem_signal(conn->op_completed); +  } +  if (conn->acceptmbox != SYS_MBOX_NULL) { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    sys_mbox_post(conn->acceptmbox, NULL); +  } +  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { +    /* calling do_writemore/do_close_internal is not necessary +       since the pcb has already been deleted! */ +    conn->state = NETCONN_NONE; +    /* wake up the waiting task */ +    sys_sem_signal(conn->op_completed); +  } +} + +/** + * Setup a tcp_pcb with the correct callback function pointers + * and their arguments. + * + * @param conn the TCP netconn to setup + */ +static void +setup_tcp(struct netconn *conn) +{ +  struct tcp_pcb *pcb; + +  pcb = conn->pcb.tcp; +  tcp_arg(pcb, conn); +  tcp_recv(pcb, recv_tcp); +  tcp_sent(pcb, sent_tcp); +  tcp_poll(pcb, poll_tcp, 4); +  tcp_err(pcb, err_tcp); +} + +/** + * Accept callback function for TCP netconns. + * Allocates a new netconn and posts that to conn->acceptmbox. + * + * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value + */ +static err_t +accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) +{ +  struct netconn *newconn; +  struct netconn *conn; + +#if API_MSG_DEBUG +#if TCP_DEBUG +  tcp_debug_print_state(newpcb->state); +#endif /* TCP_DEBUG */ +#endif /* API_MSG_DEBUG */ +  conn = (struct netconn *)arg; + +  LWIP_ERROR("accept_function: invalid conn->acceptmbox", +             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;); + +  /* We have to set the callback here even though +   * the new socket is unknown. conn->socket is marked as -1. */ +  newconn = netconn_alloc(conn->type, conn->callback); +  if (newconn == NULL) { +    return ERR_MEM; +  } +  newconn->pcb.tcp = newpcb; +  setup_tcp(newconn); +  newconn->err = err; + +  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { +    /* When returning != ERR_OK, the connection is aborted in tcp_process(), +       so do nothing here! */ +    newconn->pcb.tcp = NULL; +    netconn_free(newconn); +    return ERR_MEM; +  } else { +    /* Register event with callback */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +  } + +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Create a new pcb of a specific type. + * Called from do_newconn(). + * + * @param msg the api_msg_msg describing the connection type + * @return msg->conn->err, but the return value is currently ignored + */ +static err_t +pcb_new(struct api_msg_msg *msg) +{ +   msg->conn->err = ERR_OK; + +   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + +   /* Allocate a PCB for this connection */ +   switch(NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +   case NETCONN_RAW: +     msg->conn->pcb.raw = raw_new(msg->msg.n.proto); +     if(msg->conn->pcb.raw == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); +     break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +   case NETCONN_UDP: +     msg->conn->pcb.udp = udp_new(); +     if(msg->conn->pcb.udp == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +#if LWIP_UDPLITE +     if (msg->conn->type==NETCONN_UDPLITE) { +       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); +     } +#endif /* LWIP_UDPLITE */ +     if (msg->conn->type==NETCONN_UDPNOCHKSUM) { +       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); +     } +     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); +     break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +   case NETCONN_TCP: +     msg->conn->pcb.tcp = tcp_new(); +     if(msg->conn->pcb.tcp == NULL) { +       msg->conn->err = ERR_MEM; +       break; +     } +     setup_tcp(msg->conn); +     break; +#endif /* LWIP_TCP */ +   default: +     /* Unsupported netconn type, e.g. protocol disabled */ +     msg->conn->err = ERR_VAL; +     break; +   } + +  return msg->conn->err; +} + +/** + * Create a new pcb of a specific type inside a netconn. + * Called from netconn_new_with_proto_and_callback. + * + * @param msg the api_msg_msg describing the connection type + */ +void +do_newconn(struct api_msg_msg *msg) +{ +   if(msg->conn->pcb.tcp == NULL) { +     pcb_new(msg); +   } +   /* Else? This "new" connection already has a PCB allocated. */ +   /* Is this an error condition? Should it be deleted? */ +   /* We currently just are happy and return. */ + +   TCPIP_APIMSG_ACK(msg); +} + +/** + * Create a new netconn (of a specific type) that has a callback function. + * The corresponding pcb is NOT created! + * + * @param t the type of 'connection' to create (@see enum netconn_type) + * @param proto the IP protocol for RAW IP pcbs + * @param callback a function to call on status changes (RX available, TX'ed) + * @return a newly allocated struct netconn or + *         NULL on memory error + */ +struct netconn* +netconn_alloc(enum netconn_type t, netconn_callback callback) +{ +  struct netconn *conn; +  int size; + +  conn = memp_malloc(MEMP_NETCONN); +  if (conn == NULL) { +    return NULL; +  } + +  conn->err = ERR_OK; +  conn->type = t; +  conn->pcb.tcp = NULL; + +#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \ +    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE) +  size = DEFAULT_RAW_RECVMBOX_SIZE; +#else +  switch(NETCONNTYPE_GROUP(t)) { +#if LWIP_RAW +  case NETCONN_RAW: +    size = DEFAULT_RAW_RECVMBOX_SIZE; +    break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +  case NETCONN_UDP: +    size = DEFAULT_UDP_RECVMBOX_SIZE; +    break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +  case NETCONN_TCP: +    size = DEFAULT_TCP_RECVMBOX_SIZE; +    break; +#endif /* LWIP_TCP */ +  default: +    LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0); +    break; +  } +#endif + +  if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) { +    memp_free(MEMP_NETCONN, conn); +    return NULL; +  } +  if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) { +    sys_sem_free(conn->op_completed); +    memp_free(MEMP_NETCONN, conn); +    return NULL; +  } + +  conn->acceptmbox   = SYS_MBOX_NULL; +  conn->state        = NETCONN_NONE; +  /* initialize socket to -1 since 0 is a valid socket */ +  conn->socket       = -1; +  conn->callback     = callback; +  conn->recv_avail   = 0; +#if LWIP_TCP +  conn->write_msg    = NULL; +  conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING +  conn->write_delayed = 0; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ +#if LWIP_SO_RCVTIMEO +  conn->recv_timeout = 0; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +  conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; +#endif /* LWIP_SO_RCVBUF */ +  return conn; +} + +/** + * Delete a netconn and all its resources. + * The pcb is NOT freed (since we might not be in the right thread context do this). + * + * @param conn the netconn to free + */ +void +netconn_free(struct netconn *conn) +{ +  void *mem; +  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + +  /* Drain the recvmbox. */ +  if (conn->recvmbox != SYS_MBOX_NULL) { +    while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +      if (conn->type == NETCONN_TCP) { +        if(mem != NULL) { +          pbuf_free((struct pbuf *)mem); +        } +      } else { +        netbuf_delete((struct netbuf *)mem); +      } +    } +    sys_mbox_free(conn->recvmbox); +    conn->recvmbox = SYS_MBOX_NULL; +  } + +  /* Drain the acceptmbox. */ +  if (conn->acceptmbox != SYS_MBOX_NULL) { +    while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { +      netconn_delete((struct netconn *)mem); +    } +    sys_mbox_free(conn->acceptmbox); +    conn->acceptmbox = SYS_MBOX_NULL; +  } + +  sys_sem_free(conn->op_completed); +  conn->op_completed = SYS_SEM_NULL; + +  memp_free(MEMP_NETCONN, conn); +} + +#if LWIP_TCP +/** + * Internal helper function to close a TCP netconn: since this sometimes + * doesn't work at the first attempt, this function is called from multiple + * places. + * + * @param conn the TCP netconn to close + */ +static void +do_close_internal(struct netconn *conn) +{ +  err_t err; + +  LWIP_ASSERT("invalid conn", (conn != NULL)); +  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); +  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); +  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + +  /* Set back some callback pointers */ +  tcp_arg(conn->pcb.tcp, NULL); +  if (conn->pcb.tcp->state == LISTEN) { +    tcp_accept(conn->pcb.tcp, NULL); +  } else { +    tcp_recv(conn->pcb.tcp, NULL); +    tcp_accept(conn->pcb.tcp, NULL); +    /* some callbacks have to be reset if tcp_close is not successful */ +    tcp_sent(conn->pcb.tcp, NULL); +    tcp_poll(conn->pcb.tcp, NULL, 4); +    tcp_err(conn->pcb.tcp, NULL); +  } +  /* Try to close the connection */ +  err = tcp_close(conn->pcb.tcp); +  if (err == ERR_OK) { +    /* Closing succeeded */ +    conn->state = NETCONN_NONE; +    /* Set back some callback pointers as conn is going away */ +    conn->pcb.tcp = NULL; +    conn->err = ERR_OK; +    /* Trigger select() in socket layer. This send should something else so the +       errorfd is set, not the read and write fd! */ +    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); +    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); +    /* wake up the application task */ +    sys_sem_signal(conn->op_completed); +  } else { +    /* Closing failed, restore some of the callbacks */ +    /* Closing of listen pcb will never fail! */ +    LWIP_ASSERT("Closing a listen pcb may not fail!", (conn->pcb.tcp->state != LISTEN)); +    tcp_sent(conn->pcb.tcp, sent_tcp); +    tcp_poll(conn->pcb.tcp, poll_tcp, 4); +    tcp_err(conn->pcb.tcp, err_tcp); +    tcp_arg(conn->pcb.tcp, conn); +  } +  /* If closing didn't succeed, we get called again either +     from poll_tcp or from sent_tcp */ +} +#endif /* LWIP_TCP */ + +/** + * Delete the pcb inside a netconn. + * Called from netconn_delete. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_delconn(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.tcp != NULL) { +    switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +    case NETCONN_RAW: +      raw_remove(msg->conn->pcb.raw); +      break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +    case NETCONN_UDP: +      msg->conn->pcb.udp->recv_arg = NULL; +      udp_remove(msg->conn->pcb.udp); +      break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +    case NETCONN_TCP: +      msg->conn->state = NETCONN_CLOSE; +      do_close_internal(msg->conn); +      /* API_EVENT is called inside do_close_internal, before releasing +         the application thread, so we can return at this point! */ +      return; +#endif /* LWIP_TCP */ +    default: +      break; +    } +  } +  /* tcp netconns don't come here! */ + +  /* Trigger select() in socket layer. This send should something else so the +     errorfd is set, not the read and write fd! */ +  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); +  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + +  if (msg->conn->op_completed != SYS_SEM_NULL) { +    sys_sem_signal(msg->conn->op_completed); +  } +} + +/** + * Bind a pcb contained in a netconn + * Called from netconn_bind. + * + * @param msg the api_msg_msg pointing to the connection and containing + *            the IP address and port to bind to + */ +void +do_bind(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +      case NETCONN_RAW: +        msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); +        break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +      case NETCONN_UDP: +        msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); +        break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +      case NETCONN_TCP: +        msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); +        break; +#endif /* LWIP_TCP */ +      default: +        break; +      } +    } else { +      /* msg->conn->pcb is NULL */ +      msg->conn->err = ERR_VAL; +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * TCP callback function if a connection (opened by tcp_connect/do_connect) has + * been established (or reset by the remote host). + * + * @see tcp.h (struct tcp_pcb.connected) for parameters and return values + */ +static err_t +do_connected(void *arg, struct tcp_pcb *pcb, err_t err) +{ +  struct netconn *conn; + +  LWIP_UNUSED_ARG(pcb); + +  conn = arg; + +  if (conn == NULL) { +    return ERR_VAL; +  } + +  conn->err = err; +  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { +    setup_tcp(conn); +  } +  conn->state = NETCONN_NONE; +  sys_sem_signal(conn->op_completed); +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Connect a pcb contained inside a netconn + * Called from netconn_connect. + * + * @param msg the api_msg_msg pointing to the connection and containing + *            the IP address and port to connect to + */ +void +do_connect(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.tcp == NULL) { +    sys_sem_signal(msg->conn->op_completed); +    return; +  } + +  switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +  case NETCONN_RAW: +    msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); +    sys_sem_signal(msg->conn->op_completed); +    break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +  case NETCONN_UDP: +    msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); +    sys_sem_signal(msg->conn->op_completed); +    break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +  case NETCONN_TCP: +    msg->conn->state = NETCONN_CONNECT; +    setup_tcp(msg->conn); +    msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, +                                 do_connected); +    /* sys_sem_signal() is called from do_connected (or err_tcp()), +     * when the connection is established! */ +    break; +#endif /* LWIP_TCP */ +  default: +    break; +  } +} + +/** + * Connect a pcb contained inside a netconn + * Only used for UDP netconns. + * Called from netconn_disconnect. + * + * @param msg the api_msg_msg pointing to the connection to disconnect + */ +void +do_disconnect(struct api_msg_msg *msg) +{ +#if LWIP_UDP +  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +    udp_disconnect(msg->conn->pcb.udp); +  } +#endif /* LWIP_UDP */ +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Set a TCP pcb contained in a netconn into listen mode + * Called from netconn_listen. + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_listen(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (msg->conn->type == NETCONN_TCP) { +        if (msg->conn->pcb.tcp->state == CLOSED) { +#if TCP_LISTEN_BACKLOG +          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); +#else  /* TCP_LISTEN_BACKLOG */ +          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); +#endif /* TCP_LISTEN_BACKLOG */ +          if (lpcb == NULL) { +            msg->conn->err = ERR_MEM; +          } else { +            /* delete the recvmbox and allocate the acceptmbox */ +            if (msg->conn->recvmbox != SYS_MBOX_NULL) { +              /** @todo: should we drain the recvmbox here? */ +              sys_mbox_free(msg->conn->recvmbox); +              msg->conn->recvmbox = SYS_MBOX_NULL; +            } +            if (msg->conn->acceptmbox == SYS_MBOX_NULL) { +              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { +                msg->conn->err = ERR_MEM; +              } +            } +            if (msg->conn->err == ERR_OK) { +              msg->conn->state = NETCONN_LISTEN; +              msg->conn->pcb.tcp = lpcb; +              tcp_arg(msg->conn->pcb.tcp, msg->conn); +              tcp_accept(msg->conn->pcb.tcp, accept_function); +            } +          } +        } else { +          msg->conn->err = ERR_CONN; +        } +      } +    } +  } +#endif /* LWIP_TCP */ +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Send some data on a RAW or UDP pcb contained in a netconn + * Called from netconn_send + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_send(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +      case NETCONN_RAW: +        if (msg->msg.b->addr == NULL) { +          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); +        } else { +          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); +        } +        break; +#endif +#if LWIP_UDP +      case NETCONN_UDP: +        if (msg->msg.b->addr == NULL) { +          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); +        } else { +          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); +        } +        break; +#endif /* LWIP_UDP */ +      default: +        break; +      } +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Indicate data has been received from a TCP pcb contained in a netconn + * Called from netconn_recv + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_recv(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (msg->conn->type == NETCONN_TCP) { +#if TCP_LISTEN_BACKLOG +        if (msg->conn->pcb.tcp->state == LISTEN) { +          tcp_accepted(msg->conn->pcb.tcp); +        } else +#endif /* TCP_LISTEN_BACKLOG */ +        { +          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); +        } +      } +    } +  } +#endif /* LWIP_TCP */ +  TCPIP_APIMSG_ACK(msg); +} + +#if LWIP_TCP +/** + * See if more data needs to be written from a previous call to netconn_write. + * Called initially from do_write. If the first call can't send all data + * (because of low memory or empty send-buffer), this function is called again + * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the + * blocking application thread (waiting in netconn_write) is released. + * + * @param conn netconn (that is currently in state NETCONN_WRITE) to process + * @return ERR_OK + *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished + */ +static err_t +do_writemore(struct netconn *conn) +{ +  err_t err; +  void *dataptr; +  u16_t len, available; +  u8_t write_finished = 0; +  size_t diff; + +  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + +  dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; +  diff = conn->write_msg->msg.w.len - conn->write_offset; +  if (diff > 0xffffUL) { /* max_u16_t */ +    len = 0xffff; +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } else { +    len = (u16_t)diff; +  } +  available = tcp_sndbuf(conn->pcb.tcp); +  if (available < len) { +    /* don't try to write more than sendbuf */ +    len = available; +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } + +  err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); +  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); +  if (err == ERR_OK) { +    conn->write_offset += len; +    if (conn->write_offset == conn->write_msg->msg.w.len) { +      /* everything was written */ +      write_finished = 1; +      conn->write_msg = NULL; +      conn->write_offset = 0; +      /* API_EVENT might call tcp_tmr, so reset conn->state now */ +      conn->state = NETCONN_NONE; +    } +    err = tcp_output_nagle(conn->pcb.tcp); +    conn->err = err; +    if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { +      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); +    } +  } else if (err == ERR_MEM) { +    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called +       we do NOT return to the application thread, since ERR_MEM is +       only a temporary error! */ + +    /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */ +    err = tcp_output(conn->pcb.tcp); + +#if LWIP_TCPIP_CORE_LOCKING +    conn->write_delayed = 1; +#endif +  } else { +    /* On errors != ERR_MEM, we don't try writing any more but return +       the error to the application thread. */ +    conn->err = err; +    write_finished = 1; +  } + +  if (write_finished) { +    /* everything was written: set back connection state +       and back to application task */ +    conn->state = NETCONN_NONE; +#if LWIP_TCPIP_CORE_LOCKING +    if (conn->write_delayed != 0) +#endif +    { +      sys_sem_signal(conn->op_completed); +    } +  } +#if LWIP_TCPIP_CORE_LOCKING +  else +    return ERR_MEM; +#endif +  return ERR_OK; +} +#endif /* LWIP_TCP */ + +/** + * Send some data on a TCP pcb contained in a netconn + * Called from netconn_write + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_write(struct api_msg_msg *msg) +{ +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { +#if LWIP_TCP +      msg->conn->state = NETCONN_WRITE; +      /* set all the variables used by do_writemore */ +      LWIP_ASSERT("already writing", msg->conn->write_msg == NULL && +        msg->conn->write_offset == 0); +      msg->conn->write_msg = msg; +      msg->conn->write_offset = 0; +#if LWIP_TCPIP_CORE_LOCKING +      msg->conn->write_delayed = 0; +      if (do_writemore(msg->conn) != ERR_OK) { +        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); +        UNLOCK_TCPIP_CORE(); +        sys_arch_sem_wait(msg->conn->op_completed, 0); +        LOCK_TCPIP_CORE(); +        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); +      } +#else +      do_writemore(msg->conn); +#endif +      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */ +      return; +#endif /* LWIP_TCP */ +#if (LWIP_UDP || LWIP_RAW) +    } else { +      msg->conn->err = ERR_VAL; +#endif /* (LWIP_UDP || LWIP_RAW) */ +    } +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Return a connection's local or remote address + * Called from netconn_getaddr + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_getaddr(struct api_msg_msg *msg) +{ +  if (msg->conn->pcb.ip != NULL) { +    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); +     +    switch (NETCONNTYPE_GROUP(msg->conn->type)) { +#if LWIP_RAW +    case NETCONN_RAW: +      if (msg->msg.ad.local) { +        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; +      } else { +        /* return an error as connecting is only a helper for upper layers */ +        msg->conn->err = ERR_CONN; +      } +      break; +#endif /* LWIP_RAW */ +#if LWIP_UDP +    case NETCONN_UDP: +      if (msg->msg.ad.local) { +        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; +      } else { +        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { +          msg->conn->err = ERR_CONN; +        } else { +          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; +        } +      } +      break; +#endif /* LWIP_UDP */ +#if LWIP_TCP +    case NETCONN_TCP: +      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); +      break; +#endif /* LWIP_TCP */ +    } +  } else { +    msg->conn->err = ERR_CONN; +  } +  TCPIP_APIMSG_ACK(msg); +} + +/** + * Close a TCP pcb contained in a netconn + * Called from netconn_close + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_close(struct api_msg_msg *msg) +{ +#if LWIP_TCP +  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { +      msg->conn->state = NETCONN_CLOSE; +      do_close_internal(msg->conn); +      /* for tcp netconns, do_close_internal ACKs the message */ +  } else +#endif /* LWIP_TCP */ +  { +    msg->conn->err = ERR_VAL; +    TCPIP_APIMSG_ACK(msg); +  } +} + +#if LWIP_IGMP +/** + * Join multicast groups for UDP netconns. + * Called from netconn_join_leave_group + * + * @param msg the api_msg_msg pointing to the connection + */ +void +do_join_leave_group(struct api_msg_msg *msg) +{  +  if (!ERR_IS_FATAL(msg->conn->err)) { +    if (msg->conn->pcb.tcp != NULL) { +      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { +#if LWIP_UDP +        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { +          msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); +        } else { +          msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); +        } +#endif /* LWIP_UDP */ +#if (LWIP_TCP || LWIP_RAW) +      } else { +        msg->conn->err = ERR_VAL; +#endif /* (LWIP_TCP || LWIP_RAW) */ +      } +    } +  } +  TCPIP_APIMSG_ACK(msg); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Callback function that is called when DNS name is resolved + * (or on timeout). A waiting application thread is waked up by + * signaling the semaphore. + */ +static void +do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg) +{ +  struct dns_api_msg *msg = (struct dns_api_msg*)arg; + +  LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); + +  if (ipaddr == NULL) { +    /* timeout or memory error */ +    *msg->err = ERR_VAL; +  } else { +    /* address was resolved */ +    *msg->err = ERR_OK; +    *msg->addr = *ipaddr; +  } +  /* wake up the application task waiting in netconn_gethostbyname */ +  sys_sem_signal(msg->sem); +} + +/** + * Execute a DNS query + * Called from netconn_gethostbyname + * + * @param arg the dns_api_msg pointing to the query + */ +void +do_gethostbyname(void *arg) +{ +  struct dns_api_msg *msg = (struct dns_api_msg*)arg; + +  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg); +  if (*msg->err != ERR_INPROGRESS) { +    /* on error or immediate success, wake up the application +     * task waiting in netconn_gethostbyname */ +    sys_sem_signal(msg->sem); +  } +} +#endif /* LWIP_DNS */ + +#endif /* LWIP_NETCONN */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/err.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/err.c new file mode 100644 index 000000000..a90cb98c8 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/err.c @@ -0,0 +1,74 @@ +/** + * @file + * Error Management 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/err.h" + +#ifdef LWIP_DEBUG + +static const char *err_strerr[] = { +           "Ok.",                    /* ERR_OK          0  */ +           "Out of memory error.",   /* ERR_MEM        -1  */ +           "Buffer error.",          /* ERR_BUF        -2  */ +           "Timeout.",               /* ERR_TIMEOUT    -3 */ +           "Routing problem.",       /* ERR_RTE        -4  */ +           "Connection aborted.",    /* ERR_ABRT       -5  */ +           "Connection reset.",      /* ERR_RST        -6  */ +           "Connection closed.",     /* ERR_CLSD       -7  */ +           "Not connected.",         /* ERR_CONN       -8  */ +           "Illegal value.",         /* ERR_VAL        -9  */ +           "Illegal argument.",      /* ERR_ARG        -10 */ +           "Address in use.",        /* ERR_USE        -11 */ +           "Low-level netif error.", /* ERR_IF         -12 */ +           "Already connected.",     /* ERR_ISCONN     -13 */ +           "Operation in progress."  /* ERR_INPROGRESS -14 */ +}; + +/** + * Convert an lwip internal error to a string representation. + * + * @param err an lwip internal err_t + * @return a string representation for err + */ +const char * +lwip_strerr(err_t err) +{ +  return err_strerr[-err]; + +} + +#endif /* LWIP_DEBUG */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/netbuf.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netbuf.c new file mode 100644 index 000000000..af44eefc7 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netbuf.c @@ -0,0 +1,235 @@ +/** + * @file + * Network buffer management + * + */ +  +/* + * 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_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netbuf.h" +#include "lwip/memp.h" + +#include <string.h> + +/** + * Create (allocate) and initialize a new netbuf. + * The netbuf doesn't yet contain a packet buffer! + * + * @return a pointer to a new netbuf + *         NULL on lack of memory + */ +struct +netbuf *netbuf_new(void) +{ +  struct netbuf *buf; + +  buf = memp_malloc(MEMP_NETBUF); +  if (buf != NULL) { +    buf->p = NULL; +    buf->ptr = NULL; +    buf->addr = NULL; +    return buf; +  } else { +    return NULL; +  } +} + +/** + * Deallocate a netbuf allocated by netbuf_new(). + * + * @param buf pointer to a netbuf allocated by netbuf_new() + */ +void +netbuf_delete(struct netbuf *buf) +{ +  if (buf != NULL) { +    if (buf->p != NULL) { +      pbuf_free(buf->p); +      buf->p = buf->ptr = NULL; +    } +    memp_free(MEMP_NETBUF, buf); +  } +} + +/** + * Allocate memory for a packet buffer for a given netbuf. + * + * @param buf the netbuf for which to allocate a packet buffer + * @param size the size of the packet buffer to allocate + * @return pointer to the allocated memory + *         NULL if no memory could be allocated + */ +void * +netbuf_alloc(struct netbuf *buf, u16_t size) +{ +  LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;); + +  /* Deallocate any previously allocated memory. */ +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM); +  if (buf->p == NULL) { +     return NULL; +  } +  LWIP_ASSERT("check that first pbuf can hold size", +             (buf->p->len >= size)); +  buf->ptr = buf->p; +  return buf->p->payload; +} + +/** + * Free the packet buffer included in a netbuf + * + * @param buf pointer to the netbuf which contains the packet buffer to free + */ +void +netbuf_free(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = buf->ptr = NULL; +} + +/** + * Let a netbuf reference existing (non-volatile) data. + * + * @param buf netbuf which should reference the data + * @param dataptr pointer to the data to reference + * @param size size of the data + * @return ERR_OK if data is referenced + *         ERR_MEM if data couldn't be referenced due to lack of memory + */ +err_t +netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size) +{ +  LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;); +  if (buf->p != NULL) { +    pbuf_free(buf->p); +  } +  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); +  if (buf->p == NULL) { +    buf->ptr = NULL; +    return ERR_MEM; +  } +  buf->p->payload = (void*)dataptr; +  buf->p->len = buf->p->tot_len = size; +  buf->ptr = buf->p; +  return ERR_OK; +} + +/** + * Chain one netbuf to another (@see pbuf_chain) + * + * @param head the first netbuf + * @param tail netbuf to chain after head, freed by this function, may not be reference after returning + */ +void +netbuf_chain(struct netbuf *head, struct netbuf *tail) +{ +  LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;); +  LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;); +  pbuf_cat(head->p, tail->p); +  head->ptr = head->p; +  memp_free(MEMP_NETBUF, tail); +} + +/** + * Get the data pointer and length of the data inside a netbuf. + * + * @param buf netbuf to get the data from + * @param dataptr pointer to a void pointer where to store the data pointer + * @param len pointer to an u16_t where the length of the data is stored + * @return ERR_OK if the information was retreived, + *         ERR_BUF on error. + */ +err_t +netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len) +{ +  LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;); +  LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;); +  LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;); + +  if (buf->ptr == NULL) { +    return ERR_BUF; +  } +  *dataptr = buf->ptr->payload; +  *len = buf->ptr->len; +  return ERR_OK; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the next part. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + * @return -1 if there is no next part + *         1  if moved to the next part but now there is no next part + *         0  if moved to the next part and there are still more parts + */ +s8_t +netbuf_next(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;); +  if (buf->ptr->next == NULL) { +    return -1; +  } +  buf->ptr = buf->ptr->next; +  if (buf->ptr->next == NULL) { +    return 1; +  } +  return 0; +} + +/** + * Move the current data pointer of a packet buffer contained in a netbuf + * to the beginning of the packet. + * The packet buffer itself is not modified. + * + * @param buf the netbuf to modify + */ +void +netbuf_first(struct netbuf *buf) +{ +  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;); +  buf->ptr = buf->p; +} + +#endif /* LWIP_NETCONN */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/netdb.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netdb.c new file mode 100644 index 000000000..8aa237f4c --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netdb.c @@ -0,0 +1,356 @@ +/** + * @file + * API functions for name resolving + * + */ + +/* + * 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/netdb.h" + +#if LWIP_DNS && LWIP_SOCKET + +#include "lwip/err.h" +#include "lwip/mem.h" +#include "lwip/ip_addr.h" +#include "lwip/api.h" + +#include <string.h> +#include <stdlib.h> + +/** helper struct for gethostbyname_r to access the char* buffer */ +struct gethostbyname_r_helper { +  struct ip_addr *addrs; +  struct ip_addr addr; +  char *aliases; +}; + +/** h_errno is exported in netdb.h for access by applications. */ +#if LWIP_DNS_API_DECLARE_H_ERRNO +int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */ + +/** define "hostent" variables storage: 0 if we use a static (but unprotected) + * set of variables for lwip_gethostbyname, 1 if we use a local storage */ +#ifndef LWIP_DNS_API_HOSTENT_STORAGE +#define LWIP_DNS_API_HOSTENT_STORAGE 0 +#endif + +/** define "hostent" variables storage */ +#if LWIP_DNS_API_HOSTENT_STORAGE +#define HOSTENT_STORAGE +#else +#define HOSTENT_STORAGE static +#endif /* LWIP_DNS_API_STATIC_HOSTENT */ + +/** + * Returns an entry containing addresses of address family AF_INET + * for the host with name name. + * Due to dns_gethostbyname limitations, only one address is returned. + * + * @param name the hostname to resolve + * @return an entry containing addresses of address family AF_INET + *         for the host with name name + */ +struct hostent* +lwip_gethostbyname(const char *name) +{ +  err_t err; +  struct ip_addr addr; + +  /* buffer variables for lwip_gethostbyname() */ +  HOSTENT_STORAGE struct hostent s_hostent; +  HOSTENT_STORAGE char *s_aliases; +  HOSTENT_STORAGE struct ip_addr s_hostent_addr; +  HOSTENT_STORAGE struct ip_addr *s_phostent_addr; + +  /* query host IP address */ +  err = netconn_gethostbyname(name, &addr); +  if (err != ERR_OK) { +    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); +    h_errno = HOST_NOT_FOUND; +    return NULL; +  } + +  /* fill hostent */ +  s_hostent_addr = addr; +  s_phostent_addr = &s_hostent_addr; +  s_hostent.h_name = (char*)name; +  s_hostent.h_aliases = &s_aliases; +  s_hostent.h_addrtype = AF_INET; +  s_hostent.h_length = sizeof(struct ip_addr); +  s_hostent.h_addr_list = (char**)&s_phostent_addr; + +#if DNS_DEBUG +  /* dump hostent */ +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n", s_hostent.h_name)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == %p\n", s_hostent.h_aliases)); +  if (s_hostent.h_aliases != NULL) { +    u8_t idx; +    for ( idx=0; s_hostent.h_aliases[idx]; idx++) { +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %p\n", idx, s_hostent.h_aliases[idx])); +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx])); +    } +  } +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %d\n", s_hostent.h_addrtype)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %d\n", s_hostent.h_length)); +  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == %p\n", s_hostent.h_addr_list)); +  if (s_hostent.h_addr_list != NULL) { +    u8_t idx; +    for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == %p\n", idx, s_hostent.h_addr_list[idx])); +      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx]))))); +    } +  } +#endif /* DNS_DEBUG */ + +#if LWIP_DNS_API_HOSTENT_STORAGE +  /* this function should return the "per-thread" hostent after copy from s_hostent */ +  return sys_thread_hostent(&s_hostent); +#else +  return &s_hostent; +#endif /* LWIP_DNS_API_HOSTENT_STORAGE */ +} + +/** + * Thread-safe variant of lwip_gethostbyname: instead of using a static + * buffer, this function takes buffer and errno pointers as arguments + * and uses these for the result. + * + * @param name the hostname to resolve + * @param ret pre-allocated struct where to store the result + * @param buf pre-allocated buffer where to store additional data + * @param buflen the size of buf + * @param result pointer to a hostent pointer that is set to ret on success + *               and set to zero on error + * @param h_errnop pointer to an int where to store errors (instead of modifying + *                 the global h_errno) + * @return 0 on success, non-zero on error, additional error information + *         is stored in *h_errnop instead of h_errno to be thread-safe + */ +int +lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, +                size_t buflen, struct hostent **result, int *h_errnop) +{ +  err_t err; +  struct gethostbyname_r_helper *h; +  char *hostname; +  size_t namelen; +  int lh_errno; + +  if (h_errnop == NULL) { +    /* ensure h_errnop is never NULL */ +    h_errnop = &lh_errno; +  } + +  if (result == NULL) { +    /* not all arguments given */ +    *h_errnop = EINVAL; +    return -1; +  } +  /* first thing to do: set *result to nothing */ +  *result = NULL; +  if ((name == NULL) || (ret == NULL) || (buf == 0)) { +    /* not all arguments given */ +    *h_errnop = EINVAL; +    return -1; +  } + +  namelen = strlen(name); +  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) { +    /* buf can't hold the data needed + a copy of name */ +    *h_errnop = ERANGE; +    return -1; +  } + +  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf); +  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper); + +  /* query host IP address */ +  err = netconn_gethostbyname(name, &(h->addr)); +  if (err != ERR_OK) { +    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err)); +    *h_errnop = ENSRNOTFOUND; +    return -1; +  } + +  /* copy the hostname into buf */ +  MEMCPY(hostname, name, namelen); +  hostname[namelen] = 0; + +  /* fill hostent */ +  h->addrs = &(h->addr); +  h->aliases = NULL; +  ret->h_name = (char*)hostname; +  ret->h_aliases = &(h->aliases); +  ret->h_addrtype = AF_INET; +  ret->h_length = sizeof(struct ip_addr); +  ret->h_addr_list = (char**)&(h->addrs); + +  /* set result != NULL */ +  *result = ret; + +  /* return success */ +  return 0; +} + +/** + * Frees one or more addrinfo structures returned by getaddrinfo(), along with + * any additional storage associated with those structures. If the ai_next field + * of the structure is not null, the entire list of structures is freed. + * + * @param ai struct addrinfo to free + */ +void +lwip_freeaddrinfo(struct addrinfo *ai) +{ +  struct addrinfo *next; + +  while (ai != NULL) { +    if (ai->ai_addr != NULL) { +      mem_free(ai->ai_addr); +    } +    if (ai->ai_canonname != NULL) { +      mem_free(ai->ai_canonname); +    } +    next = ai->ai_next; +    mem_free(ai); +    ai = next; +  } +} + +/** + * Translates the name of a service location (for example, a host name) and/or + * a service name and returns a set of socket addresses and associated + * information to be used in creating a socket with which to address the + * specified service. + * Memory for the result is allocated internally and must be freed by calling + * lwip_freeaddrinfo()! + * + * Due to a limitation in dns_gethostbyname, only the first address of a + * host is returned. + * Also, service names are not supported (only port numbers)! + * + * @param nodename descriptive name or address string of the host + *                 (may be NULL -> local address) + * @param servname port number as string of NULL  + * @param hints structure containing input values that set socktype and protocol + * @param res pointer to a pointer where to store the result (set to NULL on failure) + * @return 0 on success, non-zero on failure + */ +int +lwip_getaddrinfo(const char *nodename, const char *servname, +       const struct addrinfo *hints, struct addrinfo **res) +{ +  err_t err; +  struct ip_addr addr; +  struct addrinfo *ai; +  struct sockaddr_in *sa = NULL; +  int port_nr = 0; + +  if (res == NULL) { +    return EAI_FAIL; +  } +  *res = NULL; +  if ((nodename == NULL) && (servname == NULL)) { +    return EAI_NONAME; +  } + +  if (servname != NULL) { +    /* service name specified: convert to port number +     * @todo?: currently, only ASCII integers (port numbers) are supported! */ +    port_nr = atoi(servname); +    if ((port_nr <= 0) || (port_nr > 0xffff)) { +      return EAI_SERVICE; +    } +  } + +  if (nodename != NULL) { +    /* service location specified, try to resolve */ +    err = netconn_gethostbyname(nodename, &addr); +    if (err != ERR_OK) { +      return EAI_FAIL; +    } +  } else { +    /* service location specified, use loopback address */ +    addr.addr = INADDR_LOOPBACK; +  } + +  ai = mem_malloc(sizeof(struct addrinfo)); +  if (ai == NULL) { +    goto memerr; +  } +  memset(ai, 0, sizeof(struct addrinfo)); +  sa = mem_malloc(sizeof(struct sockaddr_in)); +  if (sa == NULL) { +    goto memerr; +  } +  memset(sa, 0, sizeof(struct sockaddr_in)); +  /* set up sockaddr */ +  sa->sin_addr.s_addr = addr.addr; +  sa->sin_family = AF_INET; +  sa->sin_len = sizeof(struct sockaddr_in); +  sa->sin_port = htons(port_nr); + +  /* set up addrinfo */ +  ai->ai_family = AF_INET; +  if (hints != NULL) { +    /* copy socktype & protocol from hints if specified */ +    ai->ai_socktype = hints->ai_socktype; +    ai->ai_protocol = hints->ai_protocol; +  } +  if (nodename != NULL) { +    /* copy nodename to canonname if specified */ +    size_t namelen = strlen(nodename); +    LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); +    ai->ai_canonname = mem_malloc((mem_size_t)(namelen + 1)); +    if (ai->ai_canonname == NULL) { +      goto memerr; +    } +    MEMCPY(ai->ai_canonname, nodename, namelen); +    ai->ai_canonname[namelen] = 0; +  } +  ai->ai_addrlen = sizeof(struct sockaddr_in); +  ai->ai_addr = (struct sockaddr*)sa; + +  *res = ai; + +  return 0; +memerr: +  if (ai != NULL) { +    mem_free(ai); +  } +  if (sa != NULL) { +    mem_free(sa); +  } +  return EAI_MEMORY; +} + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/netifapi.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netifapi.c new file mode 100644 index 000000000..491837378 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/netifapi.c @@ -0,0 +1,126 @@ +/** + * @file + * Network Interface Sequential API module + * + */ + +/* + * 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. + *  + */ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netifapi.h" +#include "lwip/tcpip.h" + +/** + * Call netif_add() inside the tcpip_thread context. + */ +void +do_netifapi_netif_add( struct netifapi_msg_msg *msg) +{ +  if (!netif_add( msg->netif, +                  msg->msg.add.ipaddr, +                  msg->msg.add.netmask, +                  msg->msg.add.gw, +                  msg->msg.add.state, +                  msg->msg.add.init, +                  msg->msg.add.input)) { +    msg->err = ERR_IF; +  } else { +    msg->err = ERR_OK; +  } +  TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the + * tcpip_thread context. + */ +void +do_netifapi_netif_common( struct netifapi_msg_msg *msg) +{ +  if (msg->msg.common.errtfunc!=NULL) { +    msg->err = +    msg->msg.common.errtfunc(msg->netif); +  } else { +    msg->err = ERR_OK; +    msg->msg.common.voidfunc(msg->netif); +  } +  TCPIP_NETIFAPI_ACK(msg); +} + +/** + * Call netif_add() in a thread-safe way by running that function inside the + * tcpip_thread context. + * + * @note for params @see netif_add() + */ +err_t +netifapi_netif_add(struct netif *netif, +                   struct ip_addr *ipaddr, +                   struct ip_addr *netmask, +                   struct ip_addr *gw, +                   void *state, +                   err_t (* init)(struct netif *netif), +                   err_t (* input)(struct pbuf *p, struct netif *netif)) +{ +  struct netifapi_msg msg; +  msg.function = do_netifapi_netif_add; +  msg.msg.netif = netif; +  msg.msg.msg.add.ipaddr  = ipaddr; +  msg.msg.msg.add.netmask = netmask; +  msg.msg.msg.add.gw      = gw; +  msg.msg.msg.add.state   = state; +  msg.msg.msg.add.init    = init; +  msg.msg.msg.add.input   = input; +  TCPIP_NETIFAPI(&msg); +  return msg.msg.err; +} + +/** + * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe + * way by running that function inside the tcpip_thread context. + * + * @note use only for functions where there is only "netif" parameter. + */ +err_t +netifapi_netif_common( struct netif *netif, +                       void  (* voidfunc)(struct netif *netif), +                       err_t (* errtfunc)(struct netif *netif) ) +{ +  struct netifapi_msg msg; +  msg.function = do_netifapi_netif_common; +  msg.msg.netif = netif; +  msg.msg.msg.common.voidfunc = voidfunc; +  msg.msg.msg.common.errtfunc = errtfunc; +  TCPIP_NETIFAPI(&msg); +  return msg.msg.err; +} + +#endif /* LWIP_NETIF_API */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/sockets.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/sockets.c new file mode 100644 index 000000000..f177261e1 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/sockets.c @@ -0,0 +1,1970 @@ +/** + * @file + * Sockets BSD-Like API 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> + * + * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu> + * + */ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sockets.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/inet.h" +#include "lwip/tcp.h" +#include "lwip/raw.h" +#include "lwip/udp.h" +#include "lwip/tcpip.h" + +#include <string.h> + +#define NUM_SOCKETS MEMP_NUM_NETCONN + +/** Contains all internal pointers and states used for a socket */ +struct lwip_socket { +  /** sockets currently are built on netconns, each socket has one netconn */ +  struct netconn *conn; +  /** data that was left from the previous read */ +  struct netbuf *lastdata; +  /** offset in the data that was left from the previous read */ +  u16_t lastoffset; +  /** number of times data was received, set by event_callback(), +      tested by the receive and select functions */ +  s16_t rcvevent; +  /** number of times data was received, set by event_callback(), +      tested by select */ +  u16_t sendevent; +  /** socket flags (currently, only used for O_NONBLOCK) */ +  u16_t flags; +  /** last error that occurred on this socket */ +  int err; +}; + +/** Description for a task waiting in select */ +struct lwip_select_cb { +  /** Pointer to the next waiting task */ +  struct lwip_select_cb *next; +  /** readset passed to select */ +  fd_set *readset; +  /** writeset passed to select */ +  fd_set *writeset; +  /** unimplemented: exceptset passed to select */ +  fd_set *exceptset; +  /** don't signal the same semaphore twice: set to 1 when signalled */ +  int sem_signalled; +  /** semaphore to wake up a task waiting for select */ +  sys_sem_t sem; +}; + +/** This struct is used to pass data to the set/getsockopt_internal + * functions running in tcpip_thread context (only a void* is allowed) */ +struct lwip_setgetsockopt_data { +  /** socket struct for which to change options */ +  struct lwip_socket *sock; +  /** socket index for which to change options */ +  int s; +  /** level of the option to process */ +  int level; +  /** name of the option to process */ +  int optname; +  /** set: value to set the option to +    * get: value of the option is stored here */ +  void *optval; +  /** size of *optval */ +  socklen_t *optlen; +  /** if an error occures, it is temporarily stored here */ +  err_t err; +}; + +/** The global array of available sockets */ +static struct lwip_socket sockets[NUM_SOCKETS]; +/** The global list of tasks waiting for select */ +static struct lwip_select_cb *select_cb_list; + +/** Semaphore protecting the sockets array */ +static sys_sem_t socksem; +/** Semaphore protecting select_cb_list */ +static sys_sem_t selectsem; + +/** Table to quickly map an lwIP error (err_t) to a socket error +  * by using -err as an index */ +static const int err_to_errno_table[] = { +  0,             /* ERR_OK          0      No error, everything OK. */ +  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */ +  ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */ +  ETIMEDOUT,     /* ERR_TIMEOUT    -3      Timeout                  */ +  EHOSTUNREACH,  /* ERR_RTE        -4      Routing problem.         */ +  ECONNABORTED,  /* ERR_ABRT       -5      Connection aborted.      */ +  ECONNRESET,    /* ERR_RST        -6      Connection reset.        */ +  ESHUTDOWN,     /* ERR_CLSD       -7      Connection closed.       */ +  ENOTCONN,      /* ERR_CONN       -8      Not connected.           */ +  EINVAL,        /* ERR_VAL        -9      Illegal value.           */ +  EIO,           /* ERR_ARG        -10     Illegal argument.        */ +  EADDRINUSE,    /* ERR_USE        -11     Address in use.          */ +  -1,            /* ERR_IF         -12     Low-level netif error    */ +  -1,            /* ERR_ISCONN     -13     Already connected.       */ +  EINPROGRESS    /* ERR_INPROGRESS -14     Operation in progress    */ +}; + +#define ERR_TO_ERRNO_TABLE_SIZE \ +  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0])) + +#define err_to_errno(err) \ +  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \ +    err_to_errno_table[-(err)] : EIO) + +#ifdef ERRNO +#ifndef set_errno +#define set_errno(err) errno = (err) +#endif +#else +#define set_errno(err) +#endif + +#define sock_set_errno(sk, e) do { \ +  sk->err = (e); \ +  set_errno(sk->err); \ +} while (0) + +/* Forward delcaration of some functions */ +static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len); +static void lwip_getsockopt_internal(void *arg); +static void lwip_setsockopt_internal(void *arg); + +/** + * Initialize this module. This function has to be called before any other + * functions in this module! + */ +void +lwip_socket_init(void) +{ +  socksem   = sys_sem_new(1); +  selectsem = sys_sem_new(1); +} + +/** + * Map a externally used socket index to the internal socket representation. + * + * @param s externally used socket index + * @return struct lwip_socket for the socket or NULL if not found + */ +static struct lwip_socket * +get_socket(int s) +{ +  struct lwip_socket *sock; + +  if ((s < 0) || (s >= NUM_SOCKETS)) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); +    set_errno(EBADF); +    return NULL; +  } + +  sock = &sockets[s]; + +  if (!sock->conn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s)); +    set_errno(EBADF); +    return NULL; +  } + +  return sock; +} + +/** + * Allocate a new socket for a given netconn. + * + * @param newconn the netconn for which to allocate a socket + * @return the index of the new socket; -1 on error + */ +static int +alloc_socket(struct netconn *newconn) +{ +  int i; + +  /* Protect socket array */ +  sys_sem_wait(socksem); + +  /* allocate a new socket identifier */ +  for (i = 0; i < NUM_SOCKETS; ++i) { +    if (!sockets[i].conn) { +      sockets[i].conn       = newconn; +      sockets[i].lastdata   = NULL; +      sockets[i].lastoffset = 0; +      sockets[i].rcvevent   = 0; +      sockets[i].sendevent  = 1; /* TCP send buf is empty */ +      sockets[i].flags      = 0; +      sockets[i].err        = 0; +      sys_sem_signal(socksem); +      return i; +    } +  } +  sys_sem_signal(socksem); +  return -1; +} + +/* Below this, the well-known socket functions are implemented. + * Use google.com or opengroup.org to get a good description :-) + * + * Exceptions are documented! + */ + +int +lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) +{ +  struct lwip_socket *sock, *nsock; +  struct netconn *newconn; +  struct ip_addr naddr; +  u16_t port; +  int newsock; +  struct sockaddr_in sin; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); +    sock_set_errno(sock, EWOULDBLOCK); +    return -1; +  } + +  newconn = netconn_accept(sock->conn); +  if (!newconn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err)); +    sock_set_errno(sock, err_to_errno(sock->conn->err)); +    return -1; +  } + +  /* get the IP address and port of the remote host */ +  err = netconn_peer(newconn, &naddr, &port); +  if (err != ERR_OK) { +    netconn_delete(newconn); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  /* Note that POSIX only requires us to check addr is non-NULL. addrlen must +   * not be NULL if addr is valid. +   */ +  if (NULL != addr) { +    LWIP_ASSERT("addr valid but addrlen NULL", addrlen != NULL); +    memset(&sin, 0, sizeof(sin)); +    sin.sin_len = sizeof(sin); +    sin.sin_family = AF_INET; +    sin.sin_port = htons(port); +    sin.sin_addr.s_addr = naddr.addr; + +    if (*addrlen > sizeof(sin)) +      *addrlen = sizeof(sin); + +    MEMCPY(addr, &sin, *addrlen); +  } + +  newsock = alloc_socket(newconn); +  if (newsock == -1) { +    netconn_delete(newconn); +    sock_set_errno(sock, ENFILE); +    return -1; +  } +  LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); +  newconn->callback = event_callback; +  nsock = &sockets[newsock]; +  LWIP_ASSERT("invalid socket pointer", nsock != NULL); + +  sys_sem_wait(socksem); +  /* See event_callback: If data comes in right away after an accept, even +   * though the server task might not have created a new socket yet. +   * In that case, newconn->socket is counted down (newconn->socket--), +   * so nsock->rcvevent is >= 1 here! +   */ +  nsock->rcvevent += -1 - newconn->socket; +  newconn->socket = newsock; +  sys_sem_signal(socksem); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); +  ip_addr_debug_print(SOCKETS_DEBUG, &naddr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", port)); + +  sock_set_errno(sock, 0); +  return newsock; +} + +int +lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) +{ +  struct lwip_socket *sock; +  struct ip_addr local_addr; +  u16_t local_port; +  err_t err; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +  local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; +  local_port = ((const struct sockaddr_in *)name)->sin_port; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); +  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(local_port))); + +  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port)); + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s)); +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_close(int s) +{ +  struct lwip_socket *sock; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); + +  sock = get_socket(s); +  if (!sock) { +    return -1; +  } + +  netconn_delete(sock->conn); + +  sys_sem_wait(socksem); +  if (sock->lastdata) { +    netbuf_delete(sock->lastdata); +  } +  sock->lastdata   = NULL; +  sock->lastoffset = 0; +  sock->conn       = NULL; +  sock_set_errno(sock, 0); +  sys_sem_signal(socksem); +  return 0; +} + +int +lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) +{ +  struct lwip_socket *sock; +  err_t err; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +  if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); +    err = netconn_disconnect(sock->conn); +  } else { +    struct ip_addr remote_addr; +    u16_t remote_port; + +    remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; +    remote_port = ((const struct sockaddr_in *)name)->sin_port; + +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); +    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); +    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", ntohs(remote_port))); + +    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port)); +  } + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s)); +  sock_set_errno(sock, 0); +  return 0; +} + +/** + * Set a socket into listen mode. + * The socket may not have been used for another connection previously. + * + * @param s the socket to set to listening mode + * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1) + * @return 0 on success, non-zero on failure + */ +int +lwip_listen(int s, int backlog) +{ +  struct lwip_socket *sock; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  /* limit the "backlog" parameter to fit in an u8_t */ +  if (backlog < 0) { +    backlog = 0; +  } +  if (backlog > 0xff) { +    backlog = 0xff; +  } + +  err = netconn_listen_with_backlog(sock->conn, backlog); + +  if (err != ERR_OK) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); +    sock_set_errno(sock, err_to_errno(err)); +    return -1; +  } + +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_recvfrom(int s, void *mem, size_t len, int flags, +        struct sockaddr *from, socklen_t *fromlen) +{ +  struct lwip_socket *sock; +  struct netbuf      *buf; +  u16_t               buflen, copylen, off = 0; +  struct ip_addr     *addr; +  u16_t               port; +  u8_t                done = 0; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); +  sock = get_socket(s); +  if (!sock) +    return -1; + +  do { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata)); +    /* Check if there is data left from the last recv operation. */ +    if (sock->lastdata) { +      buf = sock->lastdata; +    } else { +      /* If this is non-blocking call, then check first */ +      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) &&  +          (sock->rcvevent <= 0)) { +        if (off > 0) { +          /* already received data, return that */ +          sock_set_errno(sock, 0); +          return off; +        } +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s)); +        sock_set_errno(sock, EWOULDBLOCK); +        return -1; +      } + +      /* No data was left from the previous operation, so we try to get +      some from the network. */ +      sock->lastdata = buf = netconn_recv(sock->conn); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); + +      if (!buf) { +        if (off > 0) { +          /* already received data, return that */ +          sock_set_errno(sock, 0); +          return off; +        } +        /* We should really do some error checking here. */ +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); +        sock_set_errno(sock, (((sock->conn->pcb.ip != NULL) && (sock->conn->err == ERR_OK)) +          ? ETIMEDOUT : err_to_errno(sock->conn->err))); +        return 0; +      } +    } + +    buflen = netbuf_len(buf); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%"U16_F" sock->lastoffset=%"U16_F"\n", +      buflen, len, off, sock->lastoffset)); + +    buflen -= sock->lastoffset; + +    if (len > buflen) { +      copylen = buflen; +    } else { +      copylen = (u16_t)len; +    } + +    /* copy the contents of the received buffer into +    the supplied memory pointer mem */ +    netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset); + +    off += copylen; + +    if (netconn_type(sock->conn) == NETCONN_TCP) { +      LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); +      len -= copylen; +      if ( (len <= 0) ||  +           (buf->p->flags & PBUF_FLAG_PUSH) ||  +           (sock->rcvevent <= 0) ||  +           ((flags & MSG_PEEK)!=0)) { +        done = 1; +      } +    } else { +      done = 1; +    } + +    /* Check to see from where the data was.*/ +    if (done) { +      if (from && fromlen) { +        struct sockaddr_in sin; + +        if (netconn_type(sock->conn) == NETCONN_TCP) { +          addr = (struct ip_addr*)&(sin.sin_addr.s_addr); +          netconn_getaddr(sock->conn, addr, &port, 0); +        } else { +          addr = netbuf_fromaddr(buf); +          port = netbuf_fromport(buf); +        } + +        memset(&sin, 0, sizeof(sin)); +        sin.sin_len = sizeof(sin); +        sin.sin_family = AF_INET; +        sin.sin_port = htons(port); +        sin.sin_addr.s_addr = addr->addr; + +        if (*fromlen > sizeof(sin)) { +          *fromlen = sizeof(sin); +        } + +        MEMCPY(from, &sin, *fromlen); + +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); +        ip_addr_debug_print(SOCKETS_DEBUG, addr); +        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); +      } else { +  #if SOCKETS_DEBUG +        struct sockaddr_in sin; + +        if (netconn_type(sock->conn) == NETCONN_TCP) { +          addr = (struct ip_addr*)&(sin.sin_addr.s_addr); +          netconn_getaddr(sock->conn, addr, &port, 0); +        } else { +          addr = netbuf_fromaddr(buf); +          port = netbuf_fromport(buf); +        } + +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); +        ip_addr_debug_print(SOCKETS_DEBUG, addr); +        LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); +  #endif /*  SOCKETS_DEBUG */ +      } +    } + +    /* If we don't peek the incoming message... */ +    if ((flags & MSG_PEEK)==0) { +      /* If this is a TCP socket, check if there is data left in the +         buffer. If so, it should be saved in the sock structure for next +         time around. */ +      if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { +        sock->lastdata = buf; +        sock->lastoffset += copylen; +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); +      } else { +        sock->lastdata = NULL; +        sock->lastoffset = 0; +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); +        netbuf_delete(buf); +      } +    } +  } while (!done); + +  sock_set_errno(sock, 0); +  return off; +} + +int +lwip_read(int s, void *mem, size_t len) +{ +  return lwip_recvfrom(s, mem, len, 0, NULL, NULL); +} + +int +lwip_recv(int s, void *mem, size_t len, int flags) +{ +  return lwip_recvfrom(s, mem, len, flags, NULL, NULL); +} + +int +lwip_send(int s, const void *data, size_t size, int flags) +{ +  struct lwip_socket *sock; +  err_t err; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", +                              s, data, size, flags)); + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if (sock->conn->type != NETCONN_TCP) { +#if (LWIP_UDP || LWIP_RAW) +    return lwip_sendto(s, data, size, flags, NULL, 0); +#else +    sock_set_errno(sock, err_to_errno(ERR_ARG)); +    return -1; +#endif /* (LWIP_UDP || LWIP_RAW) */ +  } + +  err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0)); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); +  sock_set_errno(sock, err_to_errno(err)); +  return (err == ERR_OK ? (int)size : -1); +} + +int +lwip_sendto(int s, const void *data, size_t size, int flags, +       const struct sockaddr *to, socklen_t tolen) +{ +  struct lwip_socket *sock; +  struct ip_addr remote_addr; +  err_t err; +  u16_t short_size; +#if !LWIP_TCPIP_CORE_LOCKING +  struct netbuf buf; +  u16_t remote_port; +#endif + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  if (sock->conn->type == NETCONN_TCP) { +#if LWIP_TCP +    return lwip_send(s, data, size, flags); +#else +    sock_set_errno(sock, err_to_errno(ERR_ARG)); +    return -1; +#endif /* LWIP_TCP */ +  } + +  LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); +  short_size = (u16_t)size; +  LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || +             ((tolen == sizeof(struct sockaddr_in)) && +             ((((const struct sockaddr_in *)to)->sin_family) == AF_INET))), +             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + +#if LWIP_TCPIP_CORE_LOCKING +  /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ +  { struct pbuf* p; +   +    p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); +    if (p == NULL) { +      err = ERR_MEM; +    } else { +      p->payload = (void*)data; +      p->len = p->tot_len = short_size; +       +      remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; +       +      LOCK_TCPIP_CORE(); +      if (sock->conn->type==NETCONN_RAW) { +        err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr); +      } else { +        err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port)); +      } +      UNLOCK_TCPIP_CORE(); +       +      pbuf_free(p); +    } +  } +#else +  /* initialize a buffer */ +  buf.p = buf.ptr = NULL; +  if (to) { +    remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; +    remote_port      = ntohs(((const struct sockaddr_in *)to)->sin_port); +    buf.addr         = &remote_addr; +    buf.port         = remote_port; +  } else { +    remote_addr.addr = 0; +    remote_port      = 0; +    buf.addr         = NULL; +    buf.port         = 0; +  } + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", +              s, data, short_size, flags)); +  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); + +  /* make the buffer point to the data that should be sent */ +#if LWIP_NETIF_TX_SINGLE_PBUF +  /* Allocate a new netbuf and copy the data into it. */ +  if (netbuf_alloc(&buf, short_size) == NULL) { +    err = ERR_MEM; +  } else { +    err = netbuf_take(&buf, data, short_size); +  } +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ +  err = netbuf_ref(&buf, data, short_size); +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ +  if (err == ERR_OK) { +    /* send the data */ +    err = netconn_send(sock->conn, &buf); +  } + +  /* deallocated the buffer */ +  netbuf_free(&buf); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +  sock_set_errno(sock, err_to_errno(err)); +  return (err == ERR_OK ? short_size : -1); +} + +int +lwip_socket(int domain, int type, int protocol) +{ +  struct netconn *conn; +  int i; + +  LWIP_UNUSED_ARG(domain); + +  /* create a netconn */ +  switch (type) { +  case SOCK_RAW: +    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  case SOCK_DGRAM: +    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ? +                 NETCONN_UDPLITE : NETCONN_UDP, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  case SOCK_STREAM: +    conn = netconn_new_with_callback(NETCONN_TCP, event_callback); +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", +                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); +    break; +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", +                                 domain, type, protocol)); +    set_errno(EINVAL); +    return -1; +  } + +  if (!conn) { +    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n")); +    set_errno(ENOBUFS); +    return -1; +  } + +  i = alloc_socket(conn); + +  if (i == -1) { +    netconn_delete(conn); +    set_errno(ENFILE); +    return -1; +  } +  conn->socket = i; +  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i)); +  set_errno(0); +  return i; +} + +int +lwip_write(int s, const void *data, size_t size) +{ +  return lwip_send(s, data, size, 0); +} + +/** + * Go through the readset and writeset lists and see which socket of the sockets + * set in the sets has events. On return, readset, writeset and exceptset have + * the sockets enabled that had events. + * + * exceptset is not used for now!!! + * + * @param maxfdp1 the highest socket index in the sets + * @param readset in: set of sockets to check for read events; + *                out: set of sockets that had read events + * @param writeset in: set of sockets to check for write events; + *                 out: set of sockets that had write events + * @param exceptset not yet implemented + * @return number of sockets that had events (read+write) + */ +static int +lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) +{ +  int i, nready = 0; +  fd_set lreadset, lwriteset, lexceptset; +  struct lwip_socket *p_sock; +   +  FD_ZERO(&lreadset); +  FD_ZERO(&lwriteset); +  FD_ZERO(&lexceptset); +   +  /* Go through each socket in each list to count number of sockets which +  currently match */ +  for(i = 0; i < maxfdp1; i++) { +    if (FD_ISSET(i, readset)) { +      /* See if netconn of this socket is ready for read */ +      p_sock = get_socket(i); +      if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) { +        FD_SET(i, &lreadset); +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); +        nready++; +      } +    } +    if (FD_ISSET(i, writeset)) { +      /* See if netconn of this socket is ready for write */ +      p_sock = get_socket(i); +      if (p_sock && p_sock->sendevent) { +        FD_SET(i, &lwriteset); +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); +        nready++; +      } +    } +  } +  *readset = lreadset; +  *writeset = lwriteset; +  FD_ZERO(exceptset); +   +  return nready; +} + + +/** + * Processing exceptset is not yet implemented. + */ +int +lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, +               struct timeval *timeout) +{ +  int i; +  int nready; +  fd_set lreadset, lwriteset, lexceptset; +  u32_t msectimeout; +  struct lwip_select_cb select_cb; +  struct lwip_select_cb *p_selcb; + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", +                  maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, +                  timeout ? (long)timeout->tv_sec : (long)-1, +                  timeout ? (long)timeout->tv_usec : (long)-1)); + +  select_cb.next = 0; +  select_cb.readset = readset; +  select_cb.writeset = writeset; +  select_cb.exceptset = exceptset; +  select_cb.sem_signalled = 0; + +  /* Protect ourselves searching through the list */ +  sys_sem_wait(selectsem); + +  if (readset) +    lreadset = *readset; +  else +    FD_ZERO(&lreadset); +  if (writeset) +    lwriteset = *writeset; +  else +    FD_ZERO(&lwriteset); +  if (exceptset) +    lexceptset = *exceptset; +  else +    FD_ZERO(&lexceptset); + +  /* Go through each socket in each list to count number of sockets which +     currently match */ +  nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); + +  /* If we don't have any current events, then suspend if we are supposed to */ +  if (!nready) { +    if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { +      sys_sem_signal(selectsem); +      if (readset) +        FD_ZERO(readset); +      if (writeset) +        FD_ZERO(writeset); +      if (exceptset) +        FD_ZERO(exceptset); +   +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); +      set_errno(0); +   +      return 0; +    } +     +    /* add our semaphore to list */ +    /* We don't actually need any dynamic memory. Our entry on the +     * list is only valid while we are in this function, so it's ok +     * to use local variables */ +     +    select_cb.sem = sys_sem_new(0); +    /* Note that we are still protected */ +    /* Put this select_cb on top of list */ +    select_cb.next = select_cb_list; +    select_cb_list = &select_cb; +     +    /* Now we can safely unprotect */ +    sys_sem_signal(selectsem); +     +    /* Now just wait to be woken */ +    if (timeout == 0) +      /* Wait forever */ +      msectimeout = 0; +    else { +      msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); +      if(msectimeout == 0) +        msectimeout = 1; +    } +     +    i = sys_sem_wait_timeout(select_cb.sem, msectimeout); +     +    /* Take us off the list */ +    sys_sem_wait(selectsem); +    if (select_cb_list == &select_cb) +      select_cb_list = select_cb.next; +    else +      for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) { +        if (p_selcb->next == &select_cb) { +          p_selcb->next = select_cb.next; +          break; +        } +      } +     +    sys_sem_signal(selectsem); +     +    sys_sem_free(select_cb.sem); +    if (i == 0)  { +      /* Timeout */ +      if (readset) +        FD_ZERO(readset); +      if (writeset) +        FD_ZERO(writeset); +      if (exceptset) +        FD_ZERO(exceptset); +   +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); +      set_errno(0); +   +      return 0; +    } +     +    if (readset) +      lreadset = *readset; +    else +      FD_ZERO(&lreadset); +    if (writeset) +      lwriteset = *writeset; +    else +      FD_ZERO(&lwriteset); +    if (exceptset) +      lexceptset = *exceptset; +    else +      FD_ZERO(&lexceptset); +     +    /* See what's set */ +    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); +  } else +    sys_sem_signal(selectsem); +   +  if (readset) +    *readset = lreadset; +  if (writeset) +    *writeset = lwriteset; +  if (exceptset) +    *exceptset = lexceptset; +   +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); +  set_errno(0); +   +  return nready; +} + +/** + * Callback registered in the netconn layer for each socket-netconn. + * Processes recvevent (data available) and wakes up tasks waiting for select. + */ +static void +event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) +{ +  int s; +  struct lwip_socket *sock; +  struct lwip_select_cb *scb; + +  LWIP_UNUSED_ARG(len); + +  /* Get socket */ +  if (conn) { +    s = conn->socket; +    if (s < 0) { +      /* Data comes in right away after an accept, even though +       * the server task might not have created a new socket yet. +       * Just count down (or up) if that's the case and we +       * will use the data later. Note that only receive events +       * can happen before the new socket is set up. */ +      sys_sem_wait(socksem); +      if (conn->socket < 0) { +        if (evt == NETCONN_EVT_RCVPLUS) { +          conn->socket--; +        } +        sys_sem_signal(socksem); +        return; +      } +      sys_sem_signal(socksem); +    } + +    sock = get_socket(s); +    if (!sock) { +      return; +    } +  } else { +    return; +  } + +  sys_sem_wait(selectsem); +  /* Set event as required */ +  switch (evt) { +    case NETCONN_EVT_RCVPLUS: +      sock->rcvevent++; +      break; +    case NETCONN_EVT_RCVMINUS: +      sock->rcvevent--; +      break; +    case NETCONN_EVT_SENDPLUS: +      sock->sendevent = 1; +      break; +    case NETCONN_EVT_SENDMINUS: +      sock->sendevent = 0; +      break; +    default: +      LWIP_ASSERT("unknown event", 0); +      break; +  } +  sys_sem_signal(selectsem); + +  /* Now decide if anyone is waiting for this socket */ +  /* NOTE: This code is written this way to protect the select link list +     but to avoid a deadlock situation by releasing socksem before +     signalling for the select. This means we need to go through the list +     multiple times ONLY IF a select was actually waiting. We go through +     the list the number of waiting select calls + 1. This list is +     expected to be small. */ +  while (1) { +    sys_sem_wait(selectsem); +    for (scb = select_cb_list; scb; scb = scb->next) { +      if (scb->sem_signalled == 0) { +        /* Test this select call for our socket */ +        if (scb->readset && FD_ISSET(s, scb->readset)) +          if (sock->rcvevent > 0) +            break; +        if (scb->writeset && FD_ISSET(s, scb->writeset)) +          if (sock->sendevent) +            break; +      } +    } +    if (scb) { +      scb->sem_signalled = 1; +      sys_sem_signal(scb->sem); +      sys_sem_signal(selectsem); +    } else { +      sys_sem_signal(selectsem); +      break; +    } +  } +} + +/** + * Unimplemented: Close one end of a full-duplex connection. + * Currently, the full connection is closed. + */ +int +lwip_shutdown(int s, int how) +{ +  LWIP_UNUSED_ARG(how); +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); +  return lwip_close(s); /* XXX temporary hack until proper implementation */ +} + +static int +lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) +{ +  struct lwip_socket *sock; +  struct sockaddr_in sin; +  struct ip_addr naddr; + +  sock = get_socket(s); +  if (!sock) +    return -1; + +  memset(&sin, 0, sizeof(sin)); +  sin.sin_len = sizeof(sin); +  sin.sin_family = AF_INET; + +  /* get the IP address and port */ +  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local); + +  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s)); +  ip_addr_debug_print(SOCKETS_DEBUG, &naddr); +  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); + +  sin.sin_port = htons(sin.sin_port); +  sin.sin_addr.s_addr = naddr.addr; + +  if (*namelen > sizeof(sin)) +    *namelen = sizeof(sin); + +  MEMCPY(name, &sin, *namelen); +  sock_set_errno(sock, 0); +  return 0; +} + +int +lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen) +{ +  return lwip_getaddrname(s, name, namelen, 0); +} + +int +lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen) +{ +  return lwip_getaddrname(s, name, namelen, 1); +} + +int +lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) +{ +  err_t err = ERR_OK; +  struct lwip_socket *sock = get_socket(s); +  struct lwip_setgetsockopt_data data; + +  if (!sock) +    return -1; + +  if ((NULL == optval) || (NULL == optlen)) { +    sock_set_errno(sock, EFAULT); +    return -1; +  } + +  /* Do length and type checks for the various options first, to keep it readable. */ +  switch (level) { +    +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { +        +    case SO_ACCEPTCONN: +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_ERROR: +    case SO_KEEPALIVE: +    /* UNIMPL case SO_CONTIMEO: */ +    /* UNIMPL case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ +    /* UNIMPL case SO_OOBINLINE: */ +    /* UNIMPL case SO_SNDBUF: */ +    /* UNIMPL case SO_RCVLOWAT: */ +    /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    case SO_TYPE: +    /* UNIMPL case SO_USELOOPBACK: */ +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; + +    case SO_NO_CHECK: +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +#if LWIP_UDP +      if ((sock->conn->type != NETCONN_UDP) || +          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { +        /* this flag is only available for UDP, not for UDP lite */ +        err = EAFNOSUPPORT; +      } +#endif /* LWIP_UDP */ +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +                      +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    /* UNIMPL case IP_HDRINCL: */ +    /* UNIMPL case IP_RCVDSTADDR: */ +    /* UNIMPL case IP_RCVIF: */ +    case IP_TTL: +    case IP_TOS: +      if (*optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      if (*optlen < sizeof(u8_t)) { +        err = EINVAL; +      } +      break; +    case IP_MULTICAST_IF: +      if (*optlen < sizeof(struct in_addr)) { +        err = EINVAL; +      } +      break; +#endif /* LWIP_IGMP */ + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +          +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    if (*optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } +     +    /* If this is no TCP socket, ignore any options. */ +    if (sock->conn->type != NETCONN_TCP) +      return 0; + +    switch (optname) { +    case TCP_NODELAY: +    case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +    case TCP_KEEPINTVL: +    case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ +      break; +        +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    if (*optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } +     +    /* If this is no UDP lite socket, ignore any options. */ +    if (sock->conn->type != NETCONN_UDPLITE) +      return 0; + +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +    case UDPLITE_RECV_CSCOV: +      break; +        +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", +                                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP && LWIP_UDPLITE*/ +/* UNDEFINED LEVEL */ +  default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", +                                  s, level, optname)); +      err = ENOPROTOOPT; +  }  /* switch */ + +    +  if (err != ERR_OK) { +    sock_set_errno(sock, err); +    return -1; +  } + +  /* Now do the actual option processing */ +  data.sock = sock; +  data.level = level; +  data.optname = optname; +  data.optval = optval; +  data.optlen = optlen; +  data.err = err; +  tcpip_callback(lwip_getsockopt_internal, &data); +  sys_arch_sem_wait(sock->conn->op_completed, 0); +  /* maybe lwip_getsockopt_internal has changed err */ +  err = data.err; + +  sock_set_errno(sock, err); +  return err ? -1 : 0; +} + +static void +lwip_getsockopt_internal(void *arg) +{ +  struct lwip_socket *sock; +#ifdef LWIP_DEBUG +  int s; +#endif /* LWIP_DEBUG */ +  int level, optname; +  void *optval; +  struct lwip_setgetsockopt_data *data; + +  LWIP_ASSERT("arg != NULL", arg != NULL); + +  data = (struct lwip_setgetsockopt_data*)arg; +  sock = data->sock; +#ifdef LWIP_DEBUG +  s = data->s; +#endif /* LWIP_DEBUG */ +  level = data->level; +  optname = data->optname; +  optval = data->optval; + +  switch (level) { +    +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    /* The option flags */ +    case SO_ACCEPTCONN: +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /*case SO_USELOOPBACK: UNIMPL */ +      *(int*)optval = sock->conn->pcb.ip->so_options & optname; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n", +                                  s, optname, (*(int*)optval?"on":"off"))); +      break; + +    case SO_TYPE: +      switch (NETCONNTYPE_GROUP(sock->conn->type)) { +      case NETCONN_RAW: +        *(int*)optval = SOCK_RAW; +        break; +      case NETCONN_TCP: +        *(int*)optval = SOCK_STREAM; +        break; +      case NETCONN_UDP: +        *(int*)optval = SOCK_DGRAM; +        break; +      default: /* unrecognized socket type */ +        *(int*)optval = sock->conn->type; +        LWIP_DEBUGF(SOCKETS_DEBUG, +                    ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n", +                    s, *(int *)optval)); +      }  /* switch (sock->conn->type) */ +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n", +                  s, *(int *)optval)); +      break; + +    case SO_ERROR: +      if (sock->err == 0) { +        sock_set_errno(sock, err_to_errno(sock->conn->err)); +      }  +      *(int *)optval = sock->err; +      sock->err = 0; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n", +                  s, *(int *)optval)); +      break; + +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +      *(int *)optval = sock->conn->recv_timeout; +      break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +      *(int *)optval = sock->conn->recv_bufsize; +      break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP +    case SO_NO_CHECK: +      *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; +      break; +#endif /* LWIP_UDP*/ +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    case IP_TTL: +      *(int*)optval = sock->conn->pcb.ip->ttl; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n", +                  s, *(int *)optval)); +      break; +    case IP_TOS: +      *(int*)optval = sock->conn->pcb.ip->tos; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n", +                  s, *(int *)optval)); +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      *(u8_t*)optval = sock->conn->pcb.ip->ttl; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n", +                  s, *(int *)optval)); +      break; +    case IP_MULTICAST_IF: +      ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", +                  s, *(u32_t *)optval)); +      break; +#endif /* LWIP_IGMP */ +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    switch (optname) { +    case TCP_NODELAY: +      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n", +                  s, (*(int*)optval)?"on":"off") ); +      break; +    case TCP_KEEPALIVE: +      *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n", +                  s, *(int *)optval)); +      break; + +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n", +                  s, *(int *)optval)); +      break; +    case TCP_KEEPINTVL: +      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n", +                  s, *(int *)optval)); +      break; +    case TCP_KEEPCNT: +      *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n", +                  s, *(int *)optval)); +      break; +#endif /* LWIP_TCP_KEEPALIVE */ + +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +  /* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +      *(int*)optval = sock->conn->pcb.udp->chksum_len_tx; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n", +                  s, (*(int*)optval)) ); +      break; +    case UDPLITE_RECV_CSCOV: +      *(int*)optval = sock->conn->pcb.udp->chksum_len_rx; +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", +                  s, (*(int*)optval)) ); +      break; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP */ +  } /* switch (level) */ +  sys_sem_signal(sock->conn->op_completed); +} + +int +lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) +{ +  struct lwip_socket *sock = get_socket(s); +  int err = ERR_OK; +  struct lwip_setgetsockopt_data data; + +  if (!sock) +    return -1; + +  if (NULL == optval) { +    sock_set_errno(sock, EFAULT); +    return -1; +  } + +  /* Do length and type checks for the various options first, to keep it readable. */ +  switch (level) { + +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case case SO_CONTIMEO: */ +    /* UNIMPL case case SO_SNDTIMEO: */ +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +#endif /* LWIP_SO_RCVBUF */ +    /* UNIMPL case SO_OOBINLINE: */ +    /* UNIMPL case SO_SNDBUF: */ +    /* UNIMPL case SO_RCVLOWAT: */ +    /* UNIMPL case SO_SNDLOWAT: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /* UNIMPL case SO_USELOOPBACK: */ +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +    case SO_NO_CHECK: +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +#if LWIP_UDP +      if ((sock->conn->type != NETCONN_UDP) || +          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) { +        /* this flag is only available for UDP, not for UDP lite */ +        err = EAFNOSUPPORT; +      } +#endif /* LWIP_UDP */ +      break; +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    /* UNIMPL case IP_HDRINCL: */ +    /* UNIMPL case IP_RCVDSTADDR: */ +    /* UNIMPL case IP_RCVIF: */ +    case IP_TTL: +    case IP_TOS: +      if (optlen < sizeof(int)) { +        err = EINVAL; +      } +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      if (optlen < sizeof(u8_t)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +    case IP_MULTICAST_IF: +      if (optlen < sizeof(struct in_addr)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +    case IP_ADD_MEMBERSHIP: +    case IP_DROP_MEMBERSHIP: +      if (optlen < sizeof(struct ip_mreq)) { +        err = EINVAL; +      } +      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { +        err = EAFNOSUPPORT; +      } +      break; +#endif /* LWIP_IGMP */ +      default: +        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n", +                    s, optname)); +        err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    if (optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } + +    /* If this is no TCP socket, ignore any options. */ +    if (sock->conn->type != NETCONN_TCP) +      return 0; + +    switch (optname) { +    case TCP_NODELAY: +    case TCP_KEEPALIVE: +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +    case TCP_KEEPINTVL: +    case TCP_KEEPCNT: +#endif /* LWIP_TCP_KEEPALIVE */ +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP */ +#if LWIP_UDP && LWIP_UDPLITE +/* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    if (optlen < sizeof(int)) { +      err = EINVAL; +      break; +    } + +    /* If this is no UDP lite socket, ignore any options. */ +    if (sock->conn->type != NETCONN_UDPLITE) +      return 0; + +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +    case UDPLITE_RECV_CSCOV: +      break; + +    default: +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n", +                  s, optname)); +      err = ENOPROTOOPT; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP && LWIP_UDPLITE */ +/* UNDEFINED LEVEL */ +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n", +                s, level, optname)); +    err = ENOPROTOOPT; +  }  /* switch (level) */ + + +  if (err != ERR_OK) { +    sock_set_errno(sock, err); +    return -1; +  } + + +  /* Now do the actual option processing */ +  data.sock = sock; +  data.level = level; +  data.optname = optname; +  data.optval = (void*)optval; +  data.optlen = &optlen; +  data.err = err; +  tcpip_callback(lwip_setsockopt_internal, &data); +  sys_arch_sem_wait(sock->conn->op_completed, 0); +  /* maybe lwip_setsockopt_internal has changed err */ +  err = data.err; + +  sock_set_errno(sock, err); +  return err ? -1 : 0; +} + +static void +lwip_setsockopt_internal(void *arg) +{ +  struct lwip_socket *sock; +#ifdef LWIP_DEBUG +  int s; +#endif /* LWIP_DEBUG */ +  int level, optname; +  const void *optval; +  struct lwip_setgetsockopt_data *data; + +  LWIP_ASSERT("arg != NULL", arg != NULL); + +  data = (struct lwip_setgetsockopt_data*)arg; +  sock = data->sock; +#ifdef LWIP_DEBUG +  s = data->s; +#endif /* LWIP_DEBUG */ +  level = data->level; +  optname = data->optname; +  optval = data->optval; + +  switch (level) { + +/* Level: SOL_SOCKET */ +  case SOL_SOCKET: +    switch (optname) { + +    /* The option flags */ +    case SO_BROADCAST: +    /* UNIMPL case SO_DEBUG: */ +    /* UNIMPL case SO_DONTROUTE: */ +    case SO_KEEPALIVE: +    /* UNIMPL case SO_OOBINCLUDE: */ +#if SO_REUSE +    case SO_REUSEADDR: +    case SO_REUSEPORT: +#endif /* SO_REUSE */ +    /* UNIMPL case SO_USELOOPBACK: */ +      if (*(int*)optval) { +        sock->conn->pcb.ip->so_options |= optname; +      } else { +        sock->conn->pcb.ip->so_options &= ~optname; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n", +                  s, optname, (*(int*)optval?"on":"off"))); +      break; +#if LWIP_SO_RCVTIMEO +    case SO_RCVTIMEO: +      sock->conn->recv_timeout = ( *(int*)optval ); +      break; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +    case SO_RCVBUF: +      sock->conn->recv_bufsize = ( *(int*)optval ); +      break; +#endif /* LWIP_SO_RCVBUF */ +#if LWIP_UDP +    case SO_NO_CHECK: +      if (*(int*)optval) { +        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM); +      } else { +        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM); +      } +      break; +#endif /* LWIP_UDP */ +    }  /* switch (optname) */ +    break; + +/* Level: IPPROTO_IP */ +  case IPPROTO_IP: +    switch (optname) { +    case IP_TTL: +      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %d\n", +                  s, sock->conn->pcb.ip->ttl)); +      break; +    case IP_TOS: +      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %d\n", +                  s, sock->conn->pcb.ip->tos)); +      break; +#if LWIP_IGMP +    case IP_MULTICAST_TTL: +      sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); +      break; +    case IP_MULTICAST_IF: +      sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr; +      break; +    case IP_ADD_MEMBERSHIP: +    case IP_DROP_MEMBERSHIP: +      { +        /* If this is a TCP or a RAW socket, ignore these options. */ +        struct ip_mreq *imr = (struct ip_mreq *)optval; +        if(optname == IP_ADD_MEMBERSHIP){ +          data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); +        } else { +          data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); +        } +        if(data->err != ERR_OK) { +          data->err = EADDRNOTAVAIL; +        } +      } +      break; +#endif /* LWIP_IGMP */ +    }  /* switch (optname) */ +    break; + +#if LWIP_TCP +/* Level: IPPROTO_TCP */ +  case IPPROTO_TCP: +    switch (optname) { +    case TCP_NODELAY: +      if (*(int*)optval) { +        sock->conn->pcb.tcp->flags |= TF_NODELAY; +      } else { +        sock->conn->pcb.tcp->flags &= ~TF_NODELAY; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n", +                  s, (*(int *)optval)?"on":"off") ); +      break; +    case TCP_KEEPALIVE: +      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_idle)); +      break; + +#if LWIP_TCP_KEEPALIVE +    case TCP_KEEPIDLE: +      sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_idle)); +      break; +    case TCP_KEEPINTVL: +      sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_intvl)); +      break; +    case TCP_KEEPCNT: +      sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval); +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %"U32_F"\n", +                  s, sock->conn->pcb.tcp->keep_cnt)); +      break; +#endif /* LWIP_TCP_KEEPALIVE */ + +    }  /* switch (optname) */ +    break; +#endif /* LWIP_TCP*/ +#if LWIP_UDP && LWIP_UDPLITE +  /* Level: IPPROTO_UDPLITE */ +  case IPPROTO_UDPLITE: +    switch (optname) { +    case UDPLITE_SEND_CSCOV: +      if ((*(int*)optval != 0) && (*(int*)optval < 8)) { +        /* don't allow illegal values! */ +        sock->conn->pcb.udp->chksum_len_tx = 8; +      } else { +        sock->conn->pcb.udp->chksum_len_tx = *(int*)optval; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", +                  s, (*(int*)optval)) ); +      break; +    case UDPLITE_RECV_CSCOV: +      if ((*(int*)optval != 0) && (*(int*)optval < 8)) { +        /* don't allow illegal values! */ +        sock->conn->pcb.udp->chksum_len_rx = 8; +      } else { +        sock->conn->pcb.udp->chksum_len_rx = *(int*)optval; +      } +      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", +                  s, (*(int*)optval)) ); +      break; +    }  /* switch (optname) */ +    break; +#endif /* LWIP_UDP */ +  }  /* switch (level) */ +  sys_sem_signal(sock->conn->op_completed); +} + +int +lwip_ioctl(int s, long cmd, void *argp) +{ +  struct lwip_socket *sock = get_socket(s); +  u16_t buflen = 0; +  s16_t recv_avail; + +  if (!sock) +    return -1; + +  switch (cmd) { +  case FIONREAD: +    if (!argp) { +      sock_set_errno(sock, EINVAL); +      return -1; +    } + +    SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); +    if (recv_avail < 0) +      recv_avail = 0; +    *((u16_t*)argp) = (u16_t)recv_avail; + +    /* Check if there is data left from the last recv operation. /maq 041215 */ +    if (sock->lastdata) { +      buflen = netbuf_len(sock->lastdata); +      buflen -= sock->lastoffset; + +      *((u16_t*)argp) += buflen; +    } + +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); +    sock_set_errno(sock, 0); +    return 0; + +  case FIONBIO: +    if (argp && *(u32_t*)argp) +      sock->flags |= O_NONBLOCK; +    else +      sock->flags &= ~O_NONBLOCK; +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK))); +    sock_set_errno(sock, 0); +    return 0; + +  default: +    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp)); +    sock_set_errno(sock, ENOSYS); /* not yet implemented */ +    return -1; +  } /* switch (cmd) */ +} + +#endif /* LWIP_SOCKET */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/api/tcpip.c b/firmware/usrp3/lwip/lwip-1.3.1/src/api/tcpip.c new file mode 100644 index 000000000..002df90b2 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/api/tcpip.c @@ -0,0 +1,596 @@ +/** + * @file + * Sequential API Main thread 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 !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/memp.h" +#include "lwip/pbuf.h" +#include "lwip/ip_frag.h" +#include "lwip/tcp.h" +#include "lwip/autoip.h" +#include "lwip/dhcp.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "lwip/tcpip.h" +#include "lwip/init.h" +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + +/* global variables */ +static void (* tcpip_init_done)(void *arg); +static void *tcpip_init_done_arg; +static sys_mbox_t mbox = SYS_MBOX_NULL; + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +sys_sem_t lock_tcpip_core; +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +#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; +  } +} + +#if !NO_SYS +/** + * 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 /* !NO_SYS */ +#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(TCPIP_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(TCPIP_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(TCPIP_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(TCPIP_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(TCPIP_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(TCPIP_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(TCPIP_DEBUG, ("tcpip: dns_tmr()\n")); +  dns_tmr(); +  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +} +#endif /* LWIP_DNS */ + +/** + * The main lwIP thread. This thread has exclusive access to lwIP core functions + * (unless access to them is not locked). Other threads communicate with this + * thread using message boxes. + * + * It also starts all the timers to make sure they are running in the right + * thread context. + * + * @param arg unused argument + */ +static void +tcpip_thread(void *arg) +{ +  struct tcpip_msg *msg; +  LWIP_UNUSED_ARG(arg); + +#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 (tcpip_init_done != NULL) { +    tcpip_init_done(tcpip_init_done_arg); +  } + +  LOCK_TCPIP_CORE(); +  while (1) {                          /* MAIN Loop */ +    sys_mbox_fetch(mbox, (void *)&msg); +    switch (msg->type) { +#if LWIP_NETCONN +    case TCPIP_MSG_API: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg)); +      msg->msg.apimsg->function(&(msg->msg.apimsg->msg)); +      break; +#endif /* LWIP_NETCONN */ + +    case TCPIP_MSG_INPKT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); +#if LWIP_ARP +      if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) { +        ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); +      } else +#endif /* LWIP_ARP */ +      { ip_input(msg->msg.inp.p, msg->msg.inp.netif); +      } +      memp_free(MEMP_TCPIP_MSG_INPKT, msg); +      break; + +#if LWIP_NETIF_API +    case TCPIP_MSG_NETIFAPI: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg)); +      msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg)); +      break; +#endif /* LWIP_NETIF_API */ + +    case TCPIP_MSG_CALLBACK: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); +      msg->msg.cb.f(msg->msg.cb.ctx); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; + +    case TCPIP_MSG_TIMEOUT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); +      sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; +    case TCPIP_MSG_UNTIMEOUT: +      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg)); +      sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); +      memp_free(MEMP_TCPIP_MSG_API, msg); +      break; + +    default: +      break; +    } +  } +} + +/** + * Pass a received packet to tcpip_thread for input processing + * + * @param p the received packet, p->payload pointing to the Ethernet header or + *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag) + * @param inp the network interface on which the packet was received + */ +err_t +tcpip_input(struct pbuf *p, struct netif *inp) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_INPKT); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_INPKT; +    msg->msg.inp.p = p; +    msg->msg.inp.netif = inp; +    if (sys_mbox_trypost(mbox, msg) != ERR_OK) { +      memp_free(MEMP_TCPIP_MSG_INPKT, msg); +      return ERR_MEM; +    } +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * Call a specific function in the thread context of + * tcpip_thread for easy access synchronization. + * A function called in that way may access lwIP core code + * without fearing concurrent access. + * + * @param f the function to call + * @param ctx parameter passed to f + * @param block 1 to block until the request is posted, 0 to non-blocking mode + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_CALLBACK; +    msg->msg.cb.f = f; +    msg->msg.cb.ctx = ctx; +    if (block) { +      sys_mbox_post(mbox, msg); +    } else { +      if (sys_mbox_trypost(mbox, msg) != ERR_OK) { +        memp_free(MEMP_TCPIP_MSG_API, msg); +        return ERR_MEM; +      } +    } +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * call sys_timeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_TIMEOUT; +    msg->msg.tmo.msecs = msecs; +    msg->msg.tmo.h = h; +    msg->msg.tmo.arg = arg; +    sys_mbox_post(mbox, msg); +    return ERR_OK; +  } +  return ERR_VAL; +} + +/** + * call sys_untimeout in tcpip_thread + * + * @param msec time in miliseconds for timeout + * @param h function to be called on timeout + * @param arg argument to pass to timeout function h + * @return ERR_MEM on memory error, ERR_OK otherwise + */ +err_t +tcpip_untimeout(sys_timeout_handler h, void *arg) +{ +  struct tcpip_msg *msg; + +  if (mbox != SYS_MBOX_NULL) { +    msg = memp_malloc(MEMP_TCPIP_MSG_API); +    if (msg == NULL) { +      return ERR_MEM; +    } + +    msg->type = TCPIP_MSG_UNTIMEOUT; +    msg->msg.tmo.h = h; +    msg->msg.tmo.arg = arg; +    sys_mbox_post(mbox, msg); +    return ERR_OK; +  } +  return ERR_VAL; +} + +#if LWIP_NETCONN +/** + * Call the lower part of a netconn_* function + * This function is then running in the thread context + * of tcpip_thread and has exclusive access to lwIP core code. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK if the function was called, another err_t if not + */ +err_t +tcpip_apimsg(struct api_msg *apimsg) +{ +  struct tcpip_msg msg; +   +  if (mbox != SYS_MBOX_NULL) { +    msg.type = TCPIP_MSG_API; +    msg.msg.apimsg = apimsg; +    sys_mbox_post(mbox, &msg); +    sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0); +    return ERR_OK; +  } +  return ERR_VAL; +} + +#if LWIP_TCPIP_CORE_LOCKING +/** + * Call the lower part of a netconn_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param apimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_apimsg()) + */ +err_t +tcpip_apimsg_lock(struct api_msg *apimsg) +{ +  LOCK_TCPIP_CORE(); +  apimsg->function(&(apimsg->msg)); +  UNLOCK_TCPIP_CORE(); +  return ERR_OK; + +} +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +#if LWIP_NETIF_API +#if !LWIP_TCPIP_CORE_LOCKING +/** + * Much like tcpip_apimsg, but calls the lower part of a netifapi_* + * function. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return error code given back by the function that was called + */ +err_t +tcpip_netifapi(struct netifapi_msg* netifapimsg) +{ +  struct tcpip_msg msg; +   +  if (mbox != SYS_MBOX_NULL) { +    netifapimsg->msg.sem = sys_sem_new(0); +    if (netifapimsg->msg.sem == SYS_SEM_NULL) { +      netifapimsg->msg.err = ERR_MEM; +      return netifapimsg->msg.err; +    } +     +    msg.type = TCPIP_MSG_NETIFAPI; +    msg.msg.netifapimsg = netifapimsg; +    sys_mbox_post(mbox, &msg); +    sys_sem_wait(netifapimsg->msg.sem); +    sys_sem_free(netifapimsg->msg.sem); +    return netifapimsg->msg.err; +  } +  return ERR_VAL; +} +#else /* !LWIP_TCPIP_CORE_LOCKING */ +/** + * Call the lower part of a netifapi_* function + * This function has exclusive access to lwIP core code by locking it + * before the function is called. + * + * @param netifapimsg a struct containing the function to call and its parameters + * @return ERR_OK (only for compatibility fo tcpip_netifapi()) + */ +err_t +tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) +{ +  LOCK_TCPIP_CORE();   +  netifapimsg->function(&(netifapimsg->msg)); +  UNLOCK_TCPIP_CORE(); +  return netifapimsg->msg.err; +} +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +/** + * Initialize this module: + * - initialize all sub modules + * - start the tcpip_thread + * + * @param initfunc a function to call when tcpip_thread is running and finished initializing + * @param arg argument to pass to initfunc + */ +void +tcpip_init(void (* initfunc)(void *), void *arg) +{ +  lwip_init(); + +  tcpip_init_done = initfunc; +  tcpip_init_done_arg = arg; +  mbox = sys_mbox_new(TCPIP_MBOX_SIZE); +#if LWIP_TCPIP_CORE_LOCKING +  lock_tcpip_core = sys_sem_new(1); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); +} + +/** + * Simple callback function used with tcpip_callback to free a pbuf + * (pbuf_free has a wrong signature for tcpip_callback) + * + * @param p The pbuf (chain) to be dereferenced. + */ +static void +pbuf_free_int(void *p) +{ +  struct pbuf *q = p; +  pbuf_free(q); +} + +/** + * A simple wrapper function that allows you to free a pbuf from interrupt context. + * + * @param p The pbuf (chain) to be dereferenced. + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +pbuf_free_callback(struct pbuf *p) +{ +  return tcpip_callback_with_block(pbuf_free_int, p, 0); +} + +/** + * A simple wrapper function that allows you to free heap memory from + * interrupt context. + * + * @param m the heap memory to free + * @return ERR_OK if callback could be enqueued, an err_t if not + */ +err_t +mem_free_callback(void *m) +{ +  return tcpip_callback_with_block(mem_free, m, 0); +} + +#endif /* !NO_SYS */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/dhcp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/dhcp.c new file mode 100644 index 000000000..df0f97881 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/dhcp.c @@ -0,0 +1,1633 @@ +/** + * @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: + * - Proper parsing of DHCP messages exploiting file/sname field overloading. + * - Add JavaDoc style documentation (API, internals). + * - 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/inet.h" +#include "lwip/sys.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/dns.h" +#include "netif/etharp.h" + +#include <string.h> + +/** 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 + +/* DHCP client state machine functions */ +static void dhcp_handle_ack(struct netif *netif); +static void dhcp_handle_nak(struct netif *netif); +static void dhcp_handle_offer(struct netif *netif); + +static err_t dhcp_discover(struct netif *netif); +static err_t dhcp_select(struct netif *netif); +static void dhcp_check(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 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, struct ip_addr *addr, u16_t port); +static err_t dhcp_unfold_reply(struct dhcp *dhcp); +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type); +static u8_t dhcp_get_option_byte(u8_t *ptr); +#if 0 +static u16_t dhcp_get_option_short(u8_t *ptr); +#endif +static u32_t dhcp_get_option_long(u8_t *ptr); +static void dhcp_free_reply(struct dhcp *dhcp); + +/* 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 request, fill in common headers */ +static err_t dhcp_create_request(struct netif *netif); +/* free a DHCP request */ +static void dhcp_delete_request(struct netif *netif); +/* 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); +/* 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 | 3, ("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); +} + +/** + * 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 | 3, ("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 | 2, ("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)); +} + +/** + * 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; +  /* obtain the server address */ +  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", +    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); +  if (option_ptr != NULL) { +    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr)); +    /* remember offered address */ +    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + +    dhcp_select(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; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("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_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    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(dhcp->offered_ip_addr.addr)); + +    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.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 +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#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); + +    /* TODO: we really should bind to a specific local interface here +       but we cannot specify an unconfigured netif as it is addressless */ +    /* send broadcast to any DHCP server */ +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    /* reconnect to any (or to server here?!) */ +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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 clients' 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 | 3, ("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); +    } +  /* 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); +    } +  } +  /* 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); +    } +  } +} + +/** + * 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")); +    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")); +    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; +  u8_t *option_ptr; +  /* clear options we might not get from the ACK */ +  dhcp->offered_sn_mask.addr = 0; +  dhcp->offered_gw_addr.addr = 0; +  dhcp->offered_bc_addr.addr = 0; + +  /* lease time given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME); +  if (option_ptr != NULL) { +    /* remember offered lease time */ +    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); +  } +  /* renewal period given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1); +  if (option_ptr != NULL) { +    /* remember given renewal period */ +    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); +  } else { +    /* calculate safe periods for renewal */ +    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; +  } + +  /* renewal period given? */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2); +  if (option_ptr != NULL) { +    /* remember given rebind period */ +    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); +  } else { +    /* calculate safe periods for rebinding */ +    dhcp->offered_t2_rebind = dhcp->offered_t0_lease; +  } + +  /* (y)our internet address */ +  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr); + +/** + * Patch #1308 + * TODO: we must check if the file field is not overloaded by DHCP options! + */ +#if 0 +  /* boot server address */ +  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr); +  /* boot file name */ +  if (dhcp->msg_in->file[0]) { +    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1); +    strcpy(dhcp->boot_file_name, dhcp->msg_in->file); +  } +#endif + +  /* subnet mask */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK); +  /* subnet mask given? */ +  if (option_ptr != NULL) { +    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } + +  /* gateway router */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER); +  if (option_ptr != NULL) { +    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } + +  /* broadcast address */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST); +  if (option_ptr != NULL) { +    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); +  } +   +  /* DNS servers */ +  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER); +  if (option_ptr != NULL) { +    u8_t n; +    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr); +    /* limit to at most DHCP_MAX_DNS DNS servers */ +    if (dhcp->dns_count > DHCP_MAX_DNS) +      dhcp->dns_count = DHCP_MAX_DNS; +    for (n = 0; n < dhcp->dns_count; n++) { +      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4])); +#if LWIP_DNS +      dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr))); +#endif /* LWIP_DNS */ +    } +#if LWIP_DNS +    dns_setserver( n, (struct ip_addr *)(&ip_addr_any)); +#endif /* LWIP_DNS */ +  } +} + +/** + * 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 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 = 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 | 3, ("dhcp_start(): restarting DHCP configuration\n")); +    if (dhcp->pcb != NULL) { +      udp_remove(dhcp->pcb); +    } +    if (dhcp->p != NULL) { +      pbuf_free(dhcp->p); +    } +  } +     +  /* clear data structure */ +  memset(dhcp, 0, sizeof(struct dhcp)); +  /* 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")); +    mem_free((void *)dhcp); +    netif->dhcp = dhcp = NULL; +    return ERR_MEM; +  } +#if IP_SOF_BROADCAST +  dhcp->pcb->so_options|=SOF_BROADCAST; +#endif /* IP_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, *old_dhcp = netif->dhcp; +  err_t result = ERR_OK; +  dhcp = mem_malloc(sizeof(struct dhcp)); +  if (dhcp == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n")); +    return; +  } +  netif->dhcp = dhcp; +  memset(dhcp, 0, sizeof(struct dhcp)); + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n")); +  dhcp->pcb = udp_new(); +  if (dhcp->pcb == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb")); +    mem_free((void *)dhcp); +    return; +  } +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_INFORM); + +    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); + +#if IP_SOF_BROADCAST +    dhcp->pcb->so_options|=SOF_BROADCAST; +#endif /* IP_SOF_BROADCAST */ +    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); +    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    dhcp_delete_request(netif); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n")); +  } + +  if (dhcp->pcb != NULL) { +    udp_remove(dhcp->pcb); +  } +  dhcp->pcb = NULL; +  mem_free((void *)dhcp); +  netif->dhcp = old_dhcp; +} + +#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, struct ip_addr *addr) +{ +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("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", addr->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 | 1, ("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 | 3, ("dhcp_decline()\n")); +  dhcp_set_state(dhcp, DHCP_BACKING_OFF); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_DECLINE); + +    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); +    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.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); + +    /* @todo: should we really connect here? we are performing sendto() */ +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    /* 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_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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 + + +/** + * 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 | 3, ("dhcp_discover()\n")); +  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY); +  dhcp_set_state(dhcp, DHCP_SELECTING); +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_DISCOVER); + +    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); + +    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    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_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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; +  struct ip_addr 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 | 3, ("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)); +  } +  /* copy offered network mask */ +  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask); + +  /* subnet mask not given? */ +  /* TODO: this is not a valid check. what if the network mask is 0? */ +  if (sn_mask.addr == 0) { +    /* choose a safe subnet mask given the network class */ +    u8_t first_octet = ip4_addr1(&sn_mask); +    if (first_octet <= 127) { +      sn_mask.addr = htonl(0xff000000); +    } else if (first_octet >= 192) { +      sn_mask.addr = htonl(0xffffff00); +    } else { +      sn_mask.addr = htonl(0xffff0000); +    } +  } + +  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr); +  /* gateway address not given? */ +  if (gw_addr.addr == 0) { +    /* copy network address */ +    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr); +    /* use first host address on network as gateway */ +    gw_addr.addr |= htonl(0x00000001); +  } + +#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", dhcp->offered_ip_addr.addr)); +  netif_set_ipaddr(netif, &dhcp->offered_ip_addr); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr)); +  netif_set_netmask(netif, &sn_mask); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.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; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n")); +  dhcp_set_state(dhcp, DHCP_RENEWING); + +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    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 +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#endif /* LWIP_NETIF_HOSTNAME */ + +#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 +    /* 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_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); + +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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; +#if LWIP_NETIF_HOSTNAME +  const char *p; +#endif /* LWIP_NETIF_HOSTNAME */ +  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_request(netif); +  if (result == ERR_OK) { + +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_REQUEST); + +    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 +    p = (const char*)netif->hostname; +    if (p != NULL) { +      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); +      while (*p) { +        dhcp_option_byte(dhcp, *p++); +      } +    } +#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_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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; +} + +/** + * 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 | 3, ("dhcp_release()\n")); + +  /* idle DHCP client */ +  dhcp_set_state(dhcp, DHCP_OFF); +  /* clean old DHCP offer */ +  dhcp->server_ip_addr.addr = 0; +  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0; +  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0; +  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; +  dhcp->dns_count = 0; +   +  /* create and initialize the DHCP message header */ +  result = dhcp_create_request(netif); +  if (result == ERR_OK) { +    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); +    dhcp_option_byte(dhcp, DHCP_RELEASE); + +    dhcp_option_trailer(dhcp); + +    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + +    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT); +    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); +    dhcp_delete_request(netif); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); +  } else { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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); +   +  /* TODO: netif_down(netif); */ +  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 = netif->dhcp; +  LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); +  /* Remove the flag that says this netif is handled by DHCP. */ +  netif->flags &= ~NETIF_FLAG_DHCP; + +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("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; +    } +    if (dhcp->p != NULL) { +      pbuf_free(dhcp->p); +      dhcp->p = NULL; +    } +    /* free unfolded reply */ +    dhcp_free_reply(dhcp); +    mem_free((void *)dhcp); +    netif->dhcp = NULL; +  } +} + +/* + * Set the DHCP state of a DHCP client. + * + * If the state changed, reset the number of tries. + * + * TODO: we might also want to reset the timeout here? + */ +static void +dhcp_set_state(struct dhcp *dhcp, u8_t new_state) +{ +  if (new_state != dhcp->state) { +    dhcp->state = new_state; +    dhcp->tries = 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)); +} + +/** + * 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_unfold_reply(struct dhcp *dhcp) +{ +  u16_t ret; +  LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;); +  LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;); +  /* free any left-overs from previous unfolds */ +  dhcp_free_reply(dhcp); +  /* options present? */ +  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) { +    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +    dhcp->options_in = mem_malloc(dhcp->options_in_len); +    if (dhcp->options_in == NULL) { +      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n")); +      return ERR_MEM; +    } +  } +  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +  if (dhcp->msg_in == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); +    mem_free((void *)dhcp->options_in); +    dhcp->options_in = NULL; +    return ERR_MEM; +  } + +  /** copy the DHCP message without options */ +  ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0); +  LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", +     sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)); + +  if (dhcp->options_in != NULL) { +    /** copy the DHCP options */ +    ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); +    LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len); +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", +      dhcp->options_in_len)); +  } +  LWIP_UNUSED_ARG(ret); +  return ERR_OK; +} + +/** + * Free the incoming DHCP message including contiguous copy of + * its DHCP options. + * + */ +static void dhcp_free_reply(struct dhcp *dhcp) +{ +  if (dhcp->msg_in != NULL) { +    mem_free((void *)dhcp->msg_in); +    dhcp->msg_in = NULL; +  } +  if (dhcp->options_in) { +    mem_free((void *)dhcp->options_in); +    dhcp->options_in = NULL; +    dhcp->options_in_len = 0; +  } +  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n")); +} + + +/** + * 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, struct ip_addr *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 *options_ptr; +  u8_t msg_type; +  u8_t i; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, +    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff), +    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), 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); +  dhcp->p = p; +  /* TODO: check packet length before reading them */ +  if (reply_msg->op != DHCP_BOOTREPLY) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("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 | 2, ("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 | 2, ("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_unfold_reply(dhcp) != ERR_OK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("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 */ +  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE); +  if (options_ptr == NULL) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); +    goto free_pbuf_and_return; +  } + +  /* read DHCP message type */ +  msg_type = dhcp_get_option_byte(options_ptr + 2); +  /* message type is DHCP ACK? */ +  if (msg_type == DHCP_ACK) { +    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n")); +    /* in requesting state? */ +    if (dhcp->state == DHCP_REQUESTING) { +      dhcp_handle_ack(netif); +      dhcp->request_timeout = 0; +#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->request_timeout = 0; +      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 | 1, ("DHCP_NAK received\n")); +    dhcp->request_timeout = 0; +    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 | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n")); +    dhcp->request_timeout = 0; +    /* remember offered lease */ +    dhcp_handle_offer(netif); +  } +free_pbuf_and_return: +  dhcp_free_reply(dhcp); +  pbuf_free(p); +  dhcp->p = NULL; +} + +/** + * Create a DHCP request, fill in common headers + * + * @param netif the netif under DHCP control + */ +static err_t +dhcp_create_request(struct netif *netif) +{ +  struct dhcp *dhcp; +  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 */ +  static u32_t xid = 0xABCD0000; +#else +  static u32_t xid; +  static u8_t xid_initialised = 0; +  if (!xid_initialised) { +    xid = DHCP_GLOBAL_XID; +    xid_initialised = !xid_initialised; +  } +#endif +  LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;); +  dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); +  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL); +  LWIP_ASSERT("dhcp_create_request: 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 | 2, ("dhcp_create_request(): could not allocate pbuf\n")); +    return ERR_MEM; +  } +  LWIP_ASSERT("dhcp_create_request: 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) +      xid++; +  dhcp->xid = xid; +  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, +              ("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; +  /* TODO: make link layer independent */ +  dhcp->msg_out->hlen = DHCP_HLEN_ETH; +  dhcp->msg_out->hops = 0; +  dhcp->msg_out->xid = htonl(dhcp->xid); +  dhcp->msg_out->secs = 0; +  dhcp->msg_out->flags = 0; +  dhcp->msg_out->ciaddr.addr = 0; +  if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) { +    dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; +  } +  dhcp->msg_out->yiaddr.addr = 0; +  dhcp->msg_out->siaddr.addr = 0; +  dhcp->msg_out->giaddr.addr = 0; +  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 = htonl(0x63825363UL); +  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 */ +  } +  return ERR_OK; +} + +/** + * Free previously allocated memory used to send a DHCP request. + * + * @param netif the netif under DHCP control + */ +static void +dhcp_delete_request(struct netif *netif) +{ +  struct dhcp *dhcp; +  LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;); +  dhcp = netif->dhcp; +  LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;); +  LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL); +  LWIP_ASSERT("dhcp_delete_request: 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)) { +    /* LWIP_DEBUGF(DHCP_DEBUG,("dhcp_option_trailer:dhcp->options_out_len=%"U16_F", DHCP_OPTIONS_LEN=%"U16_F, dhcp->options_out_len, DHCP_OPTIONS_LEN)); */ +    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN); +    /* add a fill/padding byte */ +    dhcp->msg_out->options[dhcp->options_out_len++] = 0; +  } +} + +/** + * Find the offset of a DHCP option inside the DHCP message. + * + * @param dhcp DHCP client + * @param option_type + * + * @return a byte offset into the UDP message where the option was found, or + * zero if the given option was not found. + */ +static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type) +{ +  u8_t overload = DHCP_OVERLOAD_NONE; + +  /* options available? */ +  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) { +    /* start with options field */ +    u8_t *options = (u8_t *)dhcp->options_in; +    u16_t offset = 0; +    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ +    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) { +      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ +      /* are the sname and/or file field overloaded with options? */ +      if (options[offset] == DHCP_OPTION_OVERLOAD) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n")); +        /* skip option type and length */ +        offset += 2; +        overload = options[offset++]; +      } +      /* requested option found */ +      else if (options[offset] == option_type) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset)); +        return &options[offset]; +      /* skip option */ +      } else { +         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset])); +        /* skip option type */ +        offset++; +        /* skip option length, and then length bytes */ +        offset += 1 + options[offset]; +      } +    } +    /* is this an overloaded message? */ +    if (overload != DHCP_OVERLOAD_NONE) { +      u16_t field_len; +      if (overload == DHCP_OVERLOAD_FILE) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n")); +        options = (u8_t *)&dhcp->msg_in->file; +        field_len = DHCP_FILE_LEN; +      } else if (overload == DHCP_OVERLOAD_SNAME) { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n")); +        options = (u8_t *)&dhcp->msg_in->sname; +        field_len = DHCP_SNAME_LEN; +      /* TODO: check if else if () is necessary */ +      } else { +        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n")); +        options = (u8_t *)&dhcp->msg_in->sname; +        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; +      } +      offset = 0; + +      /* at least 1 byte to read and no end marker */ +      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) { +        if (options[offset] == option_type) { +           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset)); +          return &options[offset]; +        /* skip option */ +        } else { +          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset])); +          /* skip option type */ +          offset++; +          offset += 1 + options[offset]; +        } +      } +    } +  } +  return NULL; +} + +/** + * Return the byte of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u8_t +dhcp_get_option_byte(u8_t *ptr) +{ +  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr))); +  return *ptr; +} + +#if 0 /* currently unused */ +/** + * Return the 16-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u16_t +dhcp_get_option_short(u8_t *ptr) +{ +  u16_t value; +  value = *ptr++ << 8; +  value |= *ptr; +  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value)); +  return value; +} +#endif + +/** + * Return the 32-bit value of DHCP option data. + * + * @param client DHCP client. + * @param ptr pointer obtained by dhcp_get_option_ptr(). + * + * @return byte value at the given address. + */ +static u32_t dhcp_get_option_long(u8_t *ptr) +{ +  u32_t value; +  value = (u32_t)(*ptr++) << 24; +  value |= (u32_t)(*ptr++) << 16; +  value |= (u32_t)(*ptr++) << 8; +  value |= (u32_t)(*ptr++); +  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value)); +  return value; +} + +#endif /* LWIP_DHCP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/dns.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/dns.c new file mode 100644 index 000000000..62a2592e9 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/dns.c @@ -0,0 +1,980 @@ +/** + * @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/dns.h" + +#include <string.h> + +/** DNS server IP address */ +#ifndef DNS_SERVER_ADDRESS +#define DNS_SERVER_ADDRESS        inet_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 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS query message structure */ +struct dns_query { +  /* DNS query record starts with either a domain name or a pointer +     to a name already present somewhere in the packet. */ +  PACK_STRUCT_FIELD(u16_t type); +  PACK_STRUCT_FIELD(u16_t class); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif +#define SIZEOF_DNS_QUERY 4 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** DNS answer message structure */ +struct dns_answer { +  /* DNS answer record starts with either a domain name or a pointer +     to a name already present somewhere in the packet. */ +  PACK_STRUCT_FIELD(u16_t type); +  PACK_STRUCT_FIELD(u16_t class); +  PACK_STRUCT_FIELD(u32_t ttl); +  PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif +#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]; +  struct ip_addr ipaddr; +  /* pointer to callback on DNS query done */ +  dns_found_callback found; +  void *arg; +}; + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { +  /** static hostname */ +  const char *name; +  /** static host address in network byteorder */ +  u32_t addr; +  struct local_hostlist_entry *next; +}; + +#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, struct ip_addr *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 struct ip_addr         dns_servers[DNS_MAX_SERVERS]; + +#if (DNS_USES_STATIC_BUF == 1) +static u8_t                   dns_payload[DNS_MSG_SIZE]; +#endif /* (DNS_USES_STATIC_BUF == 1) */ + +/** + * Initialize the resolver: set up the UDP pcb and configure the default server + * (DNS_SERVER_ADDRESS). + */ +void +dns_init() +{ +  struct ip_addr dnsserver; +   +  /* initialize default DNS server address */ +  dnsserver.addr = DNS_SERVER_ADDRESS; + +  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, struct ip_addr *dnsserver) +{ +  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && +      (dnsserver != NULL) && (dnsserver->addr !=0 )) { +    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. + */ +struct ip_addr +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; +  for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { +    entry = mem_malloc(sizeof(struct local_hostlist_entry)); +    LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); +    if (entry != NULL) { +      struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; +      entry->name = init_entry->name; +      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 + *         INADDR_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 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 local_hostlist_static[i].addr; +    } +  } +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +  return INADDR_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 struct ip_addr *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) || (entry->addr == 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; +      mem_free(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 struct ip_addr *addr) +{ +  struct local_hostlist_entry *entry; +  entry = mem_malloc(sizeof(struct local_hostlist_entry)); +  if (entry == NULL) { +    return ERR_MEM; +  } +  entry->name = hostname; +  entry->addr = 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 struct ip_addr to + *         better check for failure: != INADDR_NONE) or INADDR_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)) != INADDR_NONE) { +    return addr; +  } +#endif /* DNS_LOCAL_HOSTLIST */ +#ifdef DNS_LOOKUP_LOCAL_EXTERN +  if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_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 dns_table[i].ipaddr.addr; +    } +  } + +  return INADDR_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", dns_servers[numdns].addr != 0); + +  /* 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 = 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  = htons(DNS_RRTYPE_A); +    qry.class = htons(DNS_RRCLASS_IN); +    MEMCPY( query, &qry, SIZEOF_DNS_QUERY); + +    /* resize pbuf to the exact dns query */ +    pbuf_realloc(p, (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) +{ +  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 */ +      dns_send(pEntry->numdns, pEntry->name, i); +      break; +    } + +    case DNS_STATE_ASKING: { +      if (--pEntry->tmr == 0) { +        if (++pEntry->retries == DNS_MAX_RETRIES) { +          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) { +            /* 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 */ +        dns_send(pEntry->numdns, pEntry->name, i); +      } +      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, struct ip_addr *addr, u16_t port) +{ +  u8_t i; +  char *pHostname; +  struct dns_hdr *hdr; +  struct dns_answer ans; +  struct dns_table_entry *pEntry; +  u8_t nquestions, nanswers; +#if (DNS_USES_STATIC_BUF == 0) +  u8_t dns_payload[DNS_MSG_SIZE]; +#endif /* (DNS_USES_STATIC_BUF == 0) */ +#if (DNS_USES_STATIC_BUF == 2) +  u8_t* dns_payload; +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +  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 memerr1; +  } + +  /* 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 memerr1; +  } + +#if (DNS_USES_STATIC_BUF == 2) +  dns_payload = mem_malloc(p->tot_len); +  if (dns_payload == NULL) { +    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n")); +    /* free pbuf and return */ +    goto memerr1; +  } +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +  /* 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. */ +          MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); +          if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) { +            /* 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 */ +            MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr)); +            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 memerr2; +          } 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 memerr2; + +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; + +memerr2: +#if (DNS_USES_STATIC_BUF == 2) +  /* free dns buffer */ +  mem_free(dns_payload); +#endif /* (DNS_USES_STATIC_BUF == 2) */ + +memerr1: +  /* 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; + +  /* 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; +  strcpy(pEntry->name, name); + +  /* 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. + * + * @param hostname the hostname that is to be queried + * @param addr pointer to a struct ip_addr 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, struct ip_addr *addr, dns_found_callback found, +                  void *callback_arg) +{ +  /* 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_VAL; +  } + +#if LWIP_HAVE_LOOPIF +  if (strcmp(hostname,"localhost")==0) { +    addr->addr = INADDR_LOOPBACK; +    return ERR_OK; +  } +#endif /* LWIP_HAVE_LOOPIF */ + +  /* host name already in octet notation? set ip addr and return ERR_OK +   * already have this address cached? */ +  if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) || +      ((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) { +    return ERR_OK; +  } + +  /* queue query with specified callback */ +  return dns_enqueue(hostname, found, callback_arg); +} + +#endif /* LWIP_DNS */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/init.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/init.c new file mode 100644 index 000000000..277811a6a --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/init.c @@ -0,0 +1,269 @@ +/** + * @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.h" +#include "lwip/snmp_msg.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" +#include "netif/etharp.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_ARP && ARP_QUEUEING) +  #error "If you want to use ARP Queueing, you have to define LWIP_ARP=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_DNS) +  #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) +  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" +#endif +#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_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_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_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 (PPP_SUPPORT && (NO_SYS==1)) +  #error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h" +#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) && (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 +#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 +/* There must be sufficient timeouts, taking into account requirements of the subsystems. */ +#if ((NO_SYS==0) && (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 +#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 (TCP_QUEUE_OOSEQ && !LWIP_TCP) +  #error "TCP_QUEUE_OOSEQ requires LWIP_TCP" +#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 + + +/* 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 +#if SO_REUSE +/* I removed the lot since this was an ugly hack. It broke the raw-API. +   It also came with many ugly goto's, Christiaan Simons. */ +  #error "SO_REUSE currently unavailable, this was a hack" +#endif + +#ifdef LWIP_DEBUG +static void +lwip_sanity_check(void) +{ +  /* Warnings */ +#if LWIP_NETCONN +  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB)) +    LWIP_PLATFORM_DIAG(("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\n")); +#endif /* LWIP_NETCONN */ +#if LWIP_TCP +  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n")); +  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); +  if (TCP_SNDLOWAT > TCP_SND_BUF) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n")); +  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); +  if (TCP_WND < TCP_MSS) +    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); +#endif /* LWIP_TCP */ +} +#else  /* LWIP_DEBUG */ +#define lwip_sanity_check() +#endif /* LWIP_DEBUG */ + +/** + * Perform Sanity check of user-configurable values, and initialize all modules. + */ +void +lwip_init(void) +{ +  /* Sanity check user-configurable values */ +  lwip_sanity_check(); + +  /* Modules initialization */ +  stats_init(); +  sys_init(); +  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 */ +} diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/autoip.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/autoip.c new file mode 100644 index 000000000..367adb060 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/autoip.c @@ -0,0 +1,453 @@ +/** + * @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) \ +  (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, struct ip_addr *IPAddr); + +/* 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); + +/** + * Initialize this module + */ +void +autoip_init(void) +{ +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n")); +} + +/** + * 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 | 1, +        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); + +      /* TODO: close all TCP sessions */ +      autoip_start(netif); +    } else { +      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +        ("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 | 1, +      ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); +    /* TODO: close all TCP sessions */ +    autoip_start(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, struct ip_addr *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)); +  IPAddr->addr = htonl(addr); +   +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, +    ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", +    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(IPAddr->addr))); +} + +/** + * 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; +  struct ip_addr sn_mask, gw_addr; + +  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +    ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n", +    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr)); + +  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 +   */ +  netif->ip_addr.addr = 0; +  netif->netmask.addr = 0; +  netif->gw.addr      = 0; + +  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 = 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; +    memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); +    autoip->lastconflict = 0; +  } + +  autoip_create_addr(netif, &(autoip->llipaddr)); +  autoip->tried_llipaddr++; +  autoip->state = AUTOIP_STATE_PROBING; +  autoip->sent_num = 0; + +  /* 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; +  } + +  return result; +} + +/** + * 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; +            } else { +              etharp_request(netif, &(netif->autoip->llipaddr)); +              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +                ("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(netif); +            } + +            if(netif->autoip->sent_num == ANNOUNCE_NUM) { +              netif->autoip->state = AUTOIP_STATE_BOUND; +              netif->autoip->sent_num = 0; +              netif->autoip->ttw = 0; +            } else { +              autoip_arp_announce(netif); +              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, +                ("autoip_tmr() ANNOUNCING Sent Announce\n")); +              netif->autoip->sent_num++; +              netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND; +            } +          } +          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 | 3, ("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 +    */ +    struct ip_addr sipaddr, dipaddr; +    struct eth_addr netifaddr; +    netifaddr.addr[0] = netif->hwaddr[0]; +    netifaddr.addr[1] = netif->hwaddr[1]; +    netifaddr.addr[2] = netif->hwaddr[2]; +    netifaddr.addr[3] = netif->hwaddr[3]; +    netifaddr.addr[4] = netif->hwaddr[4]; +    netifaddr.addr[5] = netif->hwaddr[5]; + +    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without +     * structure packing (not using structure copy which breaks strict-aliasing rules). +     */ +    SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); +    SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(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 | 1, +          ("autoip_arp_reply(): Probe Conflict detected\n")); +        autoip_start(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 | 1, +          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n")); +        autoip_handle_arp_conflict(netif); +      } +    } +  } +} + +#endif /* LWIP_AUTOIP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/icmp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/icmp.c new file mode 100644 index 000000000..b97a587a7 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/icmp.c @@ -0,0 +1,331 @@ +/** + * @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.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; +  struct ip_addr tmpaddr; +  s16_t hlen; + +  ICMP_STATS_INC(icmp.recv); +  snmp_inc_icmpinmsgs(); + + +  iphdr = 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_ECHO: +#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING +    { +      int accepted = 1; +#if !LWIP_MULTICAST_PING +      /* multicast destination address? */ +      if (ip_addr_ismulticast(&iphdr->dest)) { +        accepted = 0; +      } +#endif /* LWIP_MULTICAST_PING */ +#if !LWIP_BROADCAST_PING +      /* broadcast destination address? */ +      if (ip_addr_isbroadcast(&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 = 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 = p->payload; +    tmpaddr.addr = iphdr->src.addr; +    iphdr->src.addr = iphdr->dest.addr; +    iphdr->dest.addr = tmpaddr.addr; +    ICMPH_TYPE_SET(iecho, ICMP_ER); +    /* adjust the checksum */ +    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { +      iecho->chksum += htons(ICMP_ECHO << 8) + 1; +    } else { +      iecho->chksum += htons(ICMP_ECHO << 8); +    } + +    /* 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; +      ret = ip_output_if(p, &(iphdr->src), 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; + +  /* 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 = 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 = 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_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); +  pbuf_free(q); +} + +#endif /* LWIP_ICMP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/igmp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/igmp.c new file mode 100644 index 000000000..7c07bc465 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/igmp.c @@ -0,0 +1,757 @@ +/** + * @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.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" + +/*----------------------------------------------------------------------------- + * Globales + *----------------------------------------------------------------------------*/ + +static struct igmp_group* igmp_group_list; +static struct ip_addr     allsystems; +static struct ip_addr     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->interface)); +    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->interface == 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->interface == 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, struct ip_addr *addr) +{ +  struct igmp_group *group = igmp_group_list; + +  while (group != NULL) { +    if ((group->interface == 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, struct ip_addr *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 = memp_malloc(MEMP_IGMP_GROUP); +  if (group != NULL) { +    group->interface          = 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 + */ +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, struct ip_addr *dest) +{ +  struct ip_hdr *    iphdr; +  struct igmp_msg*   igmp; +  struct igmp_group* group; +  struct igmp_group* groupref; + +  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */     +  iphdr = 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 incoming IP address! */ +   +  /* If group can be found or create... */ +  if (!group) { +    pbuf_free(p); +    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)) && (igmp->igmp_group_address.addr == 0)) { +       /* 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.v1_rxed); +         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; +       } + +       IGMP_STATS_INC(igmp.group_query_rxed); +       groupref = igmp_group_list; +       while (groupref) { +         /* Do not send messages on the all systems group address! */ +         if ((groupref->interface == 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 (group->group_address.addr != 0) { +         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); +         ip_addr_debug_print(IGMP_DEBUG, &group->group_address); +         if (ip_addr_cmp (dest, &allsystems)) { +           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-lookfor the group since we used dest last time */ +           group = igmp_lookfor_group(inp, &igmp->igmp_group_address); +         } 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.unicast_query); +           igmp_delaying_member( group, igmp->igmp_maxresp); +         } +       } +     } +     break; +   } +   case IGMP_V2_MEMB_REPORT: { +     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); + +     IGMP_STATS_INC(igmp.report_rxed); +     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->interface)); +     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(struct ip_addr *ifaddr, struct ip_addr *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.join_sent); +          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(struct ip_addr *ifaddr, struct ip_addr *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.leave_sent); +            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 -= 1; +      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 + */ +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->interface)); + +    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()) + */ +void +igmp_start_timer(struct igmp_group *group, u8_t max_time) +{ +  /** +   * @todo Important !! this should be random 0 -> max_time. Find out how to do this +   */ +  group->timer = max_time; +} + +/** + * Stop a timer for an igmp_group + * + * @param group the igmp_group for which to stop the timer + */ +void +igmp_stop_timer(struct igmp_group *group) +{ +  group->timer = 0; +} + +/** + * Delaying membership report for a group if necessary + * + * @param group the igmp_group for which "delaying" membership report + * @param maxresp query delay + */ +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) && (maxresp > group->timer))) { +    igmp_start_timer(group, (maxresp)/2); +    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 + */ +err_t +igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +                  u8_t ttl, u8_t proto, struct netif *netif) +{ +  /* This is the "router alert" option */ +  u16_t ra[2]; +  ra[0] = htons (ROUTER_ALERT); +  ra[1] = 0x0000; /* Router shall examine packet */ +  return ip_output_if_opt(p, src, dest, ttl, 0, proto, 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 + */ +void +igmp_send(struct igmp_group *group, u8_t type) +{ +  struct pbuf*     p    = NULL; +  struct igmp_msg* igmp = NULL; +  struct ip_addr   src  = {0}; +  struct ip_addr*  dest = NULL; + +  /* IP header + "router alert" option + IGMP header */ +  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); +   +  if (p) { +    igmp = p->payload; +    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", +               (p->len >= sizeof(struct igmp_msg))); +    ip_addr_set(&src, &((group->interface)->ip_addr)); +      +    if (type == IGMP_V2_MEMB_REPORT) { +      dest = &(group->group_address); +      IGMP_STATS_INC(igmp.report_sent); +      ip_addr_set(&(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_set(&(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, IGMP_TTL, IP_PROTO_IGMP, group->interface); +    } + +    pbuf_free(p); +  } else { +    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); +  } +} + +#endif /* LWIP_IGMP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet.c new file mode 100644 index 000000000..69baf1d50 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet.c @@ -0,0 +1,278 @@ +/** + * @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" + +/* 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 +inet_addr(const char *cp) +{ +  struct in_addr val; + +  if (inet_aton(cp, &val)) { +    return (val.s_addr); +  } +  return (INADDR_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 +inet_aton(const char *cp, struct in_addr *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; +  } +  if (addr) +    addr->s_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 * +inet_ntoa(struct in_addr addr) +{ +  static char str[16]; +  u32_t s_addr = addr.s_addr; +  char inv[3]; +  char *rp; +  u8_t *ap; +  u8_t rem; +  u8_t n; +  u8_t i; + +  rp = str; +  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--) +      *rp++ = inv[i]; +    *rp++ = '.'; +    ap++; +  } +  *--rp = 0; +  return str; +} + +/** + * 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 +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 +ntohs(u16_t n) +{ +  return 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 +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 +ntohl(u32_t n) +{ +  return htonl(n); +} + +#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c new file mode 100644 index 000000000..185881efd --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/inet_chksum.c @@ -0,0 +1,438 @@ +/** + * @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/inet.h" + +#include <stddef.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 1 +# endif +#endif +/* If none set: */ +#ifndef LWIP_CHKSUM_ALGORITHM +# define LWIP_CHKSUM_ALGORITHM 0 +#endif + +/** Like the name says... */ +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8) +#endif + +/** Split an u32_t in two u16_ts and add them up */ +#define FOLD_U32T(u)          ((u >> 16) + (u & 0x0000ffffUL)) + +#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 = dataptr; +  u16_t *ps, t = 0; +  u32_t sum = 0; +  int odd = ((u32_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 *)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 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 = dataptr; +  u16_t *ps, t = 0; +  u32_t *pl; +  u32_t sum = 0, tmp; +  /* starts at odd byte address? */ +  int odd = ((u32_t)pb & 1); + +  if (odd && len > 0) { +    ((u8_t *)&t)[1] = *pb++; +    len--; +  } + +  ps = (u16_t *)pb; + +  if (((u32_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 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, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len) +{ +  u32_t acc; +  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); +  } +  acc += (src->addr & 0xffffUL); +  acc += ((src->addr >> 16) & 0xffffUL); +  acc += (dest->addr & 0xffffUL); +  acc += ((dest->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 + */ +/* Currently only used by UDPLITE, although this could change in the future. */ +#if LWIP_UDPLITE +u16_t +inet_chksum_pseudo_partial(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len, u16_t chksum_len) +{ +  u32_t acc; +  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); +  } +  acc += (src->addr & 0xffffUL); +  acc += ((src->addr >> 16) & 0xffffUL); +  acc += (dest->addr & 0xffffUL); +  acc += ((dest->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); +} +#endif /* LWIP_UDPLITE */ + +/* 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); +} diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip.c new file mode 100644 index 000000000..7e404a9f3 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip.c @@ -0,0 +1,749 @@ +/** + * @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.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.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/stats.h" +#include "arch/perf.h" + +#include <string.h> + +/** + * The interface that provided the packet for the current callback + * invocation. + */ +static struct netif *current_netif; + +/** + * Header of the input packet currently being processed. + */ +static const struct ip_hdr *current_header; + +/** + * Get the interface that received the current packet. + * + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. + * + * @param pcb Pointer to the pcb receiving a packet. + */ +struct netif * +ip_current_netif(void) +{ +  return current_netif; +} + +/** + * Get the IP header of the current packet. + * + * This function must only be called from a receive callback (udp_recv, + * raw_recv, tcp_accept). It will return NULL otherwise. + * + * @param pcb Pointer to the pcb receiving a packet. + */ +const struct ip_hdr * +ip_current_header(void) +{ +  return current_header; +} + +/** + * 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(struct ip_addr *dest) +{ +  struct netif *netif; + +  /* 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 | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr)); +    IP_STATS_INC(ip.rterr); +    snmp_inc_ipoutnoroutes(); +    return NULL; +  } +  /* no matching netif found, use default netif */ +  return netif_default; +} + +#if 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. + * + * @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 + * @return the netif on which the packet was sent (NULL if it wasn't sent) + */ +static struct netif * +ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) +{ +  struct netif *netif; + +  PERF_START; +  /* Find network interface where to forward this IP packet to. */ +  netif = ip_route((struct ip_addr *)&(iphdr->dest)); +  if (netif == NULL) { +    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n", +                      iphdr->dest.addr)); +    snmp_inc_ipoutnoroutes(); +    return (struct netif *)NULL; +  } +  /* 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")); +    snmp_inc_ipoutnoroutes(); +    return (struct netif *)NULL; +  } + +  /* 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 (struct netif *)NULL; +  } + +  /* Incrementally update the IP checksum. */ +  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { +    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); +  } else { +    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); +  } + +  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n", +                    iphdr->dest.addr)); + +  IP_STATS_INC(ip.fw); +  IP_STATS_INC(ip.xmit); +  snmp_inc_ipforwdatagrams(); + +  PERF_STOP("ip_forward"); +  /* transmit pbuf on chosen interface */ +  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); +  return netif; +} +#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 LWIP_DHCP +  int check_ip_src=1; +#endif /* LWIP_DHCP */ + +  IP_STATS_INC(ip.recv); +  snmp_inc_ipinreceives(); + +  /* identify the IP header */ +  iphdr = p->payload; +  if (IPH_V(iphdr) != 4) { +    LWIP_DEBUGF(IP_DEBUG | 1, ("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; +  } + +  /* 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 | 2, ("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 | 2, ("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 | 2, ("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); + +  /* match packet against an interface, i.e. is this packet for us? */ +#if LWIP_IGMP +  if (ip_addr_ismulticast(&(iphdr->dest))) { +    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(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", +          iphdr->dest.addr, netif->ip_addr.addr, +          iphdr->dest.addr & netif->netmask.addr, +          netif->ip_addr.addr & netif->netmask.addr, +          iphdr->dest.addr & ~(netif->netmask.addr))); + +      /* 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(&(iphdr->dest), &(netif->ip_addr)) || +            /* or broadcast on this interface network address? */ +            ip_addr_isbroadcast(&(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 (first) { +        first = 0; +        netif = netif_list; +      } else { +        netif = netif->next; +      } +      if (netif == inp) { +        netif = netif->next; +      } +    } while(netif != NULL); +  } + +#if LWIP_DHCP +  /* 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 (netif == NULL) { +    /* remote port is DHCP server? */ +    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { +      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", +        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); +      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { +        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n")); +        netif = inp; +        check_ip_src = 0; +      } +    } +  } +#endif /* LWIP_DHCP */ + +  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ +#if LWIP_DHCP +  if (check_ip_src) +#endif /* LWIP_DHCP */ +  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || +         (ip_addr_ismulticast(&(iphdr->src)))) { +      /* packet source is not valid */ +      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("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 | 1, ("ip_input: packet not for us.\n")); +#if IP_FORWARD +    /* non-broadcast packet? */ +    if (!ip_addr_isbroadcast(&(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) & 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) & 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 = p->payload; +#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ +    pbuf_free(p); +    LWIP_DEBUGF(IP_DEBUG | 2, ("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 | 2, ("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,&(iphdr->dest)); +      break; +#endif /* LWIP_IGMP */ +    default: +#if LWIP_ICMP +      /* send ICMP destination protocol unreachable unless is was a broadcast */ +      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && +          !ip_addr_ismulticast(&(iphdr->dest))) { +        p->payload = iphdr; +        icmp_dest_unreach(p, ICMP_DUR_PROTO); +      } +#endif /* LWIP_ICMP */ +      pbuf_free(p); + +      LWIP_DEBUGF(IP_DEBUG | 2, ("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; + +  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, struct ip_addr *src, struct ip_addr *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, struct ip_addr *src, struct ip_addr *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; +  static u16_t ip_id = 0; + +  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) { +      /* 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 | 2, ("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); +      } +    } +#endif /* IP_OPTIONS_SEND */ +    /* generate IP header */ +    if (pbuf_header(p, IP_HLEN)) { +      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n")); + +      IP_STATS_INC(ip.err); +      snmp_inc_ipoutdiscards(); +      return ERR_BUF; +    } + +    iphdr = 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); + +    ip_addr_set(&(iphdr->dest), dest); + +    IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); +    IPH_LEN_SET(iphdr, htons(p->tot_len)); +    IPH_OFFSET_SET(iphdr, 0); +    IPH_ID_SET(iphdr, htons(ip_id)); +    ++ip_id; + +    if (ip_addr_isany(src)) { +      ip_addr_set(&(iphdr->src), &(netif->ip_addr)); +    } else { +      ip_addr_set(&(iphdr->src), src); +    } + +    IPH_CHKSUM_SET(iphdr, 0); +#if CHECKSUM_GEN_IP +    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); +#endif +  } else { +    /* IP header already included in p */ +    iphdr = p->payload; +    dest = &(iphdr->dest); +  } + +#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_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 (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) +  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); +  } else +#endif /* (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) */ +  { +    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, struct ip_addr *src, struct ip_addr *dest, +          u8_t ttl, u8_t tos, 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, 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, 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; +  } + +  netif->addr_hint = addr_hint; +  err = ip_output_if(p, src, dest, ttl, tos, proto, netif); +  netif->addr_hint = 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 = p->payload; +  u8_t *payload; + +  payload = (u8_t *)iphdr + IP_HLEN; + +  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(&iphdr->src), +                    ip4_addr2(&iphdr->src), +                    ip4_addr3(&iphdr->src), +                    ip4_addr4(&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(&iphdr->dest), +                    ip4_addr2(&iphdr->dest), +                    ip4_addr3(&iphdr->dest), +                    ip4_addr4(&iphdr->dest))); +  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); +} +#endif /* IP_DEBUG */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c new file mode 100644 index 000000000..94bf4678a --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_addr.c @@ -0,0 +1,84 @@ +/** + * @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/inet.h" +#include "lwip/netif.h" + +#define IP_ADDR_ANY_VALUE 0x00000000UL +#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL + +/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ +const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE }; +const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE }; + +/** + * 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 ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif) +{ +  u32_t addr2test; + +  addr2test = addr->addr; +  /* all ones (broadcast) or all zeroes (old skool broadcast) */ +  if ((~addr2test == IP_ADDR_ANY_VALUE) || +      (addr2test == IP_ADDR_ANY_VALUE)) +    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 (addr2test == netif->ip_addr.addr) +    return 0; +  /*  on the same (sub) network... */ +  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask)) +         /* ...and host identifier bits are all ones? =>... */ +          && ((addr2test & ~netif->netmask.addr) == +           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr))) +    /* => network broadcast address */ +    return 1; +  else +    return 0; +} diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c new file mode 100644 index 000000000..1939d831b --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv4/ip_frag.c @@ -0,0 +1,792 @@ +/** + * @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/ip.h" +#include "lwip/inet.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 to be packed since it has to fit inside the IP header. + */ +#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) +{ +  int pbufs_freed = 0; +  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); +    pbufs_freed += pbuf_clen(p); +    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; +    pbufs_freed += pbuf_clen(pcur); +    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 = memp_malloc(MEMP_REASSDATA); +  if (ipr == NULL) { +#if IP_REASS_FREE_OLDEST +    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { +      ipr = 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 ((ntohs(IPH_OFFSET(fraghdr)) & 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)]; +#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, struct ip_addr *dest) +{ +  struct pbuf *rambuf; +#if IP_FRAG_USES_STATIC_BUF +  struct pbuf *header; +#else +  struct pbuf *newpbuf; +  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 +  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 = rambuf->payload; +  SMEMCPY(iphdr, p->payload, IP_HLEN); +#else /* IP_FRAG_USES_STATIC_BUF */ +  original_iphdr = 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 */ +    /* 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 = 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) { +      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; +      /* Is this pbuf already empty? */ +      if (!newpbuflen) { +        p = p->next; +        continue; +      } +      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF); +      if (newpbuf == NULL) { +        pbuf_free(rambuf); +        return ERR_MEM; +      } +      /* Mirror this pbuf, although we might not need all of it. */ +      newpbuf->payload = p->payload; +      newpbuf->len = newpbuf->tot_len = newpbuflen; +      /* 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 /* 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/README b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/README new file mode 100644 index 000000000..362000486 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/README @@ -0,0 +1 @@ +IPv6 support in lwIP is very experimental. diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c new file mode 100644 index 000000000..4fcc89551 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/icmp6.c @@ -0,0 +1,179 @@ +/* + * 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/inet6.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/inet6.c new file mode 100644 index 000000000..c3de85c09 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/inet6.c @@ -0,0 +1,163 @@ +/** + * @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/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6.c new file mode 100644 index 000000000..7e4342001 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6.c @@ -0,0 +1,397 @@ +/* + * 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.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; +  } + +  netif->addr_hint = addr_hint; +  err = ip_output_if(p, src, dest, ttl, tos, proto, netif); +  netif->addr_hint = 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c new file mode 100644 index 000000000..2da6cea42 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/ipv6/ip6_addr.c @@ -0,0 +1,72 @@ +/* + * 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/mem.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/mem.c new file mode 100644 index 000000000..b5f13ab3b --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/mem.c @@ -0,0 +1,633 @@ +/** + * @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 <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) +{ +  struct memp_malloc_helper *element; +  memp_t poolnr; +  mem_size_t required_size = size + sizeof(struct memp_malloc_helper); + +  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) { +#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 */ +  element++; + +  return element; +} + +/** + * 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 = (struct memp_malloc_helper*)rmem; + +  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--; + +  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[next]) of the next 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) + +/** the heap. we need one struct mem at the end and some room for alignment */ +static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; +/** 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 */ +static sys_sem_t mem_sem; + +#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_arch_sem_wait(mem_sem, 0) +#define LWIP_MEM_FREE_UNPROTECT()  sys_sem_signal(mem_sem) +/* 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_realloc() + * + * 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 *)&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 *)&ram[nmem->next])->prev = (u8_t *)mem - ram; +  } + +  /* plug hole backward */ +  pmem = (struct mem *)&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 *)&ram[mem->next])->prev = (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 = LWIP_MEM_ALIGN(ram_heap); +  /* initialize the start of the heap */ +  mem = (struct mem *)ram; +  mem->next = MEM_SIZE_ALIGNED; +  mem->prev = 0; +  mem->used = 0; +  /* initialize the end of the heap */ +  ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; +  ram_end->used = 1; +  ram_end->next = MEM_SIZE_ALIGNED; +  ram_end->prev = MEM_SIZE_ALIGNED; + +  mem_sem = sys_sem_new(1); + +  /* initialize the lowest-free pointer to the start of the heap */ +  lfree = (struct mem *)ram; + +  MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); +} + +/** + * 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 | 2, ("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 | 3, ("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 *)((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 - ((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(); +} + +/** + * In contrast to its name, mem_realloc can only shrink memory, not expand it. + * Since the only use (for now) is in pbuf_realloc (which also can only shrink), + * this shouldn't be a problem! + * + * @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_realloc(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_realloc: 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 | 3, ("mem_realloc: 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 *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); +  /* ... and its offset pointer */ +  ptr = (u8_t *)mem - ram; + +  size = mem->next - ptr - SIZEOF_STRUCT_MEM; +  LWIP_ASSERT("mem_realloc 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(); + +  MEM_STATS_DEC_USED(used, (size - newsize)); + +  mem2 = (struct mem *)&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 *)&ram[ptr2]; +    } +    mem2 = (struct mem *)&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 *)&ram[mem2->next])->prev = ptr2; +    } +    /* 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 *)&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 *)&ram[mem2->next])->prev = ptr2; +    } +    /* 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). + */ +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_arch_sem_wait(mem_sem, 0); +  LWIP_MEM_ALLOC_PROTECT(); +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +  /* run as long as a mem_free disturbed mem_malloc */ +  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. +     */ +    for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; +         ptr = ((struct mem *)&ram[ptr])->next) { +      mem = (struct mem *)&ram[ptr]; +#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +      mem_free_count = 0; +      LWIP_MEM_ALLOC_UNPROTECT(); +      /* allow mem_free to run */ +      LWIP_MEM_ALLOC_PROTECT(); +      if (mem_free_count != 0) { +        local_mem_free_count = mem_free_count; +      } +      mem_free_count = 0; +#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ + +      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 *)&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 *)&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 - ((u8_t *)mem - ram)); +        } + +        if (mem == lfree) { +          /* Find next free block after mem and update lowest free pointer */ +          while (lfree->used && lfree != ram_end) { +            LWIP_MEM_ALLOC_UNPROTECT(); +            /* prevent high interrupt latency... */ +            LWIP_MEM_ALLOC_PROTECT(); +            lfree = (struct mem *)&ram[lfree->next]; +          } +          LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); +        } +        LWIP_MEM_ALLOC_UNPROTECT(); +        sys_sem_signal(mem_sem); +        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 | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); +  MEM_STATS_INC(err); +  LWIP_MEM_ALLOC_UNPROTECT(); +  sys_sem_signal(mem_sem); +  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/firmware/usrp3/lwip/lwip-1.3.1/src/core/memp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/memp.c new file mode 100644 index 000000000..dfc32213d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/memp.c @@ -0,0 +1,386 @@ +/** + * @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.h" +#include "lwip/igmp.h" +#include "lwip/api.h" +#include "lwip/api_msg.h" +#include "lwip/tcpip.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "netif/etharp.h" +#include "lwip/ip_frag.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 */ + +/** This is the actual memory used by the pools. */ +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" +]; + +#if MEMP_SANITY_CHECK +/** + * Check that memp-lists don't form a circle + */ +static int +memp_sanity(void) +{ +  s16_t i, c; +  struct memp *m, *n; + +  for (i = 0; i < MEMP_MAX; i++) { +    for (m = memp_tab[i]; m != NULL; m = m->next) { +      c = 1; +      for (n = memp_tab[i]; n != NULL; n = n->next) { +        if (n == m && --c < 0) { +          return 0; +        } +      } +    } +  } +  return 1; +} +#endif /* MEMP_SANITY_CHECK*/ +#if MEMP_OVERFLOW_CHECK +/** + * 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_size the element size of the pool p comes from + */ +static void +memp_overflow_check_element(struct memp *p, u16_t memp_size) +{ +  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) { +      LWIP_ASSERT("detected memp underflow!", 0); +    } +  } +#endif +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 +  m = (u8_t*)p + MEMP_SIZE + memp_size; +  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { +    if (m[k] != 0xcd) { +      LWIP_ASSERT("detected memp overflow!", 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 = 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(p, memp_sizes[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 = 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]); +  } + +  memp = LWIP_MEM_ALIGN(memp_memory); +  /* for every pool: */ +  for (i = 0; i < MEMP_MAX; ++i) { +    memp_tab[i] = NULL; +    /* 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 *)((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*)((u8_t*)memp + MEMP_SIZE); +  } else { +    LWIP_DEBUGF(MEMP_DEBUG | 2, ("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 *)((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(memp, memp_sizes[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/firmware/usrp3/lwip/lwip-1.3.1/src/core/netif.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/netif.c new file mode 100644 index 000000000..c9b6b9b5e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/netif.c @@ -0,0 +1,655 @@ +/** + * @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.h" +#include "lwip/snmp.h" +#include "lwip/igmp.h" +#include "netif/etharp.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_NETIF_STATUS_CALLBACK +#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } +#else +#define NETIF_STATUS_CALLBACK(n) { /* NOP */ } +#endif /* LWIP_NETIF_STATUS_CALLBACK */  + +#if LWIP_NETIF_LINK_CALLBACK +#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); } +#else +#define NETIF_LINK_CALLBACK(n) { /* NOP */ } +#endif /* LWIP_NETIF_LINK_CALLBACK */  + +struct netif *netif_list; +struct netif *netif_default; + +/** + * 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, struct ip_addr *ipaddr, struct ip_addr *netmask, +  struct ip_addr *gw, +  void *state, +  err_t (* init)(struct netif *netif), +  err_t (* input)(struct pbuf *p, struct netif *netif)) +{ +  static u8_t netifnum = 0; + +  /* reset new interface configuration state */ +  netif->ip_addr.addr = 0; +  netif->netmask.addr = 0; +  netif->gw.addr = 0; +  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 = netifnum++; +  netif->input = input; +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +#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, struct ip_addr *ipaddr, struct ip_addr *netmask, +    struct ip_addr *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 */ + +  snmp_delete_ipaddridx_tree(netif); + +  /*  is it the first netif? */ +  if (netif_list == netif) { +    netif_list = netif->next; +    snmp_dec_iflist(); +  } +  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; +        snmp_dec_iflist(); +        break; +      } +    } +    if (tmpNetif == NULL) +      return; /*  we didn't find any netif today */ +  } +  /* this netif is default? */ +  if (netif_default == netif) +    /* reset default netif */ +    netif_set_default(NULL); +  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, struct ip_addr *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 ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) +  { +    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ +    LWIP_DEBUGF(NETIF_DEBUG | 1, ("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))) { +        /* this connection must be aborted */ +        struct tcp_pcb *next = pcb->next; +        LWIP_DEBUGF(NETIF_DEBUG | 1, ("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 | 3, ("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(&netif->ip_addr), +    ip4_addr2(&netif->ip_addr), +    ip4_addr3(&netif->ip_addr), +    ip4_addr4(&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, struct ip_addr *gw) +{ +  ip_addr_set(&(netif->gw), gw); +  LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("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(&netif->gw), +    ip4_addr2(&netif->gw), +    ip4_addr3(&netif->gw), +    ip4_addr4(&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, struct ip_addr *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 | 3, ("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(&netif->netmask), +    ip4_addr2(&netif->netmask), +    ip4_addr3(&netif->netmask), +    ip4_addr4(&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_LINK_CALLBACK(netif); +    NETIF_STATUS_CALLBACK(netif); + +#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 */ +     +  } +} + +/** + * 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 +       +      NETIF_LINK_CALLBACK(netif); +      NETIF_STATUS_CALLBACK(netif); +    } +} + +/** + * Ask if an interface is up + */  +u8_t netif_is_up(struct netif *netif) +{ +  return (netif->flags & NETIF_FLAG_UP)?1:0; +} + +#if LWIP_NETIF_STATUS_CALLBACK +/** + * Set callback to be called when interface is brought up/down + */ +void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif )) +{ +    if ( netif ) +        netif->status_callback = status_callback; +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +/** + * Called by a driver when its link goes up + */ +void netif_set_link_up(struct netif *netif ) +{ +  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 */ + +  NETIF_LINK_CALLBACK(netif); +} + +/** + * Called by a driver when its link goes down + */ +void netif_set_link_down(struct netif *netif ) +{ +  netif->flags &= ~NETIF_FLAG_LINK_UP; +  NETIF_LINK_CALLBACK(netif); +} + +/** + * Ask if a link is up + */  +u8_t netif_is_link_up(struct netif *netif) +{ +  return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0; +} + +/** + * Set callback to be called when link is brought up/down + */ +void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif )) +{ +  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, +       struct ip_addr *ipaddr) +{ +  struct pbuf *r; +  err_t err; +  struct pbuf *last; +#if LWIP_LOOPBACK_MAX_PBUFS +  u8_t clen = 0; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +  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) { +    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); +      r = NULL; +      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); +    r = NULL; +    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); + +#if LWIP_NETIF_LOOPBACK_MULTITHREADING +  /* For multithreading environment, schedule a call to netif_poll */ +  tcpip_callback((void (*)(void *))(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; +  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) { +      /* 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/pbuf.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/pbuf.c new file mode 100644 index 000000000..50b22c354 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/pbuf.c @@ -0,0 +1,895 @@ +/** + * @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 TCP_QUEUE_OOSEQ +#include "lwip/tcp.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 TCP_QUEUE_OOSEQ +#define ALLOC_POOL_PBUF(p) do { (p) = alloc_pool_pbuf(); } while (0) +#else +#define ALLOC_POOL_PBUF(p) do { (p) = memp_malloc(MEMP_PBUF_POOL); } while (0) +#endif + + +#if TCP_QUEUE_OOSEQ +/** + * 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. + * + * @return the allocated pbuf. + */ +static struct pbuf * +alloc_pool_pbuf(void) +{ +  struct tcp_pcb *pcb; +  struct pbuf *p; + +retry: +  p = memp_malloc(MEMP_PBUF_POOL); +  if (NULL == p) { +    for (pcb=tcp_active_pcbs; NULL != pcb; pcb = pcb->next) { +      if (NULL != pcb->ooseq) { +        tcp_segs_free(pcb->ooseq); +        pcb->ooseq = NULL; +        goto retry; +      } +    } +  } +  return p; +} +#endif /* TCP_QUEUE_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 | 3, ("pbuf_alloc(length=%"U16_F")\n", length)); + +  /* determine header offset */ +  offset = 0; +  switch (layer) { +  case PBUF_TRANSPORT: +    /* add room for transport (often TCP) layer header */ +    offset += PBUF_TRANSPORT_HLEN; +    /* FALLTHROUGH */ +  case PBUF_IP: +    /* add room for IP layer header */ +    offset += PBUF_IP_HLEN; +    /* FALLTHROUGH */ +  case PBUF_LINK: +    /* add room for link layer header */ +    offset += PBUF_LINK_HLEN; +    break; +  case PBUF_RAW: +    break; +  default: +    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0); +    return NULL; +  } + +  switch (type) { +  case PBUF_POOL: +    /* allocate head of pbuf chain into p */ +    ALLOC_POOL_PBUF(p); +    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); +    if (p == NULL) { +      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) { +      ALLOC_POOL_PBUF(q); +      if (q == NULL) { +        /* 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 = memp_malloc(MEMP_PBUF); +    if (p == NULL) { +      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("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 | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p)); +  return p; +} + + +/** + * 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 = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); +    LWIP_ASSERT("mem_realloc give 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 | 2, ("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, ("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_TRACE | 2, ("pbuf_free(p == NULL) was called.\n")); +    return 0; +  } +  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("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 | 2, ("pbuf_free: deallocating %p\n", (void *)p)); +      type = p->type; +      /* 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 | 2, ("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_FRESH | 2, ("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_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q)); +    tail_gone = pbuf_free(q); +    if (tail_gone > 0) { +      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, +                  ("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 | 3, ("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 +  { +    LWIP_ASSERT("p_to != NULL", p_to != NULL); +    /* 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); +    if (offset_to == p_to->len) { +      /* on to next p_to (if any) */ +      offset_to = 0; +      p_to = p_to->next; +    } +    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((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 | 1, ("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: The source pbuf 'p' is not freed by this function because that can + *          be illegal in some places! + * + * @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; +} diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/raw.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/raw.c new file mode 100644 index 000000000..589950e75 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/raw.c @@ -0,0 +1,353 @@ +/** + * @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/inet.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/raw.h" +#include "lwip/stats.h" +#include "lwip/snmp.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 = 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) { +#if IP_SOF_BROADCAST_RECV +      /* broadcast filter? */ +      if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(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, &(iphdr->src)) != 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, struct ip_addr *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, struct ip_addr *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, +         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, +                      struct ip_addr *addr), +         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, struct ip_addr *ipaddr) +{ +  err_t err; +  struct netif *netif; +  struct ip_addr *src_ip; +  struct pbuf *q; /* q will be sent down the stack */ +   +  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("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 | 2, ("raw_sendto: could not allocate header\n")); +      return ERR_MEM; +    } +    /* 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 | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); +    /* 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 ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) { +    LWIP_DEBUGF(RAW_DEBUG | 1, ("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); +  } + +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif); +#if LWIP_NETIF_HWADDRHINT +  netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ + +  /* 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 | 3, ("raw_new\n")); + +  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/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c new file mode 100644 index 000000000..650fb4037 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_dec.c @@ -0,0 +1,657 @@ +/** + * @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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 = 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c new file mode 100644 index 000000000..77af6b4ba --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/asn1_enc.c @@ -0,0 +1,611 @@ +/** + * @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 = 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 = p->payload; +      msg_ptr += ofs - base; + +      if (length < 0x80) +      { +        *msg_ptr = 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 = p->payload; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +        *msg_ptr = 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 = p->payload; +            plen += p->len; +          } +          else +          { +            /* next octet in same pbuf */ +            msg_ptr++; +          } +          if (i == 0) +          { +            /* least significant length octet */ +            *msg_ptr = length; +          } +          else +          { +            /* most significant length octet */ +            *msg_ptr = 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, u8_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 = 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 = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      while (octets_needed > 1) +      { +        octets_needed--; +        *msg_ptr = 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 = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      /* (only) one least significant octet */ +      *msg_ptr = 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, u8_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 = p->payload; +      msg_ptr += ofs - base; + +      while (octets_needed > 1) +      { +        octets_needed--; +        *msg_ptr = 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 = p->payload; +          plen += p->len; +        } +        else +        { +          /* next octet in same pbuf */ +          msg_ptr++; +        } +      } +      /* (only) one least significant octet */ +      *msg_ptr = 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 = 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 = (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 = 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 = 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 = 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 = 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, u8_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 = 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 = 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib2.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib2.c new file mode 100644 index 000000000..33eeee66c --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib2.c @@ -0,0 +1,4126 @@ +/** + * @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/tcp.h" +#include "lwip/udp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_structs.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) +#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* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, +  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&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* const)&udp_root, (struct mib_node* const)&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* const)&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* const)&udp_scalar, (struct mib_node* const)&udp_scalar, +  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar, +  (struct mib_node* const)&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* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, +  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, +  (struct mib_node* const)&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* const)&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* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar, +  (struct mib_node* const)&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* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, +  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&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* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root, +  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&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* const)&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* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, +  (struct mib_node* const)&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* const)&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* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&ipaddrtree_root, +  (struct mib_node* const)&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* const)&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* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, +  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable, +  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable, +  (struct mib_node* const)&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* const)&arptree_root, +  (struct mib_node* const)&arptree_root, +  (struct mib_node* const)&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* const)&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* const)&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* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, +  (struct mib_node* const)&iflist_root, (struct mib_node* const)&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* const)&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* const)&interfaces_scalar, (struct mib_node* const)&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* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, +  (struct mib_node* const)&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* const)&sys_tem, +  (struct mib_node* const)&interfaces, +  (struct mib_node* const)&at, +  (struct mib_node* const)&mib2_ip, +  (struct mib_node* const)&icmp, +#if LWIP_TCP +  (struct mib_node* const)&tcp, +#endif +  (struct mib_node* const)&udp, +  (struct mib_node* const)&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* const)&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 +s32_t internet_ids[2] = { 2, 4 }; +struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&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* const)&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. + */ +void ocstrncpy(u8_t *dst, u8_t *src, u8_t n) +{ +  while (n > 0) +  { +    n--; +    *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) +{ +  while(n > 0) +  { +    n--; +    *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, struct ip_addr *ip) +{ +  struct mib_list_rootnode *at_rn; +  struct mib_list_node *at_node; +  struct ip_addr hip; +  s32_t arpidx[5]; +  u8_t level, tree; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  snmp_netiftoifindex(ni, &arpidx[0]); +  hip.addr = ntohl(ip->addr); +  snmp_iptooid(&hip, &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, struct ip_addr *ip) +{ +  struct mib_list_rootnode *at_rn, *next, *del_rn[5]; +  struct mib_list_node *at_n, *del_n[5]; +  struct ip_addr hip; +  s32_t arpidx[5]; +  u8_t fc, tree, level, del_cnt; + +  snmp_netiftoifindex(ni, &arpidx[0]); +  hip.addr = ntohl(ip->addr); +  snmp_iptooid(&hip, &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; +  struct ip_addr ip; +  s32_t ipaddridx[4]; +  u8_t level; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  ip.addr = ntohl(ni->ip_addr.addr); +  snmp_iptooid(&ip, &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]; +  struct ip_addr ip; +  s32_t ipaddridx[4]; +  u8_t fc, level, del_cnt; + +  LWIP_ASSERT("ni != NULL", ni != NULL); +  ip.addr = ntohl(ni->ip_addr.addr); +  snmp_iptooid(&ip, &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; +  struct ip_addr dst; + +  if (dflt != 0) +  { +    /* the default route 0.0.0.0 */ +    dst.addr = 0; +    insert = 1; +  } +  else +  { +    /* route to the network address */ +    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); +    /* exclude 0.0.0.0 network (reserved for default rte) */ +    if (dst.addr != 0) 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 delete = 0; +  struct ip_addr dst; + +  if (dflt != 0) +  { +    /* the default route 0.0.0.0 */ +    dst.addr = 0; +    delete = 1; +  } +  else +  { +    /* route to the network address */ +    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); +    /* exclude 0.0.0.0 network (reserved for default rte) */ +    if (dst.addr != 0) delete = 1; +  } +  if (delete) +  { +    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; +  struct ip_addr ip; +  s32_t udpidx[5]; +  u8_t level; + +  LWIP_ASSERT("pcb != NULL", pcb != NULL); +  ip.addr = ntohl(pcb->local_ip.addr); +  snmp_iptooid(&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 mib_list_rootnode *udp_rn, *next, *del_rn[5]; +  struct mib_list_node *udp_n, *del_n[5]; +  struct ip_addr ip; +  s32_t udpidx[5]; +  u8_t bindings, fc, level, del_cnt; + +  LWIP_ASSERT("pcb != NULL", pcb != NULL); +  ip.addr = ntohl(pcb->local_ip.addr); +  snmp_iptooid(&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; +  pcb = udp_pcbs; +  while ((pcb != NULL)) +  { +    if ((pcb->local_ip.addr == ip.addr) && +        (pcb->local_port == udpidx[4])) +    { +      bindings++; +    } +    pcb = pcb->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) +{ +  if (ident_len){} +  if (ident){} +  od->instance = MIB_OBJECT_NONE; +} + +void +noleafs_get_value(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (value){} +} + +u8_t +noleafs_set_test(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (value){} +  /* can't set */ +  return 0; +} + +void +noleafs_set_value(struct obj_def *od, u16_t len, void *value) +{ +  if (od){} +  if (len){} +  if (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; + +    id = 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; + +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* sysDescr */ +      ocstrncpy(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(value); +      } +      break; +    case 4: /* sysContact */ +      ocstrncpy(value,syscontact_ptr,len); +      break; +    case 5: /* sysName */ +      ocstrncpy(value,sysname_ptr,len); +      break; +    case 6: /* sysLocation */ +      ocstrncpy(value,syslocation_ptr,len); +      break; +    case 7: /* sysServices */ +      { +        s32_t *sint_ptr = 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; + +  if (value) {} +  set_ok = 0; +  id = 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; + +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 4: /* sysContact */ +      ocstrncpy(syscontact_ptr,value,len); +      *syscontact_len_ptr = len; +      break; +    case 5: /* sysName */ +      ocstrncpy(sysname_ptr,value,len); +      *sysname_len_ptr = len; +      break; +    case 6: /* sysLocation */ +      ocstrncpy(syslocation_ptr,value,len); +      *syslocation_len_ptr = 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) +{ +  if (len){} +  if (od->id_inst_ptr[0] == 1) +  { +    s32_t *sint_ptr = 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; + +    id = 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); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* ifIndex */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = od->id_inst_ptr[1]; +      } +      break; +    case 2: /* ifDescr */ +      ocstrncpy(value,(u8_t*)netif->name,len); +      break; +    case 3: /* ifType */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = netif->link_type; +      } +      break; +    case 4: /* ifMtu */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = netif->mtu; +      } +      break; +    case 5: /* ifSpeed */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->link_speed; +      } +      break; +    case 6: /* ifPhysAddress */ +      ocstrncpy(value,netif->hwaddr,len); +      break; +    case 7: /* ifAdminStatus */ +#if LWIP_NETIF_LINK_CALLBACK +      { +        s32_t *sint_ptr = 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; +#endif +    case 8: /* ifOperStatus */ +      { +        s32_t *sint_ptr = value; +        if (netif_is_up(netif)) +        { +          *sint_ptr = 1; +        } +        else +        { +          *sint_ptr = 2; +        } +      } +      break; +    case 9: /* ifLastChange */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ts; +      } +      break; +    case 10: /* ifInOctets */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinoctets; +      } +      break; +    case 11: /* ifInUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinucastpkts; +      } +      break; +    case 12: /* ifInNUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifinnucastpkts; +      } +      break; +    case 13: /* ifInDiscarts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifindiscards; +      } +      break; +    case 14: /* ifInErrors */ +    case 15: /* ifInUnkownProtos */ +      /** @todo add these counters! */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = 0; +      } +      break; +    case 16: /* ifOutOctets */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutoctets; +      } +      break; +    case 17: /* ifOutUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutucastpkts; +      } +      break; +    case 18: /* ifOutNUcastPkts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutnucastpkts; +      } +      break; +    case 19: /* ifOutDiscarts */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = netif->ifoutdiscards; +      } +      break; +    case 20: /* ifOutErrors */ +       /** @todo add this counter! */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = 0; +      } +      break; +    case 21: /* ifOutQLen */ +      /** @todo figure out if this must be 0 (no queue) or 1? */ +      { +        u32_t *uint_ptr = 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; + +  set_ok = 0; +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 7: /* ifAdminStatus */ +      { +        s32_t *sint_ptr = 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; + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 7: /* ifAdminStatus */ +      { +        s32_t *sint_ptr = 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; +  struct ip_addr* ipaddr_ret; +#endif /* LWIP_ARP */ +  struct ip_addr ip; +  struct netif *netif; + +  if (len) {} + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  snmp_oidtoip(&od->id_inst_ptr[2], &ip); +  ip.addr = htonl(ip.addr); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ +  if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* atIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = od->id_inst_ptr[1]; +        } +        break; +      case 2: /* atPhysAddress */ +        { +          struct eth_addr *dst = value; + +          *dst = *ethaddr_ret; +        } +        break; +      case 3: /* atNetAddress */ +        { +          struct ip_addr *dst = 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; + +    id = 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; + +  if (len) {} +  id = od->id_inst_ptr[0]; +  switch (id) +  { +    case 1: /* ipForwarding */ +      { +        s32_t *sint_ptr = value; +#if IP_FORWARD +        /* forwarding */ +        *sint_ptr = 1; +#else +        /* not-forwarding */ +        *sint_ptr = 2; +#endif +      } +      break; +    case 2: /* ipDefaultTTL */ +      { +        s32_t *sint_ptr = value; +        *sint_ptr = IP_DEFAULT_TTL; +      } +      break; +    case 3: /* ipInReceives */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinreceives; +      } +      break; +    case 4: /* ipInHdrErrors */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinhdrerrors; +      } +      break; +    case 5: /* ipInAddrErrors */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinaddrerrors; +      } +      break; +    case 6: /* ipForwDatagrams */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipforwdatagrams; +      } +      break; +    case 7: /* ipInUnknownProtos */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipinunknownprotos; +      } +      break; +    case 8: /* ipInDiscards */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipindiscards; +      } +      break; +    case 9: /* ipInDelivers */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipindelivers; +      } +      break; +    case 10: /* ipOutRequests */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutrequests; +      } +      break; +    case 11: /* ipOutDiscards */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutdiscards; +      } +      break; +    case 12: /* ipOutNoRoutes */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipoutnoroutes; +      } +      break; +    case 13: /* ipReasmTimeout */ +      { +        s32_t *sint_ptr = value; +#if IP_REASSEMBLY +        *sint_ptr = IP_REASS_MAXAGE; +#else +        *sint_ptr = 0; +#endif +      } +      break; +    case 14: /* ipReasmReqds */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmreqds; +      } +      break; +    case 15: /* ipReasmOKs */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmoks; +      } +      break; +    case 16: /* ipReasmFails */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipreasmfails; +      } +      break; +    case 17: /* ipFragOKs */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragoks; +      } +      break; +    case 18: /* ipFragFails */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragfails; +      } +      break; +    case 19: /* ipFragCreates */ +      { +        u32_t *uint_ptr = value; +        *uint_ptr = ipfragcreates; +      } +      break; +    case 23: /* ipRoutingDiscards */ +      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ +      { +        u32_t *uint_ptr = 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 = value; + +  if (len) {} +  set_ok = 0; +  id = 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; + +    id = 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; +  struct ip_addr ip; +  struct netif *netif = netif_list; + +  if (len) {} +  snmp_oidtoip(&od->id_inst_ptr[1], &ip); +  ip.addr = htonl(ip.addr); +  ifidx = 0; +  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) +  { +    netif = netif->next; +    ifidx++; +  } + +  if (netif != NULL) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* ipAdEntAddr */ +        { +          struct ip_addr *dst = value; +          *dst = netif->ip_addr; +        } +        break; +      case 2: /* ipAdEntIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = ifidx + 1; +        } +        break; +      case 3: /* ipAdEntNetMask */ +        { +          struct ip_addr *dst = value; +          *dst = netif->netmask; +        } +        break; +      case 4: /* ipAdEntBcastAddr */ +        { +          s32_t *sint_ptr = value; + +          /* lwIP oddity, there's no broadcast +            address in the netif we can rely on */ +          *sint_ptr = ip_addr_broadcast.addr & 1; +        } +        break; +      case 5: /* ipAdEntReasmMaxSize */ +        { +          s32_t *sint_ptr = 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; + +    id = 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; +  struct ip_addr dest; +  s32_t *ident; +  u8_t id; + +  ident = od->id_inst_ptr; +  snmp_oidtoip(&ident[1], &dest); +  dest.addr = htonl(dest.addr); + +  if (dest.addr == 0) +  { +    /* 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) +  { +    id = ident[0]; +    switch (id) +    { +      case 1: /* ipRouteDest */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte has 0.0.0.0 dest */ +            dst->addr = 0; +          } +          else +          { +            /* netifs have netaddress dest */ +            dst->addr = netif->ip_addr.addr & netif->netmask.addr; +          } +        } +        break; +      case 2: /* ipRouteIfIndex */ +        { +          s32_t *sint_ptr = value; + +          snmp_netiftoifindex(netif, sint_ptr); +        } +        break; +      case 3: /* ipRouteMetric1 */ +        { +          s32_t *sint_ptr = value; + +          if (dest.addr == 0) +          { +            /* 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 = value; +          /* not used */ +          *sint_ptr = -1; +        } +        break; +      case 7: /* ipRouteNextHop */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte: gateway */ +            *dst = netif->gw; +          } +          else +          { +            /* other rtes: netif ip_addr  */ +            *dst = netif->ip_addr; +          } +        } +        break; +      case 8: /* ipRouteType */ +        { +          s32_t *sint_ptr = value; + +          if (dest.addr == 0) +          { +            /* default rte is indirect */ +            *sint_ptr = 4; +          } +          else +          { +            /* other rtes are direct */ +            *sint_ptr = 3; +          } +        } +        break; +      case 9: /* ipRouteProto */ +        { +          s32_t *sint_ptr = value; +          /* locally defined routes */ +          *sint_ptr = 2; +        } +        break; +      case 10: /* ipRouteAge */ +        { +          s32_t *sint_ptr = value; +          /** @todo (sysuptime - timestamp last change) / 100 +              @see snmp_insert_iprteidx_tree() */ +          *sint_ptr = 0; +        } +        break; +      case 11: /* ipRouteMask */ +        { +          struct ip_addr *dst = value; + +          if (dest.addr == 0) +          { +            /* default rte use 0.0.0.0 mask */ +            dst->addr = 0; +          } +          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; + +    id = 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; +  struct ip_addr* ipaddr_ret; +#endif /* LWIP_ARP */ +  struct ip_addr ip; +  struct netif *netif; + +  if (len) {} + +  snmp_ifindextonetif(od->id_inst_ptr[1], &netif); +  snmp_oidtoip(&od->id_inst_ptr[2], &ip); +  ip.addr = htonl(ip.addr); + +#if LWIP_ARP /** @todo implement a netif_find_addr */ +  if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* ipNetToMediaIfIndex */ +        { +          s32_t *sint_ptr = value; +          *sint_ptr = od->id_inst_ptr[1]; +        } +        break; +      case 2: /* ipNetToMediaPhysAddress */ +        { +          struct eth_addr *dst = value; + +          *dst = *ethaddr_ret; +        } +        break; +      case 3: /* ipNetToMediaNetAddress */ +        { +          struct ip_addr *dst = value; + +          *dst = *ipaddr_ret; +        } +        break; +      case 4: /* ipNetToMediaType */ +        { +          s32_t *sint_ptr = 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 = value; +  u8_t id; + +  if (len){} +  id = 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; + +    id = 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 = value; +  s32_t *sint_ptr = value; +  u8_t id; + +  if (len){} +  id = 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) +{ +  struct ip_addr lip, rip; +  u16_t lport, rport; +  s32_t *ident; + +  ident = od->id_inst_ptr; +  snmp_oidtoip(&ident[1], &lip); +  lip.addr = htonl(lip.addr); +  lport = ident[5]; +  snmp_oidtoip(&ident[6], &rip); +  rip.addr = htonl(rip.addr); +  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 = value; +  u8_t id; + +  if (len){} +  id = 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; +  struct ip_addr ip; +  u16_t port; + +  if (len){} +  snmp_oidtoip(&od->id_inst_ptr[1], &ip); +  ip.addr = htonl(ip.addr); +  port = od->id_inst_ptr[5]; + +  pcb = udp_pcbs; +  while ((pcb != NULL) && +         !((pcb->local_ip.addr == ip.addr) && +           (pcb->local_port == port))) +  { +    pcb = pcb->next; +  } + +  if (pcb != NULL) +  { +    id = od->id_inst_ptr[0]; +    switch (id) +    { +      case 1: /* udpLocalAddress */ +        { +          struct ip_addr *dst = value; +          *dst = pcb->local_ip; +        } +        break; +      case 2: /* udpLocalPort */ +        { +          s32_t *sint_ptr = 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; + +    id = 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 = value; +  u8_t id; + +  if (len){} +  id = 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; + +  if (len) {} +  set_ok = 0; +  id = od->id_inst_ptr[0]; +  if (id == 30) +  { +    /* snmpEnableAuthenTraps */ +    s32_t *sint_ptr = 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; + +  if (len) {} +  id = od->id_inst_ptr[0]; +  if (id == 30) +  { +    /* snmpEnableAuthenTraps */ +    s32_t *sint_ptr = value; +    *snmpenableauthentraps_ptr = *sint_ptr; +  } +} + +#endif /* LWIP_SNMP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c new file mode 100644 index 000000000..af8994ed2 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/mib_structs.c @@ -0,0 +1,1183 @@ +/** + * @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/mem.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; +  u16_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 != 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, struct ip_addr *ip) +{ +  u32_t ipa; + +  ipa = ident[0]; +  ipa <<= 8; +  ipa |= ident[1]; +  ipa <<= 8; +  ipa |= ident[2]; +  ipa <<= 8; +  ipa |= ident[3]; +  ip->addr = ipa; +} + +/** + * 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(struct ip_addr *ip, s32_t *ident) +{ +  u32_t ipa; + +  ipa = ip->addr; +  ident[0] = (ipa >> 24) & 0xff; +  ident[1] = (ipa >> 16) & 0xff; +  ident[2] = (ipa >> 8) & 0xff; +  ident[3] = ipa & 0xff; +} + +struct mib_list_node * +snmp_mib_ln_alloc(s32_t id) +{ +  struct mib_list_node *ln; + +  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_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) +{ +  mem_free(ln); +} + +struct mib_list_rootnode * +snmp_mib_lrn_alloc(void) +{ +  struct mib_list_rootnode *lrn; + +  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_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) +{ +  mem_free(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 (rerurn) + * @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 */ +            j = 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 */ +            j = 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_in.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_in.c new file mode 100644 index 000000000..d0c3c7534 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_in.c @@ -0,0 +1,1454 @@ +/** + * @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/ip_addr.h" +#include "lwip/mem.h" +#include "lwip/udp.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/snmp_asn1.h" +#include "lwip/snmp_msg.h" +#include "lwip/snmp_structs.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, struct ip_addr *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; +  /* 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) +{ +  snmp_varbind_list_free(&msg_ps->outvb); +  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; +  msg_ps->error_index = 1 + msg_ps->vb_idx; +  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->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 *)mem_malloc(sizeof(struct snmp_varbind)); +    LWIP_ASSERT("vb != NULL",vb != NULL); +    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; +      vb->value_len =  msg_ps->ext_object_def.v_len; +      if (vb->value_len > 0) +      { +        vb->value = mem_malloc(vb->value_len); +        LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +        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; +          mem_free(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) +          { +            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 *)mem_malloc(sizeof(struct snmp_varbind)); +            LWIP_ASSERT("vb != NULL",vb != NULL); +            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; +              vb->value_len = object_def.v_len; +              if (vb->value_len > 0) +              { +                vb->value = mem_malloc(vb->value_len); +                LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +                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; +                  mem_free(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; + +    vb = snmp_varbind_alloc(&msg_ps->ext_oid, +                            msg_ps->ext_object_def.asn_type, +                            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); + +        vb = snmp_varbind_alloc(&oid, object_def.asn_type, 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_OBJECT_READ_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_OBJECT_READ_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, struct ip_addr *addr, u16_t port) +{ +  struct udp_hdr *udphdr; + +  /* suppress unused argument warning */ +  LWIP_UNUSED_ARG(arg); +  /* peek in the UDP header (goto IP payload) */ +  if(pbuf_header(p, UDP_HLEN)){ +    LWIP_ASSERT("Can't move to UDP header", 0); +    pbuf_free(p); +    return; +  } +  udphdr = p->payload; + +  /* check if datagram is really directed at us (including broadcast requests) */ +  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT)) +  { +    struct snmp_msg_pstat *msg_ps; +    u8_t req_idx; + +    /* 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) +    { +      err_t err_ret; +      u16_t payload_len; +      u16_t payload_ofs; +      u16_t varbind_ofs = 0; + +      /* 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; +      /* read UDP payload length from UDP header */ +      payload_len = ntohs(udphdr->len) - UDP_HLEN; + +      /* adjust to UDP payload */ +      payload_ofs = UDP_HLEN; + +      /* check total length, version, community, pdu type */ +      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); +      if (((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)) ) +      { +        /* Only accept requests and requests without error (be robust) */ +        err_ret = err_ret; +      } +      else +      { +        /* Reject response and trap headers or error requests as input! */ +        err_ret = ERR_ARG; +      } +      if (err_ret == ERR_OK) +      { +        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); +        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0)) +        { +          /* we've decoded the incoming message, release input msg now */ +          pbuf_free(p); + +          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); +        } +        else +        { +          /* varbind-list decode failed, or varbind list empty. +             drop request silently, do not return error! +             (errors are only returned for a specific varbind failure) */ +          pbuf_free(p); +          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); +        } +      } +      else +      { +        /* header check failed +           drop request silently, do not return error! */ +        pbuf_free(p); +        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); +      } +    } +    else +    { +      /* exceeding number of concurrent requests */ +      pbuf_free(p); +    } +  } +  else +  { +    /* datagram not for us */ +    pbuf_free(p); +  } +} + +/** + * 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 = 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 = 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 = 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): +        vb = snmp_varbind_alloc(&oid, type, len); +        if (vb != NULL) +        { +          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, 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 = 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, 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 *)mem_malloc(sizeof(struct snmp_varbind)); +  LWIP_ASSERT("vb != NULL",vb != NULL); +  if (vb != NULL) +  { +    u8_t i; + +    vb->next = NULL; +    vb->prev = NULL; +    i = oid->len; +    vb->ident_len = i; +    if (i > 0) +    { +      /* allocate array of s32_t for our object identifier */ +      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i); +      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL); +      if (vb->ident == NULL) +      { +        mem_free(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) +    { +      /* allocate raw bytes for our object value */ +      vb->value = mem_malloc(len); +      LWIP_ASSERT("vb->value != NULL",vb->value != NULL); +      if (vb->value == NULL) +      { +        if (vb->ident != NULL) +        { +          mem_free(vb->ident); +        } +        mem_free(vb); +        return NULL; +      } +    } +    else +    { +      /* ASN1_NUL type, or zero length ASN1_OC_STR */ +      vb->value = NULL; +    } +  } +  return vb; +} + +void +snmp_varbind_free(struct snmp_varbind *vb) +{ +  if (vb->value != NULL ) +  { +    mem_free(vb->value); +  } +  if (vb->ident != NULL ) +  { +    mem_free(vb->ident); +  } +  mem_free(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/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_out.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_out.c new file mode 100644 index 000000000..b705aaca7 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/snmp/msg_out.c @@ -0,0 +1,683 @@ +/** + * @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 */ +  struct ip_addr 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, struct ip_addr *dst) +{ +  if (dst_idx < SNMP_TRAP_DESTINATIONS) +  { +    trap_dst[dst_idx].dip.addr = htonl(dst->addr); +  } +} + +/** + * 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); +    if (m_stat->error_status == SNMP_ES_TOOBIG) +    { +      snmp_varbind_list_enc(&emptyvb, p, ofs); +    } +    else +    { +      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; +  struct ip_addr 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) && (td->dip.addr != 0)) +    { +      /* network order trap destination */ +      trap_msg.dip.addr = td->dip.addr; +      /* lookup current source address for this dst */ +      dst_if = ip_route(&td->dip); +      dst_ip.addr = ntohl(dst_if->ip_addr.addr); +      trap_msg.sip_raw[0] = dst_ip.addr >> 24; +      trap_msg.sip_raw[1] = dst_ip.addr >> 16; +      trap_msg.sip_raw[2] = dst_ip.addr >> 8; +      trap_msg.sip_raw[3] = dst_ip.addr; +      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(); + +        /** connect to the TRAP destination */ +        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT); +        udp_send(trap_msg.pcb, p); +        /** disassociate remote address and port with this pcb */ +        udp_disconnect(trap_msg.pcb); + +        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 = 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 = 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 = 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 = 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 = 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 = 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 = 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/stats.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/stats.c new file mode 100644 index 000000000..a036d83bb --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/stats.c @@ -0,0 +1,149 @@ +/** + * @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; + +#if LWIP_STATS_DISPLAY +void +stats_display_proto(struct stats_proto *proto, 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(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));  +  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));  +  LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));  +  LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));  +  LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));  +  LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));  +  LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));  +  LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));  +  LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed)); +} +#endif /* IGMP_STATS */ + +#if MEM_STATS || MEMP_STATS +void +stats_display_mem(struct stats_mem *mem, 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(("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/firmware/usrp3/lwip/lwip-1.3.1/src/core/sys.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/sys.c new file mode 100644 index 000000000..d1fbda4e6 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/sys.c @@ -0,0 +1,344 @@ +/** + * @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" + +#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/tcpip.h" + +/** + * Struct used for sys_sem_wait_timeout() to tell wether the time + * has run out or the semaphore has really become available. + */ +struct sswt_cb +{ +  s16_t timeflag; +  sys_sem_t *psem; +}; + +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts (for this thread) are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +void +sys_mbox_fetch(sys_mbox_t mbox, void **msg) +{ +  u32_t time_needed; +  struct sys_timeouts *timeouts; +  struct sys_timeo *tmptimeout; +  sys_timeout_handler h; +  void *arg; + + again: +  timeouts = sys_arch_timeouts(); + +  if (!timeouts || !timeouts->next) { +    UNLOCK_TCPIP_CORE(); +    time_needed = sys_arch_mbox_fetch(mbox, msg, 0); +    LOCK_TCPIP_CORE(); +  } else { +    if (timeouts->next->time > 0) { +      UNLOCK_TCPIP_CORE(); +      time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); +      LOCK_TCPIP_CORE(); +    } 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 = timeouts->next; +      timeouts->next = tmptimeout->next; +      h   = tmptimeout->h; +      arg = tmptimeout->arg; +      memp_free(MEMP_SYS_TIMEOUT, tmptimeout); +      if (h != NULL) { +        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg)); +        h(arg); +      } + +      /* 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 < timeouts->next->time) { +        timeouts->next->time -= time_needed; +      } else { +        timeouts->next->time = 0; +      } +    } +  } +} + +/** + * Wait (forever) for a semaphore to become available. + * While waiting, timeouts (for this thread) are processed. + * + * @param sem semaphore to wait for + */ +void +sys_sem_wait(sys_sem_t sem) +{ +  u32_t time_needed; +  struct sys_timeouts *timeouts; +  struct sys_timeo *tmptimeout; +  sys_timeout_handler h; +  void *arg; + + again: + +  timeouts = sys_arch_timeouts(); + +  if (!timeouts || !timeouts->next) { +    sys_arch_sem_wait(sem, 0); +  } else { +    if (timeouts->next->time > 0) { +      time_needed = sys_arch_sem_wait(sem, timeouts->next->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 = timeouts->next; +      timeouts->next = tmptimeout->next; +      h = tmptimeout->h; +      arg = tmptimeout->arg; +      memp_free(MEMP_SYS_TIMEOUT, tmptimeout); +      if (h != NULL) { +        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg)); +        h(arg); +      } + +      /* 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 < timeouts->next->time) { +        timeouts->next->time -= time_needed; +      } else { +        timeouts->next->time = 0; +      } +    } +  } +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_mbox_fetch() + * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout() + * - while sleeping using the inbuilt sys_msleep() + * + * @param msecs time in milliseconds after that the timer should expire + * @param h callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +void +sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) +{ +  struct sys_timeouts *timeouts; +  struct sys_timeo *timeout, *t; + +  timeout = memp_malloc(MEMP_SYS_TIMEOUT); +  if (timeout == NULL) { +    LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL); +    return; +  } +  timeout->next = NULL; +  timeout->h = h; +  timeout->arg = arg; +  timeout->time = msecs; + +  timeouts = sys_arch_timeouts(); + +  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n", +    (void *)timeout, msecs, (void*)&h, (void *)arg)); + +  if (timeouts == NULL) { +    LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL); +    return; +  } + +  if (timeouts->next == NULL) { +    timeouts->next = timeout; +    return; +  } + +  if (timeouts->next->time > msecs) { +    timeouts->next->time -= msecs; +    timeout->next = timeouts->next; +    timeouts->next = timeout; +  } else { +    for(t = timeouts->next; 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 'h' in the list of timeouts. + * + * @param h callback function that would be called by the timeout + * @param arg callback argument that would be passed to h +*/ +void +sys_untimeout(sys_timeout_handler h, void *arg) +{ +  struct sys_timeouts *timeouts; +  struct sys_timeo *prev_t, *t; + +  timeouts = sys_arch_timeouts(); + +  if (timeouts == NULL) { +    LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL); +    return; +  } +  if (timeouts->next == NULL) { +    return; +  } + +  for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { +    if ((t->h == h) && (t->arg == arg)) { +      /* We have a match */ +      /* Unlink from previous in list */ +      if (prev_t == NULL) +        timeouts->next = 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; +} + +/** + * Timeout handler function for sys_sem_wait_timeout() + * + * @param arg struct sswt_cb* used to signal a semaphore and end waiting. + */ +static void +sswt_handler(void *arg) +{ +  struct sswt_cb *sswt_cb = (struct sswt_cb *) arg; + +  /* Timeout. Set flag to TRUE and signal semaphore */ +  sswt_cb->timeflag = 1; +  sys_sem_signal(*(sswt_cb->psem)); +} + +/** + * Wait for a semaphore with timeout (specified in ms) + * + * @param sem semaphore to wait + * @param timeout timeout in ms (0: wait forever) + * @return 0 on timeout, 1 otherwise + */ +int +sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) +{ +  struct sswt_cb sswt_cb; + +  sswt_cb.psem = &sem; +  sswt_cb.timeflag = 0; + +  /* If timeout is zero, then just wait forever */ +  if (timeout > 0) { +    /* Create a timer and pass it the address of our flag */ +    sys_timeout(timeout, sswt_handler, &sswt_cb); +  } +  sys_sem_wait(sem); +  /* Was it a timeout? */ +  if (sswt_cb.timeflag) { +    /* timeout */ +    return 0; +  } else { +    /* Not a timeout. Remove timeout entry */ +    sys_untimeout(sswt_handler, &sswt_cb); +    return 1; +  } +} + +/** + * Sleep for some ms. Timeouts are processed while sleeping. + * + * @param ms number of milliseconds to sleep + */ +void +sys_msleep(u32_t ms) +{ +  sys_sem_t delaysem = sys_sem_new(0); + +  sys_sem_wait_timeout(delaysem, ms); + +  sys_sem_free(delaysem); +} + + +#endif /* NO_SYS */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp.c new file mode 100644 index 000000000..0f3fd41c3 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp.c @@ -0,0 +1,1458 @@ +/** + * @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/debug.h" + +#include <string.h> + +/* 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; + +struct tcp_pcb *tcp_tmp_pcb; + +static u8_t tcp_timer; +static u16_t tcp_new_port(void); + +/** + * 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 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. + * + * @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) +{ +  err_t err; + +#if TCP_DEBUG +  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); +  tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ + +  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; +    TCP_RMV(&tcp_bound_pcbs, pcb); +    memp_free(MEMP_TCP_PCB, pcb); +    pcb = NULL; +    break; +  case LISTEN: +    err = ERR_OK; +    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); +    memp_free(MEMP_TCP_PCB_LISTEN, pcb); +    pcb = NULL; +    break; +  case SYN_SENT: +    err = ERR_OK; +    tcp_pcb_remove(&tcp_active_pcbs, pcb); +    memp_free(MEMP_TCP_PCB, pcb); +    pcb = NULL; +    snmp_inc_tcpattemptfails(); +    break; +  case SYN_RCVD: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    if (err == ERR_OK) { +      snmp_inc_tcpattemptfails(); +      pcb->state = FIN_WAIT_1; +    } +    break; +  case ESTABLISHED: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    if (err == ERR_OK) { +      snmp_inc_tcpestabresets(); +      pcb->state = FIN_WAIT_1; +    } +    break; +  case CLOSE_WAIT: +    err = tcp_send_ctrl(pcb, TCP_FIN); +    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 when tcp_close returns. */ +    tcp_output(pcb); +  } +  return err; +} + +/** + * 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; +  u16_t remote_port, local_port; +  struct ip_addr remote_ip, local_ip; +#if LWIP_CALLBACK_API   +  void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ +  void *errf_arg; + +   +  /* 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; +    ip_addr_set(&local_ip, &(pcb->local_ip)); +    ip_addr_set(&remote_ip, &(pcb->remote_ip)); +    local_port = pcb->local_port; +    remote_port = pcb->remote_port; +#if LWIP_CALLBACK_API +    errf = pcb->errf; +#endif /* LWIP_CALLBACK_API */ +    errf_arg = pcb->callback_arg; +    tcp_pcb_remove(&tcp_active_pcbs, 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 */ +    memp_free(MEMP_TCP_PCB, pcb); +    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT); +    if (reset) { +      LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abandon: sending RST\n")); +      tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port); +    } +  } +} + +/** + * 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_OK if bound + */ +err_t +tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +{ +  struct tcp_pcb *cpcb; + +  LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + +  if (port == 0) { +    port = tcp_new_port(); +  } +  /* Check if the address already is in use. */ +  /* Check the listen pcbs. */ +  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; +      cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* Check the connected pcbs. */ +  for(cpcb = tcp_active_pcbs; +      cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* Check the bound, not yet connected pcbs. */ +  for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (ip_addr_isany(&(cpcb->local_ip)) || +          ip_addr_isany(ipaddr) || +          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { +        return ERR_USE; +      } +    } +  } +  /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah), +   * we have to check the pcbs in TIME-WAIT state, also: */ +  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) { +    if (cpcb->local_port == port) { +      if (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; +  } +  lpcb = 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->so_options = pcb->so_options; +  lpcb->so_options |= SOF_ACCEPTCONN; +  lpcb->ttl = pcb->ttl; +  lpcb->tos = pcb->tos; +  ip_addr_set(&lpcb->local_ip, &pcb->local_ip); +  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.listen_pcbs, 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 + 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 */ +      pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; +    } +    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; + +  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/2), 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); + +  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)); +} + +/** + * A nastly hack featuring 'goto' statements that allocates a + * new TCP local port. + * + * @return a new (free) local TCP port number + */ +static u16_t +tcp_new_port(void) +{ +  struct tcp_pcb *pcb; +#ifndef TCP_LOCAL_PORT_RANGE_START +#define TCP_LOCAL_PORT_RANGE_START 4096 +#define TCP_LOCAL_PORT_RANGE_END   0x7fff +#endif +  static u16_t port = TCP_LOCAL_PORT_RANGE_START; +   + again: +  if (++port > TCP_LOCAL_PORT_RANGE_END) { +    port = TCP_LOCAL_PORT_RANGE_START; +  } +   +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { +    if (pcb->local_port == port) { +      goto again; +    } +  } +  return 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, struct ip_addr *ipaddr, u16_t port, +      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) +{ +  err_t ret; +  u32_t iss; + +  LWIP_ERROR("tcp_connect: can only connected 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; +  if (pcb->local_port == 0) { +    pcb->local_port = tcp_new_port(); +  } +  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; +  pcb->state = SYN_SENT; +#if LWIP_CALLBACK_API   +  pcb->connected = connected; +#endif /* LWIP_CALLBACK_API */ +  TCP_RMV(&tcp_bound_pcbs, pcb); +  TCP_REG(&tcp_active_pcbs, pcb); + +  snmp_inc_tcpactiveopens(); +   +  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS +                    | TF_SEG_OPTS_TS +#endif +                    ); +  if (ret == ERR_OK) {  +    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, *pcb2, *prev; +  u16_t eff_wnd; +  u8_t pcb_remove;      /* flag if a PCB should be removed */ +  err_t err; + +  err = ERR_OK; + +  ++tcp_ticks; + +  /* 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); + +    pcb_remove = 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) { +            pcb->ssthresh = pcb->mss * 2; +          } +          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 ((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((pcb->so_options & SOF_KEEPALIVE) &&  +       ((pcb->state == ESTABLISHED) ||  +        (pcb->state == CLOSE_WAIT))) { +#if LWIP_TCP_KEEPALIVE +      if((u32_t)(tcp_ticks - pcb->tmr) >  +         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) +         / TCP_SLOW_INTERVAL) +#else       +      if((u32_t)(tcp_ticks - pcb->tmr) >  +         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ +      { +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", +                                ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                                ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); +         +        tcp_abort(pcb); +      } +#if LWIP_TCP_KEEPALIVE +      else if((u32_t)(tcp_ticks - pcb->tmr) >  +              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl) +              / TCP_SLOW_INTERVAL) +#else +      else if((u32_t)(tcp_ticks - pcb->tmr) >  +              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)  +              / TCP_SLOW_INTERVAL) +#endif /* LWIP_TCP_KEEPALIVE */ +      { +        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) { +      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; +      } + +      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT); + +      pcb2 = pcb->next; +      memp_free(MEMP_TCP_PCB, pcb); +      pcb = pcb2; +    } else { + +      /* We check if we should poll the connection. */ +      ++pcb->polltmr; +      if (pcb->polltmr >= pcb->pollinterval) { +        pcb->polltmr = 0; +        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); +        TCP_EVENT_POLL(pcb, err); +        if (err == ERR_OK) { +          tcp_output(pcb); +        } +      } +       +      prev = pcb; +      pcb = pcb->next; +    } +  } + +   +  /* 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) { +      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->next; +      memp_free(MEMP_TCP_PCB, pcb); +      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; + +  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { +    /* If there is data which was previously "refused" by upper layer */ +    if (pcb->refused_data != NULL) { +      /* Notify again application with data previously received. */ +      err_t err; +      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n")); +      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); +      if (err == ERR_OK) { +        pcb->refused_data = NULL; +      } +    } + +    /* send delayed ACKs */   +    if (pcb->flags & TF_ACK_DELAY) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); +      tcp_ack_now(pcb); +      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); +    } +  } +} + +/** + * Deallocates a list of TCP segments (tcp_seg structures). + * + * @param seg tcp_seg list of TCP segments to free + * @return the number of pbufs that were deallocated + */ +u8_t +tcp_segs_free(struct tcp_seg *seg) +{ +  u8_t count = 0; +  struct tcp_seg *next; +  while (seg != NULL) { +    next = seg->next; +    count += tcp_seg_free(seg); +    seg = next; +  } +  return count; +} + +/** + * Frees a TCP segment (tcp_seg structure). + * + * @param seg single tcp_seg to free + * @return the number of pbufs that were deallocated + */ +u8_t +tcp_seg_free(struct tcp_seg *seg) +{ +  u8_t count = 0; +   +  if (seg != NULL) { +    if (seg->p != NULL) { +      count = pbuf_free(seg->p); +#if TCP_DEBUG +      seg->p = NULL; +#endif /* TCP_DEBUG */ +    } +    memp_free(MEMP_TCP_SEG, seg); +  } +  return count; +} + +/** + * 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 = 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 + +#if LWIP_CALLBACK_API +/** + * Default receive callback that is called if the user didn't register + * a recv callback for the pcb. + */ +static err_t +tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) +{ +  arg = arg; +  if (p != NULL) { +    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 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 = 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 = memp_malloc(MEMP_TCP_PCB); +    if (pcb == NULL) { +      /* Try killing active connections with lower priority than the new one. */ +      tcp_kill_prio(prio); +      /* Try to allocate a tcp_pcb again. */ +      pcb = memp_malloc(MEMP_TCP_PCB); +    } +  } +  if (pcb != NULL) { +    memset(pcb, 0, sizeof(struct tcp_pcb)); +    pcb->prio = TCP_PRIO_NORMAL; +    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->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) +{   +  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, +   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) +{ +  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, +   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) +{ +  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 errf callback function to call for this pcb when a fatal error + *        has occured on the connection + */  +void +tcp_err(struct tcp_pcb *pcb, +   void (* errf)(void *arg, err_t err)) +{ +  pcb->errf = errf; +} + +/** + * 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, +     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) +{ +  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, +   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) +{ +#if LWIP_CALLBACK_API +  pcb->poll = 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 /* LW */ +    if (pcb->ooseq != NULL) { +      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); +    } + +    /* Stop the retransmission timer as it will expect data on unacked +       queue if it fires */ +    pcb->rtime = -1; + +    tcp_segs_free(pcb->ooseq); +    pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ +    tcp_segs_free(pcb->unsent); +    tcp_segs_free(pcb->unacked); +    pcb->unacked = pcb->unsent = NULL; +  } +} + +/** + * 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 also 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, struct ip_addr *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_enqueue(), and don't support +     * IP options +     */ +    sendmss = LWIP_MIN(sendmss, mss_s); +  } +  return sendmss; +} +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#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: ")); +  switch (s) { +  case CLOSED: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n")); +    break; + case LISTEN: +   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n")); +   break; +  case SYN_SENT: +    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n")); +    break; +  case SYN_RCVD: +    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n")); +    break; +  case ESTABLISHED: +    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n")); +    break; +  case FIN_WAIT_1: +    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n")); +    break; +  case FIN_WAIT_2: +    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n")); +    break; +  case CLOSE_WAIT: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n")); +    break; +  case CLOSING: +    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n")); +    break; +  case LAST_ACK: +    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n")); +    break; +  case TIME_WAIT: +    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n")); +   break; +  } +} + +/** + * 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_in.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_in.c new file mode 100644 index 000000000..362a4a62d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_in.c @@ -0,0 +1,1419 @@ +/** + * @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.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.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 u8_t 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; +  u8_t hdrlen; +  err_t err; + +  PERF_START; + +  TCP_STATS_INC(tcp.recv); +  snmp_inc_tcpinsegs(); + +  iphdr = 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); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +  /* Don't even process incoming broadcasts/multicasts. */ +  if (ip_addr_isbroadcast(&(iphdr->dest), inp) || +      ip_addr_ismulticast(&(iphdr->dest))) { +    TCP_STATS_INC(tcp.proterr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +#if CHECKSUM_CHECK_TCP +  /* Verify TCP checksum. */ +  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), +      (struct ip_addr *)&(iphdr->dest), +      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, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), +      IP_PROTO_TCP, p->tot_len))); +#if TCP_DEBUG +    tcp_debug_print(tcphdr); +#endif /* TCP_DEBUG */ +    TCP_STATS_INC(tcp.chkerr); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } +#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); +    TCP_STATS_INC(tcp.drop); +    snmp_inc_tcpinerrs(); +    pbuf_free(p); +    return; +  } + +  /* 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), &(iphdr->src)) && +       ip_addr_cmp(&(pcb->local_ip), &(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), &(iphdr->src)) && +         ip_addr_cmp(&(pcb->local_ip), &(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 ((ip_addr_isany(&(lpcb->local_ip)) || +        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && +        lpcb->local_port == tcphdr->dest) { +        /* 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; +      } +      prev = (struct tcp_pcb *)lpcb; +    } +  } + +#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.dataptr = p->payload; +    inseg.p = p; +    inseg.tcphdr = tcphdr; + +    recv_data = NULL; +    recv_flags = 0; + +    /* If there is data which was previously "refused" by upper layer */ +    if (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, pcb->refused_data, ERR_OK, err); +      if (err == ERR_OK) { +        pcb->refused_data = NULL; +      } else { +        /* drop incoming packets, because pcb is "full" */ +        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); +        TCP_STATS_INC(tcp.drop); +        snmp_inc_tcpinerrs(); +        pbuf_free(p); +        return; +      } +    } + +    tcp_input_pcb = pcb; +    err = tcp_process(pcb); +    tcp_input_pcb = NULL; +    /* 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. */ +        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 (recv_data != NULL) { +          if(flags & TCP_PSH) { +            recv_data->flags |= PBUF_FLAG_PUSH; +          } + +          /* Notify application that data has been received. */ +          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + +          /* 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) { +          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); +        } + +        /* If there were no errors, we try to send something out. */ +        if (err == ERR_OK) { +          tcp_output(pcb); +        } +      } +    } + + +    /* give up our reference to inseg.p */ +    if (inseg.p != NULL) +    { +      pbuf_free(inseg.p); +      inseg.p = NULL; +    } +#if TCP_INPUT_DEBUG +#if TCP_DEBUG +    tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ +#endif /* TCP_INPUT_DEBUG */ +       +  } 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, +        &(iphdr->dest), &(iphdr->src), +        tcphdr->dest, tcphdr->src); +    } +    pbuf_free(p); +  } + +  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane()); +  PERF_STOP("tcp_input"); +} + +/** + * 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; + +  /* 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 + 1, seqno + tcplen, +      &(iphdr->dest), &(iphdr->src), +      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_set(&(npcb->local_ip), &(iphdr->dest)); +    npcb->local_port = pcb->local_port; +    ip_addr_set(&(npcb->remote_ip), &(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->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_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); +    /* Register the new PCB so that we can begin receiving segments +       for it. */ +    TCP_REG(&tcp_active_pcbs, 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(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS +#if LWIP_TCP_TIMESTAMPS +      /* and maybe include the TIMESTAMP option */ +     | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0) +#endif +      ); +    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) +{ +  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) { +    pcb->rcv_nxt = seqno + tcplen; +  } +  if (tcplen > 0) { +    tcp_ack_now(pcb); +  } +  return tcp_output(pcb); +} + +/** + * 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; +  } +   +  /* Update the PCB (in)activity timer. */ +  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_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; + +      /* 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; +      } + +      tcp_seg_free(rseg); + +      /* Call the user specified function to call when sucessfully +       * connected. */ +      TCP_EVENT_CONNECTED(pcb, ERR_OK, err); +      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, &(iphdr->dest), &(iphdr->src), +        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. */ +          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); + +        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss); + +        if (recv_flags & TF_GOT_FIN) { +          tcp_ack_now(pcb); +          pcb->state = CLOSE_WAIT; +        } +      } +      /* incorrect ACK number */ +      else { +        /* send RST */ +        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), +                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 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +        tcp_ack_now(pcb); +        tcp_pcb_purge(pcb); +        TCP_RMV(&tcp_active_pcbs, 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 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +      tcp_ack_now(pcb); +      tcp_pcb_purge(pcb); +      TCP_RMV(&tcp_active_pcbs, 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 %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest)); +      tcp_pcb_purge(pcb); +      TCP_RMV(&tcp_active_pcbs, 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 %"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; +} + +/** + * 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 + * i 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(). + * + * @return 1 if the incoming segment is the next in sequence, 0 if not + */ +static u8_t +tcp_receive(struct tcp_pcb *pcb) +{ +  struct tcp_seg *next; +#if TCP_QUEUE_OOSEQ +  struct tcp_seg *prev, *cseg; +#endif +  struct pbuf *p; +  s32_t off; +  s16_t m; +  u32_t right_wnd_edge; +  u16_t new_tot_len; +  u8_t accepted_inseq = 0; + +  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; +      pcb->snd_wl1 = seqno; +      pcb->snd_wl2 = ackno; +      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) { +          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 */ +    } + +    if (pcb->lastack == ackno) { +      pcb->acked = 0; + +      if (pcb->snd_wl2 + pcb->snd_wnd == right_wnd_edge){ +        ++pcb->dupacks; +        if (pcb->dupacks >= 3 && pcb->unacked != NULL) { +          if (!(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 max (FlightSize / 2, 2*SMSS) */ +            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max - +                                      pcb->lastack) / 2, +                                      2 * pcb->mss);*/ +            /* 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; +          } else { +            /* 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 { +        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", +                                   pcb->snd_wl2 + pcb->snd_wnd, right_wnd_edge)); +      } +    } 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))); +        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; +      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))); +      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. */ +  if (tcplen > 0) { +    /* 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); +        } +      } +      /* KJM following line changed to use p->payload rather than inseg->p->payload +         to fix bug #9076 */ +      inseg.dataptr = p->payload; +      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) { +        accepted_inseq = 1;  +        /* 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 %"U32_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 +        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; +              memp_free(MEMP_TCP_SEG, old_ooseq); +            }                +          } else if (TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + tcplen)) { +            if (pcb->ooseq->len > 0) { +              /* We have to trim the second edge of the incoming segment. */ +              LWIP_ASSERT("tcp_receive: trimmed segment would have zero length\n", +                          TCP_SEQ_GT(pcb->ooseq->tcphdr->seqno, seqno)); +              /* FIN in inseg already handled by dropping whole ooseq queue */ +              inseg.len = (u16_t)(pcb->ooseq->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) == pcb->ooseq->tcphdr->seqno); +            } else { +              /* does the ooseq segment contain only flags that are in inseg also? */ +              if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) == +                  (TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) { +                struct tcp_seg *old_ooseq = pcb->ooseq; +                pcb->ooseq = pcb->ooseq->next; +                memp_free(MEMP_TCP_SEG, old_ooseq); +              } +            } +          } +        } +#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 +           is 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_ack_now(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 the old segment with the new +                   one. */ +                cseg = tcp_seg_copy(&inseg); +                if (cseg != NULL) { +                  cseg->next = next->next; +                  if (prev != NULL) { +                    prev->next = cseg; +                  } else { +                    pcb->ooseq = cseg; +                  } +                  tcp_seg_free(next); +                  if (cseg->next != NULL) { +                    next = cseg->next; +                    if (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); +                    } +                  } +                } +                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. */ + +                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { +                    /* We need to trim the incoming segment. */ +                    inseg.len = (u16_t)(next->tcphdr->seqno - seqno); +                    pbuf_realloc(inseg.p, inseg.len); +                  } +                  cseg = tcp_seg_copy(&inseg); +                  if (cseg != NULL) { +                    cseg->next = next; +                    pcb->ooseq = cseg; +                  } +                  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 and insert the +                   incoming segment and trim the previous segment, if +                   needed. */ +                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) { +                  /* We need to trim the incoming segment. */ +                  inseg.len = (u16_t)(next->tcphdr->seqno - seqno); +                  pbuf_realloc(inseg.p, inseg.len); +                } + +                cseg = tcp_seg_copy(&inseg); +                if (cseg != NULL) { +                  cseg->next = next; +                  prev->next = cseg; +                  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); +                  } +                } +                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)) { +                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); +                  } +                } +                break; +              } +            } +            prev = next; +          } +        } +#endif /* TCP_QUEUE_OOSEQ */ + +      } +    } else { +      tcp_ack_now(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); +    } +  } +  return accepted_inseq; +} + +/** + * 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/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_out.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_out.c new file mode 100644 index 000000000..ca72d9dcc --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/tcp_out.c @@ -0,0 +1,981 @@ +/** + * @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.h" +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/inet.h" +#include "lwip/inet_chksum.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" + +#include <string.h> + +/* Forward declarations.*/ +static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); + +static struct tcp_hdr * +tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen, +                      u32_t seqno_be /* already in network byte order */) +{ +  struct tcp_hdr *tcphdr = 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_FLAGS_SET(tcphdr, TCP_ACK); +  tcphdr->wnd = htons(pcb->rcv_ann_wnd); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4)); +  tcphdr->chksum = 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 tcphdr; +} + +/** + * Called by tcp_close() to send a segment including flags but not data. + * + * @param pcb the tcp_pcb over which to send a segment + * @param flags the flags to set in the segment header + * @return ERR_OK if sent, another err_t otherwise + */ +err_t +tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) +{ +  /* no data, no length, flags, copy=1, no optdata */ +  return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); +} + +/** + * 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 of the TCP connection to enqueue data for. + * @param data pointer to the data to send + * @param len length (in bytes) of the data to send + * @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 + *  + * @see tcp_write() + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) +{ +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, +    data, len, (u16_t)apiflags)); +  /* connection is in valid state for data transmission? */ +  if (pcb->state == ESTABLISHED || +     pcb->state == CLOSE_WAIT || +     pcb->state == SYN_SENT || +     pcb->state == SYN_RCVD) { +    if (len > 0) { +#if LWIP_TCP_TIMESTAMPS +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags,  +                         pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); +#else +      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); +#endif +    } +    return ERR_OK; +  } else { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n")); +    return ERR_CONN; +  } +} + +/** + * Enqueue data and/or TCP options for transmission + * + * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and 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 flags tcp header flags to set in the outgoing segment + * @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, + * @param optflags options to include in segment later on (see definition of struct tcp_seg) + */ +err_t +tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, +            u8_t flags, u8_t apiflags, u8_t optflags) +{ +  struct pbuf *p; +  struct tcp_seg *seg, *useg, *queue; +  u32_t seqno; +  u16_t left, seglen; +  void *ptr; +  u16_t queuelen; +  u8_t optlen; + +  LWIP_DEBUGF(TCP_OUTPUT_DEBUG,  +              ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", +               (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); +  LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)", +             ((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)), +             return ERR_ARG;); +  LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)",  +             ((len != 0) || (arg == NULL)), return ERR_ARG;); + +  /* fail on too much data */ +  if (len > pcb->snd_buf) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  left = len; +  ptr = arg; + +  optlen = LWIP_TCP_OPT_LENGTH(optflags); + +  /* seqno will be the sequence number of the first segment enqueued +   * by the call to this function. */ +  seqno = pcb->snd_lbb; + +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: 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 */ +  queuelen = pcb->snd_queuelen; +  /* check for configured max queuelen and possible overflow */ +  if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +    TCP_STATS_INC(tcp.memerr); +    pcb->flags |= TF_NAGLEMEMERR; +    return ERR_MEM; +  } +  if (queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } else { +    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty", +      pcb->unacked == NULL && pcb->unsent == NULL); +  } + +  /* First, break up the data into segments and tuck them together in +   * the local "queue" variable. */ +  useg = queue = seg = NULL; +  seglen = 0; +  while (queue == NULL || left > 0) { +    /* The segment length (including options) should be at most the MSS */ +    seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left; + +    /* Allocate memory for tcp_seg, and fill in fields. */ +    seg = memp_malloc(MEMP_TCP_SEG); +    if (seg == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                  ("tcp_enqueue: could not allocate memory for tcp_seg\n")); +      goto memerr; +    } +    seg->next = NULL; +    seg->p = NULL; + +    /* first segment of to-be-queued data? */ +    if (queue == NULL) { +      queue = seg; +    } +    /* subsequent segments of to-be-queued data */ +    else { +      /* Attach the segment to the end of the queued segments */ +      LWIP_ASSERT("useg != NULL", useg != NULL); +      useg->next = seg; +    } +    /* remember last segment of to-be-queued data for next iteration */ +    useg = seg; + +    /* If copy is set, memory should be allocated +     * and data copied into pbuf, otherwise data comes from +     * ROM or other static memory, and need not be copied.  */ +    if (apiflags & TCP_WRITE_FLAG_COPY) { +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); +        goto memerr; +      } +      LWIP_ASSERT("check that first pbuf can hold the complete seglen", +                  (seg->p->len >= seglen + optlen)); +      queuelen += pbuf_clen(seg->p); +      if (arg != NULL) { +        MEMCPY((char *)seg->p->payload + optlen, ptr, seglen); +      } +      seg->dataptr = seg->p->payload; +    } +    /* do not copy data */ +    else { +      /* First, allocate a pbuf for the headers. */ +      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { +        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                    ("tcp_enqueue: could not allocate memory for header pbuf\n")); +        goto memerr; +      } +      queuelen += pbuf_clen(seg->p); + +      /* Second, 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. +       */ +      if (left > 0) { +        if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { +          /* If allocation fails, we have to deallocate the header pbuf as well. */ +          pbuf_free(seg->p); +          seg->p = NULL; +          LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2,  +                      ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); +          goto memerr; +        } +        ++queuelen; +        /* reference the non-volatile payload data */ +        p->payload = ptr; +        seg->dataptr = ptr; + +        /* Concatenate the headers and data pbufs together. */ +        pbuf_cat(seg->p/*header*/, p/*data*/); +        p = NULL; +      } +    } + +    /* 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_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); +      goto memerr; +    } + +    seg->len = seglen; + +    /* build TCP header */ +    if (pbuf_header(seg->p, TCP_HLEN)) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n")); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    seg->tcphdr = seg->p->payload; +    seg->tcphdr->src = htons(pcb->local_port); +    seg->tcphdr->dest = htons(pcb->remote_port); +    seg->tcphdr->seqno = htonl(seqno); +    seg->tcphdr->urgp = 0; +    TCPH_FLAGS_SET(seg->tcphdr, flags); +    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ + +    seg->flags = optflags; + +    /* Set the length of the header */ +    TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", +      ntohl(seg->tcphdr->seqno), +      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), +      (u16_t)flags)); + +    left -= seglen; +    seqno += seglen; +    ptr = (void *)((u8_t *)ptr + seglen); +  } + +  /* Now that the data to be enqueued has been broken up into TCP +  segments in the queue variable, we add them to the end of the +  pcb->unsent queue. */ +  if (pcb->unsent == NULL) { +    useg = NULL; +  } +  else { +    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); +  } +  /* { useg is last segment on the unsent queue, NULL if list is empty } */ + +  /* If there is room in the last pbuf on the unsent queue, +  chain the first pbuf on the queue together with that. */ +  if (useg != NULL && +    TCP_TCPLEN(useg) != 0 && +    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && +    !(flags & (TCP_SYN | TCP_FIN)) && +    /* fit within max seg size */ +    (useg->len + queue->len <= pcb->mss) && +    /* only concatenate segments with the same options */ +    (useg->flags == queue->flags)) { +    /* Remove TCP header from first segment of our to-be-queued list */ +    if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      TCP_STATS_INC(tcp.err); +      goto memerr; +    } +    if (queue->p->len == 0) { +      /* free the first (header-only) pbuf if it is now empty (contained only headers) */ +      struct pbuf *old_q = queue->p; +      queue->p = queue->p->next; +      old_q->next = NULL; +      queuelen--; +      pbuf_free(old_q); +    } +    LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0)); +    pbuf_cat(useg->p, queue->p); +    useg->len += queue->len; +    useg->next = queue->next; + +    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len)); +    if (seg == queue) { +      seg = useg; +      seglen = useg->len; +    } +    memp_free(MEMP_TCP_SEG, queue); +  } +  else { +    /* empty list */ +    if (useg == NULL) { +      /* initialize list with this segment */ +      pcb->unsent = queue; +    } +    /* enqueue segment */ +    else { +      useg->next = queue; +    } +  } +  if ((flags & TCP_SYN) || (flags & TCP_FIN)) { +    ++len; +  } +  if (flags & TCP_FIN) { +    pcb->flags |= TF_FIN; +  } +  pcb->snd_lbb += len; + +  pcb->snd_buf -= len; + +  /* update number of segments on the queues */ +  pcb->snd_queuelen = queuelen; +  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", +      pcb->unacked != NULL || pcb->unsent != NULL); +  } + +  /* Set the PSH flag in the last segment that we enqueued, but only +  if the segment has data (indicated by seglen > 0). */ +  if (seg != NULL && seglen > 0 && 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 (queue != NULL) { +    tcp_segs_free(queue); +  } +  if (pcb->snd_queuelen != 0) { +    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || +      pcb->unsent != NULL); +  } +  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); +  return ERR_MEM; +} + + +#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] = htonl(0x0101080A); +  opts[1] = htonl(sys_now()); +  opts[2] = htonl(pcb->ts_recent); +} +#endif + + +/** + * 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 pbuf *p; +  struct tcp_hdr *tcphdr; +  struct tcp_seg *seg, *useg; +  u32_t wnd, snd_nxt; +#if TCP_CWND_DEBUG +  s16_t i = 0; +#endif /* TCP_CWND_DEBUG */ +  u8_t optlen = 0; + +  /* 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; + +  /* useg should point to last segment on unacked queue */ +  useg = pcb->unacked; +  if (useg != NULL) { +    for (; useg->next != NULL; useg = useg->next); +  } + +  /* 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)) { +#if LWIP_TCP_TIMESTAMPS +    if (pcb->flags & TF_TIMESTAMP) +      optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); +#endif +    p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM); +    if (p == NULL) { +      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); +      return ERR_BUF; +    } +    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); + +    tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt)); + +    /* 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; +  } + +#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_enqueue 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_enqueue/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 (seg != NULL && pcb->persist_backoff == 0 &&  +      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { +    /* prepare for persist timer */ +    pcb->persist_cnt = 0; +    pcb->persist_backoff = 1; +  } + +  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 *)(seg->tcphdr + 1); +  if (seg->flags & TF_SEG_OPTS_MSS) { +    TCP_BUILD_MSS_OPTION(*opts); +    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 + +  /* 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_set(&(pcb->local_ip), &(netif->ip_addr)); +  } + +  /* Set retransmission timer running if it is not currently enabled */ +  if(pcb->rtime == -1) +    pcb->rtime = 0; + +  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 +  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, +             &(pcb->local_ip), +             &(pcb->remote_ip), +             IP_PROTO_TCP, seg->p->tot_len); +#endif +  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, +  struct ip_addr *local_ip, struct ip_addr *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 = p->payload; +  tcphdr->src = htons(local_port); +  tcphdr->dest = htons(remote_port); +  tcphdr->seqno = htonl(seqno); +  tcphdr->ackno = htonl(ackno); +  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); +  tcphdr->wnd = htons(TCP_WND); +  tcphdr->urgp = 0; +  TCPH_HDRLEN_SET(tcphdr, 5); + +  tcphdr->chksum = 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; + +  /* 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; + +  ++pcb->nrtx; + +  /* Don't take any rtt measurements after retransmitting. */ +  pcb->rttest = 0; + +  /* Do the actual retransmission. */ +  snmp_inc_tcpretranssegs(); +  tcp_output(pcb); +} + +/** + * 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(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                          ip4_addr3(&pcb->remote_ip), ip4_addr4(&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 = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG,  +                ("tcp_keepalive: 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 = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1)); + +#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; + +  LWIP_DEBUGF(TCP_DEBUG,  +              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" +               U16_F".%"U16_F".%"U16_F".%"U16_F"\n", +               ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +               ip4_addr3(&pcb->remote_ip), ip4_addr4(&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; + +  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM); +    +  if(p == NULL) { +    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); +    return; +  } +  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", +              (p->len >= sizeof(struct tcp_hdr))); + +  tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno); + +  /* Copy in one byte from the head of the unacked queue */ +  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr; + +#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/firmware/usrp3/lwip/lwip-1.3.1/src/core/udp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/core/udp.c new file mode 100644 index 000000000..d8d644d44 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/core/udp.c @@ -0,0 +1,840 @@ +/** + * @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.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> + +/* The list of UDP PCBs */ +/* exported in udp.h (was static) */ +struct udp_pcb *udp_pcbs; + +/** + * 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 = 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(&(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(&iphdr->dest), ip4_addr2(&iphdr->dest), +               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), +               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), +               ip4_addr3(&iphdr->src), ip4_addr4(&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), &(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(&pcb->local_ip), ip4_addr2(&pcb->local_ip), +                   ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, +                   ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), +                   ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port)); + +      /* compare PCB local addr+port to UDP destination addr+port */ +      if ((pcb->local_port == dest) && +          ((!broadcast && ip_addr_isany(&pcb->local_ip)) || +           ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || +#if LWIP_IGMP +           ip_addr_ismulticast(&(iphdr->dest)) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV +           (broadcast && (pcb->so_options & SOF_BROADCAST)))) { +#else  /* IP_SOF_BROADCAST_RECV */ +           (broadcast))) { +#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), &(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, &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, (struct ip_addr *)&(iphdr->src), +                             (struct ip_addr *)&(iphdr->dest), +                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { +        LWIP_DEBUGF(UDP_DEBUG | 2, +                    ("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, (struct ip_addr *)&(iphdr->src), +                               (struct ip_addr *)&(iphdr->dest), +                               IP_PROTO_UDP, p->tot_len) != 0) { +          LWIP_DEBUGF(UDP_DEBUG | 2, +                      ("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(); +      /* callback */ +      if (pcb->recv != NULL) { +        /* now the recv function is responsible for freeing p */ +        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), 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(&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); +} + +/** + * 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, +  struct ip_addr *dst_ip, u16_t dst_port) +{ +  struct netif *netif; + +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("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 | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr)); +    UDP_STATS_INC(udp.rterr); +    return ERR_RTE; +  } +  return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +} + +/** + * 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, +  struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif) +{ +  struct udp_hdr *udphdr; +  struct ip_addr *src_ip; +  err_t err; +  struct pbuf *q; /* q will be sent down the stack */ + +#if IP_SOF_BROADCAST +  /* broadcast filter? */ +  if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(dst_ip, netif) ) { +    LWIP_DEBUGF(UDP_DEBUG | 1, ("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 | 2, ("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 | 2, ("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 | 2, ("udp_send: could not allocate header\n")); +      return ERR_MEM; +    } +    /* chain header q in front of given pbuf p */ +    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 = q->payload; +  udphdr->src = htons(pcb->local_port); +  udphdr->dest = htons(dst_port); +  /* in UDP, 0 checksum means 'no checksum' */ +  udphdr->chksum = 0x0000;  + +  /* 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, chklen); +    /* chksum zero must become 0xffff, as zero means 'no checksum' */ +    if (udphdr->chksum == 0x0000) +      udphdr->chksum = 0xffff; +#endif /* CHECKSUM_CHECK_UDP */ +    /* output to IP */ +    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +  } 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) { +      udphdr->chksum = 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 (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; +    } +#endif /* CHECKSUM_CHECK_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 */ +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = &(pcb->addr_hint); +#endif /* LWIP_NETIF_HWADDRHINT*/ +    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif); +#if LWIP_NETIF_HWADDRHINT +    netif->addr_hint = NULL; +#endif /* LWIP_NETIF_HWADDRHINT*/ +  } +  /* 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, struct ip_addr *ipaddr, u16_t port) +{ +  struct udp_pcb *ipcb; +  u8_t rebind; + +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = ")); +  ip_addr_debug_print(UDP_DEBUG, ipaddr); +  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", 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; +    } + +    /* this code does not allow upper layer to share a UDP port for +       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and +       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR +       combine with implementation of UDP PCB flags. Leon Woestenberg. */ +#ifdef LWIP_UDP_TODO +    /* port matches that of PCB in list? */ +    else +      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; +      } +#endif +  } + +  ip_addr_set(&pcb->local_ip, ipaddr); + +  /* no port specified? */ +  if (port == 0) { +#ifndef UDP_LOCAL_PORT_RANGE_START +#define UDP_LOCAL_PORT_RANGE_START 4096 +#define UDP_LOCAL_PORT_RANGE_END   0x7fff +#endif +    port = UDP_LOCAL_PORT_RANGE_START; +    ipcb = udp_pcbs; +    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) { +      if (ipcb->local_port == port) { +        /* port is already used by another udp_pcb */ +        port++; +        /* restart scanning all udp pcbs */ +        ipcb = udp_pcbs; +      } else +        /* go on with next udp pcb */ +        ipcb = ipcb->next; +    } +    if (ipcb != NULL) { +      /* 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", +               (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff), +               (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff), +               (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff), +               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), 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, struct ip_addr *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", +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff), +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff), +               (u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff), +               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_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(&pcb->remote_ip, IP_ADDR_ANY); +  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, +         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, +                       struct ip_addr *addr, u16_t port), +         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 = 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 */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h new file mode 100644 index 000000000..076a2ed23 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/autoip.h @@ -0,0 +1,105 @@ +/** + * @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> + */ +  +#ifndef __LWIP_AUTOIP_H__ +#define __LWIP_AUTOIP_H__ + +#include "lwip/opt.h" + +#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" +#include "netif/etharp.h" + +/* AutoIP Timing */ +#define AUTOIP_TMR_INTERVAL      100 +#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL) + +/* RFC 3927 Constants */ +#define PROBE_WAIT               1   /* second   (initial random delay)                 */ +#define PROBE_MIN                1   /* second   (minimum delay till repeated probe)    */ +#define PROBE_MAX                2   /* seconds  (maximum delay till repeated probe)    */ +#define PROBE_NUM                3   /*          (number of probe packets)              */ +#define ANNOUNCE_NUM             2   /*          (number of announcement packets)       */ +#define ANNOUNCE_INTERVAL        2   /* seconds  (time between announcement packets)    */ +#define ANNOUNCE_WAIT            2   /* seconds  (delay before announcing)              */ +#define MAX_CONFLICTS            10  /*          (max conflicts before rate limiting)   */ +#define RATE_LIMIT_INTERVAL      60  /* seconds  (delay between successive attempts)    */ +#define DEFEND_INTERVAL          10  /* seconds  (min. wait between defensive ARPs)     */ + +/* AutoIP client states */ +#define AUTOIP_STATE_OFF         0 +#define AUTOIP_STATE_PROBING     1 +#define AUTOIP_STATE_ANNOUNCING  2 +#define AUTOIP_STATE_BOUND       3 + +struct autoip +{ +  struct ip_addr llipaddr;  /* the currently selected, probed, announced or used LL IP-Address */ +  u8_t state;               /* current AutoIP state machine state */ +  u8_t sent_num;            /* sent number of probes or announces, dependent on state */ +  u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ +  u8_t lastconflict;        /* ticks until a conflict can be solved by defending */ +  u8_t tried_llipaddr;      /* total number of probed/used Link Local IP-Addresses */ +}; + + +/** Init srand, has to be called before entering mainloop */ +void autoip_init(void); + +/** Start AutoIP client */ +err_t autoip_start(struct netif *netif); + +/** Stop AutoIP client */ +err_t autoip_stop(struct netif *netif); + +/** Handles every incoming ARP Packet, called by etharp_arp_input */ +void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr); + +/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */ +void autoip_tmr(void); + +#endif /* LWIP_AUTOIP */ + +#endif /* __LWIP_AUTOIP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h new file mode 100644 index 000000000..ff838f43a --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/icmp.h @@ -0,0 +1,112 @@ +/* + * 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> + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP_ER 0      /* echo reply */ +#define ICMP_DUR 3     /* destination unreachable */ +#define ICMP_SQ 4      /* source quench */ +#define ICMP_RD 5      /* redirect */ +#define ICMP_ECHO 8    /* echo */ +#define ICMP_TE 11     /* time exceeded */ +#define ICMP_PP 12     /* parameter problem */ +#define ICMP_TS 13     /* timestamp */ +#define ICMP_TSR 14    /* timestamp reply */ +#define ICMP_IRQ 15    /* information request */ +#define ICMP_IR 16     /* information reply */ + +enum icmp_dur_type { +  ICMP_DUR_NET = 0,    /* net unreachable */ +  ICMP_DUR_HOST = 1,   /* host unreachable */ +  ICMP_DUR_PROTO = 2,  /* protocol unreachable */ +  ICMP_DUR_PORT = 3,   /* port unreachable */ +  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */ +  ICMP_DUR_SR = 5      /* source route failed */ +}; + +enum icmp_te_type { +  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */ +  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */ +}; + +void icmp_input(struct pbuf *p, struct netif *inp); + +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +/** This is the standard ICMP header only that the u32_t data + *  is splitted to two u16_t like ICMP echo needs it. + *  This header is also used for other ICMP types that do not + *  use the data part. + */ +PACK_STRUCT_BEGIN +struct icmp_echo_hdr { +  PACK_STRUCT_FIELD(u8_t type); +  PACK_STRUCT_FIELD(u8_t code); +  PACK_STRUCT_FIELD(u16_t chksum); +  PACK_STRUCT_FIELD(u16_t id); +  PACK_STRUCT_FIELD(u16_t seqno); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define ICMPH_TYPE(hdr) ((hdr)->type) +#define ICMPH_CODE(hdr) ((hdr)->code) + +/** Combines type and code to an u16_t */ +#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t)) +#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c)) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ICMP */ + +#endif /* __LWIP_ICMP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h new file mode 100644 index 000000000..59c933f35 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/igmp.h @@ -0,0 +1,162 @@ +/* + * 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. +*/ + +#ifndef __LWIP_IGMP_H__ +#define __LWIP_IGMP_H__ + +#include "lwip/opt.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/pbuf.h" + +#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */ + +#ifdef __cplusplus +extern "C" { +#endif + +/*  + * IGMP constants + */ +#define IP_PROTO_IGMP                  2 +#define IGMP_TTL                       1 +#define IGMP_MINLEN                    8 +#define ROUTER_ALERT                   0x9404 +#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      */ + +/* IGMP timer */ +#define IGMP_TMR_INTERVAL              100 /* Milliseconds */ +#define IGMP_V1_DELAYING_MEMBER_TMR   (1000/IGMP_TMR_INTERVAL) +#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) + +/* MAC Filter Actions */ +#define IGMP_DEL_MAC_FILTER            0 +#define IGMP_ADD_MAC_FILTER            1 + +/* 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(struct ip_addr igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/*  + * now a group structure - there is + * a list of groups for each interface + * these should really be linked from the interface, but + * if we keep them separate we will not affect the lwip original code + * too much + *  + * There will be a group for the all systems group address but this  + * will not run the state machine as it is used to kick off reports + * from all the other groups + */ + +struct igmp_group { +  struct igmp_group *next; +  struct netif      *interface; +  struct ip_addr     group_address; +  u8_t               last_reporter_flag; /* signifies we were the last person to report */ +  u8_t               group_state; +  u16_t              timer; +  u8_t               use; /* counter of simultaneous uses */ +}; + + +/*  Prototypes */ +void   igmp_init(void); + +err_t  igmp_start( struct netif *netif); + +err_t  igmp_stop( struct netif *netif); + +void   igmp_report_groups( struct netif *netif); + +struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr); + +struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr); + +err_t  igmp_remove_group( struct igmp_group *group); + +void   igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest); + +err_t  igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); + +err_t  igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); + +void   igmp_tmr(void); + +void   igmp_timeout( struct igmp_group *group); + +void   igmp_start_timer( struct igmp_group *group, u8_t max_time); + +void   igmp_stop_timer( struct igmp_group *group); + +void   igmp_delaying_member( struct igmp_group *group, u8_t maxresp); + +err_t  igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif); + +void   igmp_send( struct igmp_group *group, u8_t type); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_IGMP */ + +#endif /* __LWIP_IGMP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h new file mode 100644 index 000000000..6f30d0d12 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet.h @@ -0,0 +1,103 @@ +/* + * 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> + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* For compatibility with BSD code */ +struct in_addr { +  u32_t s_addr; +}; + +#define INADDR_NONE         ((u32_t)0xffffffffUL)  /* 255.255.255.255 */ +#define INADDR_LOOPBACK     ((u32_t)0x7f000001UL)  /* 127.0.0.1 */ +#define INADDR_ANY          ((u32_t)0x00000000UL)  /* 0.0.0.0 */ +#define INADDR_BROADCAST    ((u32_t)0xffffffffUL)  /* 255.255.255.255 */ + +u32_t inet_addr(const char *cp); +int inet_aton(const char *cp, struct in_addr *addr); +char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#if BYTE_ORDER == BIG_ENDIAN +#define htons(x) (x) +#define ntohs(x) (x) +#define htonl(x) (x) +#define ntohl(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#ifdef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ +#define htons lwip_htons +#define ntohs lwip_ntohs +#define htonl lwip_htonl +#define ntohl lwip_ntohl +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ +#if LWIP_PLATFORM_BYTESWAP +#define htons(x) LWIP_PLATFORM_HTONS(x) +#define ntohs(x) LWIP_PLATFORM_HTONS(x) +#define htonl(x) LWIP_PLATFORM_HTONL(x) +#define ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t htons(u16_t x); +u16_t ntohs(u16_t x); +u32_t htonl(u32_t x); +u32_t ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h new file mode 100644 index 000000000..5cae59cbd --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/inet_chksum.h @@ -0,0 +1,60 @@ +/* + * 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> + * + */ +#ifndef __LWIP_INET_CHKSUM_H__ +#define __LWIP_INET_CHKSUM_H__ + +#include "lwip/opt.h" + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *dataptr, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +u16_t inet_chksum_pseudo(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len); +#if LWIP_UDPLITE +u16_t inet_chksum_pseudo_partial(struct pbuf *p, +       struct ip_addr *src, struct ip_addr *dest, +       u8_t proto, u16_t proto_len, u16_t chksum_len); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h new file mode 100644 index 000000000..14eba3ca5 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip.h @@ -0,0 +1,187 @@ +/* + * 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> + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Currently, the function ip_output_if_opt() is only used with IGMP */ +#define IP_OPTIONS_SEND   LWIP_IGMP + +#define IP_HLEN 20 + +#define IP_PROTO_ICMP    1 +#define IP_PROTO_UDP     17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP     6 + +/* This is passed as the destination address to ip_output_if (not +   to ip_output), meaning that an IP header already is constructed +   in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL  NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the +   beginning of a PCB type definition. It is located here so that +   changes to this common part are made in one location instead of +   having to change all PCB structs. */ +#define IP_PCB \ +  /* ip addresses in network byte order */ \ +  struct ip_addr local_ip; \ +  struct ip_addr remote_ip; \ +   /* Socket options */  \ +  u16_t so_options;      \ +   /* Type Of Service */ \ +  u8_t tos;              \ +  /* Time To Live */     \ +  u8_t ttl               \ +  /* link layer address resolution hint */ \ +  IP_PCB_ADDRHINT + +struct ip_pcb { +/* Common members of all PCB types */ +  IP_PCB; +}; + +/* + * Option flags per-socket. These are the same like SO_XXX. + */ +#define SOF_DEBUG       (u16_t)0x0001U    /* turn on debugging info recording */ +#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */ +#define SOF_REUSEADDR   (u16_t)0x0004U    /* allow local address reuse */ +#define SOF_KEEPALIVE   (u16_t)0x0008U    /* keep connections alive */ +#define SOF_DONTROUTE   (u16_t)0x0010U    /* just use interface addresses */ +#define SOF_BROADCAST   (u16_t)0x0020U    /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */ +#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */ +#define SOF_OOBINLINE   (u16_t)0x0100U    /* leave received OOB data in line */ +#define SOF_REUSEPORT   (u16_t)0x0200U    /* allow local address & port reuse */ + + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_hdr { +  /* version / header length / type of service */ +  PACK_STRUCT_FIELD(u16_t _v_hl_tos); +  /* total length */ +  PACK_STRUCT_FIELD(u16_t _len); +  /* identification */ +  PACK_STRUCT_FIELD(u16_t _id); +  /* fragment offset field */ +  PACK_STRUCT_FIELD(u16_t _offset); +#define IP_RF 0x8000        /* reserved fragment flag */ +#define IP_DF 0x4000        /* dont fragment flag */ +#define IP_MF 0x2000        /* more fragments flag */ +#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */ +  /* time to live / protocol*/ +  PACK_STRUCT_FIELD(u16_t _ttl_proto); +  /* checksum */ +  PACK_STRUCT_FIELD(u16_t _chksum); +  /* source and destination IP addresses */ +  PACK_STRUCT_FIELD(struct ip_addr src); +  PACK_STRUCT_FIELD(struct ip_addr dest);  +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12) +#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f) +#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff) +#define IPH_LEN(hdr) ((hdr)->_len) +#define IPH_ID(hdr) ((hdr)->_id) +#define IPH_OFFSET(hdr) ((hdr)->_offset) +#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8) +#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff) +#define IPH_CHKSUM(hdr) ((hdr)->_chksum) + +#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) +#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) +#define IPH_ID_SET(hdr, id) (hdr)->_id = (id) +#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8))) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8))) +#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) + +#define ip_init() /* Compatibility define, not init needed. */ +struct netif *ip_route(struct ip_addr *dest); +err_t ip_input(struct pbuf *p, struct netif *inp); +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto); +err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, +       struct netif *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); +#endif /* LWIP_NETIF_HWADDRHINT */ +#if IP_OPTIONS_SEND +err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +       u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, +       u16_t optlen); +#endif /* IP_OPTIONS_SEND */ +struct netif *ip_current_netif(void); +const struct ip_hdr *ip_current_header(void); +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#else +#define ip_debug_print(p) +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h new file mode 100644 index 000000000..f2e4c2233 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_addr.h @@ -0,0 +1,168 @@ +/* + * 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> + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" + +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr { +  PACK_STRUCT_FIELD(u32_t addr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { +  PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +struct netif; + +extern const struct ip_addr ip_addr_any; +extern const struct ip_addr ip_addr_broadcast; + +/** IP_ADDR_ can be used as a fixed IP address + *  for the wildcard and the broadcast address + */ +#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any) +#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast) + +/* Definitions of the bits in an Internet address integer. + +   On subnets, host and network parts are found according to +   the subnet mask, not these masks.  */ + +#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IN_CLASSA_NET       0xff000000 +#define IN_CLASSA_NSHIFT    24 +#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX       128 + +#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IN_CLASSB_NET       0xffff0000 +#define IN_CLASSB_NSHIFT    16 +#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX       65536 + +#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IN_CLASSC_NET       0xffffff00 +#define IN_CLASSC_NSHIFT    8 +#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */ +#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */ +#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */ +#define IN_MULTICAST(a)     IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) + +#define IN_LOOPBACKNET      127                 /* official! */ + +#define IP4_ADDR(ipaddr, a,b,c,d) \ +        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \ +                               ((u32_t)((b) & 0xff) << 16) | \ +                               ((u32_t)((c) & 0xff) << 8) | \ +                                (u32_t)((d) & 0xff)) + +#define ip_addr_set(dest, src) (dest)->addr = \ +                               ((src) == NULL? 0:\ +                               (src)->addr) +/** + * Determine if two address are on the same network. + * + * @arg addr1 IP address 1 + * @arg addr2 IP address 2 + * @arg mask network identifier mask + * @return !0 if the network identifiers of both address match + */ +#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \ +                                              (mask)->addr) == \ +                                             ((addr2)->addr & \ +                                              (mask)->addr)) +#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) + +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0) + +u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *); + +#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL)) + +#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL)) + +#define ip_addr_debug_print(debug, ipaddr) \ +  LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F,              \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0,  \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0,  \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0,   \ +                      ipaddr != NULL ?                                  \ +                      (u16_t)ntohl((ipaddr)->addr) & 0xff : 0)) + +/* These are cast to u16_t, with the intent that they are often arguments + * to printf using the U16_F format from cc.h. */ +#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) +#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) +#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) +#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h new file mode 100644 index 000000000..380e604dc --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv4/lwip/ip_frag.h @@ -0,0 +1,76 @@ +/* + * 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> + * + */ + +#ifndef __LWIP_IP_FRAG_H__ +#define __LWIP_IP_FRAG_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if IP_REASSEMBLY +/* The IP reassembly timer interval in milliseconds. */ +#define IP_TMR_INTERVAL 1000 + +/* IP reassembly helper struct. + * This is exported because memp needs to know the size. + */ +struct ip_reassdata { +  struct ip_reassdata *next; +  struct pbuf *p; +  struct ip_hdr iphdr; +  u16_t datagram_len; +  u8_t flags; +  u8_t timer; +}; + +void ip_reass_init(void); +void ip_reass_tmr(void); +struct pbuf * ip_reass(struct pbuf *p); +#endif /* IP_REASSEMBLY */ + +#if IP_FRAG +err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest); +#endif /* IP_FRAG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_FRAG_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h new file mode 100644 index 000000000..87e9ffd96 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/icmp.h @@ -0,0 +1,100 @@ +/* + * 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> + * + */ +#ifndef __LWIP_ICMP_H__ +#define __LWIP_ICMP_H__ + +#include "lwip/opt.h" + +#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define ICMP6_DUR  1 +#define ICMP6_TE   3 +#define ICMP6_ECHO 128    /* echo */ +#define ICMP6_ER   129      /* echo reply */ + + +enum icmp_dur_type { +  ICMP_DUR_NET = 0,    /* net unreachable */ +  ICMP_DUR_HOST = 1,   /* host unreachable */ +  ICMP_DUR_PROTO = 2,  /* protocol unreachable */ +  ICMP_DUR_PORT = 3,   /* port unreachable */ +  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */ +  ICMP_DUR_SR = 5      /* source route failed */ +}; + +enum icmp_te_type { +  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */ +  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */ +}; + +void icmp_input(struct pbuf *p, struct netif *inp); + +void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t); +void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t); + +struct icmp_echo_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u16_t id; +  u16_t seqno; +}; + +struct icmp_dur_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u32_t unused; +}; + +struct icmp_te_hdr { +  u8_t type; +  u8_t icode; +  u16_t chksum; +  u32_t unused; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ICMP */ + +#endif /* __LWIP_ICMP_H__ */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h new file mode 100644 index 000000000..de1a0b636 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/inet.h @@ -0,0 +1,68 @@ +/* + * 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> + * + */ +#ifndef __LWIP_INET_H__ +#define __LWIP_INET_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +u16_t inet_chksum(void *data, u16_t len); +u16_t inet_chksum_pbuf(struct pbuf *p); +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 inet_addr(const char *cp); +s8_t inet_aton(const char *cp, struct in_addr *addr); + +#ifndef _MACHINE_ENDIAN_H_ +#ifndef _NETINET_IN_H +#ifndef _LINUX_BYTEORDER_GENERIC_H +u16_t htons(u16_t n); +u16_t ntohs(u16_t n); +u32_t htonl(u32_t n); +u32_t ntohl(u32_t n); +#endif /* _LINUX_BYTEORDER_GENERIC_H */ +#endif /* _NETINET_IN_H */ +#endif /* _MACHINE_ENDIAN_H_ */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INET_H__ */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h new file mode 100644 index 000000000..a01cfc65b --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip.h @@ -0,0 +1,130 @@ +/* + * 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> + * + */ +#ifndef __LWIP_IP_H__ +#define __LWIP_IP_H__ + +#include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" + +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_HLEN 40 + +#define IP_PROTO_ICMP    58 +#define IP_PROTO_UDP     17 +#define IP_PROTO_UDPLITE 136 +#define IP_PROTO_TCP     6 + +/* This is passed as the destination address to ip_output_if (not +   to ip_output), meaning that an IP header already is constructed +   in the pbuf. This is used when TCP retransmits. */ +#ifdef IP_HDRINCL +#undef IP_HDRINCL +#endif /* IP_HDRINCL */ +#define IP_HDRINCL  NULL + +#if LWIP_NETIF_HWADDRHINT +#define IP_PCB_ADDRHINT ;u8_t addr_hint +#else +#define IP_PCB_ADDRHINT +#endif /* LWIP_NETIF_HWADDRHINT */ + +/* This is the common part of all PCB types. It needs to be at the +   beginning of a PCB type definition. It is located here so that +   changes to this common part are made in one location instead of +   having to change all PCB structs. */ +#define IP_PCB struct ip_addr local_ip; \ +  struct ip_addr remote_ip; \ +   /* Socket options */  \ +  u16_t so_options;      \ +   /* Type Of Service */ \ +  u8_t tos;              \ +  /* Time To Live */     \ +  u8_t ttl;              \ +  /* link layer address resolution hint */ \ +  IP_PCB_ADDRHINT + + +/* The IPv6 header. */ +struct ip_hdr { +#if BYTE_ORDER == LITTLE_ENDIAN +  u8_t tclass1:4, v:4; +  u8_t flow1:4, tclass2:4;   +#else +  u8_t v:4, tclass1:4; +  u8_t tclass2:8, flow1:4; +#endif +  u16_t flow2; +  u16_t len;                /* payload length */ +  u8_t nexthdr;             /* next header */ +  u8_t hoplim;              /* hop limit (TTL) */ +  struct ip_addr src, dest;          /* source and destination IP addresses */ +}; + +#define IPH_PROTO(hdr) (iphdr->nexthdr) + +void ip_init(void); + +#include "lwip/netif.h" + +struct netif *ip_route(struct ip_addr *dest); + +void ip_input(struct pbuf *p, struct netif *inp); + +/* source and destination addresses in network byte order, please */ +err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +         u8_t ttl, u8_t proto); + +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); + +#define ip_current_netif() NULL +#define ip_current_header() NULL + +#if IP_DEBUG +void ip_debug_print(struct pbuf *p); +#endif /* IP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_H__ */ + + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h new file mode 100644 index 000000000..b2d8ae566 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/ipv6/lwip/ip_addr.h @@ -0,0 +1,97 @@ +/* + * 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> + * + */ +#ifndef __LWIP_IP_ADDR_H__ +#define __LWIP_IP_ADDR_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define IP_ADDR_ANY 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN + struct ip_addr { +  PACK_STRUCT_FIELD(u32_t addr[4]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/* + * struct ipaddr2 is used in the definition of the ARP packet format in + * order to support compilers that don't have structure packing. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ip_addr2 { +  PACK_STRUCT_FIELD(u16_t addrw[2]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \ +                                               (ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \ +                                               (ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \ +                                               (ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0) + +u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2, +        struct ip_addr *mask); +u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2); +void ip_addr_set(struct ip_addr *dest, struct ip_addr *src); +u8_t ip_addr_isany(struct ip_addr *addr); + +#define ip_addr_debug_print(debug, ipaddr) \ +        LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \ +         (ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[0]) & 0xffff, \ +         (ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[1]) & 0xffff, \ +         (ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[2]) & 0xffff, \ +         (ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \ +         ntohl(ipaddr->addr[3]) & 0xffff)); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_IP_ADDR_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api.h new file mode 100644 index 000000000..f6b1f7434 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api.h @@ -0,0 +1,222 @@ +/* + * 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> + * + */ +#ifndef __LWIP_API_H__ +#define __LWIP_API_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/netbuf.h" +#include "lwip/sys.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ + +/* Flags for netconn_write */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY   0x01 +#define NETCONN_MORE   0x02 + +/* Helpers to process several netconn_types by the same code */ +#define NETCONNTYPE_GROUP(t)    (t&0xF0) +#define NETCONNTYPE_DATAGRAM(t) (t&0xE0) + +enum netconn_type { +  NETCONN_INVALID    = 0, +  /* NETCONN_TCP Group */ +  NETCONN_TCP        = 0x10, +  /* NETCONN_UDP Group */ +  NETCONN_UDP        = 0x20, +  NETCONN_UDPLITE    = 0x21, +  NETCONN_UDPNOCHKSUM= 0x22, +  /* NETCONN_RAW Group */ +  NETCONN_RAW        = 0x40 +}; + +enum netconn_state { +  NETCONN_NONE, +  NETCONN_WRITE, +  NETCONN_LISTEN, +  NETCONN_CONNECT, +  NETCONN_CLOSE +}; + +enum netconn_evt { +  NETCONN_EVT_RCVPLUS, +  NETCONN_EVT_RCVMINUS, +  NETCONN_EVT_SENDPLUS, +  NETCONN_EVT_SENDMINUS +}; + +#if LWIP_IGMP +enum netconn_igmp { +  NETCONN_JOIN, +  NETCONN_LEAVE +}; +#endif /* LWIP_IGMP */ + +/* forward-declare some structs to avoid to include their headers */ +struct ip_pcb; +struct tcp_pcb; +struct udp_pcb; +struct raw_pcb; +struct netconn; + +/** A callback prototype to inform about events for a netconn */ +typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); + +/** A netconn descriptor */ +struct netconn { +  /** type of the netconn (TCP, UDP or RAW) */ +  enum netconn_type type; +  /** current state of the netconn */ +  enum netconn_state state; +  /** the lwIP internal protocol control block */ +  union { +    struct ip_pcb  *ip; +    struct tcp_pcb *tcp; +    struct udp_pcb *udp; +    struct raw_pcb *raw; +  } pcb; +  /** the last error this netconn had */ +  err_t err; +  /** sem that is used to synchroneously execute functions in the core context */ +  sys_sem_t op_completed; +  /** mbox where received packets are stored until they are fetched +      by the netconn application thread (can grow quite big) */ +  sys_mbox_t recvmbox; +  /** mbox where new connections are stored until processed +      by the application thread */ +  sys_mbox_t acceptmbox; +  /** only used for socket layer */ +  int socket; +#if LWIP_SO_RCVTIMEO +  /** timeout to wait for new data to be received +      (or connections to arrive for listening netconns) */ +  int recv_timeout; +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +  /** maximum amount of bytes queued in recvmbox */ +  int recv_bufsize; +#endif /* LWIP_SO_RCVBUF */ +  s16_t recv_avail; +#if LWIP_TCP +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores the message. */ +  struct api_msg_msg *write_msg; +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores how much is already sent. */ +  size_t write_offset; +#if LWIP_TCPIP_CORE_LOCKING +  /** TCP: when data passed to netconn_write doesn't fit into the send buffer, +      this temporarily stores whether to wake up the original application task +      if data couldn't be sent in the first try. */ +  u8_t write_delayed; +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_TCP */ +  /** A callback function that is informed about events for this netconn */ +  netconn_callback callback; +}; + +/* Register an Network connection event */ +#define API_EVENT(c,e,l) if (c->callback) {         \ +                           (*c->callback)(c, e, l); \ +                         } + +/* Network connection functions: */ +#define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL) +#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) +struct +netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, +                                   netconn_callback callback); +err_t             netconn_delete  (struct netconn *conn); +/** Get the type of a netconn (as enum netconn_type). */ +#define netconn_type(conn) (conn->type) + +err_t             netconn_getaddr (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t *port, +                                   u8_t local); +#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) +#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) + +err_t             netconn_bind    (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t port); +err_t             netconn_connect (struct netconn *conn, +                                   struct ip_addr *addr, +                                   u16_t port); +err_t             netconn_disconnect (struct netconn *conn); +err_t             netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) +struct netconn *  netconn_accept  (struct netconn *conn); +struct netbuf *   netconn_recv    (struct netconn *conn); +err_t             netconn_sendto  (struct netconn *conn, +                                   struct netbuf *buf, struct ip_addr *addr, u16_t port); +err_t             netconn_send    (struct netconn *conn, +                                   struct netbuf *buf); +err_t             netconn_write   (struct netconn *conn, +                                   const void *dataptr, size_t size, +                                   u8_t apiflags); +err_t             netconn_close   (struct netconn *conn); + +#if LWIP_IGMP +err_t             netconn_join_leave_group (struct netconn *conn, +                                            struct ip_addr *multiaddr, +                                            struct ip_addr *interface, +                                            enum netconn_igmp join_or_leave); +#endif /* LWIP_IGMP */ +#if LWIP_DNS +err_t             netconn_gethostbyname(const char *name, struct ip_addr *addr); +#endif /* LWIP_DNS */ + +#define netconn_err(conn)          ((conn)->err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api_msg.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api_msg.h new file mode 100644 index 000000000..4272d77cc --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/api_msg.h @@ -0,0 +1,162 @@ +/* + * 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> + * + */ +#ifndef __LWIP_API_MSG_H__ +#define __LWIP_API_MSG_H__ + +#include "lwip/opt.h" + +#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/err.h" +#include "lwip/sys.h" +#include "lwip/igmp.h" +#include "lwip/api.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* IP addresses and port numbers are expected to be in + * the same byte order as in the corresponding pcb. + */ +/** This struct includes everything that is necessary to execute a function +    for a netconn in another thread context (mainly used to process netconns +    in the tcpip_thread context to be thread safe). */ +struct api_msg_msg { +  /** The netconn which to process - always needed: it includes the semaphore +      which is used to block the application thread until the function finished. */ +  struct netconn *conn; +  /** Depending on the executed function, one of these union members is used */ +  union { +    /** used for do_send */ +    struct netbuf *b; +    /** used for do_newconn */ +    struct { +      u8_t proto; +    } n; +    /** used for do_bind and do_connect */ +    struct { +      struct ip_addr *ipaddr; +      u16_t port; +    } bc; +    /** used for do_getaddr */ +    struct { +      struct ip_addr *ipaddr; +      u16_t *port; +      u8_t local; +    } ad; +    /** used for do_write */ +    struct { +      const void *dataptr; +      size_t len; +      u8_t apiflags; +    } w; +    /** used ofr do_recv */ +    struct { +      u16_t len; +    } r; +#if LWIP_IGMP +    /** used for do_join_leave_group */ +    struct { +      struct ip_addr *multiaddr; +      struct ip_addr *interface; +      enum netconn_igmp join_or_leave; +    } jl; +#endif /* LWIP_IGMP */ +#if TCP_LISTEN_BACKLOG +    struct { +      u8_t backlog; +    } lb; +#endif /* TCP_LISTEN_BACKLOG */ +  } msg; +}; + +/** This struct contains a function to execute in another thread context and +    a struct api_msg_msg that serves as an argument for this function. +    This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */ +struct api_msg { +  /** function to execute in tcpip_thread context */ +  void (* function)(struct api_msg_msg *msg); +  /** arguments for this function */ +  struct api_msg_msg msg; +}; + +#if LWIP_DNS +/** As do_gethostbyname requires more arguments but doesn't require a netconn, +    it has its own struct (to avoid struct api_msg getting bigger than necessary). +    do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg +    (see netconn_gethostbyname). */ +struct dns_api_msg { +  /** Hostname to query or dotted IP address string */ +  const char *name; +  /** Rhe resolved address is stored here */ +  struct ip_addr *addr; +  /** This semaphore is posted when the name is resolved, the application thread +      should wait on it. */ +  sys_sem_t sem; +  /** Errors are given back here */ +  err_t *err; +}; +#endif /* LWIP_DNS */ + +void do_newconn         ( struct api_msg_msg *msg); +void do_delconn         ( struct api_msg_msg *msg); +void do_bind            ( struct api_msg_msg *msg); +void do_connect         ( struct api_msg_msg *msg); +void do_disconnect      ( struct api_msg_msg *msg); +void do_listen          ( struct api_msg_msg *msg); +void do_send            ( struct api_msg_msg *msg); +void do_recv            ( struct api_msg_msg *msg); +void do_write           ( struct api_msg_msg *msg); +void do_getaddr         ( struct api_msg_msg *msg); +void do_close           ( struct api_msg_msg *msg); +#if LWIP_IGMP +void do_join_leave_group( struct api_msg_msg *msg); +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +void do_gethostbyname(void *arg); +#endif /* LWIP_DNS */ + +struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback); +void netconn_free(struct netconn *conn); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETCONN */ + +#endif /* __LWIP_API_MSG_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/arch.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/arch.h new file mode 100644 index 000000000..3a5a0e4f2 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/arch.h @@ -0,0 +1,233 @@ +/* + * 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> + * + */ +#ifndef __LWIP_ARCH_H__ +#define __LWIP_ARCH_H__ + +#ifndef LITTLE_ENDIAN +#define LITTLE_ENDIAN 1234 +#endif + +#ifndef BIG_ENDIAN +#define BIG_ENDIAN 4321 +#endif + +#include "arch/cc.h" + +/** Temporary: define format string for size_t if not defined in cc.h */ +#ifndef SZT_F +#define SZT_F U32_F +#endif /* SZT_F */ + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef PACK_STRUCT_BEGIN +#define PACK_STRUCT_BEGIN +#endif /* PACK_STRUCT_BEGIN */ + +#ifndef PACK_STRUCT_END +#define PACK_STRUCT_END +#endif /* PACK_STRUCT_END */ + +#ifndef PACK_STRUCT_FIELD +#define PACK_STRUCT_FIELD(x) x +#endif /* PACK_STRUCT_FIELD */ + + +#ifndef LWIP_UNUSED_ARG +#define LWIP_UNUSED_ARG(x) (void)x +#endif /* LWIP_UNUSED_ARG */  + + +#ifdef LWIP_PROVIDE_ERRNO + +#define  EPERM     1  /* Operation not permitted */ +#define  ENOENT     2  /* No such file or directory */ +#define  ESRCH     3  /* No such process */ +#define  EINTR     4  /* Interrupted system call */ +#define  EIO     5  /* I/O error */ +#define  ENXIO     6  /* No such device or address */ +#define  E2BIG     7  /* Arg list too long */ +#define  ENOEXEC     8  /* Exec format error */ +#define  EBADF     9  /* Bad file number */ +#define  ECHILD    10  /* No child processes */ +#define  EAGAIN    11  /* Try again */ +#define  ENOMEM    12  /* Out of memory */ +#define  EACCES    13  /* Permission denied */ +#define  EFAULT    14  /* Bad address */ +#define  ENOTBLK    15  /* Block device required */ +#define  EBUSY    16  /* Device or resource busy */ +#define  EEXIST    17  /* File exists */ +#define  EXDEV    18  /* Cross-device link */ +#define  ENODEV    19  /* No such device */ +#define  ENOTDIR    20  /* Not a directory */ +#define  EISDIR    21  /* Is a directory */ +#define  EINVAL    22  /* Invalid argument */ +#define  ENFILE    23  /* File table overflow */ +#define  EMFILE    24  /* Too many open files */ +#define  ENOTTY    25  /* Not a typewriter */ +#define  ETXTBSY    26  /* Text file busy */ +#define  EFBIG    27  /* File too large */ +#define  ENOSPC    28  /* No space left on device */ +#define  ESPIPE    29  /* Illegal seek */ +#define  EROFS    30  /* Read-only file system */ +#define  EMLINK    31  /* Too many links */ +#define  EPIPE    32  /* Broken pipe */ +#define  EDOM    33  /* Math argument out of domain of func */ +#define  ERANGE    34  /* Math result not representable */ +#define  EDEADLK    35  /* Resource deadlock would occur */ +#define  ENAMETOOLONG  36  /* File name too long */ +#define  ENOLCK    37  /* No record locks available */ +#define  ENOSYS    38  /* Function not implemented */ +#define  ENOTEMPTY  39  /* Directory not empty */ +#define  ELOOP    40  /* Too many symbolic links encountered */ +#define  EWOULDBLOCK  EAGAIN  /* Operation would block */ +#define  ENOMSG    42  /* No message of desired type */ +#define  EIDRM    43  /* Identifier removed */ +#define  ECHRNG    44  /* Channel number out of range */ +#define  EL2NSYNC  45  /* Level 2 not synchronized */ +#define  EL3HLT    46  /* Level 3 halted */ +#define  EL3RST    47  /* Level 3 reset */ +#define  ELNRNG    48  /* Link number out of range */ +#define  EUNATCH    49  /* Protocol driver not attached */ +#define  ENOCSI    50  /* No CSI structure available */ +#define  EL2HLT    51  /* Level 2 halted */ +#define  EBADE    52  /* Invalid exchange */ +#define  EBADR    53  /* Invalid request descriptor */ +#define  EXFULL    54  /* Exchange full */ +#define  ENOANO    55  /* No anode */ +#define  EBADRQC    56  /* Invalid request code */ +#define  EBADSLT    57  /* Invalid slot */ + +#define  EDEADLOCK  EDEADLK + +#define  EBFONT    59  /* Bad font file format */ +#define  ENOSTR    60  /* Device not a stream */ +#define  ENODATA    61  /* No data available */ +#define  ETIME    62  /* Timer expired */ +#define  ENOSR    63  /* Out of streams resources */ +#define  ENONET    64  /* Machine is not on the network */ +#define  ENOPKG    65  /* Package not installed */ +#define  EREMOTE    66  /* Object is remote */ +#define  ENOLINK    67  /* Link has been severed */ +#define  EADV    68  /* Advertise error */ +#define  ESRMNT    69  /* Srmount error */ +#define  ECOMM    70  /* Communication error on send */ +#define  EPROTO    71  /* Protocol error */ +#define  EMULTIHOP  72  /* Multihop attempted */ +#define  EDOTDOT    73  /* RFS specific error */ +#define  EBADMSG    74  /* Not a data message */ +#define  EOVERFLOW  75  /* Value too large for defined data type */ +#define  ENOTUNIQ  76  /* Name not unique on network */ +#define  EBADFD    77  /* File descriptor in bad state */ +#define  EREMCHG    78  /* Remote address changed */ +#define  ELIBACC    79  /* Can not access a needed shared library */ +#define  ELIBBAD    80  /* Accessing a corrupted shared library */ +#define  ELIBSCN    81  /* .lib section in a.out corrupted */ +#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */ +#define  ELIBEXEC  83  /* Cannot exec a shared library directly */ +#define  EILSEQ    84  /* Illegal byte sequence */ +#define  ERESTART  85  /* Interrupted system call should be restarted */ +#define  ESTRPIPE  86  /* Streams pipe error */ +#define  EUSERS    87  /* Too many users */ +#define  ENOTSOCK  88  /* Socket operation on non-socket */ +#define  EDESTADDRREQ  89  /* Destination address required */ +#define  EMSGSIZE  90  /* Message too long */ +#define  EPROTOTYPE  91  /* Protocol wrong type for socket */ +#define  ENOPROTOOPT  92  /* Protocol not available */ +#define  EPROTONOSUPPORT  93  /* Protocol not supported */ +#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */ +#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */ +#define  EPFNOSUPPORT  96  /* Protocol family not supported */ +#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */ +#define  EADDRINUSE  98  /* Address already in use */ +#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */ +#define  ENETDOWN  100  /* Network is down */ +#define  ENETUNREACH  101  /* Network is unreachable */ +#define  ENETRESET  102  /* Network dropped connection because of reset */ +#define  ECONNABORTED  103  /* Software caused connection abort */ +#define  ECONNRESET  104  /* Connection reset by peer */ +#define  ENOBUFS    105  /* No buffer space available */ +#define  EISCONN    106  /* Transport endpoint is already connected */ +#define  ENOTCONN  107  /* Transport endpoint is not connected */ +#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */ +#define  ETOOMANYREFS  109  /* Too many references: cannot splice */ +#define  ETIMEDOUT  110  /* Connection timed out */ +#define  ECONNREFUSED  111  /* Connection refused */ +#define  EHOSTDOWN  112  /* Host is down */ +#define  EHOSTUNREACH  113  /* No route to host */ +#define  EALREADY  114  /* Operation already in progress */ +#define  EINPROGRESS  115  /* Operation now in progress */ +#define  ESTALE    116  /* Stale NFS file handle */ +#define  EUCLEAN    117  /* Structure needs cleaning */ +#define  ENOTNAM    118  /* Not a XENIX named type file */ +#define  ENAVAIL    119  /* No XENIX semaphores available */ +#define  EISNAM    120  /* Is a named type file */ +#define  EREMOTEIO  121  /* Remote I/O error */ +#define  EDQUOT    122  /* Quota exceeded */ + +#define  ENOMEDIUM  123  /* No medium found */ +#define  EMEDIUMTYPE  124  /* Wrong medium type */ + + +#define ENSROK    0 /* DNS server returned answer with no data */ +#define ENSRNODATA  160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162  /* DNS server returned general failure */ +#define ENSRNOTFOUND 163  /* Domain name not found */ +#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166  /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF    172 /* End of file */ +#define ENSRFILE  173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ + +#ifndef errno +extern int errno; +#endif + +#endif /* LWIP_PROVIDE_ERRNO */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ARCH_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/debug.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/debug.h new file mode 100644 index 000000000..d5c4e4747 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/debug.h @@ -0,0 +1,97 @@ +/* + * 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> + * + */ +#ifndef __LWIP_DEBUG_H__ +#define __LWIP_DEBUG_H__ + +#include "lwip/arch.h" + +/** lower two bits indicate debug level + * - 0 off + * - 1 warning + * - 2 serious + * - 3 severe + */ +#define LWIP_DBG_LEVEL_OFF     0x00 +#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */ +#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */ +#define LWIP_DBG_LEVEL_SEVERE  0x03 +#define LWIP_DBG_MASK_LEVEL    0x03 + +/** flag for LWIP_DEBUGF to enable that debug message */ +#define LWIP_DBG_ON            0x80U +/** flag for LWIP_DEBUGF to disable that debug message */ +#define LWIP_DBG_OFF           0x00U + +/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */ +#define LWIP_DBG_TRACE         0x40U +/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */ +#define LWIP_DBG_STATE         0x20U +/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */ +#define LWIP_DBG_FRESH         0x10U +/** flag for LWIP_DEBUGF to halt after printing this debug message */ +#define LWIP_DBG_HALT          0x08U + +#ifndef LWIP_NOASSERT +#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \ +  LWIP_PLATFORM_ASSERT(message); } while(0) +#else  /* LWIP_NOASSERT */ +#define LWIP_ASSERT(message, assertion)  +#endif /* LWIP_NOASSERT */ + +/** if "expression" isn't true, then print "message" and execute "handler" expression */ +#ifndef LWIP_ERROR +#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \ +  LWIP_PLATFORM_ASSERT(message); handler;}} while(0) +#endif /* LWIP_ERROR */ + +#ifdef LWIP_DEBUG +/** print debug message only if debug message type is enabled... + *  AND is of correct type AND is at least LWIP_DBG_LEVEL + */ +#define LWIP_DEBUGF(debug, message) do { \ +                               if ( \ +                                   ((debug) & LWIP_DBG_ON) && \ +                                   ((debug) & LWIP_DBG_TYPES_ON) && \ +                                   ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \ +                                 LWIP_PLATFORM_DIAG(message); \ +                                 if ((debug) & LWIP_DBG_HALT) { \ +                                   while(1); \ +                                 } \ +                               } \ +                             } while(0) + +#else  /* LWIP_DEBUG */ +#define LWIP_DEBUGF(debug, message)  +#endif /* LWIP_DEBUG */ + +#endif /* __LWIP_DEBUG_H__ */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/def.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/def.h new file mode 100644 index 000000000..d2ed251df --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/def.h @@ -0,0 +1,47 @@ +/* + * 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> + * + */ +#ifndef __LWIP_DEF_H__ +#define __LWIP_DEF_H__ + +/* this might define NULL already */ +#include "lwip/arch.h" + +#define LWIP_MAX(x , y)  (((x) > (y)) ? (x) : (y)) +#define LWIP_MIN(x , y)  (((x) < (y)) ? (x) : (y)) + +#ifndef NULL +#define NULL ((void *)0) +#endif + + +#endif /* __LWIP_DEF_H__ */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dhcp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dhcp.h new file mode 100644 index 000000000..825dba6ec --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dhcp.h @@ -0,0 +1,246 @@ +/** @file + */ + +#ifndef __LWIP_DHCP_H__ +#define __LWIP_DHCP_H__ + +#include "lwip/opt.h" + +#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** period (in seconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_SECS 60  +/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */ +#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL) +/** period (in milliseconds) of the application calling dhcp_fine_tmr() */ +#define DHCP_FINE_TIMER_MSECS 500  + +struct dhcp +{ +  /** current DHCP state machine state */ +  u8_t state; +  /** retries of current request */ +  u8_t tries; +  /** transaction identifier of last sent request */  +  u32_t xid; +  /** our connection to the DHCP server */  +  struct udp_pcb *pcb; +  /** (first) pbuf of incoming msg */ +  struct pbuf *p; +  /** incoming msg */ +  struct dhcp_msg *msg_in; +  /** incoming msg options */ +  struct dhcp_msg *options_in;  +  /** ingoing msg options length */ +  u16_t options_in_len; + +  struct pbuf *p_out; /* pbuf of outcoming msg */ +  struct dhcp_msg *msg_out; /* outgoing msg */ +  u16_t options_out_len; /* outgoing msg options length */ +  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ +  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ +  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ +  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */ +  struct ip_addr offered_ip_addr; +  struct ip_addr offered_sn_mask; +  struct ip_addr offered_gw_addr; +  struct ip_addr offered_bc_addr; +#define DHCP_MAX_DNS 2 +  u32_t dns_count; /* actual number of DNS servers obtained */ +  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */ +  +  u32_t offered_t0_lease; /* lease period (in seconds) */ +  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ +  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */ +#if LWIP_DHCP_AUTOIP_COOP +  u8_t autoip_coop_state; +#endif +/** Patch #1308 + *  TODO: See dhcp.c "TODO"s + */ +#if 0 +  struct ip_addr offered_si_addr; +  u8_t *boot_file_name; +#endif +}; + +/* MUST be compiled with "pack structs" or equivalent! */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** minimum set of fields of any DHCP message */ +struct dhcp_msg +{ +  PACK_STRUCT_FIELD(u8_t op); +  PACK_STRUCT_FIELD(u8_t htype); +  PACK_STRUCT_FIELD(u8_t hlen); +  PACK_STRUCT_FIELD(u8_t hops); +  PACK_STRUCT_FIELD(u32_t xid); +  PACK_STRUCT_FIELD(u16_t secs); +  PACK_STRUCT_FIELD(u16_t flags); +  PACK_STRUCT_FIELD(struct ip_addr ciaddr); +  PACK_STRUCT_FIELD(struct ip_addr yiaddr); +  PACK_STRUCT_FIELD(struct ip_addr siaddr); +  PACK_STRUCT_FIELD(struct ip_addr giaddr); +#define DHCP_CHADDR_LEN 16U +  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); +#define DHCP_SNAME_LEN 64U +  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); +#define DHCP_FILE_LEN 128U +  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); +  PACK_STRUCT_FIELD(u32_t cookie); +#define DHCP_MIN_OPTIONS_LEN 68U +/** make sure user does not configure this too small */ +#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN)) +#  undef DHCP_OPTIONS_LEN +#endif +/** allow this to be configured in lwipopts.h, but not too small */ +#if (!defined(DHCP_OPTIONS_LEN)) +/** set this to be sufficient for your options in outgoing DHCP msgs */ +#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN +#endif +  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/** start DHCP configuration */ +err_t dhcp_start(struct netif *netif); +/** enforce early lease renewal (not needed normally)*/ +err_t dhcp_renew(struct netif *netif); +/** release the DHCP lease, usually called before dhcp_stop()*/ +err_t dhcp_release(struct netif *netif); +/** stop DHCP configuration */ +void dhcp_stop(struct netif *netif); +/** inform server of our manual IP address */ +void dhcp_inform(struct netif *netif); + +/** if enabled, check whether the offered IP address is not in use, using ARP */ +#if DHCP_DOES_ARP_CHECK +void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr); +#endif + +/** to be called every minute */ +void dhcp_coarse_tmr(void); +/** to be called every half second */ +void dhcp_fine_tmr(void); +  +/** DHCP message item offsets and length */ +#define DHCP_MSG_OFS (UDP_DATA_OFS)   +  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0) +  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1) +  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2) +  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3) +  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4) +  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8) +  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10) +  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12) +  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16) +  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20) +  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24) +  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28) +  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44) +  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108) +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN) +#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68   +#define DHCP_SERVER_PORT 67 + +/** DHCP client states */ +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 +/** not yet implemented #define DHCP_RELEASING 11 */ +#define DHCP_BACKING_OFF 12 +#define DHCP_OFF 13 + +/** AUTOIP cooperatation flags */ +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 +  +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 + +#define DHCP_DISCOVER 1 +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +#define DHCP_HTYPE_ETH 1 + +#define DHCP_HLEN_ETH 6 + +#define DHCP_BROADCAST_FLAG 15 +#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST) + +/** BootP options */ +#define DHCP_OPTION_PAD 0 +#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */ +#define DHCP_OPTION_ROUTER 3 +#define DHCP_OPTION_DNS_SERVER 6  +#define DHCP_OPTION_HOSTNAME 12 +#define DHCP_OPTION_IP_TTL 23 +#define DHCP_OPTION_MTU 26 +#define DHCP_OPTION_BROADCAST 28 +#define DHCP_OPTION_TCP_TTL 37 +#define DHCP_OPTION_END 255 + +/** DHCP options */ +#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */ +#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */ +#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */ + +#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ +#define DHCP_OPTION_MESSAGE_TYPE_LEN 1 + + +#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ +#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ + +#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */ +#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2 + +#define DHCP_OPTION_T1 58 /* T1 renewal time */ +#define DHCP_OPTION_T2 59 /* T2 rebinding time */ +#define DHCP_OPTION_US 60 +#define DHCP_OPTION_CLIENT_ID 61 +#define DHCP_OPTION_TFTP_SERVERNAME 66 +#define DHCP_OPTION_BOOTFILE 67 + +/** possible combinations of overloading the file and sname fields with options */ +#define DHCP_OVERLOAD_NONE 0 +#define DHCP_OVERLOAD_FILE 1 +#define DHCP_OVERLOAD_SNAME  2 +#define DHCP_OVERLOAD_SNAME_FILE 3 + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_DHCP */ + +#endif /*__LWIP_DHCP_H__*/ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dns.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dns.h new file mode 100644 index 000000000..e5f4b7a3d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/dns.h @@ -0,0 +1,97 @@ +/** + * lwip DNS resolver header file. + + * Author: Jim Pettinato  + *   April 2007 + + * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels. + * + * 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. + */ + +#ifndef __LWIP_DNS_H__ +#define __LWIP_DNS_H__ + +#include "lwip/opt.h" + +#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ + +/** DNS timer period */ +#define DNS_TMR_INTERVAL          1000 + +/** DNS field TYPE used for "Resource Records" */ +#define DNS_RRTYPE_A              1     /* a host address */ +#define DNS_RRTYPE_NS             2     /* an authoritative name server */ +#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */ +#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */ +#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */ +#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */ +#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */ +#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */ +#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */ +#define DNS_RRTYPE_WKS            11    /* a well known service description */ +#define DNS_RRTYPE_PTR            12    /* a domain name pointer */ +#define DNS_RRTYPE_HINFO          13    /* host information */ +#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */ +#define DNS_RRTYPE_MX             15    /* mail exchange */ +#define DNS_RRTYPE_TXT            16    /* text strings */ + +/** DNS field CLASS used for "Resource Records" */ +#define DNS_RRCLASS_IN            1     /* the Internet */ +#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */ +#define DNS_RRCLASS_CH            3     /* the CHAOS class */ +#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */ +#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */ + +/** Callback which is invoked when a hostname is found. + * A function of this type must be implemented by the application using the DNS resolver. + * @param name pointer to the name that was looked up. + * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, + *        or NULL if the name could not be found (or on any other error). + * @param callback_arg a user-specified callback argument passed to dns_gethostbyname +*/ +typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg); + + +void           dns_init(void); + +void           dns_tmr(void); + +void           dns_setserver(u8_t numdns, struct ip_addr *dnsserver); + +struct ip_addr dns_getserver(u8_t numdns); + +err_t          dns_gethostbyname(const char *hostname, struct ip_addr *addr, +                                 dns_found_callback found, void *callback_arg); + +#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +int            dns_local_removehost(const char *hostname, const struct ip_addr *addr); +err_t          dns_local_addhost(const char *hostname, const struct ip_addr *addr); +#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +#endif /* LWIP_DNS */ + +#endif /* __LWIP_DNS_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/err.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/err.h new file mode 100644 index 000000000..696764454 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/err.h @@ -0,0 +1,87 @@ +/* + * 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> + * + */ +#ifndef __LWIP_ERR_H__ +#define __LWIP_ERR_H__ + +#include "lwip/opt.h" +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** Define LWIP_ERR_T in cc.h if you want to use + *  a different type for your platform (must be signed). */ +#ifdef LWIP_ERR_T +typedef LWIP_ERR_T err_t; +#else /* LWIP_ERR_T */ + typedef s8_t err_t; +#endif /* LWIP_ERR_T*/ + +/* Definitions for error constants. */ + +#define ERR_OK          0    /* No error, everything OK. */ +#define ERR_MEM        -1    /* Out of memory error.     */ +#define ERR_BUF        -2    /* Buffer error.            */ +#define ERR_TIMEOUT    -3    /* Timeout.                 */ +#define ERR_RTE        -4    /* Routing problem.         */ + +#define ERR_IS_FATAL(e) ((e) < ERR_RTE) + +#define ERR_ABRT       -5    /* Connection aborted.      */ +#define ERR_RST        -6    /* Connection reset.        */ +#define ERR_CLSD       -7    /* Connection closed.       */ +#define ERR_CONN       -8    /* Not connected.           */ + +#define ERR_VAL        -9    /* Illegal value.           */ + +#define ERR_ARG        -10   /* Illegal argument.        */ + +#define ERR_USE        -11   /* Address in use.          */ + +#define ERR_IF         -12   /* Low-level netif error    */ +#define ERR_ISCONN     -13   /* Already connected.       */ + +#define ERR_INPROGRESS -14   /* Operation in progress    */ + + +#ifdef LWIP_DEBUG +extern const char *lwip_strerr(err_t err); +#else +#define lwip_strerr(x) "" +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_ERR_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/init.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/init.h new file mode 100644 index 000000000..a4dc0577f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/init.h @@ -0,0 +1,72 @@ +/* + * 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> + * + */ +#ifndef __LWIP_INIT_H__ +#define __LWIP_INIT_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** X.x.x: Major version of the stack */ +#define LWIP_VERSION_MAJOR      1U +/** x.X.x: Minor version of the stack */ +#define LWIP_VERSION_MINOR      3U +/** x.x.X: Revision of the stack */ +#define LWIP_VERSION_REVISION   1U +/** For release candidates, this is set to 1..254 +  * For official releases, this is set to 255 (LWIP_RC_RELEASE) +  * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ +#define LWIP_VERSION_RC         255U + +/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */ +#define LWIP_RC_RELEASE         255U +/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */ +#define LWIP_RC_DEVELOPMENT     0U + +#define LWIP_VERSION_IS_RELEASE     (LWIP_VERSION_RC == LWIP_RC_RELEASE) +#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT) +#define LWIP_VERSION_IS_RC          ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT)) + +/** Provides the version of the stack */ +#define LWIP_VERSION   (LWIP_VERSION_MAJOR << 24   | LWIP_VERSION_MINOR << 16 | \ +                        LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC) + +/* Modules initialization */ +void lwip_init(void); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_INIT_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/mem.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/mem.h new file mode 100644 index 000000000..327c2049f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/mem.h @@ -0,0 +1,107 @@ +/* + * 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> + * + */ +#ifndef __LWIP_MEM_H__ +#define __LWIP_MEM_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if MEM_LIBC_MALLOC + +#include <stddef.h> /* for size_t */ + +typedef size_t mem_size_t; + +/* aliases for C library malloc() */ +#define mem_init() +/* in case C library malloc() needs extra protection, + * allow these defines to be overridden. + */ +#ifndef mem_free +#define mem_free free +#endif +#ifndef mem_malloc +#define mem_malloc malloc +#endif +#ifndef mem_calloc +#define mem_calloc calloc +#endif +#ifndef mem_realloc +static void *mem_realloc(void *mem, mem_size_t size) +{ +  LWIP_UNUSED_ARG(size); +  return mem; +} +#endif +#else /* MEM_LIBC_MALLOC */ + +/* MEM_SIZE would have to be aligned, but using 64000 here instead of + * 65535 leaves some room for alignment... + */ +#if MEM_SIZE > 64000l +typedef u32_t mem_size_t; +#else +typedef u16_t mem_size_t; +#endif /* MEM_SIZE > 64000 */ + +#if MEM_USE_POOLS +/** mem_init is not used when using pools instead of a heap */ +#define mem_init() +/** mem_realloc is not used when using pools instead of a heap: +    we can't free part of a pool element and don't want to copy the rest */ +#define mem_realloc(mem, size) (mem) +#else /* MEM_USE_POOLS */ +/* lwIP alternative malloc */ +void  mem_init(void); +void *mem_realloc(void *mem, mem_size_t size); +#endif /* MEM_USE_POOLS */ +void *mem_malloc(mem_size_t size); +void *mem_calloc(mem_size_t count, mem_size_t size); +void  mem_free(void *mem); +#endif /* MEM_LIBC_MALLOC */ + +#ifndef LWIP_MEM_ALIGN_SIZE +#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) +#endif + +#ifndef LWIP_MEM_ALIGN +#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEM_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp.h new file mode 100644 index 000000000..f0d073994 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp.h @@ -0,0 +1,116 @@ +/* + * 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> + * + */ + +#ifndef __LWIP_MEMP_H__ +#define __LWIP_MEMP_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */ +typedef enum { +#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name, +#include "lwip/memp_std.h" +  MEMP_MAX +} memp_t; + +#if MEM_USE_POOLS +/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */ +typedef enum { +    /* Get the first (via: +       MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/ +    MEMP_POOL_HELPER_FIRST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START 1 +#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0 +#define LWIP_MALLOC_MEMPOOL_END +#include "lwip/memp_std.h" +    ) , +    /* Get the last (via: +       MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */ +    MEMP_POOL_HELPER_LAST = ((u8_t) +#define LWIP_MEMPOOL(name,num,size,desc) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size * +#define LWIP_MALLOC_MEMPOOL_END 1 +#include "lwip/memp_std.h" +    ) +} memp_pool_helper_t; + +/* The actual start and stop values are here (cast them over) +   We use this helper type and these defines so we can avoid using const memp_t values */ +#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST) +#define MEMP_POOL_LAST   ((memp_t) MEMP_POOL_HELPER_LAST) +#endif /* MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC || MEM_USE_POOLS +extern const u16_t memp_sizes[MEMP_MAX]; +#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */ + +#if MEMP_MEM_MALLOC + +#include "mem.h" + +#define memp_init() +#define memp_malloc(type)     mem_malloc(memp_sizes[type]) +#define memp_free(type, mem)  mem_free(mem) + +#else /* MEMP_MEM_MALLOC */ + +#if MEM_USE_POOLS +/** This structure is used to save the pool one element came from. */ +struct memp_malloc_helper +{ +   memp_t poolnr; +}; +#endif /* MEM_USE_POOLS */ + +void  memp_init(void); + +#if MEMP_OVERFLOW_CHECK +void *memp_malloc_fn(memp_t type, const char* file, const int line); +#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__) +#else +void *memp_malloc(memp_t type); +#endif +void  memp_free(memp_t type, void *mem); + +#endif /* MEMP_MEM_MALLOC */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_MEMP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp_std.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp_std.h new file mode 100644 index 000000000..344690328 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/memp_std.h @@ -0,0 +1,102 @@ +/* + * SETUP: Make sure we define everything we will need. + * + * We have create three types of pools: + *   1) MEMPOOL - standard pools + *   2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c + *   3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct + * + * If the include'r doesn't require any special treatment of each of the types + * above, then will declare #2 & #3 to be just standard mempools. + */ +#ifndef LWIP_MALLOC_MEMPOOL +/* This treats "malloc pools" just like any other pool. +   The pools are a little bigger to provide 'size' as the amount of user data. */ +#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size) +#define LWIP_MALLOC_MEMPOOL_START +#define LWIP_MALLOC_MEMPOOL_END +#endif /* LWIP_MALLOC_MEMPOOL */  + +#ifndef LWIP_PBUF_MEMPOOL +/* This treats "pbuf pools" just like any other pool. + * Allocates buffers for a pbuf struct AND a payload size */ +#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc) +#endif /* LWIP_PBUF_MEMPOOL */ + + +/* + * A list of internal pools used by LWIP. + * + * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description) + *     creates a pool name MEMP_pool_name. description is used in stats.c + */ +#if LWIP_RAW +LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB") +#endif /* LWIP_RAW */ + +#if LWIP_UDP +LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB") +#endif /* LWIP_UDP */ + +#if LWIP_TCP +LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB") +LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN") +LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG") +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA") +#endif /* IP_REASSEMBLY */ + +#if LWIP_NETCONN +LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF") +LWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        "NETCONN") +#endif /* LWIP_NETCONN */ + +#if NO_SYS==0 +LWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      "TCPIP_MSG_API") +LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),      "TCPIP_MSG_INPKT") +#endif /* NO_SYS==0 */ + +#if ARP_QUEUEING +LWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_entry), "ARP_QUEUE") +#endif /* ARP_QUEUEING */ + +#if LWIP_IGMP +LWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group),     "IGMP_GROUP") +#endif /* LWIP_IGMP */ + +#if NO_SYS==0 +LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT") +#endif /* NO_SYS==0 */ + + +/* + * A list of pools of pbuf's used by LWIP. + * + * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description) + *     creates a pool name MEMP_pool_name. description is used in stats.c + *     This allocates enough space for the pbuf struct and a payload. + *     (Example: pbuf_payload_size=0 allocates only size for the struct) + */ +LWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             "PBUF_REF/ROM") +LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE,           PBUF_POOL_BUFSIZE,             "PBUF_POOL") + + +/* + * Allow for user-defined pools; this must be explicitly set in lwipopts.h + * since the default is to NOT look for lwippools.h + */ +#if MEMP_USE_CUSTOM_POOLS +#include "lwippools.h" +#endif /* MEMP_USE_CUSTOM_POOLS */ + +/* + * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later + * (#undef is ignored for something that is not defined) + */ +#undef LWIP_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL +#undef LWIP_MALLOC_MEMPOOL_START +#undef LWIP_MALLOC_MEMPOOL_END +#undef LWIP_PBUF_MEMPOOL diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netbuf.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netbuf.h new file mode 100644 index 000000000..6d84dd073 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netbuf.h @@ -0,0 +1,77 @@ +/* + * 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> + * + */ +#ifndef __LWIP_NETBUF_H__ +#define __LWIP_NETBUF_H__ + +#include "lwip/opt.h" +#include "lwip/pbuf.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netbuf { +  struct pbuf *p, *ptr; +  struct ip_addr *addr; +  u16_t port; +}; + +/* Network buffer functions: */ +struct netbuf *   netbuf_new      (void); +void              netbuf_delete   (struct netbuf *buf); +void *            netbuf_alloc    (struct netbuf *buf, u16_t size); +void              netbuf_free     (struct netbuf *buf); +err_t             netbuf_ref      (struct netbuf *buf, +           const void *dataptr, u16_t size); +void              netbuf_chain    (struct netbuf *head, +           struct netbuf *tail); + +u16_t             netbuf_len      (struct netbuf *buf); +err_t             netbuf_data     (struct netbuf *buf, +           void **dataptr, u16_t *len); +s8_t              netbuf_next     (struct netbuf *buf); +void              netbuf_first    (struct netbuf *buf); + + +#define netbuf_copy_partial(buf, dataptr, len, offset) \ +  pbuf_copy_partial((buf)->p, (dataptr), (len), (offset)) +#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) +#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) +#define netbuf_len(buf)              ((buf)->p->tot_len) +#define netbuf_fromaddr(buf)         ((buf)->addr) +#define netbuf_fromport(buf)         ((buf)->port) + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_NETBUF_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netdb.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netdb.h new file mode 100644 index 000000000..0f7b2ec04 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netdb.h @@ -0,0 +1,111 @@ +/* + * 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" + +#if LWIP_DNS && LWIP_SOCKET + +#include <stddef.h> /* for size_t */ + +#include "lwip/sockets.h" + +/* some rarely used options */ +#ifndef LWIP_DNS_API_DECLARE_H_ERRNO +#define LWIP_DNS_API_DECLARE_H_ERRNO 1 +#endif + +#ifndef LWIP_DNS_API_DEFINE_ERRORS +#define LWIP_DNS_API_DEFINE_ERRORS 1 +#endif + +#ifndef LWIP_DNS_API_DECLARE_STRUCTS +#define LWIP_DNS_API_DECLARE_STRUCTS 1 +#endif + +#if LWIP_DNS_API_DEFINE_ERRORS +/** Errors used by the DNS API functions, h_errno can be one of them */ +#define EAI_NONAME      200 +#define EAI_SERVICE     201 +#define EAI_FAIL        202 +#define EAI_MEMORY      203 + +#define HOST_NOT_FOUND  210 +#define NO_DATA         211 +#define NO_RECOVERY     212 +#define TRY_AGAIN       213 +#endif /* LWIP_DNS_API_DEFINE_ERRORS */ + +#if LWIP_DNS_API_DECLARE_STRUCTS +struct hostent { +    char  *h_name;      /* Official name of the host. */ +    char **h_aliases;   /* A pointer to an array of pointers to alternative host names, +                           terminated by a null pointer. */ +    int    h_addrtype;  /* Address type. */ +    int    h_length;    /* The length, in bytes, of the address. */ +    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in +                           network byte order) for the host, terminated by a null pointer. */ +#define h_addr h_addr_list[0] /* for backward compatibility */ +}; + +struct addrinfo { +    int               ai_flags;      /* Input flags. */ +    int               ai_family;     /* Address family of socket. */ +    int               ai_socktype;   /* Socket type. */ +    int               ai_protocol;   /* Protocol of socket. */ +    socklen_t         ai_addrlen;    /* Length of socket address. */ +    struct sockaddr  *ai_addr;       /* Socket address of socket. */ +    char             *ai_canonname;  /* Canonical name of service location. */ +    struct addrinfo  *ai_next;       /* Pointer to next in list. */ +}; +#endif /* LWIP_DNS_API_DECLARE_STRUCTS */ + +#if LWIP_DNS_API_DECLARE_H_ERRNO +/* application accessable error code set by the DNS API functions */ +extern int h_errno; +#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/ + +struct hostent *lwip_gethostbyname(const char *name); +int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, +                size_t buflen, struct hostent **result, int *h_errnop); +void lwip_freeaddrinfo(struct addrinfo *ai); +int lwip_getaddrinfo(const char *nodename, +       const char *servname, +       const struct addrinfo *hints, +       struct addrinfo **res); + +#if LWIP_COMPAT_SOCKETS +#define gethostbyname(name) lwip_gethostbyname(name) +#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \ +       lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop) +#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a) +#define getaddrinfo(nodname, servname, hints, res) \ +       lwip_getaddrinfo(nodname, servname, hints, res) +#endif /* LWIP_COMPAT_SOCKETS */ + +#endif /* LWIP_DNS && LWIP_SOCKET */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netif.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netif.h new file mode 100644 index 000000000..a32503052 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netif.h @@ -0,0 +1,263 @@ +/* + * 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> + * + */ +#ifndef __LWIP_NETIF_H__ +#define __LWIP_NETIF_H__ + +#include "lwip/opt.h" + +#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF) + +#include "lwip/err.h" + +#include "lwip/ip_addr.h" + +#include "lwip/inet.h" +#include "lwip/pbuf.h" +#if LWIP_DHCP +struct dhcp; +#endif +#if LWIP_AUTOIP +struct autoip; +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* Throughout this file, IP addresses are expected to be in + * the same byte order as in IP_PCB. */ + +/** must be the maximum of all used hardware address lengths +    across all types of interfaces in use */ +#define NETIF_MAX_HWADDR_LEN 6U + +/** TODO: define the use (where, when, whom) of netif flags */ + +/** whether the network interface is 'up'. this is + * a software flag used to control whether this network + * interface is enabled and processes traffic. + */ +#define NETIF_FLAG_UP           0x01U +/** if set, the netif has broadcast capability */ +#define NETIF_FLAG_BROADCAST    0x02U +/** if set, the netif is one end of a point-to-point connection */ +#define NETIF_FLAG_POINTTOPOINT 0x04U +/** if set, the interface is configured using DHCP */ +#define NETIF_FLAG_DHCP         0x08U +/** if set, the interface has an active link + *  (set by the network interface driver) */ +#define NETIF_FLAG_LINK_UP      0x10U +/** if set, the netif is an device using ARP */ +#define NETIF_FLAG_ETHARP       0x20U +/** if set, the netif has IGMP capability */ +#define NETIF_FLAG_IGMP         0x40U + +/** Generic data structure used for all lwIP network interfaces. + *  The following fields should be filled in by the initialization + *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ + +struct netif { +  /** pointer to next in linked list */ +  struct netif *next; + +  /** IP address configuration in network byte order */ +  struct ip_addr ip_addr; +  struct ip_addr netmask; +  struct ip_addr gw; + +  /** This function is called by the network device driver +   *  to pass a packet up the TCP/IP stack. */ +  err_t (* input)(struct pbuf *p, struct netif *inp); +  /** This function is called by the IP module when it wants +   *  to send a packet on the interface. This function typically +   *  first resolves the hardware address, then sends the packet. */ +  err_t (* output)(struct netif *netif, struct pbuf *p, +       struct ip_addr *ipaddr); +  /** This function is called by the ARP module when it wants +   *  to send a packet on the interface. This function outputs +   *  the pbuf as-is on the link medium. */ +  err_t (* linkoutput)(struct netif *netif, struct pbuf *p); +#if LWIP_NETIF_STATUS_CALLBACK +  /** This function is called when the netif state is set to up or down +   */ +  void (* status_callback)(struct netif *netif); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK +  /** This function is called when the netif link is set to up or down +   */ +  void (* link_callback)(struct netif *netif); +#endif /* LWIP_NETIF_LINK_CALLBACK */ +  /** This field can be set by the device driver and could point +   *  to state information for the device. */ +  void *state; +#if LWIP_DHCP +  /** the DHCP client state information for this netif */ +  struct dhcp *dhcp; +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP +  /** the AutoIP client state information for this netif */ +  struct autoip *autoip; +#endif +#if LWIP_NETIF_HOSTNAME +  /* the hostname for this netif, NULL is a valid value */ +  char*  hostname; +#endif /* LWIP_NETIF_HOSTNAME */ +  /** number of bytes used in hwaddr */ +  u8_t hwaddr_len; +  /** link level hardware address of this interface */ +  u8_t hwaddr[NETIF_MAX_HWADDR_LEN]; +  /** maximum transfer unit (in bytes) */ +  u16_t mtu; +  /** flags (see NETIF_FLAG_ above) */ +  u8_t flags; +  /** descriptive abbreviation */ +  char name[2]; +  /** number of this interface */ +  u8_t num; +#if LWIP_SNMP +  /** link type (from "snmp_ifType" enum from snmp.h) */ +  u8_t link_type; +  /** (estimate) link speed */ +  u32_t link_speed; +  /** timestamp at last change made (up/down) */ +  u32_t ts; +  /** counters */ +  u32_t ifinoctets; +  u32_t ifinucastpkts; +  u32_t ifinnucastpkts; +  u32_t ifindiscards; +  u32_t ifoutoctets; +  u32_t ifoutucastpkts; +  u32_t ifoutnucastpkts; +  u32_t ifoutdiscards; +#endif /* LWIP_SNMP */ +#if LWIP_IGMP +  /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ +  err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action); +#endif /* LWIP_IGMP */ +#if LWIP_NETIF_HWADDRHINT +  u8_t *addr_hint; +#endif /* LWIP_NETIF_HWADDRHINT */ +#if ENABLE_LOOPBACK +  /* List of packets to be queued for ourselves. */ +  struct pbuf *loop_first; +  struct pbuf *loop_last; +#if LWIP_LOOPBACK_MAX_PBUFS +  u16_t loop_cnt_current; +#endif /* LWIP_LOOPBACK_MAX_PBUFS */ +#endif /* ENABLE_LOOPBACK */ +}; + +#if LWIP_SNMP +#define NETIF_INIT_SNMP(netif, type, speed) \ +  /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ +  netif->link_type = type;    \ +  /* your link speed here (units: bits per second) */  \ +  netif->link_speed = speed;  \ +  netif->ts = 0;              \ +  netif->ifinoctets = 0;      \ +  netif->ifinucastpkts = 0;   \ +  netif->ifinnucastpkts = 0;  \ +  netif->ifindiscards = 0;    \ +  netif->ifoutoctets = 0;     \ +  netif->ifoutucastpkts = 0;  \ +  netif->ifoutnucastpkts = 0; \ +  netif->ifoutdiscards = 0 +#else /* LWIP_SNMP */ +#define NETIF_INIT_SNMP(netif, type, speed) +#endif /* LWIP_SNMP */ + + +/** The list of network interfaces. */ +extern struct netif *netif_list; +/** The default network interface. */ +extern struct netif *netif_default; + +#define netif_init() /* Compatibility define, not init needed. */ + +struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, +      struct ip_addr *gw, +      void *state, +      err_t (* init)(struct netif *netif), +      err_t (* input)(struct pbuf *p, struct netif *netif)); + +void +netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask, +    struct ip_addr *gw); +void netif_remove(struct netif * netif); + +/* Returns a network interface given its name. The name is of the form +   "et0", where the first two letters are the "name" field in the +   netif structure, and the digit is in the num field in the same +   structure. */ +struct netif *netif_find(char *name); + +void netif_set_default(struct netif *netif); + +void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr); +void netif_set_netmask(struct netif *netif, struct ip_addr *netmask); +void netif_set_gw(struct netif *netif, struct ip_addr *gw); + +void netif_set_up(struct netif *netif); +void netif_set_down(struct netif *netif); +u8_t netif_is_up(struct netif *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, void (* status_callback)(struct netif *netif)); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_up(struct netif *netif); +void netif_set_link_down(struct netif *netif); +u8_t netif_is_link_up(struct netif *netif); +/* + * Set callback to be called when link is brought up/down + */ +void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif)); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + +#ifdef __cplusplus +} +#endif + +#if ENABLE_LOOPBACK +err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip); +void netif_poll(struct netif *netif); +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +void netif_poll_all(void); +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#endif /* ENABLE_LOOPBACK */ + +#endif /* __LWIP_NETIF_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netifapi.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netifapi.h new file mode 100644 index 000000000..36c6bd0a2 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/netifapi.h @@ -0,0 +1,100 @@ +/* + * 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. + *  + */ +  +#ifndef __LWIP_NETIFAPI_H__ +#define __LWIP_NETIFAPI_H__ + +#include "lwip/opt.h" + +#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/netif.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct netifapi_msg_msg { +#if !LWIP_TCPIP_CORE_LOCKING +  sys_sem_t sem; +#endif /* !LWIP_TCPIP_CORE_LOCKING */ +  err_t err; +  struct netif *netif; +  union { +    struct { +      struct ip_addr *ipaddr; +      struct ip_addr *netmask; +      struct ip_addr *gw; +      void *state; +      err_t (* init) (struct netif *netif); +      err_t (* input)(struct pbuf *p, struct netif *netif); +    } add; +    struct { +      void  (* voidfunc)(struct netif *netif); +      err_t (* errtfunc)(struct netif *netif); +    } common; +  } msg; +}; + +struct netifapi_msg { +  void (* function)(struct netifapi_msg_msg *msg); +  struct netifapi_msg_msg msg; +}; + + +/* API for application */ +err_t netifapi_netif_add       ( struct netif *netif, +                                 struct ip_addr *ipaddr, +                                 struct ip_addr *netmask, +                                 struct ip_addr *gw, +                                 void *state, +                                 err_t (* init)(struct netif *netif), +                                 err_t (* input)(struct pbuf *p, struct netif *netif) ); + +err_t netifapi_netif_common    ( struct netif *netif, +                                 void  (* voidfunc)(struct netif *netif), +                                 err_t (* errtfunc)(struct netif *netif) ); + +#define netifapi_netif_remove(n)      netifapi_netif_common(n, netif_remove, NULL) +#define netifapi_netif_set_up(n)      netifapi_netif_common(n, netif_set_up, NULL) +#define netifapi_netif_set_down(n)    netifapi_netif_common(n, netif_set_down, NULL) +#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL) +#define netifapi_dhcp_start(n)        netifapi_netif_common(n, NULL, dhcp_start) +#define netifapi_dhcp_stop(n)         netifapi_netif_common(n, dhcp_stop, NULL) +#define netifapi_autoip_start(n)      netifapi_netif_common(n, NULL, autoip_start) +#define netifapi_autoip_stop(n)       netifapi_netif_common(n, NULL, autoip_stop) + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_NETIF_API */ + +#endif /* __LWIP_NETIFAPI_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/opt.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/opt.h new file mode 100644 index 000000000..e8bd8b89e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/opt.h @@ -0,0 +1,1820 @@ +/** + * @file + * + * lwIP Options Configuration + */ + +/* + * 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> + * + */ +#ifndef __LWIP_OPT_H__ +#define __LWIP_OPT_H__ + +/* + * Include user defined options first. Anything not defined in these files + * will be set to standard values. Override anything you dont like! + */ +#include "lwipopts.h" +#include "lwip/debug.h" + +/* +   ----------------------------------------------- +   ---------- Platform specific locking ---------- +   ----------------------------------------------- +*/ + +/** + * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain + * critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#ifndef SYS_LIGHTWEIGHT_PROT +#define SYS_LIGHTWEIGHT_PROT            0 +#endif + +/**  + * NO_SYS==1: Provides VERY minimal functionality. Otherwise, + * use lwIP facilities. + */ +#ifndef NO_SYS +#define NO_SYS                          0 +#endif + +/** + * MEMCPY: override this if you have a faster implementation at hand than the + * one included in your C library + */ +#ifndef MEMCPY +#define MEMCPY(dst,src,len)             memcpy(dst,src,len) +#endif + +/** + * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a + * call to memcpy() if the length is known at compile time and is small. + */ +#ifndef SMEMCPY +#define SMEMCPY(dst,src,len)            memcpy(dst,src,len) +#endif + +/* +   ------------------------------------ +   ---------- Memory options ---------- +   ------------------------------------ +*/ +/** + * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library + * instead of the lwip internal allocator. Can save code size if you + * already use it. + */ +#ifndef MEM_LIBC_MALLOC +#define MEM_LIBC_MALLOC                 0 +#endif + +/** +* MEMP_MEM_MALLOC==1: Use mem_malloc/mem_free instead of the lwip pool allocator. +* Especially useful with MEM_LIBC_MALLOC but handle with care regarding execution +* speed and usage from interrupts! +*/ +#ifndef MEMP_MEM_MALLOC +#define MEMP_MEM_MALLOC                 0 +#endif + +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + *    4 byte alignment -> #define MEM_ALIGNMENT 4 + *    2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#ifndef MEM_ALIGNMENT +#define MEM_ALIGNMENT                   1 +#endif + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#ifndef MEM_SIZE +#define MEM_SIZE                        1600 +#endif + +/** + * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable + * amount of bytes before and after each memp element in every pool and fills + * it with a prominent default value. + *    MEMP_OVERFLOW_CHECK == 0 no checking + *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed + *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time + *      memp_malloc() or memp_free() is called (useful but slow!) + */ +#ifndef MEMP_OVERFLOW_CHECK +#define MEMP_OVERFLOW_CHECK             0 +#endif + +/** + * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make + * sure that there are no cycles in the linked lists. + */ +#ifndef MEMP_SANITY_CHECK +#define MEMP_SANITY_CHECK               0 +#endif + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the length needed is returned. + * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. + */ +#ifndef MEM_USE_POOLS +#define MEM_USE_POOLS                   0 +#endif + +/** + * MEM_USE_POOLS_TRY_BIGGER_POOL==1: if one malloc-pool is empty, try the next + * bigger pool - WARNING: THIS MIGHT WASTE MEMORY but it can make a system more + * reliable. */ +#ifndef MEM_USE_POOLS_TRY_BIGGER_POOL +#define MEM_USE_POOLS_TRY_BIGGER_POOL   0 +#endif + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your  + * inlude path somewhere.  + */ +#ifndef MEMP_USE_CUSTOM_POOLS +#define MEMP_USE_CUSTOM_POOLS           0 +#endif + +/** + * Set this to 1 if you want to free PBUF_RAM pbufs (or call mem_free()) from + * interrupt context (or another context that doesn't allow waiting for a + * semaphore). + * If set to 1, mem_malloc will be protected by a semaphore and SYS_ARCH_PROTECT, + * while mem_free will only use SYS_ARCH_PROTECT. mem_malloc SYS_ARCH_UNPROTECTs + * with each loop so that mem_free can run. + * + * ATTENTION: As you can see from the above description, this leads to dis-/ + * enabling interrupts often, which can be slow! Also, on low memory, mem_malloc + * can need longer. + * + * If you don't want that, at least for NO_SYS=0, you can still use the following + * functions to enqueue a deallocation call which then runs in the tcpip_thread + * context: + * - pbuf_free_callback(p); + * - mem_free_callback(m); + */ +#ifndef LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT +#define LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT 0 +#endif + +/* +   ------------------------------------------------ +   ---------- Internal Memory Pool Sizes ---------- +   ------------------------------------------------ +*/ +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#ifndef MEMP_NUM_PBUF +#define MEMP_NUM_PBUF                   16 +#endif + +/** + * MEMP_NUM_RAW_PCB: Number of raw connection PCBs + * (requires the LWIP_RAW option) + */ +#ifndef MEMP_NUM_RAW_PCB +#define MEMP_NUM_RAW_PCB                4 +#endif + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#ifndef MEMP_NUM_UDP_PCB +#define MEMP_NUM_UDP_PCB                4 +#endif + +/** + * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB +#define MEMP_NUM_TCP_PCB                5 +#endif + +/** + * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_PCB_LISTEN +#define MEMP_NUM_TCP_PCB_LISTEN         8 +#endif + +/** + * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. + * (requires the LWIP_TCP option) + */ +#ifndef MEMP_NUM_TCP_SEG +#define MEMP_NUM_TCP_SEG                16 +#endif + +/** + * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * reassembly (whole packets, not fragments!) + */ +#ifndef MEMP_NUM_REASSDATA +#define MEMP_NUM_REASSDATA              5 +#endif + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#ifndef MEMP_NUM_ARP_QUEUE +#define MEMP_NUM_ARP_QUEUE              30 +#endif + +/** + * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces + * can be members et the same time (one per netif - allsystems group -, plus one + * per netif membership). + * (requires the LWIP_IGMP option) + */ +#ifndef MEMP_NUM_IGMP_GROUP +#define MEMP_NUM_IGMP_GROUP             8 +#endif + +/** + * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts. + * (requires NO_SYS==0) + */ +#ifndef MEMP_NUM_SYS_TIMEOUT +#define MEMP_NUM_SYS_TIMEOUT            3 +#endif + +/** + * MEMP_NUM_NETBUF: the number of struct netbufs. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETBUF +#define MEMP_NUM_NETBUF                 2 +#endif + +/** + * MEMP_NUM_NETCONN: the number of struct netconns. + * (only needed if you use the sequential API, like api_lib.c) + */ +#ifndef MEMP_NUM_NETCONN +#define MEMP_NUM_NETCONN                4 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used + * for callback/timeout API communication.  + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_API +#define MEMP_NUM_TCPIP_MSG_API          8 +#endif + +/** + * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used + * for incoming packets.  + * (only needed if you use tcpip.c) + */ +#ifndef MEMP_NUM_TCPIP_MSG_INPKT +#define MEMP_NUM_TCPIP_MSG_INPKT        8 +#endif + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.  + */ +#ifndef PBUF_POOL_SIZE +#define PBUF_POOL_SIZE                  16 +#endif + +/* +   --------------------------------- +   ---------- ARP options ---------- +   --------------------------------- +*/ +/** + * LWIP_ARP==1: Enable ARP functionality. + */ +#ifndef LWIP_ARP +#define LWIP_ARP                        1 +#endif + +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#ifndef ARP_TABLE_SIZE +#define ARP_TABLE_SIZE                  10 +#endif + +/** + * ARP_QUEUEING==1: Outgoing packets are queued during hardware address + * resolution. + */ +#ifndef ARP_QUEUEING +#define ARP_QUEUEING                    1 +#endif + +/** + * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be + * updated with the source MAC and IP addresses supplied in the packet. + * You may want to disable this if you do not trust LAN peers to have the + * correct addresses, or as a limited approach to attempt to handle + * spoofing. If disabled, lwIP will need to make a new ARP request if + * the peer is not already in the ARP table, adding a little latency. + */ +#ifndef ETHARP_TRUST_IP_MAC +#define ETHARP_TRUST_IP_MAC             1 +#endif + +/* +   -------------------------------- +   ---------- IP options ---------- +   -------------------------------- +*/ +/** + * IP_FORWARD==1: Enables the ability to forward IP packets across network + * interfaces. If you are going to run lwIP on a device with only one network + * interface, define this to 0. + */ +#ifndef IP_FORWARD +#define IP_FORWARD                      0 +#endif + +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#ifndef IP_OPTIONS_ALLOWED +#define IP_OPTIONS_ALLOWED              1 +#endif + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#ifndef IP_REASSEMBLY +#define IP_REASSEMBLY                   1 +#endif + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#ifndef IP_FRAG +#define IP_FRAG                         1 +#endif + +/** + * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally) + * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived + * in this time, the whole packet is discarded. + */ +#ifndef IP_REASS_MAXAGE +#define IP_REASS_MAXAGE                 3 +#endif + +/** + * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled. + * Since the received pbufs are enqueued, be sure to configure + * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive + * packets even if the maximum amount of fragments is enqueued for reassembly! + */ +#ifndef IP_REASS_MAX_PBUFS +#define IP_REASS_MAX_PBUFS              10 +#endif + +/** + * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP + * fragmentation. Otherwise pbufs are allocated and reference the original + * packet data to be fragmented. + */ +#ifndef IP_FRAG_USES_STATIC_BUF +#define IP_FRAG_USES_STATIC_BUF         1 +#endif + +/** + * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer + * (requires IP_FRAG_USES_STATIC_BUF==1) + */ +#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU) +#define IP_FRAG_MAX_MTU                 1500 +#endif + +/** + * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers. + */ +#ifndef IP_DEFAULT_TTL +#define IP_DEFAULT_TTL                  255 +#endif + +/** + * IP_SOF_BROADCAST=1: Use the SOF_BROADCAST field to enable broadcast + * filter per pcb on udp and raw send operations. To enable broadcast filter + * on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1. + */ +#ifndef IP_SOF_BROADCAST +#define IP_SOF_BROADCAST                0 +#endif + +/** + * IP_SOF_BROADCAST_RECV (requires IP_SOF_BROADCAST=1) enable the broadcast + * filter on recv operations. + */ +#ifndef IP_SOF_BROADCAST_RECV +#define IP_SOF_BROADCAST_RECV           0 +#endif + +/* +   ---------------------------------- +   ---------- ICMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_ICMP==1: Enable ICMP module inside the IP stack. + * Be careful, disable that make your product non-compliant to RFC1122 + */ +#ifndef LWIP_ICMP +#define LWIP_ICMP                       1 +#endif + +/** + * ICMP_TTL: Default value for Time-To-Live used by ICMP packets. + */ +#ifndef ICMP_TTL +#define ICMP_TTL                       (IP_DEFAULT_TTL) +#endif + +/** + * LWIP_BROADCAST_PING==1: respond to broadcast pings (default is unicast only) + */ +#ifndef LWIP_BROADCAST_PING +#define LWIP_BROADCAST_PING             0 +#endif + +/** + * LWIP_MULTICAST_PING==1: respond to multicast pings (default is unicast only) + */ +#ifndef LWIP_MULTICAST_PING +#define LWIP_MULTICAST_PING             0 +#endif + +/* +   --------------------------------- +   ---------- RAW options ---------- +   --------------------------------- +*/ +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef LWIP_RAW +#define LWIP_RAW                        1 +#endif + +/** + * LWIP_RAW==1: Enable application layer to hook into the IP layer itself. + */ +#ifndef RAW_TTL +#define RAW_TTL                        (IP_DEFAULT_TTL) +#endif + +/* +   ---------------------------------- +   ---------- DHCP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#ifndef LWIP_DHCP +#define LWIP_DHCP                       0 +#endif + +/** + * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address. + */ +#ifndef DHCP_DOES_ARP_CHECK +#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP)) +#endif + +/* +   ------------------------------------ +   ---------- AUTOIP options ---------- +   ------------------------------------ +*/ +/** + * LWIP_AUTOIP==1: Enable AUTOIP module. + */ +#ifndef LWIP_AUTOIP +#define LWIP_AUTOIP                     0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on + * the same interface at the same time. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP +#define LWIP_DHCP_AUTOIP_COOP           0 +#endif + +/** + * LWIP_DHCP_AUTOIP_COOP_TRIES: Set to the number of DHCP DISCOVER probes + * that should be sent before falling back on AUTOIP. This can be set + * as low as 1 to get an AutoIP address very quickly, but you should + * be prepared to handle a changing IP address when DHCP overrides + * AutoIP. + */ +#ifndef LWIP_DHCP_AUTOIP_COOP_TRIES +#define LWIP_DHCP_AUTOIP_COOP_TRIES     9 +#endif + +/* +   ---------------------------------- +   ---------- SNMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP + * transport. + */ +#ifndef LWIP_SNMP +#define LWIP_SNMP                       0 +#endif + +/** + * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will + * allow. At least one request buffer is required.  + */ +#ifndef SNMP_CONCURRENT_REQUESTS +#define SNMP_CONCURRENT_REQUESTS        1 +#endif + +/** + * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap + * destination is required + */ +#ifndef SNMP_TRAP_DESTINATIONS +#define SNMP_TRAP_DESTINATIONS          1 +#endif + +/** + * SNMP_PRIVATE_MIB:  + */ +#ifndef SNMP_PRIVATE_MIB +#define SNMP_PRIVATE_MIB                0 +#endif + +/** + * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not + * a safe action and disabled when SNMP_SAFE_REQUESTS = 1). + * Unsafe requests are disabled by default! + */ +#ifndef SNMP_SAFE_REQUESTS +#define SNMP_SAFE_REQUESTS              1 +#endif + +/* +   ---------------------------------- +   ---------- IGMP options ---------- +   ---------------------------------- +*/ +/** + * LWIP_IGMP==1: Turn on IGMP module.  + */ +#ifndef LWIP_IGMP +#define LWIP_IGMP                       0 +#endif + +/* +   ---------------------------------- +   ---------- DNS options ----------- +   ---------------------------------- +*/ +/** + * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS + * transport. + */ +#ifndef LWIP_DNS +#define LWIP_DNS                        0 +#endif + +/** DNS maximum number of entries to maintain locally. */ +#ifndef DNS_TABLE_SIZE +#define DNS_TABLE_SIZE                  4 +#endif + +/** DNS maximum host name length supported in the name table. */ +#ifndef DNS_MAX_NAME_LENGTH +#define DNS_MAX_NAME_LENGTH             256 +#endif + +/** The maximum of DNS servers */ +#ifndef DNS_MAX_SERVERS +#define DNS_MAX_SERVERS                 2 +#endif + +/** DNS do a name checking between the query and the response. */ +#ifndef DNS_DOES_NAME_CHECK +#define DNS_DOES_NAME_CHECK             1 +#endif + +/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if +    DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2. +    The buffer will be of size DNS_MSG_SIZE */ +#ifndef DNS_USES_STATIC_BUF +#define DNS_USES_STATIC_BUF             1 +#endif + +/** DNS message max. size. Default value is RFC compliant. */ +#ifndef DNS_MSG_SIZE +#define DNS_MSG_SIZE                    512 +#endif + +/** DNS_LOCAL_HOSTLIST: Implements a local host-to-address list. If enabled, + *  you have to define + *    #define DNS_LOCAL_HOSTLIST_INIT {{"host1", 0x123}, {"host2", 0x234}} + *  (an array of structs name/address, where address is an u32_t in network + *  byte order). + * + *  Instead, you can also use an external function: + *  #define DNS_LOOKUP_LOCAL_EXTERN(x) extern u32_t my_lookup_function(const char *name) + *  that returns the IP address or INADDR_NONE if not found. + */ +#ifndef DNS_LOCAL_HOSTLIST +#define DNS_LOCAL_HOSTLIST              0 +#endif /* DNS_LOCAL_HOSTLIST */ + +/** If this is turned on, the local host-list can be dynamically changed + *  at runtime. */ +#ifndef DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#define DNS_LOCAL_HOSTLIST_IS_DYNAMIC   0 +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ + +/* +   --------------------------------- +   ---------- UDP options ---------- +   --------------------------------- +*/ +/** + * LWIP_UDP==1: Turn on UDP. + */ +#ifndef LWIP_UDP +#define LWIP_UDP                        1 +#endif + +/** + * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP) + */ +#ifndef LWIP_UDPLITE +#define LWIP_UDPLITE                    0 +#endif + +/** + * UDP_TTL: Default Time-To-Live value. + */ +#ifndef UDP_TTL +#define UDP_TTL                         (IP_DEFAULT_TTL) +#endif + +/* +   --------------------------------- +   ---------- TCP options ---------- +   --------------------------------- +*/ +/** + * LWIP_TCP==1: Turn on TCP. + */ +#ifndef LWIP_TCP +#define LWIP_TCP                        1 +#endif + +/** + * TCP_TTL: Default Time-To-Live value. + */ +#ifndef TCP_TTL +#define TCP_TTL                         (IP_DEFAULT_TTL) +#endif + +/** + * TCP_WND: The size of a TCP window.  This must be at least  + * (2 * TCP_MSS) for things to work well + */ +#ifndef TCP_WND +#define TCP_WND                         2048 +#endif  + +/** + * TCP_MAXRTX: Maximum number of retransmissions of data segments. + */ +#ifndef TCP_MAXRTX +#define TCP_MAXRTX                      12 +#endif + +/** + * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments. + */ +#ifndef TCP_SYNMAXRTX +#define TCP_SYNMAXRTX                   6 +#endif + +/** + * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order. + * Define to 0 if your device is low on memory. + */ +#ifndef TCP_QUEUE_OOSEQ +#define TCP_QUEUE_OOSEQ                 (LWIP_TCP) +#endif + +/** + * TCP_MSS: TCP Maximum segment size. (default is 128, a *very* + * conservative default.) + * For the receive side, this MSS is advertised to the remote side + * when opening a connection. For the transmit size, this MSS sets + * an upper limit on the MSS advertised by the remote host. + */ +#ifndef TCP_MSS +#define TCP_MSS                         128 +#endif + +/** + * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really + * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which + * reflects the available reassembly buffer size at the remote host) and the + * largest size permitted by the IP layer" (RFC 1122) + * Setting this to 1 enables code that checks TCP_MSS against the MTU of the + * netif used for a connection and limits the MSS if it would be too big otherwise. + */ +#ifndef TCP_CALCULATE_EFF_SEND_MSS +#define TCP_CALCULATE_EFF_SEND_MSS      1 +#endif + + +/** + * TCP_SND_BUF: TCP sender buffer space (bytes).  + */ +#ifndef TCP_SND_BUF +#define TCP_SND_BUF                     256 +#endif + +/** + * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least + * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. + */ +#ifndef TCP_SND_QUEUELEN +#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF/TCP_MSS)) +#endif + +/** + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal + * to TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable. + */ +#ifndef TCP_SNDLOWAT +#define TCP_SNDLOWAT                    (TCP_SND_BUF/2) +#endif + +/** + * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. + */ +#ifndef TCP_LISTEN_BACKLOG +#define TCP_LISTEN_BACKLOG              0 +#endif + +/** + * The maximum allowed backlog for TCP listen netconns. + * This backlog is used unless another is explicitly specified. + * 0xff is the maximum (u8_t). + */ +#ifndef TCP_DEFAULT_LISTEN_BACKLOG +#define TCP_DEFAULT_LISTEN_BACKLOG      0xff +#endif + +/** + * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. + */ +#ifndef LWIP_TCP_TIMESTAMPS +#define LWIP_TCP_TIMESTAMPS             0 +#endif + +/** + * TCP_WND_UPDATE_THRESHOLD: difference in window to trigger an + * explicit window update + */ +#ifndef TCP_WND_UPDATE_THRESHOLD +#define TCP_WND_UPDATE_THRESHOLD   (TCP_WND / 4) +#endif + +/** + * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1. + *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all + *         events (accept, sent, etc) that happen in the system. + *     LWIP_CALLBACK_API==1: The PCB callback function is called directly + *         for the event. + */ +#ifndef LWIP_EVENT_API +#define LWIP_EVENT_API                  0 +#define LWIP_CALLBACK_API               1 +#else  +#define LWIP_EVENT_API                  1 +#define LWIP_CALLBACK_API               0 +#endif + + +/* +   ---------------------------------- +   ---------- Pbuf options ---------- +   ---------------------------------- +*/ +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#ifndef PBUF_LINK_HLEN +#define PBUF_LINK_HLEN                  14 +#endif + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +#ifndef PBUF_POOL_BUFSIZE +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#endif + +/* +   ------------------------------------------------ +   ---------- Network Interfaces options ---------- +   ------------------------------------------------ +*/ +/** + * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname + * field. + */ +#ifndef LWIP_NETIF_HOSTNAME +#define LWIP_NETIF_HOSTNAME             0 +#endif + +/** + * LWIP_NETIF_API==1: Support netif api (in netifapi.c) + */ +#ifndef LWIP_NETIF_API +#define LWIP_NETIF_API                  0 +#endif + +/** + * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface + * changes its up/down status (i.e., due to DHCP IP acquistion) + */ +#ifndef LWIP_NETIF_STATUS_CALLBACK +#define LWIP_NETIF_STATUS_CALLBACK      0 +#endif + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#ifndef LWIP_NETIF_LINK_CALLBACK +#define LWIP_NETIF_LINK_CALLBACK        0 +#endif + +/** + * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table + * indices) in struct netif. TCP and UDP can make use of this to prevent + * scanning the ARP table for every sent packet. While this is faster for big + * ARP tables or many concurrent connections, it might be counterproductive + * if you have a tiny ARP table or if there never are concurrent connections. + */ +#ifndef LWIP_NETIF_HWADDRHINT +#define LWIP_NETIF_HWADDRHINT           0 +#endif + +/** + * LWIP_NETIF_LOOPBACK==1: Support sending packets with a destination IP + * address equal to the netif IP address, looping them back up the stack. + */ +#ifndef LWIP_NETIF_LOOPBACK +#define LWIP_NETIF_LOOPBACK             0 +#endif + +/** + * LWIP_LOOPBACK_MAX_PBUFS: Maximum number of pbufs on queue for loopback + * sending for each netif (0 = disabled) + */ +#ifndef LWIP_LOOPBACK_MAX_PBUFS +#define LWIP_LOOPBACK_MAX_PBUFS         0 +#endif + +/** + * LWIP_NETIF_LOOPBACK_MULTITHREADING: Indicates whether threading is enabled in + * the system, as netifs must change how they behave depending on this setting + * for the LWIP_NETIF_LOOPBACK option to work. + * Setting this is needed to avoid reentering non-reentrant functions like + * tcp_input(). + *    LWIP_NETIF_LOOPBACK_MULTITHREADING==1: Indicates that the user is using a + *       multithreaded environment like tcpip.c. In this case, netif->input() + *       is called directly. + *    LWIP_NETIF_LOOPBACK_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup. + *       The packets are put on a list and netif_poll() must be called in + *       the main application loop. + */ +#ifndef LWIP_NETIF_LOOPBACK_MULTITHREADING +#define LWIP_NETIF_LOOPBACK_MULTITHREADING    (!NO_SYS) +#endif + +/** + * LWIP_NETIF_TX_SINGLE_PBUF: if this is set to 1, lwIP tries to put all data + * to be sent into one single pbuf. This is for compatibility with DMA-enabled + * MACs that do not support scatter-gather. + * Beware that this might involve CPU-memcpy before transmitting that would not + * be needed without this flag! Use this only if you need to! + * + * @todo: TCP and IP-frag do not work with this, yet: + */ +#ifndef LWIP_NETIF_TX_SINGLE_PBUF +#define LWIP_NETIF_TX_SINGLE_PBUF             0 +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + +/* +   ------------------------------------ +   ---------- LOOPIF options ---------- +   ------------------------------------ +*/ +/** + * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c + */ +#ifndef LWIP_HAVE_LOOPIF +#define LWIP_HAVE_LOOPIF                0 +#endif + +/* +   ------------------------------------ +   ---------- SLIPIF options ---------- +   ------------------------------------ +*/ +/** + * LWIP_HAVE_SLIPIF==1: Support slip interface and slipif.c + */ +#ifndef LWIP_HAVE_SLIPIF +#define LWIP_HAVE_SLIPIF                0 +#endif + +/* +   ------------------------------------ +   ---------- Thread options ---------- +   ------------------------------------ +*/ +/** + * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread. + */ +#ifndef TCPIP_THREAD_NAME +#define TCPIP_THREAD_NAME              "tcpip_thread" +#endif + +/** + * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_STACKSIZE +#define TCPIP_THREAD_STACKSIZE          0 +#endif + +/** + * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef TCPIP_THREAD_PRIO +#define TCPIP_THREAD_PRIO               1 +#endif + +/** + * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when tcpip_init is called. + */ +#ifndef TCPIP_MBOX_SIZE +#define TCPIP_MBOX_SIZE                 0 +#endif + +/** + * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread. + */ +#ifndef SLIPIF_THREAD_NAME +#define SLIPIF_THREAD_NAME             "slipif_loop" +#endif + +/** + * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_STACKSIZE +#define SLIPIF_THREAD_STACKSIZE         0 +#endif + +/** + * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef SLIPIF_THREAD_PRIO +#define SLIPIF_THREAD_PRIO              1 +#endif + +/** + * PPP_THREAD_NAME: The name assigned to the pppMain thread. + */ +#ifndef PPP_THREAD_NAME +#define PPP_THREAD_NAME                "pppMain" +#endif + +/** + * PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_STACKSIZE +#define PPP_THREAD_STACKSIZE            0 +#endif + +/** + * PPP_THREAD_PRIO: The priority assigned to the pppMain thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef PPP_THREAD_PRIO +#define PPP_THREAD_PRIO                 1 +#endif + +/** + * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread. + */ +#ifndef DEFAULT_THREAD_NAME +#define DEFAULT_THREAD_NAME            "lwIP" +#endif + +/** + * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread. + * The stack size value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_STACKSIZE +#define DEFAULT_THREAD_STACKSIZE        0 +#endif + +/** + * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread. + * The priority value itself is platform-dependent, but is passed to + * sys_thread_new() when the thread is created. + */ +#ifndef DEFAULT_THREAD_PRIO +#define DEFAULT_THREAD_PRIO             1 +#endif + +/** + * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_RAW_RECVMBOX_SIZE +#define DEFAULT_RAW_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_UDP_RECVMBOX_SIZE +#define DEFAULT_UDP_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a + * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed + * to sys_mbox_new() when the recvmbox is created. + */ +#ifndef DEFAULT_TCP_RECVMBOX_SIZE +#define DEFAULT_TCP_RECVMBOX_SIZE       0 +#endif + +/** + * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections. + * The queue size value itself is platform-dependent, but is passed to + * sys_mbox_new() when the acceptmbox is created. + */ +#ifndef DEFAULT_ACCEPTMBOX_SIZE +#define DEFAULT_ACCEPTMBOX_SIZE         0 +#endif + +/* +   ---------------------------------------------- +   ---------- Sequential layer options ---------- +   ---------------------------------------------- +*/ +/** + * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING +#define LWIP_TCPIP_CORE_LOCKING         0 +#endif + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#ifndef LWIP_NETCONN +#define LWIP_NETCONN                    1 +#endif + +/* +   ------------------------------------ +   ---------- Socket options ---------- +   ------------------------------------ +*/ +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#ifndef LWIP_SOCKET +#define LWIP_SOCKET                     1 +#endif + +/** + * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names. + * (only used if you use sockets.c) + */ +#ifndef LWIP_COMPAT_SOCKETS +#define LWIP_COMPAT_SOCKETS             1 +#endif + +/** + * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names. + * Disable this option if you use a POSIX operating system that uses the same + * names (read, write & close). (only used if you use sockets.c) + */ +#ifndef LWIP_POSIX_SOCKETS_IO_NAMES +#define LWIP_POSIX_SOCKETS_IO_NAMES     1 +#endif + +/** + * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT + * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set + * in seconds. (does not require sockets.c, and will affect tcp.c) + */ +#ifndef LWIP_TCP_KEEPALIVE +#define LWIP_TCP_KEEPALIVE              0 +#endif + +/** + * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing. + */ +#ifndef LWIP_SO_RCVTIMEO +#define LWIP_SO_RCVTIMEO                0 +#endif + +/** + * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing. + */ +#ifndef LWIP_SO_RCVBUF +#define LWIP_SO_RCVBUF                  0 +#endif + +/** + * If LWIP_SO_RCVBUF is used, this is the default value for recv_bufsize. + */ +#ifndef RECV_BUFSIZE_DEFAULT +#define RECV_BUFSIZE_DEFAULT            INT_MAX +#endif + +/** + * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE! + */ +#ifndef SO_REUSE +#define SO_REUSE                        0 +#endif + +/* +   ---------------------------------------- +   ---------- Statistics options ---------- +   ---------------------------------------- +*/ +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#ifndef LWIP_STATS +#define LWIP_STATS                      1 +#endif + +#if LWIP_STATS + +/** + * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions. + */ +#ifndef LWIP_STATS_DISPLAY +#define LWIP_STATS_DISPLAY              0 +#endif + +/** + * LINK_STATS==1: Enable link stats. + */ +#ifndef LINK_STATS +#define LINK_STATS                      1 +#endif + +/** + * ETHARP_STATS==1: Enable etharp stats. + */ +#ifndef ETHARP_STATS +#define ETHARP_STATS                    (LWIP_ARP) +#endif + +/** + * IP_STATS==1: Enable IP stats. + */ +#ifndef IP_STATS +#define IP_STATS                        1 +#endif + +/** + * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is + * on if using either frag or reass. + */ +#ifndef IPFRAG_STATS +#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG) +#endif + +/** + * ICMP_STATS==1: Enable ICMP stats. + */ +#ifndef ICMP_STATS +#define ICMP_STATS                      1 +#endif + +/** + * IGMP_STATS==1: Enable IGMP stats. + */ +#ifndef IGMP_STATS +#define IGMP_STATS                      (LWIP_IGMP) +#endif + +/** + * UDP_STATS==1: Enable UDP stats. Default is on if + * UDP enabled, otherwise off. + */ +#ifndef UDP_STATS +#define UDP_STATS                       (LWIP_UDP) +#endif + +/** + * TCP_STATS==1: Enable TCP stats. Default is on if TCP + * enabled, otherwise off. + */ +#ifndef TCP_STATS +#define TCP_STATS                       (LWIP_TCP) +#endif + +/** + * MEM_STATS==1: Enable mem.c stats. + */ +#ifndef MEM_STATS +#define MEM_STATS                       1 +#endif + +/** + * MEMP_STATS==1: Enable memp.c pool stats. + */ +#ifndef MEMP_STATS +#define MEMP_STATS                      1 +#endif + +/** + * SYS_STATS==1: Enable system stats (sem and mbox counts, etc). + */ +#ifndef SYS_STATS +#define SYS_STATS                       1 +#endif + +#else + +#define LINK_STATS                      0 +#define IP_STATS                        0 +#define IPFRAG_STATS                    0 +#define ICMP_STATS                      0 +#define IGMP_STATS                      0 +#define UDP_STATS                       0 +#define TCP_STATS                       0 +#define MEM_STATS                       0 +#define MEMP_STATS                      0 +#define SYS_STATS                       0 +#define LWIP_STATS_DISPLAY              0 + +#endif /* LWIP_STATS */ + +/* +   --------------------------------- +   ---------- PPP options ---------- +   --------------------------------- +*/ +/** + * PPP_SUPPORT==1: Enable PPP. + */ +#ifndef PPP_SUPPORT +#define PPP_SUPPORT                     0 +#endif + +/** + * PPPOE_SUPPORT==1: Enable PPP Over Ethernet + */ +#ifndef PPPOE_SUPPORT +#define PPPOE_SUPPORT                   0 +#endif + +/** + * PPPOS_SUPPORT==1: Enable PPP Over Serial + */ +#ifndef PPPOS_SUPPORT +#define PPPOS_SUPPORT                   PPP_SUPPORT +#endif + +#if PPP_SUPPORT + +/** + * NUM_PPP: Max PPP sessions. + */ +#ifndef NUM_PPP +#define NUM_PPP                         1 +#endif + +/** + * PAP_SUPPORT==1: Support PAP. + */ +#ifndef PAP_SUPPORT +#define PAP_SUPPORT                     0 +#endif + +/** + * CHAP_SUPPORT==1: Support CHAP. + */ +#ifndef CHAP_SUPPORT +#define CHAP_SUPPORT                    0 +#endif + +/** + * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef MSCHAP_SUPPORT +#define MSCHAP_SUPPORT                  0 +#endif + +/** + * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CBCP_SUPPORT +#define CBCP_SUPPORT                    0 +#endif + +/** + * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET! + */ +#ifndef CCP_SUPPORT +#define CCP_SUPPORT                     0 +#endif + +/** + * VJ_SUPPORT==1: Support VJ header compression. + */ +#ifndef VJ_SUPPORT +#define VJ_SUPPORT                      0 +#endif + +/** + * MD5_SUPPORT==1: Support MD5 (see also CHAP). + */ +#ifndef MD5_SUPPORT +#define MD5_SUPPORT                     0 +#endif + +/* + * Timeouts + */ +#ifndef FSM_DEFTIMEOUT +#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */ +#endif + +#ifndef FSM_DEFMAXTERMREQS +#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXCONFREQS +#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */ +#endif + +#ifndef FSM_DEFMAXNAKLOOPS +#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */ +#endif + +#ifndef UPAP_DEFTIMEOUT +#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */ +#endif + +#ifndef UPAP_DEFREQTIME +#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */ +#endif + +#ifndef CHAP_DEFTIMEOUT +#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */ +#endif + +#ifndef CHAP_DEFTRANSMITS +#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */ +#endif + +/* Interval in seconds between keepalive echo requests, 0 to disable. */ +#ifndef LCP_ECHOINTERVAL +#define LCP_ECHOINTERVAL                0 +#endif + +/* Number of unanswered echo requests before failure. */ +#ifndef LCP_MAXECHOFAILS +#define LCP_MAXECHOFAILS                3 +#endif + +/* Max Xmit idle time (in jiffies) before resend flag char. */ +#ifndef PPP_MAXIDLEFLAG +#define PPP_MAXIDLEFLAG                 100 +#endif + +/* + * Packet sizes + * + * Note - lcp shouldn't be allowed to negotiate stuff outside these + *    limits.  See lcp.h in the pppd directory. + * (XXX - these constants should simply be shared by lcp.c instead + *    of living in lcp.h) + */ +#define PPP_MTU                         1500     /* Default MTU (size of Info field) */ +#ifndef PPP_MAXMTU +/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */ +#define PPP_MAXMTU                      1500 /* Largest MTU we allow */ +#endif +#define PPP_MINMTU                      64 +#define PPP_MRU                         1500     /* default MRU = max length of info field */ +#define PPP_MAXMRU                      1500     /* Largest MRU we allow */ +#ifndef PPP_DEFMRU +#define PPP_DEFMRU                      296             /* Try for this */ +#endif +#define PPP_MINMRU                      128             /* No MRUs below this */ + + +#define MAXNAMELEN                      256     /* max length of hostname or name for auth */ +#define MAXSECRETLEN                    256     /* max length of password or secret */ + +#endif /* PPP_SUPPORT */ + +/* +   -------------------------------------- +   ---------- Checksum options ---------- +   -------------------------------------- +*/ +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#ifndef CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP                 1 +#endif +  +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#ifndef CHECKSUM_GEN_UDP +#define CHECKSUM_GEN_UDP                1 +#endif +  +/** + * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets. + */ +#ifndef CHECKSUM_GEN_TCP +#define CHECKSUM_GEN_TCP                1 +#endif +  +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#ifndef CHECKSUM_CHECK_IP +#define CHECKSUM_CHECK_IP               1 +#endif +  +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#ifndef CHECKSUM_CHECK_UDP +#define CHECKSUM_CHECK_UDP              1 +#endif + +/** + * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets. + */ +#ifndef CHECKSUM_CHECK_TCP +#define CHECKSUM_CHECK_TCP              1 +#endif + +/* +   --------------------------------------- +   ---------- Debugging options ---------- +   --------------------------------------- +*/ +/** + * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is + * compared against this value. If it is smaller, then debugging + * messages are written. + */ +#ifndef LWIP_DBG_MIN_LEVEL +#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF +#endif + +/** + * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable + * debug messages of certain types. + */ +#ifndef LWIP_DBG_TYPES_ON +#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON +#endif + +/** + * ETHARP_DEBUG: Enable debugging in etharp.c. + */ +#ifndef ETHARP_DEBUG +#define ETHARP_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * NETIF_DEBUG: Enable debugging in netif.c. + */ +#ifndef NETIF_DEBUG +#define NETIF_DEBUG                     LWIP_DBG_OFF +#endif + +/** + * PBUF_DEBUG: Enable debugging in pbuf.c. + */ +#ifndef PBUF_DEBUG +#define PBUF_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * API_LIB_DEBUG: Enable debugging in api_lib.c. + */ +#ifndef API_LIB_DEBUG +#define API_LIB_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * API_MSG_DEBUG: Enable debugging in api_msg.c. + */ +#ifndef API_MSG_DEBUG +#define API_MSG_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * SOCKETS_DEBUG: Enable debugging in sockets.c. + */ +#ifndef SOCKETS_DEBUG +#define SOCKETS_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * ICMP_DEBUG: Enable debugging in icmp.c. + */ +#ifndef ICMP_DEBUG +#define ICMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * IGMP_DEBUG: Enable debugging in igmp.c. + */ +#ifndef IGMP_DEBUG +#define IGMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * INET_DEBUG: Enable debugging in inet.c. + */ +#ifndef INET_DEBUG +#define INET_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * IP_DEBUG: Enable debugging for IP. + */ +#ifndef IP_DEBUG +#define IP_DEBUG                        LWIP_DBG_OFF +#endif + +/** + * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass. + */ +#ifndef IP_REASS_DEBUG +#define IP_REASS_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * RAW_DEBUG: Enable debugging in raw.c. + */ +#ifndef RAW_DEBUG +#define RAW_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * MEM_DEBUG: Enable debugging in mem.c. + */ +#ifndef MEM_DEBUG +#define MEM_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * MEMP_DEBUG: Enable debugging in memp.c. + */ +#ifndef MEMP_DEBUG +#define MEMP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * SYS_DEBUG: Enable debugging in sys.c. + */ +#ifndef SYS_DEBUG +#define SYS_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCP_DEBUG: Enable debugging for TCP. + */ +#ifndef TCP_DEBUG +#define TCP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug. + */ +#ifndef TCP_INPUT_DEBUG +#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF +#endif + +/** + * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit. + */ +#ifndef TCP_FR_DEBUG +#define TCP_FR_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit + * timeout. + */ +#ifndef TCP_RTO_DEBUG +#define TCP_RTO_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_CWND_DEBUG: Enable debugging for TCP congestion window. + */ +#ifndef TCP_CWND_DEBUG +#define TCP_CWND_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating. + */ +#ifndef TCP_WND_DEBUG +#define TCP_WND_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions. + */ +#ifndef TCP_OUTPUT_DEBUG +#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF +#endif + +/** + * TCP_RST_DEBUG: Enable debugging for TCP with the RST message. + */ +#ifndef TCP_RST_DEBUG +#define TCP_RST_DEBUG                   LWIP_DBG_OFF +#endif + +/** + * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths. + */ +#ifndef TCP_QLEN_DEBUG +#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * UDP_DEBUG: Enable debugging in UDP. + */ +#ifndef UDP_DEBUG +#define UDP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * TCPIP_DEBUG: Enable debugging in tcpip.c. + */ +#ifndef TCPIP_DEBUG +#define TCPIP_DEBUG                     LWIP_DBG_OFF +#endif + +/** + * PPP_DEBUG: Enable debugging for PPP. + */ +#ifndef PPP_DEBUG +#define PPP_DEBUG                       LWIP_DBG_OFF +#endif + +/** + * SLIP_DEBUG: Enable debugging in slipif.c. + */ +#ifndef SLIP_DEBUG +#define SLIP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * DHCP_DEBUG: Enable debugging in dhcp.c. + */ +#ifndef DHCP_DEBUG +#define DHCP_DEBUG                      LWIP_DBG_OFF +#endif + +/** + * AUTOIP_DEBUG: Enable debugging in autoip.c. + */ +#ifndef AUTOIP_DEBUG +#define AUTOIP_DEBUG                    LWIP_DBG_OFF +#endif + +/** + * SNMP_MSG_DEBUG: Enable debugging for SNMP messages. + */ +#ifndef SNMP_MSG_DEBUG +#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs. + */ +#ifndef SNMP_MIB_DEBUG +#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF +#endif + +/** + * DNS_DEBUG: Enable debugging for DNS. + */ +#ifndef DNS_DEBUG +#define DNS_DEBUG                       LWIP_DBG_OFF +#endif + +#endif /* __LWIP_OPT_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/pbuf.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/pbuf.h new file mode 100644 index 000000000..8380f65da --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/pbuf.h @@ -0,0 +1,120 @@ +/* + * 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> + * + */ + +#ifndef __LWIP_PBUF_H__ +#define __LWIP_PBUF_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define PBUF_TRANSPORT_HLEN 20 +#define PBUF_IP_HLEN        20 + +typedef enum { +  PBUF_TRANSPORT, +  PBUF_IP, +  PBUF_LINK, +  PBUF_RAW +} pbuf_layer; + +typedef enum { +  PBUF_RAM, /* pbuf data is stored in RAM */ +  PBUF_ROM, /* pbuf data is stored in ROM */ +  PBUF_REF, /* pbuf comes from the pbuf pool */ +  PBUF_POOL /* pbuf payload refers to RAM */ +} pbuf_type; + + +/** indicates this packet's data should be immediately passed to the application */ +#define PBUF_FLAG_PUSH 0x01U + +struct pbuf { +  /** next pbuf in singly linked pbuf chain */ +  struct pbuf *next; + +  /** pointer to the actual data in the buffer */ +  void *payload; +   +  /** +   * total length of this buffer and all next buffers in chain +   * belonging to the same packet. +   * +   * For non-queue packet chains this is the invariant: +   * p->tot_len == p->len + (p->next? p->next->tot_len: 0) +   */ +  u16_t tot_len; +   +  /** length of this buffer */ +  u16_t len;   + +  /** pbuf_type as u8_t instead of enum to save space */ +  u8_t /*pbuf_type*/ type; + +  /** misc flags */ +  u8_t flags; + +  /** +   * the reference count always equals the number of pointers +   * that refer to this pbuf. This can be pointers from an application, +   * the stack itself, or pbuf->next pointers from a chain. +   */ +  u16_t ref; +   +}; + +/* Initializes the pbuf module. This call is empty for now, but may not be in future. */ +#define pbuf_init() + +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type); +void pbuf_realloc(struct pbuf *p, u16_t size);  +u8_t pbuf_header(struct pbuf *p, s16_t header_size); +void pbuf_ref(struct pbuf *p); +void pbuf_ref_chain(struct pbuf *p); +u8_t pbuf_free(struct pbuf *p); +u8_t pbuf_clen(struct pbuf *p);   +void pbuf_cat(struct pbuf *head, struct pbuf *tail); +void pbuf_chain(struct pbuf *head, struct pbuf *tail); +struct pbuf *pbuf_dechain(struct pbuf *p); +err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); +u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); +err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); +struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_PBUF_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/raw.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/raw.h new file mode 100644 index 000000000..20b0a11bb --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/raw.h @@ -0,0 +1,97 @@ +/* + * 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> + * + */ +#ifndef __LWIP_RAW_H__ +#define __LWIP_RAW_H__ + +#include "lwip/opt.h" + +#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/ip_addr.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct raw_pcb { +/* Common members of all PCB types */ +  IP_PCB; + +  struct raw_pcb *next; + +  u8_t protocol; + +  /* receive callback function +   * @param arg user supplied argument (raw_pcb.recv_arg) +   * @param pcb the raw_pcb which received data +   * @param p the packet buffer that was received +   * @param addr the remote IP address from which the packet was received +   * @return 1 if the packet was 'eaten' (aka. deleted), +   *         0 if the packet lives on +   * If returning 1, the callback is responsible for freeing the pbuf +   * if it's not used any more. +   */ +  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr); +  /* user-supplied argument for the recv callback */ +  void *recv_arg; +}; + +/* The following functions is the application layer interface to the +   RAW code. */ +struct raw_pcb * raw_new        (u8_t proto); +void             raw_remove     (struct raw_pcb *pcb); +err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr); +err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr); + +void             raw_recv       (struct raw_pcb *pcb, +                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb, +                                              struct pbuf *p, +                                              struct ip_addr *addr), +                                 void *recv_arg); +err_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); +err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p); + +/* The following functions are the lower layer interface to RAW. */ +u8_t             raw_input      (struct pbuf *p, struct netif *inp); +#define raw_init() /* Compatibility define, not init needed. */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_RAW */ + +#endif /* __LWIP_RAW_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sio.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sio.h new file mode 100644 index 000000000..7d9162e49 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sio.h @@ -0,0 +1,81 @@ +/* + * 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. + */ + +/* + * This is the interface to the platform specific serial IO module + * It needs to be implemented by those platforms which need SLIP or PPP + */ + +#ifndef __SIO_H__ +#define __SIO_H__ + +#include "lwip/arch.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* If you want to define sio_fd_t elsewhere or differently, +   define this in your cc.h file. */ +#ifndef __sio_fd_t_defined +typedef void * sio_fd_t; +#endif + +/* The following functions can be defined to something else in your cc.h file +   or be implemented in your custom sio.c file. */ + +#ifndef sio_open +sio_fd_t sio_open(u8_t); +#endif + +#ifndef sio_send +void sio_send(u8_t, sio_fd_t); +#endif + +#ifndef sio_recv +u8_t sio_recv(sio_fd_t); +#endif + +#ifndef sio_read +u32_t sio_read(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_write +u32_t sio_write(sio_fd_t, u8_t *, u32_t); +#endif + +#ifndef sio_read_abort +void sio_read_abort(sio_fd_t); +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* __SIO_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp.h new file mode 100644 index 000000000..dd03d5d70 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp.h @@ -0,0 +1,364 @@ +/* + * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2001, 2002 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 part of the lwIP TCP/IP stack. + *  + * Author: Leon Woestenberg <leon.woestenberg@axon.tv> + * + */ +#ifndef __LWIP_SNMP_H__ +#define __LWIP_SNMP_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/udp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @see RFC1213, "MIB-II, 6. Definitions" + */ +enum snmp_ifType { +  snmp_ifType_other=1,                /* none of the following */ +  snmp_ifType_regular1822, +  snmp_ifType_hdh1822, +  snmp_ifType_ddn_x25, +  snmp_ifType_rfc877_x25, +  snmp_ifType_ethernet_csmacd, +  snmp_ifType_iso88023_csmacd, +  snmp_ifType_iso88024_tokenBus, +  snmp_ifType_iso88025_tokenRing, +  snmp_ifType_iso88026_man, +  snmp_ifType_starLan, +  snmp_ifType_proteon_10Mbit, +  snmp_ifType_proteon_80Mbit, +  snmp_ifType_hyperchannel, +  snmp_ifType_fddi, +  snmp_ifType_lapb, +  snmp_ifType_sdlc, +  snmp_ifType_ds1,                    /* T-1 */ +  snmp_ifType_e1,                     /* european equiv. of T-1 */ +  snmp_ifType_basicISDN, +  snmp_ifType_primaryISDN,            /* proprietary serial */ +  snmp_ifType_propPointToPointSerial, +  snmp_ifType_ppp, +  snmp_ifType_softwareLoopback, +  snmp_ifType_eon,                    /* CLNP over IP [11] */ +  snmp_ifType_ethernet_3Mbit, +  snmp_ifType_nsip,                   /* XNS over IP */ +  snmp_ifType_slip,                   /* generic SLIP */ +  snmp_ifType_ultra,                  /* ULTRA technologies */ +  snmp_ifType_ds3,                    /* T-3 */ +  snmp_ifType_sip,                    /* SMDS */ +  snmp_ifType_frame_relay +}; + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +/** SNMP "sysuptime" Interval */ +#define SNMP_SYSUPTIME_INTERVAL 10 + +/** fixed maximum length for object identifier type */ +#define LWIP_SNMP_OBJ_ID_LEN 32 + +/** internal object identifier representation */ +struct snmp_obj_id +{ +  u8_t len; +  s32_t id[LWIP_SNMP_OBJ_ID_LEN]; +}; + +/* system */ +void snmp_set_sysdesr(u8_t* str, u8_t* len); +void snmp_set_sysobjid(struct snmp_obj_id *oid); +void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid); +void snmp_inc_sysuptime(void); +void snmp_add_sysuptime(u32_t value); +void snmp_get_sysuptime(u32_t *value); +void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen); +void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen); + +/* network interface */ +void snmp_add_ifinoctets(struct netif *ni, u32_t value);  +void snmp_inc_ifinucastpkts(struct netif *ni); +void snmp_inc_ifinnucastpkts(struct netif *ni); +void snmp_inc_ifindiscards(struct netif *ni); +void snmp_add_ifoutoctets(struct netif *ni, u32_t value); +void snmp_inc_ifoutucastpkts(struct netif *ni); +void snmp_inc_ifoutnucastpkts(struct netif *ni); +void snmp_inc_ifoutdiscards(struct netif *ni); +void snmp_inc_iflist(void); +void snmp_dec_iflist(void); + +/* ARP (for atTable and ipNetToMediaTable) */ +void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip); +void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip); + +/* IP */ +void snmp_inc_ipinreceives(void); +void snmp_inc_ipinhdrerrors(void); +void snmp_inc_ipinaddrerrors(void); +void snmp_inc_ipforwdatagrams(void); +void snmp_inc_ipinunknownprotos(void); +void snmp_inc_ipindiscards(void); +void snmp_inc_ipindelivers(void); +void snmp_inc_ipoutrequests(void); +void snmp_inc_ipoutdiscards(void); +void snmp_inc_ipoutnoroutes(void); +void snmp_inc_ipreasmreqds(void); +void snmp_inc_ipreasmoks(void); +void snmp_inc_ipreasmfails(void); +void snmp_inc_ipfragoks(void); +void snmp_inc_ipfragfails(void); +void snmp_inc_ipfragcreates(void); +void snmp_inc_iproutingdiscards(void); +void snmp_insert_ipaddridx_tree(struct netif *ni); +void snmp_delete_ipaddridx_tree(struct netif *ni); +void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni); +void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni); + +/* ICMP */ +void snmp_inc_icmpinmsgs(void); +void snmp_inc_icmpinerrors(void); +void snmp_inc_icmpindestunreachs(void); +void snmp_inc_icmpintimeexcds(void); +void snmp_inc_icmpinparmprobs(void); +void snmp_inc_icmpinsrcquenchs(void); +void snmp_inc_icmpinredirects(void); +void snmp_inc_icmpinechos(void); +void snmp_inc_icmpinechoreps(void); +void snmp_inc_icmpintimestamps(void); +void snmp_inc_icmpintimestampreps(void); +void snmp_inc_icmpinaddrmasks(void); +void snmp_inc_icmpinaddrmaskreps(void); +void snmp_inc_icmpoutmsgs(void); +void snmp_inc_icmpouterrors(void); +void snmp_inc_icmpoutdestunreachs(void); +void snmp_inc_icmpouttimeexcds(void); +void snmp_inc_icmpoutparmprobs(void); +void snmp_inc_icmpoutsrcquenchs(void); +void snmp_inc_icmpoutredirects(void);  +void snmp_inc_icmpoutechos(void); +void snmp_inc_icmpoutechoreps(void); +void snmp_inc_icmpouttimestamps(void); +void snmp_inc_icmpouttimestampreps(void); +void snmp_inc_icmpoutaddrmasks(void); +void snmp_inc_icmpoutaddrmaskreps(void); + +/* TCP */ +void snmp_inc_tcpactiveopens(void); +void snmp_inc_tcppassiveopens(void); +void snmp_inc_tcpattemptfails(void); +void snmp_inc_tcpestabresets(void); +void snmp_inc_tcpinsegs(void); +void snmp_inc_tcpoutsegs(void); +void snmp_inc_tcpretranssegs(void); +void snmp_inc_tcpinerrs(void); +void snmp_inc_tcpoutrsts(void); + +/* UDP */ +void snmp_inc_udpindatagrams(void); +void snmp_inc_udpnoports(void); +void snmp_inc_udpinerrors(void); +void snmp_inc_udpoutdatagrams(void); +void snmp_insert_udpidx_tree(struct udp_pcb *pcb); +void snmp_delete_udpidx_tree(struct udp_pcb *pcb); + +/* SNMP */ +void snmp_inc_snmpinpkts(void); +void snmp_inc_snmpoutpkts(void); +void snmp_inc_snmpinbadversions(void); +void snmp_inc_snmpinbadcommunitynames(void); +void snmp_inc_snmpinbadcommunityuses(void); +void snmp_inc_snmpinasnparseerrs(void); +void snmp_inc_snmpintoobigs(void); +void snmp_inc_snmpinnosuchnames(void); +void snmp_inc_snmpinbadvalues(void); +void snmp_inc_snmpinreadonlys(void); +void snmp_inc_snmpingenerrs(void); +void snmp_add_snmpintotalreqvars(u8_t value); +void snmp_add_snmpintotalsetvars(u8_t value); +void snmp_inc_snmpingetrequests(void); +void snmp_inc_snmpingetnexts(void); +void snmp_inc_snmpinsetrequests(void); +void snmp_inc_snmpingetresponses(void); +void snmp_inc_snmpintraps(void); +void snmp_inc_snmpouttoobigs(void); +void snmp_inc_snmpoutnosuchnames(void); +void snmp_inc_snmpoutbadvalues(void); +void snmp_inc_snmpoutgenerrs(void); +void snmp_inc_snmpoutgetrequests(void); +void snmp_inc_snmpoutgetnexts(void); +void snmp_inc_snmpoutsetrequests(void); +void snmp_inc_snmpoutgetresponses(void); +void snmp_inc_snmpouttraps(void); +void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid); +void snmp_set_snmpenableauthentraps(u8_t *value); +void snmp_get_snmpenableauthentraps(u8_t *value); + +/* LWIP_SNMP support not available */ +/* define everything to be empty */ +#else + +/* system */ +#define snmp_set_sysdesr(str, len) +#define snmp_set_sysobjid(oid); +#define snmp_get_sysobjid_ptr(oid) +#define snmp_inc_sysuptime() +#define snmp_add_sysuptime(value) +#define snmp_get_sysuptime(value) +#define snmp_set_syscontact(ocstr, ocstrlen); +#define snmp_set_sysname(ocstr, ocstrlen); +#define snmp_set_syslocation(ocstr, ocstrlen); + +/* network interface */ +#define snmp_add_ifinoctets(ni,value)  +#define snmp_inc_ifinucastpkts(ni) +#define snmp_inc_ifinnucastpkts(ni) +#define snmp_inc_ifindiscards(ni) +#define snmp_add_ifoutoctets(ni,value) +#define snmp_inc_ifoutucastpkts(ni) +#define snmp_inc_ifoutnucastpkts(ni) +#define snmp_inc_ifoutdiscards(ni) +#define snmp_inc_iflist() +#define snmp_dec_iflist() + +/* ARP */ +#define snmp_insert_arpidx_tree(ni,ip) +#define snmp_delete_arpidx_tree(ni,ip) + +/* IP */ +#define snmp_inc_ipinreceives() +#define snmp_inc_ipinhdrerrors() +#define snmp_inc_ipinaddrerrors() +#define snmp_inc_ipforwdatagrams() +#define snmp_inc_ipinunknownprotos() +#define snmp_inc_ipindiscards() +#define snmp_inc_ipindelivers() +#define snmp_inc_ipoutrequests() +#define snmp_inc_ipoutdiscards() +#define snmp_inc_ipoutnoroutes() +#define snmp_inc_ipreasmreqds() +#define snmp_inc_ipreasmoks() +#define snmp_inc_ipreasmfails() +#define snmp_inc_ipfragoks() +#define snmp_inc_ipfragfails() +#define snmp_inc_ipfragcreates() +#define snmp_inc_iproutingdiscards() +#define snmp_insert_ipaddridx_tree(ni) +#define snmp_delete_ipaddridx_tree(ni) +#define snmp_insert_iprteidx_tree(dflt, ni) +#define snmp_delete_iprteidx_tree(dflt, ni) + +/* ICMP */ +#define snmp_inc_icmpinmsgs() +#define snmp_inc_icmpinerrors()  +#define snmp_inc_icmpindestunreachs()  +#define snmp_inc_icmpintimeexcds() +#define snmp_inc_icmpinparmprobs()  +#define snmp_inc_icmpinsrcquenchs()  +#define snmp_inc_icmpinredirects()  +#define snmp_inc_icmpinechos()  +#define snmp_inc_icmpinechoreps() +#define snmp_inc_icmpintimestamps()  +#define snmp_inc_icmpintimestampreps() +#define snmp_inc_icmpinaddrmasks() +#define snmp_inc_icmpinaddrmaskreps() +#define snmp_inc_icmpoutmsgs() +#define snmp_inc_icmpouterrors() +#define snmp_inc_icmpoutdestunreachs()  +#define snmp_inc_icmpouttimeexcds()  +#define snmp_inc_icmpoutparmprobs() +#define snmp_inc_icmpoutsrcquenchs() +#define snmp_inc_icmpoutredirects()  +#define snmp_inc_icmpoutechos()  +#define snmp_inc_icmpoutechoreps() +#define snmp_inc_icmpouttimestamps() +#define snmp_inc_icmpouttimestampreps() +#define snmp_inc_icmpoutaddrmasks() +#define snmp_inc_icmpoutaddrmaskreps() +/* TCP */ +#define snmp_inc_tcpactiveopens() +#define snmp_inc_tcppassiveopens() +#define snmp_inc_tcpattemptfails() +#define snmp_inc_tcpestabresets() +#define snmp_inc_tcpinsegs() +#define snmp_inc_tcpoutsegs() +#define snmp_inc_tcpretranssegs() +#define snmp_inc_tcpinerrs() +#define snmp_inc_tcpoutrsts() + +/* UDP */ +#define snmp_inc_udpindatagrams() +#define snmp_inc_udpnoports() +#define snmp_inc_udpinerrors() +#define snmp_inc_udpoutdatagrams() +#define snmp_insert_udpidx_tree(pcb) +#define snmp_delete_udpidx_tree(pcb) + +/* SNMP */ +#define snmp_inc_snmpinpkts() +#define snmp_inc_snmpoutpkts() +#define snmp_inc_snmpinbadversions() +#define snmp_inc_snmpinbadcommunitynames() +#define snmp_inc_snmpinbadcommunityuses() +#define snmp_inc_snmpinasnparseerrs() +#define snmp_inc_snmpintoobigs() +#define snmp_inc_snmpinnosuchnames() +#define snmp_inc_snmpinbadvalues() +#define snmp_inc_snmpinreadonlys() +#define snmp_inc_snmpingenerrs() +#define snmp_add_snmpintotalreqvars(value) +#define snmp_add_snmpintotalsetvars(value) +#define snmp_inc_snmpingetrequests() +#define snmp_inc_snmpingetnexts() +#define snmp_inc_snmpinsetrequests() +#define snmp_inc_snmpingetresponses() +#define snmp_inc_snmpintraps() +#define snmp_inc_snmpouttoobigs() +#define snmp_inc_snmpoutnosuchnames() +#define snmp_inc_snmpoutbadvalues() +#define snmp_inc_snmpoutgenerrs() +#define snmp_inc_snmpoutgetrequests() +#define snmp_inc_snmpoutgetnexts() +#define snmp_inc_snmpoutsetrequests() +#define snmp_inc_snmpoutgetresponses() +#define snmp_inc_snmpouttraps() +#define snmp_get_snmpgrpid_ptr(oid) +#define snmp_set_snmpenableauthentraps(value) +#define snmp_get_snmpenableauthentraps(value) + +#endif /* LWIP_SNMP */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SNMP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h new file mode 100644 index 000000000..8a602881f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_asn1.h @@ -0,0 +1,101 @@ +/** + * @file + * Abstract Syntax Notation One (ISO 8824, 8825) codec. + */ +  +/* + * 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> + */ + +#ifndef __LWIP_SNMP_ASN1_H__ +#define __LWIP_SNMP_ASN1_H__ + +#include "lwip/opt.h" +#include "lwip/err.h" +#include "lwip/pbuf.h" +#include "lwip/snmp.h" + +#if LWIP_SNMP + +#ifdef __cplusplus +extern "C" { +#endif + +#define SNMP_ASN1_UNIV   (!0x80 | !0x40) +#define SNMP_ASN1_APPLIC (!0x80 |  0x40) +#define SNMP_ASN1_CONTXT ( 0x80 | !0x40) + +#define SNMP_ASN1_CONSTR (0x20) +#define SNMP_ASN1_PRIMIT (!0x20) + +/* universal tags */ +#define SNMP_ASN1_INTEG  2 +#define SNMP_ASN1_OC_STR 4 +#define SNMP_ASN1_NUL    5 +#define SNMP_ASN1_OBJ_ID 6 +#define SNMP_ASN1_SEQ    16 + +/* application specific (SNMP) tags */ +#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */ +#define SNMP_ASN1_COUNTER 1   /* u32_t */ +#define SNMP_ASN1_GAUGE 2     /* u32_t */ +#define SNMP_ASN1_TIMETICKS 3 /* u32_t */ +#define SNMP_ASN1_OPAQUE 4    /* octet string */ + +/* context specific (SNMP) tags */ +#define SNMP_ASN1_PDU_GET_REQ 0 +#define SNMP_ASN1_PDU_GET_NEXT_REQ 1 +#define SNMP_ASN1_PDU_GET_RESP 2 +#define SNMP_ASN1_PDU_SET_REQ 3 +#define SNMP_ASN1_PDU_TRAP 4 + +err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type); +err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length); +err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value); +err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value); +err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid); +err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw); + +void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed); +void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed); +void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); +void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); +err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); +err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value); +err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_ASN1_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h new file mode 100644 index 000000000..b2f69c4be --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_msg.h @@ -0,0 +1,311 @@ +/** + * @file + * SNMP Agent message handling structures. + */ + +/* + * 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> + */ + +#ifndef __LWIP_SNMP_MSG_H__ +#define __LWIP_SNMP_MSG_H__ + +#include "lwip/opt.h" +#include "lwip/snmp.h" +#include "lwip/snmp_structs.h" + +#if LWIP_SNMP + +#if SNMP_PRIVATE_MIB +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* The listen port of the SNMP agent. Clients have to make their requests to +   this port. Most standard clients won't work if you change this! */ +#ifndef SNMP_IN_PORT +#define SNMP_IN_PORT 161 +#endif +/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't +   work if you change this! */ +#ifndef SNMP_TRAP_PORT +#define SNMP_TRAP_PORT 162 +#endif + +#define SNMP_ES_NOERROR 0 +#define SNMP_ES_TOOBIG 1 +#define SNMP_ES_NOSUCHNAME 2 +#define SNMP_ES_BADVALUE 3 +#define SNMP_ES_READONLY 4 +#define SNMP_ES_GENERROR 5 + +#define SNMP_GENTRAP_COLDSTART 0 +#define SNMP_GENTRAP_WARMSTART 1 +#define SNMP_GENTRAP_AUTHFAIL 4 +#define SNMP_GENTRAP_ENTERPRISESPC 6 + +struct snmp_varbind +{ +  /* next pointer, NULL for last in list */ +  struct snmp_varbind *next; +  /* previous pointer, NULL for first in list */ +  struct snmp_varbind *prev; + +  /* object identifier length (in s32_t) */ +  u8_t ident_len; +  /* object identifier array */ +  s32_t *ident; + +  /* object value ASN1 type */ +  u8_t value_type; +  /* object value length (in u8_t) */ +  u8_t value_len; +  /* object value */ +  void *value; + +  /* encoding varbind seq length length */ +  u8_t seqlenlen; +  /* encoding object identifier length length */ +  u8_t olenlen; +  /* encoding object value length length */ +  u8_t vlenlen; +  /* encoding varbind seq length */ +  u16_t seqlen; +  /* encoding object identifier length */ +  u16_t olen; +  /* encoding object value length */ +  u16_t vlen; +}; + +struct snmp_varbind_root +{ +  struct snmp_varbind *head; +  struct snmp_varbind *tail; +  /* number of variable bindings in list */ +  u8_t count; +  /* encoding varbind-list seq length length */ +  u8_t seqlenlen; +  /* encoding varbind-list seq length */ +  u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_resp_header_lengths +{ +  /* encoding error-index length length */ +  u8_t erridxlenlen; +  /* encoding error-status length length */ +  u8_t errstatlenlen; +  /* encoding request id length length */ +  u8_t ridlenlen; +  /* encoding pdu length length */ +  u8_t pdulenlen; +  /* encoding community length length */ +  u8_t comlenlen; +  /* encoding version length length */ +  u8_t verlenlen; +  /* encoding sequence length length */ +  u8_t seqlenlen; + +  /* encoding error-index length */ +  u16_t erridxlen; +  /* encoding error-status length */ +  u16_t errstatlen; +  /* encoding request id length */ +  u16_t ridlen; +  /* encoding pdu length */ +  u16_t pdulen; +  /* encoding community length */ +  u16_t comlen; +  /* encoding version length */ +  u16_t verlen; +  /* encoding sequence length */ +  u16_t seqlen; +}; + +/** output response message header length fields */ +struct snmp_trap_header_lengths +{ +  /* encoding timestamp length length */ +  u8_t tslenlen; +  /* encoding specific-trap length length */ +  u8_t strplenlen; +  /* encoding generic-trap length length */ +  u8_t gtrplenlen; +  /* encoding agent-addr length length */ +  u8_t aaddrlenlen; +  /* encoding enterprise-id length length */ +  u8_t eidlenlen; +  /* encoding pdu length length */ +  u8_t pdulenlen; +  /* encoding community length length */ +  u8_t comlenlen; +  /* encoding version length length */ +  u8_t verlenlen; +  /* encoding sequence length length */ +  u8_t seqlenlen; + +  /* encoding timestamp length */ +  u16_t tslen; +  /* encoding specific-trap length */ +  u16_t strplen; +  /* encoding generic-trap length */ +  u16_t gtrplen; +  /* encoding agent-addr length */ +  u16_t aaddrlen; +  /* encoding enterprise-id length */ +  u16_t eidlen; +  /* encoding pdu length */ +  u16_t pdulen; +  /* encoding community length */ +  u16_t comlen; +  /* encoding version length */ +  u16_t verlen; +  /* encoding sequence length */ +  u16_t seqlen; +}; + +/* Accepting new SNMP messages. */ +#define SNMP_MSG_EMPTY                 0 +/* Search for matching object for variable binding. */ +#define SNMP_MSG_SEARCH_OBJ            1 +/* Perform SNMP operation on in-memory object. +   Pass-through states, for symmetry only. */ +#define SNMP_MSG_INTERNAL_GET_OBJDEF   2 +#define SNMP_MSG_INTERNAL_GET_VALUE    3 +#define SNMP_MSG_INTERNAL_SET_TEST     4 +#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5 +#define SNMP_MSG_INTERNAL_SET_VALUE    6 +/* Perform SNMP operation on object located externally. +   In theory this could be used for building a proxy agent. +   Practical use is for an enterprise spc. app. gateway. */ +#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7 +#define SNMP_MSG_EXTERNAL_GET_VALUE    8 +#define SNMP_MSG_EXTERNAL_SET_TEST     9 +#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10 +#define SNMP_MSG_EXTERNAL_SET_VALUE    11 + +#define SNMP_COMMUNITY_STR_LEN 64 +struct snmp_msg_pstat +{ +  /* lwIP local port (161) binding */ +  struct udp_pcb *pcb; +  /* source IP address */ +  struct ip_addr sip; +  /* source UDP port */ +  u16_t sp; +  /* request type */ +  u8_t rt; +  /* request ID */ +  s32_t rid; +  /* error status */ +  s32_t error_status; +  /* error index */ +  s32_t error_index; +  /* community name (zero terminated) */ +  u8_t community[SNMP_COMMUNITY_STR_LEN + 1]; +  /* community string length (exclusive zero term) */ +  u8_t com_strlen; +  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */ +  u8_t state; +  /* saved arguments for MSG_EXTERNAL_x */ +  struct mib_external_node *ext_mib_node; +  struct snmp_name_ptr ext_name_ptr; +  struct obj_def ext_object_def; +  struct snmp_obj_id ext_oid; +  /* index into input variable binding list */ +  u8_t vb_idx; +  /* ptr into input variable binding list */ +  struct snmp_varbind *vb_ptr; +  /* list of variable bindings from input */ +  struct snmp_varbind_root invb; +  /* list of variable bindings to output */ +  struct snmp_varbind_root outvb; +  /* output response lengths used in ASN encoding */ +  struct snmp_resp_header_lengths rhl; +}; + +struct snmp_msg_trap +{ +  /* lwIP local port (161) binding */ +  struct udp_pcb *pcb; +  /* destination IP address in network order */ +  struct ip_addr dip; + +  /* source enterprise ID (sysObjectID) */ +  struct snmp_obj_id *enterprise; +  /* source IP address, raw network order format */ +  u8_t sip_raw[4]; +  /* generic trap code */ +  u32_t gen_trap; +  /* specific trap code */ +  u32_t spc_trap; +  /* timestamp */ +  u32_t ts; +  /* list of variable bindings to output */ +  struct snmp_varbind_root outvb; +  /* output trap lengths used in ASN encoding */ +  struct snmp_trap_header_lengths thl; +}; + +/** Agent Version constant, 0 = v1 oddity */ +extern const s32_t snmp_version; +/** Agent default "public" community string */ +extern const char snmp_publiccommunity[7]; + +extern struct snmp_msg_trap trap_msg; + +/** Agent setup, start listening to port 161. */ +void snmp_init(void); +void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); +void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst); + +/** Varbind-list functions. */ +struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); +void snmp_varbind_free(struct snmp_varbind *vb); +void snmp_varbind_list_free(struct snmp_varbind_root *root); +void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb); +struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root); + +/** Handle an internal (recv) or external (private response) event. */ +void snmp_msg_event(u8_t request_id); +err_t snmp_send_response(struct snmp_msg_pstat *m_stat); +err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap); +void snmp_coldstart_trap(void); +void snmp_authfail_trap(void); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_MSG_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h new file mode 100644 index 000000000..9f3f8a94e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/snmp_structs.h @@ -0,0 +1,262 @@ +/** + * @file + * Generic MIB tree structures. + * + * @todo namespace prefixes + */ + +/* + * 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> + */ + +#ifndef __LWIP_SNMP_STRUCTS_H__ +#define __LWIP_SNMP_STRUCTS_H__ + +#include "lwip/opt.h" + +#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/snmp.h" + +#if SNMP_PRIVATE_MIB +#include "private_mib.h" +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/* MIB object instance */ +#define MIB_OBJECT_NONE 0  +#define MIB_OBJECT_SCALAR 1 +#define MIB_OBJECT_TAB 2 + +/* MIB object access */ +#define MIB_OBJECT_READ_ONLY 0 +#define MIB_OBJECT_READ_WRITE 1 +#define MIB_OBJECT_WRITE_ONLY 2 +#define MIB_OBJECT_NOT_ACCESSIBLE 3 + +/** object definition returned by (get_object_def)() */ +struct obj_def +{ +  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */ +  u8_t instance; +  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */ +  u8_t access; +  /* ASN type for this object */ +  u8_t asn_type; +  /* value length (host length) */ +  u16_t v_len; +  /* length of instance part of supplied object identifier */ +  u8_t  id_inst_len; +  /* instance part of supplied object identifier */ +  s32_t *id_inst_ptr; +}; + +struct snmp_name_ptr +{ +  u8_t ident_len; +  s32_t *ident; +}; + +/** MIB const scalar (.0) node */ +#define MIB_NODE_SC 0x01 +/** MIB const array node */ +#define MIB_NODE_AR 0x02 +/** MIB array node (mem_malloced from RAM) */ +#define MIB_NODE_RA 0x03 +/** MIB list root node (mem_malloced from RAM) */ +#define MIB_NODE_LR 0x04 +/** MIB node for external objects */ +#define MIB_NODE_EX 0x05 + +/** node "base class" layout, the mandatory fields for a node  */ +struct mib_node +{ +  /** returns struct obj_def for the given object identifier */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  /** returns object value for the given object identifier, +     @note the caller must allocate at least len bytes for the value */ +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  /** tests length and/or range BEFORE setting */ +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  /** sets object value, only to be called when set_test()  */ +  void (*set_value)(struct obj_def *od, u16_t len, void *value);   +  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ +  const u8_t node_type; +  /* array or max list length */ +  const u16_t maxlength; +}; + +/** derived node for scalars .0 index */ +typedef struct mib_node mib_scalar_node; + +/** derived node, points to a fixed size const array +    of sub-identifiers plus a 'child' pointer */ +struct mib_array_node +{ +  /* inherited "base class" members */ +  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (* const get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  const u8_t node_type; +  const u16_t maxlength; + +  /* aditional struct members */ +  const s32_t *objid; +  struct mib_node* const *nptr; +}; + +/** derived node, points to a fixed size mem_malloced array +    of sub-identifiers plus a 'child' pointer */ +struct mib_ram_array_node +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  s32_t *objid; +  struct mib_node **nptr; +}; + +struct mib_list_node +{ +  struct mib_list_node *prev;   +  struct mib_list_node *next; +  s32_t objid; +  struct mib_node *nptr; +}; + +/** derived node, points to a doubly linked list +    of sub-identifiers plus a 'child' pointer */ +struct mib_list_rootnode +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  struct mib_list_node *head; +  struct mib_list_node *tail; +  /* counts list nodes in list  */ +  u16_t count; +}; + +/** derived node, has access functions for mib object in external memory or device +    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */ +struct mib_external_node +{ +  /* inherited "base class" members */ +  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value)(struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); +  void (*set_value)(struct obj_def *od, u16_t len, void *value); + +  u8_t node_type; +  u16_t maxlength; + +  /* aditional struct members */ +  /** points to an extenal (in memory) record of some sort of addressing +      information, passed to and interpreted by the funtions below */ +  void* addr_inf; +  /** tree levels under this node */ +  u8_t tree_levels; +  /** number of objects at this level */ +  u16_t (*level_length)(void* addr_inf, u8_t level); +  /** compares object sub identifier with external id +      return zero when equal, nonzero when unequal */ +  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id); +  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id); + +  /** async Questions */ +  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident); +  void (*get_value_q)(u8_t rid, struct obj_def *od); +  void (*set_test_q)(u8_t rid, struct obj_def *od); +  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  /** async Answers */ +  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od); +  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value); +  /** async Panic Close (agent returns error reply,  +      e.g. used for external transaction cleanup) */ +  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident); +  void (*get_value_pc)(u8_t rid, struct obj_def *od); +  void (*set_test_pc)(u8_t rid, struct obj_def *od); +  void (*set_value_pc)(u8_t rid, struct obj_def *od); +}; + +/** export MIB tree from mib2.c */ +extern const struct mib_array_node internet; + +/** dummy function pointers for non-leaf MIB nodes from mib2.c */ +void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od); +void noleafs_get_value(struct obj_def *od, u16_t len, void *value); +u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); +void noleafs_set_value(struct obj_def *od, u16_t len, void *value); + +void snmp_oidtoip(s32_t *ident, struct ip_addr *ip); +void snmp_iptooid(struct ip_addr *ip, s32_t *ident); +void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); +void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); + +struct mib_list_node* snmp_mib_ln_alloc(s32_t id); +void snmp_mib_ln_free(struct mib_list_node *ln); +struct mib_list_rootnode* snmp_mib_lrn_alloc(void); +void snmp_mib_lrn_free(struct mib_list_rootnode *lrn); + +s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn); +s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn); +struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n); + +struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np); +struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); +u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident); +u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret); + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SNMP */ + +#endif /* __LWIP_SNMP_STRUCTS_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sockets.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sockets.h new file mode 100644 index 000000000..7b52e151c --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sockets.h @@ -0,0 +1,357 @@ +/* + * 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> + * + */ + + +#ifndef __LWIP_SOCKETS_H__ +#define __LWIP_SOCKETS_H__ + +#include "lwip/opt.h" + +#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */ + +#include <stddef.h> /* for size_t */ + +#include "lwip/ip_addr.h" +#include "lwip/inet.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* members are in network byte order */ +struct sockaddr_in { +  u8_t sin_len; +  u8_t sin_family; +  u16_t sin_port; +  struct in_addr sin_addr; +  char sin_zero[8]; +}; + +struct sockaddr { +  u8_t sa_len; +  u8_t sa_family; +  char sa_data[14]; +}; + +#ifndef socklen_t +#  define socklen_t u32_t +#endif + +/* Socket protocol types (TCP/UDP/RAW) */ +#define SOCK_STREAM     1 +#define SOCK_DGRAM      2 +#define SOCK_RAW        3 + +/* + * Option flags per-socket. These must match the SOF_ flags in ip.h! + */ +#define  SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */ +#define  SO_ACCEPTCONN  0x0002 /* socket has had listen() */ +#define  SO_REUSEADDR   0x0004 /* Unimplemented: allow local address reuse */ +#define  SO_KEEPALIVE   0x0008 /* keep connections alive */ +#define  SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */ +#define  SO_BROADCAST   0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +#define  SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */ +#define  SO_LINGER      0x0080 /* linger on close if data present */ +#define  SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */ +#define  SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */ + +#define SO_DONTLINGER   ((int)(~SO_LINGER)) + +/* + * Additional options, not kept in so_options. + */ +#define SO_SNDBUF    0x1001    /* Unimplemented: send buffer size */ +#define SO_RCVBUF    0x1002    /* receive buffer size */ +#define SO_SNDLOWAT  0x1003    /* Unimplemented: send low-water mark */ +#define SO_RCVLOWAT  0x1004    /* Unimplemented: receive low-water mark */ +#define SO_SNDTIMEO  0x1005    /* Unimplemented: send timeout */ +#define SO_RCVTIMEO  0x1006    /* receive timeout */ +#define SO_ERROR     0x1007    /* get error status and clear */ +#define SO_TYPE      0x1008    /* get socket type */ +#define SO_CONTIMEO  0x1009    /* Unimplemented: connect timeout */ +#define SO_NO_CHECK  0x100a    /* don't create UDP checksum */ + + +/* + * Structure used for manipulating linger option. + */ +struct linger { +       int l_onoff;                /* option on/off */ +       int l_linger;               /* linger time */ +}; + +/* + * Level number for (get/set)sockopt() to apply to socket itself. + */ +#define  SOL_SOCKET  0xfff    /* options for socket level */ + + +#define AF_UNSPEC       0 +#define AF_INET         2 +#define PF_INET         AF_INET +#define PF_UNSPEC       AF_UNSPEC + +#define IPPROTO_IP      0 +#define IPPROTO_TCP     6 +#define IPPROTO_UDP     17 +#define IPPROTO_UDPLITE 136 + +/* Flags we can use with send and recv. */ +#define MSG_PEEK       0x01    /* Peeks at an incoming message */ +#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */ +#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */ +#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */ +#define MSG_MORE       0x10    /* Sender will send more */ + + +/* + * Options for level IPPROTO_IP + */ +#define IP_TOS             1 +#define IP_TTL             2 + +#if LWIP_TCP +/* + * Options for level IPPROTO_TCP + */ +#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */ +#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */ +#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */ +#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */ +#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */ +#endif /* LWIP_TCP */ + +#if LWIP_UDP && LWIP_UDPLITE +/* + * Options for level IPPROTO_UDPLITE + */ +#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */ +#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */ +#endif /* LWIP_UDP && LWIP_UDPLITE*/ + + +#if LWIP_IGMP +/* + * Options and types for UDP multicast traffic handling + */ +#define IP_ADD_MEMBERSHIP  3 +#define IP_DROP_MEMBERSHIP 4 +#define IP_MULTICAST_TTL   5 +#define IP_MULTICAST_IF    6 +#define IP_MULTICAST_LOOP  7 + +typedef struct ip_mreq { +    struct in_addr imr_multiaddr; /* IP multicast address of group */ +    struct in_addr imr_interface; /* local IP address of interface */ +} ip_mreq; +#endif /* LWIP_IGMP */ + +/* + * The Type of Service provides an indication of the abstract + * parameters of the quality of service desired.  These parameters are + * to be used to guide the selection of the actual service parameters + * when transmitting a datagram through a particular network.  Several + * networks offer service precedence, which somehow treats high + * precedence traffic as more important than other traffic (generally + * by accepting only traffic above a certain precedence at time of high + * load).  The major choice is a three way tradeoff between low-delay, + * high-reliability, and high-throughput. + * The use of the Delay, Throughput, and Reliability indications may + * increase the cost (in some sense) of the service.  In many networks + * better performance for one of these parameters is coupled with worse + * performance on another.  Except for very unusual cases at most two + * of these three indications should be set. + */ +#define IPTOS_TOS_MASK          0x1E +#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK) +#define IPTOS_LOWDELAY          0x10 +#define IPTOS_THROUGHPUT        0x08 +#define IPTOS_RELIABILITY       0x04 +#define IPTOS_LOWCOST           0x02 +#define IPTOS_MINCOST           IPTOS_LOWCOST + +/* + * The Network Control precedence designation is intended to be used + * within a network only.  The actual use and control of that + * designation is up to each network. The Internetwork Control + * designation is intended for use by gateway control originators only. + * If the actual use of these precedence designations is of concern to + * a particular network, it is the responsibility of that network to + * control the access to, and use of, those precedence designations. + */ +#define IPTOS_PREC_MASK                 0xe0 +#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK) +#define IPTOS_PREC_NETCONTROL           0xe0 +#define IPTOS_PREC_INTERNETCONTROL      0xc0 +#define IPTOS_PREC_CRITIC_ECP           0xa0 +#define IPTOS_PREC_FLASHOVERRIDE        0x80 +#define IPTOS_PREC_FLASH                0x60 +#define IPTOS_PREC_IMMEDIATE            0x40 +#define IPTOS_PREC_PRIORITY             0x20 +#define IPTOS_PREC_ROUTINE              0x00 + + +/* + * Commands for ioctlsocket(),  taken from the BSD file fcntl.h. + * lwip_ioctl only supports FIONREAD and FIONBIO, for now + * + * Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word.  The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +#if !defined(FIONREAD) || !defined(FIONBIO) +#define IOCPARM_MASK    0x7fU           /* parameters must be < 128 bytes */ +#define IOC_VOID        0x20000000UL    /* no parameters */ +#define IOC_OUT         0x40000000UL    /* copy out parameters */ +#define IOC_IN          0x80000000UL    /* copy in parameters */ +#define IOC_INOUT       (IOC_IN|IOC_OUT) +                                        /* 0x20000000 distinguishes new & +                                           old ioctl's */ +#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y)) + +#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) + +#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y)) +#endif /* !defined(FIONREAD) || !defined(FIONBIO) */ + +#ifndef FIONREAD +#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */ +#endif +#ifndef FIONBIO +#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */ +#endif + +/* Socket I/O Controls: unimplemented */ +#ifndef SIOCSHIWAT +#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */ +#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */ +#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */ +#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */ +#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */ +#endif + +/* Socket flags: */ +#ifndef O_NONBLOCK +#define O_NONBLOCK    04000U +#endif + +/* FD_SET used for lwip_select */ +#ifndef FD_SET +  #undef  FD_SETSIZE +  /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */ +  #define FD_SETSIZE    MEMP_NUM_NETCONN +  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7))) +  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7))) +  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7))) +  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p))) + +  typedef struct fd_set { +          unsigned char fd_bits [(FD_SETSIZE+7)/8]; +        } fd_set; + +#endif /* FD_SET */ + +/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided + * by your system, set this to 0 and include <sys/time.h> in cc.h */  +#ifndef LWIP_TIMEVAL_PRIVATE +#define LWIP_TIMEVAL_PRIVATE 1 +#endif + +#if LWIP_TIMEVAL_PRIVATE +struct timeval { +  long    tv_sec;         /* seconds */ +  long    tv_usec;        /* and microseconds */ +}; +#endif /* LWIP_TIMEVAL_PRIVATE */ + +void lwip_socket_init(void); + +int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen); +int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_shutdown(int s, int how); +int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen); +int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen); +int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen); +int lwip_close(int s); +int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen); +int lwip_listen(int s, int backlog); +int lwip_recv(int s, void *mem, size_t len, int flags); +int lwip_read(int s, void *mem, size_t len); +int lwip_recvfrom(int s, void *mem, size_t len, int flags, +      struct sockaddr *from, socklen_t *fromlen); +int lwip_send(int s, const void *dataptr, size_t size, int flags); +int lwip_sendto(int s, const void *dataptr, size_t size, int flags, +    const struct sockaddr *to, socklen_t tolen); +int lwip_socket(int domain, int type, int protocol); +int lwip_write(int s, const void *dataptr, size_t size); +int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, +                struct timeval *timeout); +int lwip_ioctl(int s, long cmd, void *argp); + +#if LWIP_COMPAT_SOCKETS +#define accept(a,b,c)         lwip_accept(a,b,c) +#define bind(a,b,c)           lwip_bind(a,b,c) +#define shutdown(a,b)         lwip_shutdown(a,b) +#define closesocket(s)        lwip_close(s) +#define connect(a,b,c)        lwip_connect(a,b,c) +#define getsockname(a,b,c)    lwip_getsockname(a,b,c) +#define getpeername(a,b,c)    lwip_getpeername(a,b,c) +#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e) +#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e) +#define listen(a,b)           lwip_listen(a,b) +#define recv(a,b,c,d)         lwip_recv(a,b,c,d) +#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f) +#define send(a,b,c,d)         lwip_send(a,b,c,d) +#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f) +#define socket(a,b,c)         lwip_socket(a,b,c) +#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e) +#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c) + +#if LWIP_POSIX_SOCKETS_IO_NAMES +#define read(a,b,c)           lwip_read(a,b,c) +#define write(a,b,c)          lwip_write(a,b,c) +#define close(s)              lwip_close(s) +#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */ + +#endif /* LWIP_COMPAT_SOCKETS */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_SOCKET */ + +#endif /* __LWIP_SOCKETS_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/stats.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/stats.h new file mode 100644 index 000000000..aa179f5c0 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/stats.h @@ -0,0 +1,283 @@ +/* + * 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> + * + */ +#ifndef __LWIP_STATS_H__ +#define __LWIP_STATS_H__ + +#include "lwip/opt.h" + +#include "lwip/mem.h" +#include "lwip/memp.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_STATS + +#ifndef LWIP_STATS_LARGE +#define LWIP_STATS_LARGE 0 +#endif + +#if LWIP_STATS_LARGE +#define STAT_COUNTER     u32_t +#define STAT_COUNTER_F   U32_F +#else +#define STAT_COUNTER     u16_t +#define STAT_COUNTER_F   U16_F +#endif  + +struct stats_proto { +  STAT_COUNTER xmit;             /* Transmitted packets. */ +  STAT_COUNTER recv;             /* Received packets. */ +  STAT_COUNTER fw;               /* Forwarded packets. */ +  STAT_COUNTER drop;             /* Dropped packets. */ +  STAT_COUNTER chkerr;           /* Checksum error. */ +  STAT_COUNTER lenerr;           /* Invalid length error. */ +  STAT_COUNTER memerr;           /* Out of memory error. */ +  STAT_COUNTER rterr;            /* Routing error. */ +  STAT_COUNTER proterr;          /* Protocol error. */ +  STAT_COUNTER opterr;           /* Error in options. */ +  STAT_COUNTER err;              /* Misc error. */ +  STAT_COUNTER cachehit; +}; + +struct stats_igmp { +  STAT_COUNTER lenerr;           /* Invalid length error. */ +  STAT_COUNTER chkerr;           /* Checksum error. */ +  STAT_COUNTER v1_rxed;          /* */ +  STAT_COUNTER join_sent;        /* */ +  STAT_COUNTER leave_sent;       /* */ +  STAT_COUNTER unicast_query;    /* */ +  STAT_COUNTER report_sent;      /* */ +  STAT_COUNTER report_rxed;      /* */ +  STAT_COUNTER group_query_rxed; /* */ +}; + +struct stats_mem { +  mem_size_t avail; +  mem_size_t used; +  mem_size_t max; +  STAT_COUNTER err; +  STAT_COUNTER illegal; +}; + +struct stats_syselem { +  STAT_COUNTER used; +  STAT_COUNTER max; +  STAT_COUNTER err; +}; + +struct stats_sys { +  struct stats_syselem sem; +  struct stats_syselem mbox; +}; + +struct stats_ { +#if LINK_STATS +  struct stats_proto link; +#endif +#if ETHARP_STATS +  struct stats_proto etharp; +#endif +#if IPFRAG_STATS +  struct stats_proto ip_frag; +#endif +#if IP_STATS +  struct stats_proto ip; +#endif +#if ICMP_STATS +  struct stats_proto icmp; +#endif +#if IGMP_STATS +  struct stats_igmp igmp; +#endif +#if UDP_STATS +  struct stats_proto udp; +#endif +#if TCP_STATS +  struct stats_proto tcp; +#endif +#if MEM_STATS +  struct stats_mem mem; +#endif +#if MEMP_STATS +  struct stats_mem memp[MEMP_MAX]; +#endif +#if SYS_STATS +  struct stats_sys sys; +#endif +}; + +extern struct stats_ lwip_stats; + +#define stats_init() /* Compatibility define, not init needed. */ + +#define STATS_INC(x) ++lwip_stats.x +#define STATS_DEC(x) --lwip_stats.x +#else +#define stats_init() +#define STATS_INC(x) +#define STATS_DEC(x) +#endif /* LWIP_STATS */ + +#if TCP_STATS +#define TCP_STATS_INC(x) STATS_INC(x) +#define TCP_STATS_DISPLAY() stats_display_proto(&lwip_stats.tcp, "TCP") +#else +#define TCP_STATS_INC(x) +#define TCP_STATS_DISPLAY() +#endif + +#if UDP_STATS +#define UDP_STATS_INC(x) STATS_INC(x) +#define UDP_STATS_DISPLAY() stats_display_proto(&lwip_stats.udp, "UDP") +#else +#define UDP_STATS_INC(x) +#define UDP_STATS_DISPLAY() +#endif + +#if ICMP_STATS +#define ICMP_STATS_INC(x) STATS_INC(x) +#define ICMP_STATS_DISPLAY() stats_display_proto(&lwip_stats.icmp, "ICMP") +#else +#define ICMP_STATS_INC(x) +#define ICMP_STATS_DISPLAY() +#endif + +#if IGMP_STATS +#define IGMP_STATS_INC(x) STATS_INC(x) +#define IGMP_STATS_DISPLAY() stats_display_igmp(&lwip_stats.igmp) +#else +#define IGMP_STATS_INC(x) +#define IGMP_STATS_DISPLAY() +#endif + +#if IP_STATS +#define IP_STATS_INC(x) STATS_INC(x) +#define IP_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip, "IP") +#else +#define IP_STATS_INC(x) +#define IP_STATS_DISPLAY() +#endif + +#if IPFRAG_STATS +#define IPFRAG_STATS_INC(x) STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG") +#else +#define IPFRAG_STATS_INC(x) +#define IPFRAG_STATS_DISPLAY() +#endif + +#if ETHARP_STATS +#define ETHARP_STATS_INC(x) STATS_INC(x) +#define ETHARP_STATS_DISPLAY() stats_display_proto(&lwip_stats.etharp, "ETHARP") +#else +#define ETHARP_STATS_INC(x) +#define ETHARP_STATS_DISPLAY() +#endif + +#if LINK_STATS +#define LINK_STATS_INC(x) STATS_INC(x) +#define LINK_STATS_DISPLAY() stats_display_proto(&lwip_stats.link, "LINK") +#else +#define LINK_STATS_INC(x) +#define LINK_STATS_DISPLAY() +#endif + +#if MEM_STATS +#define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y +#define MEM_STATS_INC(x) STATS_INC(mem.x) +#define MEM_STATS_INC_USED(x, y) do { lwip_stats.mem.used += y; \ +                                    if (lwip_stats.mem.max < lwip_stats.mem.used) { \ +                                        lwip_stats.mem.max = lwip_stats.mem.used; \ +                                    } \ +                                 } while(0) +#define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y +#define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") +#else +#define MEM_STATS_AVAIL(x, y) +#define MEM_STATS_INC(x) +#define MEM_STATS_INC_USED(x, y) +#define MEM_STATS_DEC_USED(x, y) +#define MEM_STATS_DISPLAY() +#endif + +#if MEMP_STATS +#define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y +#define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) +#define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) +#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \ +                                    if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \ +                                        lwip_stats.memp[i].max = lwip_stats.memp[i].used; \ +                                    } \ +                                 } while(0) +#define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) +#else +#define MEMP_STATS_AVAIL(x, i, y) +#define MEMP_STATS_INC(x, i) +#define MEMP_STATS_DEC(x, i) +#define MEMP_STATS_INC_USED(x, i) +#define MEMP_STATS_DISPLAY(i) +#endif + +#if SYS_STATS +#define SYS_STATS_INC(x) STATS_INC(sys.x) +#define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) +#else +#define SYS_STATS_INC(x) +#define SYS_STATS_DEC(x) +#define SYS_STATS_DISPLAY() +#endif + +/* Display of statistics */ +#if LWIP_STATS_DISPLAY +void stats_display(void); +void stats_display_proto(struct stats_proto *proto, char *name); +void stats_display_igmp(struct stats_igmp *igmp); +void stats_display_mem(struct stats_mem *mem, char *name); +void stats_display_memp(struct stats_mem *mem, int index); +void stats_display_sys(struct stats_sys *sys); +#else +#define stats_display() +#define stats_display_proto(proto, name) +#define stats_display_igmp(igmp) +#define stats_display_mem(mem, name) +#define stats_display_memp(mem, index) +#define stats_display_sys(sys) +#endif /* LWIP_STATS_DISPLAY */ + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_STATS_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sys.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sys.h new file mode 100644 index 000000000..0cc84ddf1 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/sys.h @@ -0,0 +1,243 @@ +/* + * 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> + * + */ +#ifndef __LWIP_SYS_H__ +#define __LWIP_SYS_H__ + +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if NO_SYS + +/* For a totally minimal and standalone system, we provide null +   definitions of the sys_ functions. */ +typedef u8_t sys_sem_t; +typedef u8_t sys_mbox_t; +struct sys_timeo {u8_t dummy;}; + +#define sys_init() +#define sys_timeout(m,h,a) +#define sys_untimeout(m,a) +#define sys_sem_new(c) c +#define sys_sem_signal(s) +#define sys_sem_wait(s) +#define sys_sem_wait_timeout(s,t) +#define sys_arch_sem_wait(s,t) +#define sys_sem_free(s) +#define sys_mbox_new(s) 0 +#define sys_mbox_fetch(m,d) +#define sys_mbox_tryfetch(m,d) +#define sys_mbox_post(m,d) +#define sys_mbox_trypost(m,d) +#define sys_mbox_free(m) + +#define sys_thread_new(n,t,a,s,p) + +#else /* NO_SYS */ + +/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ +#define SYS_ARCH_TIMEOUT 0xffffffffUL + +/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate. + * For now we use the same magic value, but we allow this to change in future. + */ +#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT  + +#include "lwip/err.h" +#include "arch/sys_arch.h" + +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { +  struct sys_timeo *next; +  u32_t time; +  sys_timeout_handler h; +  void *arg; +}; + +struct sys_timeouts { +  struct sys_timeo *next; +}; + +/* sys_init() must be called before anthing else. */ +void sys_init(void); + +/* + * sys_timeout(): + * + * Schedule a timeout a specified amount of milliseconds in the + * future. When the timeout occurs, the specified timeout handler will + * be called. The handler will be passed the "arg" argument when + * called. + * + */ +void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +void sys_untimeout(sys_timeout_handler h, void *arg); +struct sys_timeouts *sys_arch_timeouts(void); + +/* Semaphore functions. */ +sys_sem_t sys_sem_new(u8_t count); +void sys_sem_signal(sys_sem_t sem); +u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout); +void sys_sem_free(sys_sem_t sem); +void sys_sem_wait(sys_sem_t sem); +int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout); + +/* Time functions. */ +#ifndef sys_msleep +void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ +#endif +#ifndef sys_jiffies +u32_t sys_jiffies(void); /* since power up. */ +#endif + +/* Mailbox functions. */ +sys_mbox_t sys_mbox_new(int size); +void sys_mbox_post(sys_mbox_t mbox, void *msg); +err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg); +u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout); +#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg); +#endif +/* For now, we map straight to sys_arch implementation. */ +#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) +void sys_mbox_free(sys_mbox_t mbox); +void sys_mbox_fetch(sys_mbox_t mbox, void **msg); + +/* Thread functions. */ +sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio); + +#endif /* NO_SYS */ + +/** Returns the current time in milliseconds. */ +u32_t sys_now(void); + +/* Critical Region Protection */ +/* These functions must be implemented in the sys_arch.c file. +   In some implementations they can provide a more light-weight protection +   mechanism than using semaphores. Otherwise semaphores can be used for +   implementation */ +#ifndef SYS_ARCH_PROTECT +/** SYS_LIGHTWEIGHT_PROT + * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection + * for certain critical regions during buffer allocation, deallocation and memory + * allocation and deallocation. + */ +#if SYS_LIGHTWEIGHT_PROT + +/** SYS_ARCH_DECL_PROTECT + * declare a protection variable. This macro will default to defining a variable of + * type sys_prot_t. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h. + */ +#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev +/** SYS_ARCH_PROTECT + * Perform a "fast" protect. This could be implemented by + * disabling interrupts for an embedded system or by using a semaphore or + * mutex. The implementation should allow calling SYS_ARCH_PROTECT when + * already protected. The old protection level is returned in the variable + * "lev". This macro will default to calling the sys_arch_protect() function + * which should be implemented in sys_arch.c. If a particular port needs a + * different implementation, then this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect() +/** SYS_ARCH_UNPROTECT + * Perform a "fast" set of the protection level to "lev". This could be + * implemented by setting the interrupt level to "lev" within the MACRO or by + * using a semaphore or mutex.  This macro will default to calling the + * sys_arch_unprotect() function which should be implemented in + * sys_arch.c. If a particular port needs a different implementation, then + * this macro may be defined in sys_arch.h + */ +#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev) +sys_prot_t sys_arch_protect(void); +void sys_arch_unprotect(sys_prot_t pval); + +#else + +#define SYS_ARCH_DECL_PROTECT(lev) +#define SYS_ARCH_PROTECT(lev) +#define SYS_ARCH_UNPROTECT(lev) + +#endif /* SYS_LIGHTWEIGHT_PROT */ + +#endif /* SYS_ARCH_PROTECT */ + +/* + * Macros to set/get and increase/decrease variables in a thread-safe way. + * Use these for accessing variable that are used from more than one thread. + */ + +#ifndef SYS_ARCH_INC +#define SYS_ARCH_INC(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var += val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_INC */ + +#ifndef SYS_ARCH_DEC +#define SYS_ARCH_DEC(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var -= val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_DEC */ + +#ifndef SYS_ARCH_GET +#define SYS_ARCH_GET(var, ret) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                ret = var; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_GET */ + +#ifndef SYS_ARCH_SET +#define SYS_ARCH_SET(var, val) do { \ +                                SYS_ARCH_DECL_PROTECT(old_level); \ +                                SYS_ARCH_PROTECT(old_level); \ +                                var = val; \ +                                SYS_ARCH_UNPROTECT(old_level); \ +                              } while(0) +#endif /* SYS_ARCH_SET */ + + +#ifdef __cplusplus +} +#endif + +#endif /* __LWIP_SYS_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcp.h new file mode 100644 index 000000000..8f6b9d3c1 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcp.h @@ -0,0 +1,699 @@ +/* + * 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> + * + */ +#ifndef __LWIP_TCP_H__ +#define __LWIP_TCP_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +struct tcp_pcb; + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, not init needed. */ +void             tcp_tmr     (void);  /* Must be called every +                                         TCP_TMR_INTERVAL +                                         ms. (Typically 250 ms). */ +/* Application program's interface: */ +struct tcp_pcb * tcp_new     (void); +struct tcp_pcb * tcp_alloc   (u8_t prio); + +void             tcp_arg     (struct tcp_pcb *pcb, void *arg); +void             tcp_accept  (struct tcp_pcb *pcb, +                              err_t (* accept)(void *arg, struct tcp_pcb *newpcb, +                 err_t err)); +void             tcp_recv    (struct tcp_pcb *pcb, +                              err_t (* recv)(void *arg, struct tcp_pcb *tpcb, +                              struct pbuf *p, err_t err)); +void             tcp_sent    (struct tcp_pcb *pcb, +                              err_t (* sent)(void *arg, struct tcp_pcb *tpcb, +                              u16_t len)); +void             tcp_poll    (struct tcp_pcb *pcb, +                              err_t (* poll)(void *arg, struct tcp_pcb *tpcb), +                              u8_t interval); +void             tcp_err     (struct tcp_pcb *pcb, +                              void (* err)(void *arg, err_t err)); + +#define          tcp_mss(pcb)      ((pcb)->mss) +#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf) + +#if TCP_LISTEN_BACKLOG +#define          tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--) +#else  /* TCP_LISTEN_BACKLOG */ +#define          tcp_accepted(pcb) +#endif /* TCP_LISTEN_BACKLOG */ + +void             tcp_recved  (struct tcp_pcb *pcb, u16_t len); +err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                              u16_t port); +err_t            tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr, +                              u16_t port, err_t (* connected)(void *arg, +                              struct tcp_pcb *tpcb, +                              err_t err)); + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void             tcp_abandon (struct tcp_pcb *pcb, int reset); +#define          tcp_abort(pcb) tcp_abandon((pcb), 1) +err_t            tcp_close   (struct tcp_pcb *pcb); + +/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len, +                              u8_t apiflags); + +void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN    1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX    127 + +/* It is also possible to call these two functions at the right +   intervals (instead of calling tcp_tmr()). */ +void             tcp_slowtmr (void); +void             tcp_fasttmr (void); + + +/* Only used by IP to pass a TCP segment to TCP: */ +void             tcp_input   (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +err_t            tcp_output  (struct tcp_pcb *pcb); +void             tcp_rexmit  (struct tcp_pcb *pcb); +void             tcp_rexmit_rto  (struct tcp_pcb *pcb); +u32_t            tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + *   than one unsent segment - with lwIP, this can happen although unsent->len < mss) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ +                            ((tpcb)->flags & TF_NODELAY) || \ +                            (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ +                              ((tpcb)->unsent->len >= (tpcb)->mss))) \ +                            ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef  TCP_KEEPIDLE_DEFAULT +#define  TCP_KEEPIDLE_DEFAULT     7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef  TCP_KEEPINTVL_DEFAULT +#define  TCP_KEEPINTVL_DEFAULT    75000UL   /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef  TCP_KEEPCNT_DEFAULT +#define  TCP_KEEPCNT_DEFAULT      9U        /* Default Counter for KEEPALIVE probes */ +#endif + +#define  TCP_MAXIDLE              TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT  /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { +  PACK_STRUCT_FIELD(u16_t src); +  PACK_STRUCT_FIELD(u16_t dest); +  PACK_STRUCT_FIELD(u32_t seqno); +  PACK_STRUCT_FIELD(u32_t ackno); +  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); +  PACK_STRUCT_FIELD(u16_t wnd); +  PACK_STRUCT_FIELD(u16_t chksum); +  PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags)) +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \ +          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0)) + +enum tcp_state { +  CLOSED      = 0, +  LISTEN      = 1, +  SYN_SENT    = 2, +  SYN_RCVD    = 3, +  ESTABLISHED = 4, +  FIN_WAIT_1  = 5, +  FIN_WAIT_2  = 6, +  CLOSE_WAIT  = 7, +  CLOSING     = 8, +  LAST_ACK    = 9, +  TIME_WAIT   = 10 +}; + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */ +#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */ +#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */ + + +#if LWIP_CALLBACK_API +  /* Function to call when a listener has been connected. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb a new tcp_pcb that now is connected +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return ERR_OK: accept the new connection, +   *                 any other err_t abortsthe new connection +   */ +#define DEF_ACCEPT_CALLBACK  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err) +#else /* LWIP_CALLBACK_API */ +#define DEF_ACCEPT_CALLBACK +#endif /* LWIP_CALLBACK_API */ + +/** + * members common to struct tcp_pcb and struct tcp_listen_pcb + */ +#define TCP_PCB_COMMON(type) \ +  type *next; /* for the linked list */ \ +  enum tcp_state state; /* TCP state */ \ +  u8_t prio; \ +  void *callback_arg; \ +  /* ports are in host byte order */ \ +  u16_t local_port; \ +  /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ +  DEF_ACCEPT_CALLBACK + + +/* the TCP protocol control block */ +struct tcp_pcb { +/** common PCB members */ +  IP_PCB; +/** protocol specific PCB members */ +  TCP_PCB_COMMON(struct tcp_pcb); + +  /* ports are in host byte order */ +  u16_t remote_port; +   +  u8_t flags; +#define TF_ACK_DELAY   ((u8_t)0x01U)   /* Delayed ACK. */ +#define TF_ACK_NOW     ((u8_t)0x02U)   /* Immediate ACK. */ +#define TF_INFR        ((u8_t)0x04U)   /* In fast recovery. */ +#define TF_TIMESTAMP   ((u8_t)0x08U)   /* Timestamp option enabled */ +#define TF_FIN         ((u8_t)0x20U)   /* Connection was closed locally (FIN segment enqueued). */ +#define TF_NODELAY     ((u8_t)0x40U)   /* Disable Nagle algorithm */ +#define TF_NAGLEMEMERR ((u8_t)0x80U)   /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ + +  /* the rest of the fields are in host byte order +     as we have to do some math with them */ +  /* receiver variables */ +  u32_t rcv_nxt;   /* next seqno expected */ +  u16_t rcv_wnd;   /* receiver window available */ +  u16_t rcv_ann_wnd; /* receiver window to announce */ +  u32_t rcv_ann_right_edge; /* announced right edge of window */ + +  /* Timers */ +  u32_t tmr; +  u8_t polltmr, pollinterval; +   +  /* Retransmission timer. */ +  s16_t rtime; +   +  u16_t mss;   /* maximum segment size */ +   +  /* RTT (round trip time) estimation variables */ +  u32_t rttest; /* RTT estimate in 500ms ticks */ +  u32_t rtseq;  /* sequence number being timed */ +  s16_t sa, sv; /* @todo document this */ + +  s16_t rto;    /* retransmission time-out */ +  u8_t nrtx;    /* number of retransmissions */ + +  /* fast retransmit/recovery */ +  u32_t lastack; /* Highest acknowledged seqno. */ +  u8_t dupacks; +   +  /* congestion avoidance/control variables */ +  u16_t cwnd;   +  u16_t ssthresh; + +  /* sender variables */ +  u32_t snd_nxt;   /* next new seqno to be sent */ +  u16_t snd_wnd;   /* sender window */ +  u32_t snd_wl1, snd_wl2; /* Sequence and acknowledgement numbers of last +                             window update. */ +  u32_t snd_lbb;       /* Sequence number of next byte to be buffered. */ + +  u16_t acked; +   +  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */ +#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) +  u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ +   +   +  /* These are ordered by sequence number: */ +  struct tcp_seg *unsent;   /* Unsent (queued) segments. */ +  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */ +#if TCP_QUEUE_OOSEQ   +  struct tcp_seg *ooseq;    /* Received out of sequence segments. */ +#endif /* TCP_QUEUE_OOSEQ */ + +  struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ + +#if LWIP_CALLBACK_API +  /* Function to be called when more send buffer space is available. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb which has send buffer space available +   * @param space the amount of bytes available +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space); +   +  /* Function to be called when (in-sequence) data has arrived. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb for which data has arrived +   * @param p the packet buffer which arrived +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); + +  /* Function to be called when a connection has been set up. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb that now is connected +   * @param err an error argument (TODO: that is current always ERR_OK?) +   * @return value is currently ignored +   */ +  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err); + +  /* Function which is called periodically. +   * The period can be adjusted in multiples of the TCP slow timer interval +   * by changing tcp_pcb.polltmr. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param pcb the tcp_pcb to poll for +   * @return ERR_OK: try to send some data by calling tcp_output +   */ +  err_t (* poll)(void *arg, struct tcp_pcb *pcb); + +  /* Function to be called whenever a fatal error occurs. +   * There is no pcb parameter since most of the times, the pcb is +   * already deallocated (or there is no pcb) when this function is called. +   * @param arg user-supplied argument (tcp_pcb.callback_arg) +   * @param err an indication why the error callback is called: +   *            ERR_ABRT: aborted through tcp_abort or by a TCP timer +   *            ERR_RST: the connection was reset by the remote host +   */ +  void (* errf)(void *arg, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if LWIP_TCP_TIMESTAMPS +  u32_t ts_lastacksent; +  u32_t ts_recent; +#endif /* LWIP_TCP_TIMESTAMPS */ + +  /* idle time before KEEPALIVE is sent */ +  u32_t keep_idle; +#if LWIP_TCP_KEEPALIVE +  u32_t keep_intvl; +  u32_t keep_cnt; +#endif /* LWIP_TCP_KEEPALIVE */ +   +  /* Persist timer counter */ +  u32_t persist_cnt; +  /* Persist timer back-off */ +  u8_t persist_backoff; + +  /* KEEPALIVE counter */ +  u8_t keep_cnt_sent; +}; + +struct tcp_pcb_listen {   +/* Common members of all PCB types */ +  IP_PCB; +/* Protocol specific PCB members */ +  TCP_PCB_COMMON(struct tcp_pcb_listen); + +#if TCP_LISTEN_BACKLOG +  u8_t backlog; +  u8_t accepts_pending; +#endif /* TCP_LISTEN_BACKLOG */ +}; + +#if LWIP_EVENT_API + +enum lwip_event { +  LWIP_EVENT_ACCEPT, +  LWIP_EVENT_SENT, +  LWIP_EVENT_RECV, +  LWIP_EVENT_CONNECTED, +  LWIP_EVENT_POLL, +  LWIP_EVENT_ERR +}; + +err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, +         enum lwip_event, +         struct pbuf *p, +         u16_t size, +         err_t err); + +#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                   LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ +                LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \ +                LWIP_EVENT_ERR, NULL, 0, (err)) +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret)                          \ +  do {                                                         \ +    if((pcb)->accept != NULL)                                  \ +      (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err));  \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret)                          \ +  do {                                                         \ +    if((pcb)->sent != NULL)                                    \ +      (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space));  \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret)                           \ +  do {                                                          \ +    if((pcb)->recv != NULL) {                                   \ +      (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \ +    } else {                                                    \ +      (ret) = ERR_OK;                                           \ +      if (p != NULL)                                            \ +        pbuf_free(p);                                           \ +    }                                                           \ +  } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret)                         \ +  do {                                                           \ +    if((pcb)->connected != NULL)                                 \ +      (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ +    else (ret) = ERR_OK;                                         \ +  } while (0) + +#define TCP_EVENT_POLL(pcb,ret)                                \ +  do {                                                         \ +    if((pcb)->poll != NULL)                                    \ +      (ret) = (pcb)->poll((pcb)->callback_arg,(pcb));          \ +    else (ret) = ERR_OK;                                       \ +  } while (0) + +#define TCP_EVENT_ERR(errf,arg,err)                            \ +  do {                                                         \ +    if((errf) != NULL)                                         \ +      (errf)((arg),(err));                                     \ +  } while (0) + +#endif /* LWIP_EVENT_API */ + +/* This structure represents a TCP segment on the unsent and unacked queues */ +struct tcp_seg { +  struct tcp_seg *next;    /* used when putting segements on a queue */ +  struct pbuf *p;          /* buffer containing data + TCP header */ +  void *dataptr;           /* pointer to the TCP data in the pbuf */ +  u16_t len;               /* the TCP length of this segment */ +  u8_t  flags; +#define TF_SEG_OPTS_MSS   (u8_t)0x01U   /* Include MSS option. */ +#define TF_SEG_OPTS_TS    (u8_t)0x02U   /* Include timestamp option. */ +  struct tcp_hdr *tcphdr;  /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags)              \ +  (flags & TF_SEG_OPTS_MSS ? 4  : 0) +          \ +  (flags & TF_SEG_OPTS_TS  ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) |          \ +                                            ((u32_t)4 << 16) |          \ +                                            (((u32_t)TCP_MSS / 256) << 8) | \ +                                            (TCP_MSS & 255)) + +/* Internal functions and global variables: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +u8_t tcp_segs_free(struct tcp_seg *seg); +u8_t tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb)                               \ +  do {                                             \ +    if((pcb)->flags & TF_ACK_DELAY) {              \ +      (pcb)->flags &= ~TF_ACK_DELAY;               \ +      (pcb)->flags |= TF_ACK_NOW;                  \ +      tcp_output(pcb);                             \ +    }                                              \ +    else {                                         \ +      (pcb)->flags |= TF_ACK_DELAY;                \ +    }                                              \ +  } while (0) + +#define tcp_ack_now(pcb)                           \ +  do {                                             \ +    (pcb)->flags |= TF_ACK_NOW;                    \ +    tcp_output(pcb);                               \ +  } while (0) + +err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags); +err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len, +                  u8_t flags, u8_t apiflags, u8_t optflags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, +       struct ip_addr *local_ip, struct ip_addr *remote_ip, +       u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(void); + +void tcp_keepalive(struct tcp_pcb *pcb); +void tcp_zero_window_probe(struct tcp_pcb *pcb); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +#  define tcp_debug_print(tcphdr) +#  define tcp_debug_print_flags(flags) +#  define tcp_debug_print_state(s) +#  define tcp_debug_print_pcbs() +#  define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +#if NO_SYS +#define tcp_timer_needed() +#else +void tcp_timer_needed(void); +#endif + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ +  struct tcp_pcb_listen *listen_pcbs;  +  struct tcp_pcb *pcbs; +}; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a +              state in which they accept or send +              data. */ +extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */ + +/* Axioms about the above lists:    +   1) Every TCP PCB that is not CLOSED is in one of the lists. +   2) A PCB is only in one of the lists. +   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. +   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ + +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB +   with a PCB list or removes a PCB from a list, respectively. */ +#if 0 +#define TCP_REG(pcbs, npcb) do {\ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \ +                            for(tcp_tmp_pcb = *pcbs; \ +          tcp_tmp_pcb != NULL; \ +        tcp_tmp_pcb = tcp_tmp_pcb->next) { \ +                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \ +                            } \ +                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \ +                            npcb->next = *pcbs; \ +                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \ +                            *(pcbs) = npcb; \ +                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ +              tcp_timer_needed(); \ +                            } while(0) +#define TCP_RMV(pcbs, npcb) do { \ +                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \ +                            if(*pcbs == npcb) { \ +                               *pcbs = (*pcbs)->next; \ +                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ +                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \ +                                  tcp_tmp_pcb->next = npcb->next; \ +                                  break; \ +                               } \ +                            } \ +                            npcb->next = NULL; \ +                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ +                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \ +                            } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb)                        \ +  do {                                             \ +    npcb->next = *pcbs;                            \ +    *(pcbs) = npcb;                                \ +    tcp_timer_needed();                            \ +  } while (0) + +#define TCP_RMV(pcbs, npcb)                        \ +  do {                                             \ +    if(*(pcbs) == npcb) {                          \ +      (*(pcbs)) = (*pcbs)->next;                   \ +    }                                              \ +    else {                                         \ +      for(tcp_tmp_pcb = *pcbs;                                         \ +          tcp_tmp_pcb != NULL;                                         \ +          tcp_tmp_pcb = tcp_tmp_pcb->next) {                           \ +        if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) {   \ +          tcp_tmp_pcb->next = npcb->next;          \ +          break;                                   \ +        }                                          \ +      }                                            \ +    }                                              \ +    npcb->next = NULL;                             \ +  } while(0) + +#endif /* LWIP_DEBUG */ + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcpip.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcpip.h new file mode 100644 index 000000000..75393ee91 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/tcpip.h @@ -0,0 +1,141 @@ +/* + * 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> + * + */ +#ifndef __LWIP_TCPIP_H__ +#define __LWIP_TCPIP_H__ + +#include "lwip/opt.h" + +#if !NO_SYS /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/api_msg.h" +#include "lwip/netifapi.h" +#include "lwip/pbuf.h" +#include "lwip/api.h" +#include "lwip/sys.h" +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if LWIP_TCPIP_CORE_LOCKING +/** The global semaphore to lock the stack. */ +extern sys_sem_t lock_tcpip_core; +#define LOCK_TCPIP_CORE()     sys_sem_wait(lock_tcpip_core) +#define UNLOCK_TCPIP_CORE()   sys_sem_signal(lock_tcpip_core) +#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m) +#define TCPIP_APIMSG_ACK(m) +#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m) +#define TCPIP_NETIFAPI_ACK(m) +#else +#define LOCK_TCPIP_CORE() +#define UNLOCK_TCPIP_CORE() +#define TCPIP_APIMSG(m)       tcpip_apimsg(m) +#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(m->conn->op_completed) +#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem) +#endif /* LWIP_TCPIP_CORE_LOCKING */ + +void tcpip_init(void (* tcpip_init_done)(void *), void *arg); + +#if LWIP_NETCONN +err_t tcpip_apimsg(struct api_msg *apimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_apimsg_lock(struct api_msg *apimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETCONN */ + +err_t tcpip_input(struct pbuf *p, struct netif *inp); + +#if LWIP_NETIF_API +err_t tcpip_netifapi(struct netifapi_msg *netifapimsg); +#if LWIP_TCPIP_CORE_LOCKING +err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); +#endif /* LWIP_TCPIP_CORE_LOCKING */ +#endif /* LWIP_NETIF_API */ + +err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block); +#define tcpip_callback(f, ctx)              tcpip_callback_with_block(f, ctx, 1) + +/* free pbufs or heap memory from another context without blocking */ +err_t pbuf_free_callback(struct pbuf *p); +err_t mem_free_callback(void *m); + +err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); +err_t tcpip_untimeout(sys_timeout_handler h, void *arg); + +enum tcpip_msg_type { +#if LWIP_NETCONN +  TCPIP_MSG_API, +#endif /* LWIP_NETCONN */ +  TCPIP_MSG_INPKT, +#if LWIP_NETIF_API +  TCPIP_MSG_NETIFAPI, +#endif /* LWIP_NETIF_API */ +  TCPIP_MSG_CALLBACK, +  TCPIP_MSG_TIMEOUT, +  TCPIP_MSG_UNTIMEOUT +}; + +struct tcpip_msg { +  enum tcpip_msg_type type; +  sys_sem_t *sem; +  union { +#if LWIP_NETCONN +    struct api_msg *apimsg; +#endif /* LWIP_NETCONN */ +#if LWIP_NETIF_API +    struct netifapi_msg *netifapimsg; +#endif /* LWIP_NETIF_API */ +    struct { +      struct pbuf *p; +      struct netif *netif; +    } inp; +    struct { +      void (*f)(void *ctx); +      void *ctx; +    } cb; +    struct { +      u32_t msecs; +      sys_timeout_handler h; +      void *arg; +    } tmo; +  } msg; +}; + +#ifdef __cplusplus +} +#endif + +#endif /* !NO_SYS */ + +#endif /* __LWIP_TCPIP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/udp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/udp.h new file mode 100644 index 000000000..d7b2a3820 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/lwip/udp.h @@ -0,0 +1,150 @@ +/* + * 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> + * + */ +#ifndef __LWIP_UDP_H__ +#define __LWIP_UDP_H__ + +#include "lwip/opt.h" + +#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/netif.h" +#include "lwip/ip_addr.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define UDP_HLEN 8 + +/* Fields are (of course) in network byte order. */ +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct udp_hdr { +  PACK_STRUCT_FIELD(u16_t src); +  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */ +  PACK_STRUCT_FIELD(u16_t len); +  PACK_STRUCT_FIELD(u16_t chksum); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE  0x02U +#define UDP_FLAGS_CONNECTED  0x04U + +struct udp_pcb { +/* Common members of all PCB types */ +  IP_PCB; + +/* Protocol specific PCB members */ + +  struct udp_pcb *next; + +  u8_t flags; +  /* ports are in host byte order */ +  u16_t local_port, remote_port; + +#if LWIP_IGMP +  /* outgoing network interface for multicast packets */ +  struct ip_addr multicast_ip; +#endif /* LWIP_IGMP */ + +#if LWIP_UDPLITE +  /* used for UDP_LITE only */ +  u16_t chksum_len_rx, chksum_len_tx; +#endif /* LWIP_UDPLITE */ + +  /* receive callback function +   * addr and port are in same byte order as in the pcb +   * The callback is responsible for freeing the pbuf +   * if it's not used any more. +   * +   * @param arg user supplied argument (udp_pcb.recv_arg) +   * @param pcb the udp_pcb which received data +   * @param p the packet buffer that was received +   * @param addr the remote IP address from which the packet was received +   * @param port the remote port from which the packet was received +   */ +  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p, +    struct ip_addr *addr, u16_t port); +  /* user-supplied argument for the recv callback */ +  void *recv_arg;   +}; +/* udp_pcbs export for exernal reference (e.g. SNMP agent) */ +extern struct udp_pcb *udp_pcbs; + +/* The following functions is the application layer interface to the +   UDP code. */ +struct udp_pcb * udp_new        (void); +void             udp_remove     (struct udp_pcb *pcb); +err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port); +err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr, +                 u16_t port); +void             udp_disconnect    (struct udp_pcb *pcb); +void             udp_recv       (struct udp_pcb *pcb, +         void (* recv)(void *arg, struct udp_pcb *upcb, +                 struct pbuf *p, +                 struct ip_addr *addr, +                 u16_t port), +         void *recv_arg); +err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif); +err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port); +err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p); + +#define          udp_flags(pcb)  ((pcb)->flags) +#define          udp_setflags(pcb, f)  ((pcb)->flags = (f)) + +/* The following functions are the lower layer interface to UDP. */ +void             udp_input      (struct pbuf *p, struct netif *inp); + +#define udp_init() /* Compatibility define, not init needed. */ + +#if UDP_DEBUG +void udp_debug_print(struct udp_hdr *udphdr); +#else +#define udp_debug_print(udphdr) +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_UDP */ + +#endif /* __LWIP_UDP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/etharp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/etharp.h new file mode 100644 index 000000000..db691d91d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/etharp.h @@ -0,0 +1,180 @@ +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2003-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 part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ + +#ifndef __NETIF_ETHARP_H__ +#define __NETIF_ETHARP_H__ + +#include "lwip/opt.h" + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/pbuf.h" +#include "lwip/ip_addr.h" +#include "lwip/netif.h" +#include "lwip/ip.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE          0 +#endif + +#ifndef ETHARP_HWADDR_LEN +#define ETHARP_HWADDR_LEN     6 +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_addr { +  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct eth_hdr { +#if ETH_PAD_SIZE +  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); +#endif +  PACK_STRUCT_FIELD(struct eth_addr dest); +  PACK_STRUCT_FIELD(struct eth_addr src); +  PACK_STRUCT_FIELD(u16_t type); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +/** the ARP message */ +struct etharp_hdr { +  PACK_STRUCT_FIELD(struct eth_hdr ethhdr); +  PACK_STRUCT_FIELD(u16_t hwtype); +  PACK_STRUCT_FIELD(u16_t proto); +  PACK_STRUCT_FIELD(u16_t _hwlen_protolen); +  PACK_STRUCT_FIELD(u16_t opcode); +  PACK_STRUCT_FIELD(struct eth_addr shwaddr); +  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); +  PACK_STRUCT_FIELD(struct eth_addr dhwaddr); +  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct ethip_hdr { +  PACK_STRUCT_FIELD(struct eth_hdr eth); +  PACK_STRUCT_FIELD(struct ip_hdr ip); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +/** 5 seconds period */ +#define ARP_TMR_INTERVAL 5000 + +#define ETHTYPE_ARP       0x0806 +#define ETHTYPE_IP        0x0800 +#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */ + +/** ARP message types (opcodes) */ +#define ARP_REQUEST 1 +#define ARP_REPLY   2 + +#if ARP_QUEUEING +/** struct for queueing outgoing packets for unknown address +  * defined here to be accessed by memp.h +  */ +struct etharp_q_entry { +  struct etharp_q_entry *next; +  struct pbuf *p; +}; +#endif /* ARP_QUEUEING */ + +#define etharp_init() /* Compatibility define, not init needed. */ +void etharp_tmr(void); +s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, +         struct eth_addr **eth_ret, struct ip_addr **ip_ret); +void etharp_ip_input(struct netif *netif, struct pbuf *p); +void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, +         struct pbuf *p); +err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr); +err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); +/** For Ethernet network interfaces, we might want to send "gratuitous ARP"; + *  this is an ARP packet sent by a node in order to spontaneously cause other + *  nodes to update an entry in their ARP cache. + *  From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ +#define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) + +err_t ethernet_input(struct pbuf *p, struct netif *netif); + +#if LWIP_AUTOIP +err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, +                 const struct eth_addr *ethdst_addr, +                 const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, +                 const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, +                 const u16_t opcode); +#endif /* LWIP_AUTOIP */ + +#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) + +extern const struct eth_addr ethbroadcast, ethzero; + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_ARP */ + +#endif /* __NETIF_ARP_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/loopif.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/loopif.h new file mode 100644 index 000000000..304af4b39 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/loopif.h @@ -0,0 +1,53 @@ +/* + * 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> + * + */ +#ifndef __NETIF_LOOPIF_H__ +#define __NETIF_LOOPIF_H__ + +#include "lwip/opt.h" +#include "lwip/netif.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#if !LWIP_NETIF_LOOPBACK_MULTITHREADING +#define loopif_poll netif_poll +#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ + +err_t loopif_init(struct netif *netif); + +#ifdef __cplusplus +} +#endif + +#endif /* __NETIF_LOOPIF_H__ */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h new file mode 100644 index 000000000..3aa55aec7 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/ppp_oe.h @@ -0,0 +1,161 @@ +/***************************************************************************** +* ppp_oe.h - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann <martin@NetBSD.org>. + * + * 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. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *        This product includes software developed by the NetBSD + *        Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION 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. + */ +#ifndef PPP_OE_H +#define PPP_OE_H + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT > 0 + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoehdr { +	PACK_STRUCT_FIELD(u8_t vertype); +	PACK_STRUCT_FIELD(u8_t code); +	PACK_STRUCT_FIELD(u16_t session); +	PACK_STRUCT_FIELD(u16_t plen); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct pppoetag { +	PACK_STRUCT_FIELD(u16_t tag); +	PACK_STRUCT_FIELD(u16_t len); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +#  include "arch/epstruct.h" +#endif + + +#define PPPOE_STATE_INITIAL	0 +#define PPPOE_STATE_PADI_SENT	1 +#define	PPPOE_STATE_PADR_SENT	2 +#define	PPPOE_STATE_SESSION	3 +#define	PPPOE_STATE_CLOSING	4 +/* passive */ +#define	PPPOE_STATE_PADO_SENT	1 + +#define PPPOE_HEADERLEN	sizeof(struct pppoehdr) +#define	PPPOE_VERTYPE	0x11	/* VER=1, TYPE = 1 */ + +#define	PPPOE_TAG_EOL		0x0000		/* end of list */ +#define	PPPOE_TAG_SNAME		0x0101		/* service name */ +#define	PPPOE_TAG_ACNAME	0x0102		/* access concentrator name */ +#define	PPPOE_TAG_HUNIQUE	0x0103		/* host unique */ +#define	PPPOE_TAG_ACCOOKIE	0x0104		/* AC cookie */ +#define	PPPOE_TAG_VENDOR	0x0105		/* vendor specific */ +#define	PPPOE_TAG_RELAYSID	0x0110		/* relay session id */ +#define	PPPOE_TAG_SNAME_ERR	0x0201		/* service name error */ +#define	PPPOE_TAG_ACSYS_ERR	0x0202		/* AC system error */ +#define	PPPOE_TAG_GENERIC_ERR	0x0203		/* gerneric error */ + +#define PPPOE_CODE_PADI		0x09		/* Active Discovery Initiation */ +#define	PPPOE_CODE_PADO		0x07		/* Active Discovery Offer */ +#define	PPPOE_CODE_PADR		0x19		/* Active Discovery Request */ +#define	PPPOE_CODE_PADS		0x65		/* Active Discovery Session confirmation */ +#define	PPPOE_CODE_PADT		0xA7		/* Active Discovery Terminate */ + +#ifndef ETHERMTU +#define ETHERMTU 1500 +#endif + +/* two byte PPP protocol discriminator, then IP data */ +#define	PPPOE_MAXMTU	(ETHERMTU-PPPOE_HEADERLEN-2) + +struct pppoe_softc; + + +void pppoe_init(void); + +err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); +err_t pppoe_destroy(struct netif *ifp); + +int pppoe_connect(struct pppoe_softc *sc); +void pppoe_disconnect(struct pppoe_softc *sc); + +void pppoe_disc_input(struct netif *netif, struct pbuf *p); +void pppoe_data_input(struct netif *netif, struct pbuf *p); + +err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); + +extern int pppoe_hdrlen; + +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_OE_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/slipif.h b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/slipif.h new file mode 100644 index 000000000..aa08ada4a --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/include/netif/slipif.h @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2001, 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. Neither the name of the Institute 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 THE INSTITUTE 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 THE INSTITUTE 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 part of the lwIP TCP/IP stack. + *  + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __NETIF_SLIPIF_H__ +#define __NETIF_SLIPIF_H__ + +#include "lwip/netif.h" + +#ifdef __cplusplus +extern "C" { +#endif + +err_t slipif_init(struct netif * netif); + +#ifdef __cplusplus +} +#endif +  +#endif  + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/FILES b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/FILES new file mode 100644 index 000000000..1c4f5928d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/FILES @@ -0,0 +1,25 @@ +This directory contains generic network interface device drivers that +do not contain any hardware or architecture specific code. The files +are: + +etharp.c +          Implements the ARP (Address Resolution Protocol) over +          Ethernet. The code in this file should be used together with +          Ethernet device drivers. Note that this module has been +          largely made Ethernet independent so you should be able to +          adapt this for other link layers (such as Firewire). + +ethernetif.c +          An example of how an Ethernet device driver could look. This +          file can be used as a "skeleton" for developing new Ethernet +          network device drivers. It uses the etharp.c ARP code. + +loopif.c +          A "loopback" network interface driver. It requires configuration +          through the define LWIP_LOOPIF_MULTITHREADING (see opt.h). + +slipif.c +          A generic implementation of the SLIP (Serial Line IP) +          protocol. It requires a sio (serial I/O) module to work. + +ppp/      Point-to-Point Protocol stack diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/etharp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/etharp.c new file mode 100644 index 000000000..73ea21173 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/etharp.c @@ -0,0 +1,1185 @@ +/** + * @file + * Address Resolution Protocol module for IP over Ethernet + * + * Functionally, ARP is divided into two parts. The first maps an IP address + * to a physical address when sending a packet, and the second part answers + * requests from other machines for our physical address. + * + * This implementation complies with RFC 826 (Ethernet ARP). It supports + * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6 + * if an interface calls etharp_gratuitous(our_netif) upon address change. + */ + +/* + * Copyright (c) 2001-2003 Swedish Institute of Computer Science. + * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv> + * Copyright (c) 2003-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 part of the lwIP TCP/IP stack. + * + */ +  +#include "lwip/opt.h" + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/inet.h" +#include "lwip/ip.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "netif/etharp.h" + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include <string.h> + +/** the time an ARP entry stays valid after its last update, + *  for ARP_TMR_INTERVAL = 5000, this is + *  (240 * 5) seconds = 20 minutes. + */ +#define ARP_MAXAGE 240 +/** the time an ARP entry stays pending after first request, + *  for ARP_TMR_INTERVAL = 5000, this is + *  (2 * 5) seconds = 10 seconds. + *  + *  @internal Keep this number at least 2, otherwise it might + *  run out instantly if the timeout occurs directly after a request. + */ +#define ARP_MAXPENDING 2 + +#define HWTYPE_ETHERNET 1 + +#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) +#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) + +#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8)) +#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8)) + +enum etharp_state { +  ETHARP_STATE_EMPTY = 0, +  ETHARP_STATE_PENDING, +  ETHARP_STATE_STABLE +}; + +struct etharp_entry { +#if ARP_QUEUEING +  /**  +   * Pointer to queue of pending outgoing packets on this ARP entry. +   */ +  struct etharp_q_entry *q; +#endif +  struct ip_addr ipaddr; +  struct eth_addr ethaddr; +  enum etharp_state state; +  u8_t ctime; +  struct netif *netif; +}; + +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +const struct eth_addr ethzero = {{0,0,0,0,0,0}}; +static struct etharp_entry arp_table[ARP_TABLE_SIZE]; +#if !LWIP_NETIF_HWADDRHINT +static u8_t etharp_cached_entry; +#endif + +/** + * Try hard to create a new entry - we want the IP address to appear in + * the cache (even if this means removing an active entry or so). */ +#define ETHARP_TRY_HARD 1 +#define ETHARP_FIND_ONLY  2 + +#if LWIP_NETIF_HWADDRHINT +#define NETIF_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \ +                                      *((netif)->addr_hint) = (hint); +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif); +#else /* LWIP_NETIF_HWADDRHINT */ +static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags); +#endif /* LWIP_NETIF_HWADDRHINT */ + +static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); + + +/* Some checks, instead of etharp_init(): */ +#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) +  #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" +#endif + + +#if ARP_QUEUEING +/** + * Free a complete queue of etharp entries + * + * @param q a qeueue of etharp_q_entry's to free + */ +static void +free_etharp_q(struct etharp_q_entry *q) +{ +  struct etharp_q_entry *r; +  LWIP_ASSERT("q != NULL", q != NULL); +  LWIP_ASSERT("q->p != NULL", q->p != NULL); +  while (q) { +    r = q; +    q = q->next; +    LWIP_ASSERT("r->p != NULL", (r->p != NULL)); +    pbuf_free(r->p); +    memp_free(MEMP_ARP_QUEUE, r); +  } +} +#endif + +/** + * Clears expired entries in the ARP table. + * + * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds), + * in order to expire entries in the ARP table. + */ +void +etharp_tmr(void) +{ +  u8_t i; + +  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); +  /* remove expired entries from the ARP table */ +  for (i = 0; i < ARP_TABLE_SIZE; ++i) { +    arp_table[i].ctime++; +    if (((arp_table[i].state == ETHARP_STATE_STABLE) && +         (arp_table[i].ctime >= ARP_MAXAGE)) || +        ((arp_table[i].state == ETHARP_STATE_PENDING)  && +         (arp_table[i].ctime >= ARP_MAXPENDING))) { +         /* pending or stable entry has become old! */ +      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", +           arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); +      /* clean up entries that have just been expired */ +      /* remove from SNMP ARP index tree */ +      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); +#if ARP_QUEUEING +      /* and empty packet queue */ +      if (arp_table[i].q != NULL) { +        /* remove all queued packets */ +        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); +        free_etharp_q(arp_table[i].q); +        arp_table[i].q = NULL; +      } +#endif +      /* recycle entry for re-use */       +      arp_table[i].state = ETHARP_STATE_EMPTY; +    } +#if ARP_QUEUEING +    /* still pending entry? (not expired) */ +    if (arp_table[i].state == ETHARP_STATE_PENDING) { +        /* resend an ARP query here? */ +    } +#endif +  } +} + +/** + * Search the ARP table for a matching or new entry. + *  + * If an IP address is given, return a pending or stable ARP entry that matches + * the address. If no match is found, create a new entry with this address set, + * but in state ETHARP_EMPTY. The caller must check and possibly change the + * state of the returned entry. + *  + * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. + *  + * In all cases, attempt to create new entries from an empty entry. If no + * empty entries are available and ETHARP_TRY_HARD flag is set, recycle + * old entries. Heuristic choose the least important entry for recycling. + * + * @param ipaddr IP address to find in ARP cache, or to add if not found. + * @param flags + * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of + * active (stable or pending) entries. + *   + * @return The ARP entry index that matched or is created, ERR_MEM if no + * entry is found or could be recycled. + */ +static s8_t +#if LWIP_NETIF_HWADDRHINT +find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif) +#else /* LWIP_NETIF_HWADDRHINT */ +find_entry(struct ip_addr *ipaddr, u8_t flags) +#endif /* LWIP_NETIF_HWADDRHINT */ +{ +  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; +  s8_t empty = ARP_TABLE_SIZE; +  u8_t i = 0, age_pending = 0, age_stable = 0; +#if ARP_QUEUEING +  /* oldest entry with packets on queue */ +  s8_t old_queue = ARP_TABLE_SIZE; +  /* its age */ +  u8_t age_queue = 0; +#endif + +  /* First, test if the last call to this function asked for the +   * same address. If so, we're really fast! */ +  if (ipaddr) { +    /* ipaddr to search for was given */ +#if LWIP_NETIF_HWADDRHINT +    if ((netif != NULL) && (netif->addr_hint != NULL)) { +      /* per-pcb cached entry was given */ +      u8_t per_pcb_cache = *(netif->addr_hint); +      if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) { +        /* the per-pcb-cached entry is stable */ +        if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) { +          /* per-pcb cached entry was the right one! */ +          ETHARP_STATS_INC(etharp.cachehit); +          return per_pcb_cache; +        } +      } +    } +#else /* #if LWIP_NETIF_HWADDRHINT */ +    if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) { +      /* the cached entry is stable */ +      if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) { +        /* cached entry was the right one! */ +        ETHARP_STATS_INC(etharp.cachehit); +        return etharp_cached_entry; +      } +    } +#endif /* #if LWIP_NETIF_HWADDRHINT */ +  } + +  /** +   * a) do a search through the cache, remember candidates +   * b) select candidate entry +   * c) create new entry +   */ + +  /* a) in a single search sweep, do all of this +   * 1) remember the first empty entry (if any) +   * 2) remember the oldest stable entry (if any) +   * 3) remember the oldest pending entry without queued packets (if any) +   * 4) remember the oldest pending entry with queued packets (if any) +   * 5) search for a matching IP entry, either pending or stable +   *    until 5 matches, or all entries are searched for. +   */ + +  for (i = 0; i < ARP_TABLE_SIZE; ++i) { +    /* no empty entry found yet and now we do find one? */ +    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) { +      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); +      /* remember first empty entry */ +      empty = i; +    } +    /* pending entry? */ +    else if (arp_table[i].state == ETHARP_STATE_PENDING) { +      /* if given, does IP address match IP address in ARP entry? */ +      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); +        /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT +        NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +        etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +        return i; +#if ARP_QUEUEING +      /* pending with queued packets? */ +      } else if (arp_table[i].q != NULL) { +        if (arp_table[i].ctime >= age_queue) { +          old_queue = i; +          age_queue = arp_table[i].ctime; +        } +#endif +      /* pending without queued packets? */ +      } else { +        if (arp_table[i].ctime >= age_pending) { +          old_pending = i; +          age_pending = arp_table[i].ctime; +        } +      }         +    } +    /* stable entry? */ +    else if (arp_table[i].state == ETHARP_STATE_STABLE) { +      /* if given, does IP address match IP address in ARP entry? */ +      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); +        /* found exact IP address match, simply bail out */ +#if LWIP_NETIF_HWADDRHINT +        NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +        etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +        return i; +      /* remember entry with oldest stable entry in oldest, its age in maxtime */ +      } else if (arp_table[i].ctime >= age_stable) { +        old_stable = i; +        age_stable = arp_table[i].ctime; +      } +    } +  } +  /* { we have no match } => try to create a new entry */ +    +  /* no empty entry found and not allowed to recycle? */ +  if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0)) +      /* or don't create new entry, only search? */ +      || ((flags & ETHARP_FIND_ONLY) != 0)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); +    return (s8_t)ERR_MEM; +  } +   +  /* b) choose the least destructive entry to recycle: +   * 1) empty entry +   * 2) oldest stable entry +   * 3) oldest pending entry without queued packets +   * 4) oldest pending entry with queued packets +   *  +   * { ETHARP_TRY_HARD is set at this point } +   */  + +  /* 1) empty entry available? */ +  if (empty < ARP_TABLE_SIZE) { +    i = empty; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); +  } +  /* 2) found recyclable stable entry? */ +  else if (old_stable < ARP_TABLE_SIZE) { +    /* recycle oldest stable*/ +    i = old_stable; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); +#if ARP_QUEUEING +    /* no queued packets should exist on stable entries */ +    LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); +#endif +  /* 3) found recyclable pending entry without queued packets? */ +  } else if (old_pending < ARP_TABLE_SIZE) { +    /* recycle oldest pending */ +    i = old_pending; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); +#if ARP_QUEUEING +  /* 4) found recyclable pending entry with queued packets? */ +  } else if (old_queue < ARP_TABLE_SIZE) { +    /* recycle oldest pending */ +    i = old_queue; +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); +    free_etharp_q(arp_table[i].q); +    arp_table[i].q = NULL; +#endif +    /* no empty or recyclable entries found */ +  } else { +    return (s8_t)ERR_MEM; +  } + +  /* { empty or recyclable entry found } */ +  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + +  if (arp_table[i].state != ETHARP_STATE_EMPTY) +  { +    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); +  } +  /* recycle entry (no-op for an already empty entry) */ +  arp_table[i].state = ETHARP_STATE_EMPTY; + +  /* IP address given? */ +  if (ipaddr != NULL) { +    /* set IP address */ +    ip_addr_set(&arp_table[i].ipaddr, ipaddr); +  } +  arp_table[i].ctime = 0; +#if LWIP_NETIF_HWADDRHINT +  NETIF_SET_HINT(netif, i); +#else /* #if LWIP_NETIF_HWADDRHINT */ +  etharp_cached_entry = i; +#endif /* #if LWIP_NETIF_HWADDRHINT */ +  return (err_t)i; +} + +/** + * Send an IP packet on the network using netif->linkoutput + * The ethernet header is filled in before sending. + * + * @params netif the lwIP network interface on which to send the packet + * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header + * @params src the source MAC address to be copied into the ethernet header + * @params dst the destination MAC address to be copied into the ethernet header + * @return ERR_OK if the packet was sent, any other err_t on failure + */ +static err_t +etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) +{ +  struct eth_hdr *ethhdr = p->payload; +  u8_t k; + +  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +              (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +  k = ETHARP_HWADDR_LEN; +  while(k > 0) { +    k--; +    ethhdr->dest.addr[k] = dst->addr[k]; +    ethhdr->src.addr[k]  = src->addr[k]; +  } +  ethhdr->type = htons(ETHTYPE_IP); +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); +  /* send the packet */ +  return netif->linkoutput(netif, p); +} + +/** + * Update (or insert) a IP/MAC address pair in the ARP cache. + * + * If a pending entry is resolved, any queued packets will be sent + * at this point. + *  + * @param ipaddr IP address of the inserted ARP entry. + * @param ethaddr Ethernet address of the inserted ARP entry. + * @param flags Defines behaviour: + * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified, + * only existing ARP entries will be updated. + * + * @return + * - ERR_OK Succesfully updated ARP cache. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set. + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + * @see pbuf_free() + */ +static err_t +update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) +{ +  s8_t i; +  u8_t k; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n")); +  LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", +                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),  +                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], +                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); +  /* non-unicast address? */ +  if (ip_addr_isany(ipaddr) || +      ip_addr_isbroadcast(ipaddr, netif) || +      ip_addr_ismulticast(ipaddr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n")); +    return ERR_ARG; +  } +  /* find or create ARP entry */ +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, flags, netif); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, flags); +#endif /* LWIP_NETIF_HWADDRHINT */ +  /* bail out if no entry could be found */ +  if (i < 0) +    return (err_t)i; +   +  /* mark it stable */ +  arp_table[i].state = ETHARP_STATE_STABLE; +  /* record network interface */ +  arp_table[i].netif = netif; + +  /* insert in SNMP ARP index tree */ +  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); + +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); +  /* update address */ +  k = ETHARP_HWADDR_LEN; +  while (k > 0) { +    k--; +    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; +  } +  /* reset time stamp */ +  arp_table[i].ctime = 0; +#if ARP_QUEUEING +  /* this is where we will send out queued packets! */ +  while (arp_table[i].q != NULL) { +    struct pbuf *p; +    /* remember remainder of queue */ +    struct etharp_q_entry *q = arp_table[i].q; +    /* pop first item off the queue */ +    arp_table[i].q = q->next; +    /* get the packet pointer */ +    p = q->p; +    /* now queue entry can be freed */ +    memp_free(MEMP_ARP_QUEUE, q); +    /* send the queued IP packet */ +    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); +    /* free the queued IP packet */ +    pbuf_free(p); +  } +#endif +  return ERR_OK; +} + +/** + * Finds (stable) ethernet/IP address pair from ARP table + * using interface and IP address index. + * @note the addresses in the ARP table are in network order! + * + * @param netif points to interface index + * @param ipaddr points to the (network order) IP address index + * @param eth_ret points to return pointer + * @param ip_ret points to return pointer + * @return table index if found, -1 otherwise + */ +s8_t +etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, +         struct eth_addr **eth_ret, struct ip_addr **ip_ret) +{ +  s8_t i; + +  LWIP_UNUSED_ARG(netif); + +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, ETHARP_FIND_ONLY); +#endif /* LWIP_NETIF_HWADDRHINT */ +  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { +      *eth_ret = &arp_table[i].ethaddr; +      *ip_ret = &arp_table[i].ipaddr; +      return i; +  } +  return -1; +} + +/** + * Updates the ARP table using the given IP packet. + * + * Uses the incoming IP packet's source address to update the + * ARP cache for the local network. The function does not alter + * or free the packet. This function must be called before the + * packet p is passed to the IP layer. + * + * @param netif The lwIP network interface on which the IP packet pbuf arrived. + * @param p The IP packet that arrived on netif. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_ip_input(struct netif *netif, struct pbuf *p) +{ +  struct ethip_hdr *hdr; +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +  /* Only insert an entry if the source IP address of the +     incoming IP packet comes from a host on the local network. */ +  hdr = p->payload; +  /* source is not on the local network? */ +  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) { +    /* do nothing */ +    return; +  } + +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); +  /* update ARP table */ +  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk +   * back soon (for example, if the destination IP address is ours. */ +  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0); +} + + +/** + * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache   + * send out queued IP packets. Updates cache with snooped address pairs. + * + * Should be called for incoming ARP packets. The pbuf in the argument + * is freed by this function. + * + * @param netif The lwIP network interface on which the ARP packet pbuf arrived. + * @param ethaddr Ethernet address of netif. + * @param p The ARP packet that arrived on netif. Is freed by this function. + * + * @return NULL + * + * @see pbuf_free() + */ +void +etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) +{ +  struct etharp_hdr *hdr; +  /* these are aligned properly, whereas the ARP header fields might not be */ +  struct ip_addr sipaddr, dipaddr; +  u8_t i; +  u8_t for_us; +#if LWIP_AUTOIP +  const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + +  LWIP_ERROR("netif != NULL", (netif != NULL), return;); +   +  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here +     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ +  if (p->len < sizeof(struct etharp_hdr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, ("etharp_arp_input: packet dropped, too short (%"S16_F"/%"S16_F")\n", p->tot_len, (s16_t)sizeof(struct etharp_hdr))); +    ETHARP_STATS_INC(etharp.lenerr); +    ETHARP_STATS_INC(etharp.drop); +    pbuf_free(p); +    return; +  } + +  hdr = p->payload; + +  /* RFC 826 "Packet Reception": */ +  if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) || +      (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) || +      (hdr->proto != htons(ETHTYPE_IP)) || +      (hdr->ethhdr.type != htons(ETHTYPE_ARP)))  { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1, +      ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", +      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type)); +    ETHARP_STATS_INC(etharp.proterr); +    ETHARP_STATS_INC(etharp.drop); +    pbuf_free(p); +    return; +  } +  ETHARP_STATS_INC(etharp.recv); + +#if LWIP_AUTOIP +  /* We have to check if a host already has configured our random +   * created link local address and continously check if there is +   * a host with this IP-address so we can detect collisions */ +  autoip_arp_reply(netif, hdr); +#endif /* LWIP_AUTOIP */ + +  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without +   * structure packing (not using structure copy which breaks strict-aliasing rules). */ +  SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); +  SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + +  /* this interface is not configured? */ +  if (netif->ip_addr.addr == 0) { +    for_us = 0; +  } else { +    /* ARP packet directed to us? */ +    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr)); +  } + +  /* ARP message directed to us? */ +  if (for_us) { +    /* add IP address in ARP cache; assume requester wants to talk to us. +     * can result in directly sending the queued packets for this host. */ +    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD); +  /* ARP message not directed to us? */ +  } else { +    /* update the source IP address in the cache, if present */ +    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0); +  } + +  /* now act on the message itself */ +  switch (htons(hdr->opcode)) { +  /* ARP request? */ +  case ARP_REQUEST: +    /* ARP request. If it asked for our address, we send out a +     * reply. In any case, we time-stamp any existing ARP entry, +     * and possiby send out an IP packet that was queued on it. */ + +    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n")); +    /* ARP request for our address? */ +    if (for_us) { + +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n")); +      /* Re-use pbuf to send ARP reply. +         Since we are re-using an existing pbuf, we can't call etharp_raw since +         that would allocate a new pbuf. */ +      hdr->opcode = htons(ARP_REPLY); + +      hdr->dipaddr = hdr->sipaddr; +      SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr)); + +      LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +                  (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +      i = ETHARP_HWADDR_LEN; +#if LWIP_AUTOIP +      /* If we are using Link-Local, ARP packets must be broadcast on the +       * link layer. (See RFC3927 Section 2.5) */ +      ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; +#endif /* LWIP_AUTOIP */ + +      while(i > 0) { +        i--; +        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; +#if LWIP_AUTOIP +        hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i]; +#else  /* LWIP_AUTOIP */ +        hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i]; +#endif /* LWIP_AUTOIP */ +        hdr->shwaddr.addr[i] = ethaddr->addr[i]; +        hdr->ethhdr.src.addr[i] = ethaddr->addr[i]; +      } + +      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header +         are already correct, we tested that before */ + +      /* return ARP reply */ +      netif->linkoutput(netif, p); +    /* we are not configured? */ +    } else if (netif->ip_addr.addr == 0) { +      /* { for_us == 0 and netif->ip_addr.addr == 0 } */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); +    /* request was not directed to us */ +    } else { +      /* { for_us == 0 and netif->ip_addr.addr != 0 } */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); +    } +    break; +  case ARP_REPLY: +    /* ARP reply. We already updated the ARP cache earlier. */ +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); +#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) +    /* DHCP wants to know about ARP replies from any host with an +     * IP address also offered to us by the DHCP server. We do not +     * want to take a duplicate IP address on a single network. +     * @todo How should we handle redundant (fail-over) interfaces? */ +    dhcp_arp_reply(netif, &sipaddr); +#endif +    break; +  default: +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); +    ETHARP_STATS_INC(etharp.err); +    break; +  } +  /* free ARP packet */ +  pbuf_free(p); +} + +/** + * Resolve and fill-in Ethernet address header for outgoing IP packet. + * + * For IP multicast and broadcast, corresponding Ethernet addresses + * are selected and the packet is transmitted on the link. + * + * For unicast addresses, the packet is submitted to etharp_query(). In + * case the IP address is outside the local network, the IP address of + * the gateway is used. + * + * @param netif The lwIP network interface which the IP packet will be sent on. + * @param q The pbuf(s) containing the IP packet to be sent. + * @param ipaddr The IP address of the packet destination. + * + * @return + * - ERR_RTE No route to destination (no gateway to external networks), + * or the return type of either etharp_query() or etharp_send_ip(). + */ +err_t +etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) +{ +  struct eth_addr *dest, mcastaddr; + +  /* make room for Ethernet header - should not fail */ +  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) { +    /* bail out */ +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n")); +    LINK_STATS_INC(link.lenerr); +    return ERR_BUF; +  } + +  /* assume unresolved Ethernet address */ +  dest = NULL; +  /* Determine on destination hardware address. Broadcasts and multicasts +   * are special, other IP addresses are looked up in the ARP table. */ + +  /* broadcast destination IP address? */ +  if (ip_addr_isbroadcast(ipaddr, netif)) { +    /* broadcast on Ethernet also */ +    dest = (struct eth_addr *)ðbroadcast; +  /* multicast destination IP address? */ +  } else if (ip_addr_ismulticast(ipaddr)) { +    /* Hash IP multicast address to MAC address.*/ +    mcastaddr.addr[0] = 0x01; +    mcastaddr.addr[1] = 0x00; +    mcastaddr.addr[2] = 0x5e; +    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f; +    mcastaddr.addr[4] = ip4_addr3(ipaddr); +    mcastaddr.addr[5] = ip4_addr4(ipaddr); +    /* destination Ethernet address is multicast */ +    dest = &mcastaddr; +  /* unicast destination IP address? */ +  } else { +    /* outside local network? */ +    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { +      /* interface has default gateway? */ +      if (netif->gw.addr != 0) { +        /* send to hardware address of default gateway IP address */ +        ipaddr = &(netif->gw); +      /* no default gateway available */ +      } else { +        /* no route to destination error (default gateway missing) */ +        return ERR_RTE; +      } +    } +    /* queue on destination Ethernet address belonging to ipaddr */ +    return etharp_query(netif, ipaddr, q); +  } + +  /* continuation for multicast/broadcast destinations */ +  /* obtain source Ethernet address of the given interface */ +  /* send packet directly on the link */ +  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest); +} + +/** + * Send an ARP request for the given IP address and/or queue a packet. + * + * If the IP address was not yet in the cache, a pending ARP cache entry + * is added and an ARP request is sent for the given address. The packet + * is queued on this entry. + * + * If the IP address was already pending in the cache, a new ARP request + * is sent for the given address. The packet is queued on this entry. + * + * If the IP address was already stable in the cache, and a packet is + * given, it is directly sent and no ARP request is sent out.  + *  + * If the IP address was already stable in the cache, and no packet is + * given, an ARP request is sent out. + *  + * @param netif The lwIP network interface on which ipaddr + * must be queried for. + * @param ipaddr The IP address to be resolved. + * @param q If non-NULL, a pbuf that must be delivered to the IP address. + * q is not freed by this function. + * + * @note q must only be ONE packet, not a packet queue! + * + * @return + * - ERR_BUF Could not make room for Ethernet header. + * - ERR_MEM Hardware address unknown, and no more ARP entries available + *   to query for address or queue the packet. + * - ERR_MEM Could not queue packet due to memory shortage. + * - ERR_RTE No route to destination (no gateway to external networks). + * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. + * + */ +err_t +etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +{ +  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; +  err_t result = ERR_MEM; +  s8_t i; /* ARP entry index */ + +  /* non-unicast address? */ +  if (ip_addr_isbroadcast(ipaddr, netif) || +      ip_addr_ismulticast(ipaddr) || +      ip_addr_isany(ipaddr)) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n")); +    return ERR_ARG; +  } + +  /* find entry in ARP cache, ask to create entry if queueing packet */ +#if LWIP_NETIF_HWADDRHINT +  i = find_entry(ipaddr, ETHARP_TRY_HARD, netif); +#else /* LWIP_NETIF_HWADDRHINT */ +  i = find_entry(ipaddr, ETHARP_TRY_HARD); +#endif /* LWIP_NETIF_HWADDRHINT */ + +  /* could not find or create entry? */ +  if (i < 0) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n")); +    if (q) { +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n")); +      ETHARP_STATS_INC(etharp.memerr); +    } +    return (err_t)i; +  } + +  /* mark a fresh entry as pending (we just sent a request) */ +  if (arp_table[i].state == ETHARP_STATE_EMPTY) { +    arp_table[i].state = ETHARP_STATE_PENDING; +  } + +  /* { i is either a STABLE or (new or existing) PENDING entry } */ +  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE", +  ((arp_table[i].state == ETHARP_STATE_PENDING) || +   (arp_table[i].state == ETHARP_STATE_STABLE))); + +  /* do we have a pending entry? or an implicit query request? */ +  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) { +    /* try to resolve it; send out ARP request */ +    result = etharp_request(netif, ipaddr); +    if (result != ERR_OK) { +      /* ARP request couldn't be sent */ +      /* We don't re-send arp request in etharp_tmr, but we still queue packets, +         since this failure could be temporary, and the next packet calling +         etharp_query again could lead to sending the queued packets. */ +    } +  } +   +  /* packet given? */ +  if (q != NULL) { +    /* stable entry? */ +    if (arp_table[i].state == ETHARP_STATE_STABLE) { +      /* we have a valid IP->Ethernet address mapping */ +      /* send the packet */ +      result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); +    /* pending entry? (either just created or already pending */ +    } else if (arp_table[i].state == ETHARP_STATE_PENDING) { +#if ARP_QUEUEING /* queue the given q packet */ +      struct pbuf *p; +      int copy_needed = 0; +      /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but +       * to copy the whole queue into a new PBUF_RAM (see bug #11400)  +       * PBUF_ROMs can be left as they are, since ROM must not get changed. */ +      p = q; +      while (p) { +        LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); +        if(p->type != PBUF_ROM) { +          copy_needed = 1; +          break; +        } +        p = p->next; +      } +      if(copy_needed) { +        /* copy the whole packet into new pbufs */ +        p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +        if(p != NULL) { +          if (pbuf_copy(p, q) != ERR_OK) { +            pbuf_free(p); +            p = NULL; +          } +        } +      } else { +        /* referencing the old pbuf is enough */ +        p = q; +        pbuf_ref(p); +      } +      /* packet could be taken over? */ +      if (p != NULL) { +        /* queue packet ... */ +        struct etharp_q_entry *new_entry; +        /* allocate a new arp queue entry */ +        new_entry = memp_malloc(MEMP_ARP_QUEUE); +        if (new_entry != NULL) { +          new_entry->next = 0; +          new_entry->p = p; +          if(arp_table[i].q != NULL) { +            /* queue was already existent, append the new entry to the end */ +            struct etharp_q_entry *r; +            r = arp_table[i].q; +            while (r->next != NULL) { +              r = r->next; +            } +            r->next = new_entry; +          } else { +            /* queue did not exist, first item in queue */ +            arp_table[i].q = new_entry; +          } +          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +          result = ERR_OK; +        } else { +          /* the pool MEMP_ARP_QUEUE is empty */ +          pbuf_free(p); +          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); +          /* { result == ERR_MEM } through initialization */ +        } +      } else { +        ETHARP_STATS_INC(etharp.memerr); +        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); +        /* { result == ERR_MEM } through initialization */ +      } +#else /* ARP_QUEUEING == 0 */ +      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ +      /* { result == ERR_MEM } through initialization */ +      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); +#endif +    } +  } +  return result; +} + +/** + * Send a raw ARP packet (opcode and all addresses can be modified) + * + * @param netif the lwip network interface on which to send the ARP packet + * @param ethsrc_addr the source MAC address for the ethernet header + * @param ethdst_addr the destination MAC address for the ethernet header + * @param hwsrc_addr the source MAC address for the ARP protocol header + * @param ipsrc_addr the source IP address for the ARP protocol header + * @param hwdst_addr the destination MAC address for the ARP protocol header + * @param ipdst_addr the destination IP address for the ARP protocol header + * @param opcode the type of the ARP packet + * @return ERR_OK if the ARP packet has been sent + *         ERR_MEM if the ARP packet couldn't be allocated + *         any other err_t on failure + */ +#if !LWIP_AUTOIP +static +#endif /* LWIP_AUTOIP */ +err_t +etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, +           const struct eth_addr *ethdst_addr, +           const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, +           const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, +           const u16_t opcode) +{ +  struct pbuf *p; +  err_t result = ERR_OK; +  u8_t k; /* ARP entry index */ +  struct etharp_hdr *hdr; +#if LWIP_AUTOIP +  const u8_t * ethdst_hwaddr; +#endif /* LWIP_AUTOIP */ + +  /* allocate a pbuf for the outgoing ARP request packet */ +  p = pbuf_alloc(PBUF_RAW, sizeof(struct etharp_hdr), PBUF_RAM); +  /* could allocate a pbuf for an ARP request? */ +  if (p == NULL) { +    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n")); +    ETHARP_STATS_INC(etharp.memerr); +    return ERR_MEM; +  } +  LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", +              (p->len >= sizeof(struct etharp_hdr))); + +  hdr = p->payload; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); +  hdr->opcode = htons(opcode); + +  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", +              (netif->hwaddr_len == ETHARP_HWADDR_LEN)); +  k = ETHARP_HWADDR_LEN; +#if LWIP_AUTOIP +  /* If we are using Link-Local, ARP packets must be broadcast on the +   * link layer. (See RFC3927 Section 2.5) */ +  ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; +#endif /* LWIP_AUTOIP */ +  /* Write MAC-Addresses (combined loop for both headers) */ +  while(k > 0) { +    k--; +    /* Write the ARP MAC-Addresses */ +    hdr->shwaddr.addr[k] = hwsrc_addr->addr[k]; +    hdr->dhwaddr.addr[k] = hwdst_addr->addr[k]; +    /* Write the Ethernet MAC-Addresses */ +#if LWIP_AUTOIP +    hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k]; +#else  /* LWIP_AUTOIP */ +    hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k]; +#endif /* LWIP_AUTOIP */ +    hdr->ethhdr.src.addr[k]  = ethsrc_addr->addr[k]; +  } +  hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr; +  hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr; + +  hdr->hwtype = htons(HWTYPE_ETHERNET); +  hdr->proto = htons(ETHTYPE_IP); +  /* set hwlen and protolen together */ +  hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr)); + +  hdr->ethhdr.type = htons(ETHTYPE_ARP); +  /* send ARP query */ +  result = netif->linkoutput(netif, p); +  ETHARP_STATS_INC(etharp.xmit); +  /* free ARP query packet */ +  pbuf_free(p); +  p = NULL; +  /* could not allocate pbuf for ARP request */ + +  return result; +} + +/** + * Send an ARP request packet asking for ipaddr. + * + * @param netif the lwip network interface on which to send the request + * @param ipaddr the IP address for which to ask + * @return ERR_OK if the request has been sent + *         ERR_MEM if the ARP packet couldn't be allocated + *         any other err_t on failure + */ +err_t +etharp_request(struct netif *netif, struct ip_addr *ipaddr) +{ +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); +  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, +                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, +                    ipaddr, ARP_REQUEST); +} + +/** + * Process received ethernet frames. Using this function instead of directly + * calling ip_input and passing ARP frames through etharp in ethernetif_input, + * the ARP cache is protected from concurrent access. + * + * @param p the recevied packet, p->payload pointing to the ethernet header + * @param netif the network interface on which the packet was received + */ +err_t +ethernet_input(struct pbuf *p, struct netif *netif) +{ +  struct eth_hdr* ethhdr; + +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; +  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, +    ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n", +     (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], +     (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], +     (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], +     (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], +     (unsigned)htons(ethhdr->type))); + +  switch (htons(ethhdr->type)) { +    /* IP packet? */ +    case ETHTYPE_IP: +#if ETHARP_TRUST_IP_MAC +      /* update ARP table */ +      etharp_ip_input(netif, p); +#endif /* ETHARP_TRUST_IP_MAC */ +      /* skip Ethernet header */ +      if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) { +        LWIP_ASSERT("Can't move over header in packet", 0); +        pbuf_free(p); +        p = NULL; +      } else { +        /* pass to IP layer */ +        ip_input(p, netif); +      } +      break; +       +    case ETHTYPE_ARP: +      /* pass p to ARP module */ +      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); +      break; + +#if PPPOE_SUPPORT +    case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */ +      pppoe_disc_input(netif, p); +      break; + +    case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */ +      pppoe_data_input(netif, p); +      break; +#endif /* PPPOE_SUPPORT */ + +    default: +      ETHARP_STATS_INC(etharp.proterr); +      ETHARP_STATS_INC(etharp.drop); +      pbuf_free(p); +      p = NULL; +      break; +  } + +  /* This means the pbuf is freed or consumed, +     so the caller doesn't have to free it again */ +  return ERR_OK; +} +#endif /* LWIP_ARP */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ethernetif.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ethernetif.c new file mode 100644 index 000000000..ccd7bd67f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ethernetif.c @@ -0,0 +1,313 @@ +/** + * @file + * Ethernet Interface Skeleton + * + */ + +/* + * 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> + * + */ + +/* + * This file is a skeleton for developing Ethernet network interface + * drivers for lwIP. Add code to the low_level functions and do a + * search-and-replace for the word "ethernetif" to replace it with + * something that better describes your network interface. + */ + +#include "lwip/opt.h" + +#if 0 /* don't build, this is only a skeleton, see previous comment */ + +#include "lwip/def.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include <lwip/stats.h> +#include <lwip/snmp.h> +#include "netif/etharp.h" +#include "netif/ppp_oe.h" + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + * Keeping the ethernet address of the MAC in this struct is not necessary + * as it is already kept in the struct netif. + * But this is only an example, anyway... + */ +struct ethernetif { +  struct eth_addr *ethaddr; +  /* Add whatever per-interface state that is needed here. */ +}; + +/* Forward declarations. */ +static void  ethernetif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from ethernetif_init(). + * + * @param netif the already initialized lwip network interface structure + *        for this ethernetif + */ +static void +low_level_init(struct netif *netif) +{ +  struct ethernetif *ethernetif = netif->state; +   +  /* set MAC hardware address length */ +  netif->hwaddr_len = ETHARP_HWADDR_LEN; + +  /* set MAC hardware address */ +  netif->hwaddr[0] = ; +  ... +  netif->hwaddr[5] = ; + +  /* maximum transfer unit */ +  netif->mtu = 1500; +   +  /* device capabilities */ +  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ +  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +  +  /* Do whatever else is needed to initialize interface. */   +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this ethernetif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + *         an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + *       strange results. You might consider waiting for space in the DMA queue + *       to become availale since the stack doesn't retry to send a packet + *       dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ +  struct ethernetif *ethernetif = netif->state; +  struct pbuf *q; + +  initiate transfer(); +   +#if ETH_PAD_SIZE +  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +  for(q = p; q != NULL; q = q->next) { +    /* Send the data from the pbuf to the interface, one pbuf at a +       time. The size of the data in each pbuf is kept in the ->len +       variable. */ +    send data from(q->payload, q->len); +  } + +  signal that packet should be sent(); + +#if ETH_PAD_SIZE +  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif +   +  LINK_STATS_INC(link.xmit); + +  return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this ethernetif + * @return a pbuf filled with the received packet (including MAC header) + *         NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ +  struct ethernetif *ethernetif = netif->state; +  struct pbuf *p, *q; +  u16_t len; + +  /* Obtain the size of the packet and put it into the "len" +     variable. */ +  len = ; + +#if ETH_PAD_SIZE +  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + +  /* We allocate a pbuf chain of pbufs from the pool. */ +  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); +   +  if (p != NULL) { + +#if ETH_PAD_SIZE +    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +    /* We iterate over the pbuf chain until we have read the entire +     * packet into the pbuf. */ +    for(q = p; q != NULL; q = q->next) { +      /* Read enough bytes to fill this pbuf in the chain. The +       * available data in the pbuf is given by the q->len +       * variable. */ +      read data into(q->payload, q->len); +    } +    acknowledge that packet has been read(); + +#if ETH_PAD_SIZE +    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + +    LINK_STATS_INC(link.recv); +  } else { +    drop packet(); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +  } + +  return p;   +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this ethernetif + */ +static void +ethernetif_input(struct netif *netif) +{ +  struct ethernetif *ethernetif; +  struct eth_hdr *ethhdr; +  struct pbuf *p; + +  ethernetif = netif->state; + +  /* move received packet into a new pbuf */ +  p = low_level_input(netif); +  /* no packet could be read, silently ignore this */ +  if (p == NULL) return; +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; + +  switch (htons(ethhdr->type)) { +  /* IP or ARP packet? */ +  case ETHTYPE_IP: +  case ETHTYPE_ARP: +#if PPPOE_SUPPORT +  /* PPPoE packet? */ +  case ETHTYPE_PPPOEDISC: +  case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ +    /* full packet send to tcpip_thread to process */ +    if (netif->input(p, netif)!=ERR_OK) +     { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n")); +       pbuf_free(p); +       p = NULL; +     } +    break; + +  default: +    pbuf_free(p); +    p = NULL; +    break; +  } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this ethernetif + * @return ERR_OK if the loopif is initialized + *         ERR_MEM if private data couldn't be allocated + *         any other err_t on error + */ +err_t +ethernetif_init(struct netif *netif) +{ +  struct ethernetif *ethernetif; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +     +  ethernetif = mem_malloc(sizeof(struct ethernetif)); +  if (ethernetif == NULL) { +    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n")); +    return ERR_MEM; +  } + +#if LWIP_NETIF_HOSTNAME +  /* Initialize interface hostname */ +  netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + +  /* +   * Initialize the snmp variables and counters inside the struct netif. +   * The last argument should be replaced with your link speed, in units +   * of bits per second. +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + +  netif->state = ethernetif; +  netif->name[0] = IFNAME0; +  netif->name[1] = IFNAME1; +  /* We directly use etharp_output() here to save a function call. +   * You can instead declare your own function an call etharp_output() +   * from it if you have to do some checks before sending (e.g. if link +   * is available...) */ +  netif->output = etharp_output; +  netif->linkoutput = low_level_output; +   +  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); +   +  /* initialize the hardware */ +  low_level_init(netif); + +  return ERR_OK; +} + +#endif /* 0 */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/loopif.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/loopif.c new file mode 100644 index 000000000..1e1f28cf1 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/loopif.c @@ -0,0 +1,66 @@ +/** + * @file + * Loop Interface + * + */ + +/* + * 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_HAVE_LOOPIF + +#include "netif/loopif.h" +#include "lwip/snmp.h" + +/** + * 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 + */ +err_t +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 */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.c new file mode 100644 index 000000000..4c0ee6a8e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.c @@ -0,0 +1,988 @@ +/***************************************************************************** +* auth.c - Network Authentication and Phase Control program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Ported from public pppd code. +*****************************************************************************/ +/* + * auth.c - PPP authentication and phase control. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "lcp.h" +#include "pap.h" +#include "chap.h" +#include "auth.h" +#include "ipcp.h" + +#if CBCP_SUPPORT +#include "cbcp.h" +#endif /* CBCP_SUPPORT */ + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* Bits in auth_pending[] */ +#define PAP_WITHPEER    1 +#define PAP_PEER        2 +#define CHAP_WITHPEER   4 +#define CHAP_PEER       8 + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +/* Used for storing a sequence of words.  Usually malloced. */ +struct wordlist { +  struct wordlist *next; +  char        word[1]; +}; + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +extern char *crypt (const char *, const char *); + +/* Prototypes for procedures local to this file. */ + +static void network_phase (int); +static void check_idle (void *); +static void connect_time_expired (void *); +#if 0 +static int  login (char *, char *, char **, int *); +#endif +static void logout (void); +static int  null_login (int); +static int  get_pap_passwd (int, char *, char *); +static int  have_pap_secret (void); +static int  have_chap_secret (char *, char *, u32_t); +static int  ip_addr_check (u32_t, struct wordlist *); +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +static void set_allowed_addrs(int unit, struct wordlist *addrs); +static void free_wordlist (struct wordlist *); +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ +#if CBCP_SUPPORT +static void callback_phase (int); +#endif /* CBCP_SUPPORT */ + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +#if PAP_SUPPORT || CHAP_SUPPORT +/* The name by which the peer authenticated itself to us. */ +static char peer_authname[MAXNAMELEN]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +/* Records which authentication operations haven't completed yet. */ +static int auth_pending[NUM_PPP]; + +/* Set if we have successfully called login() */ +static int logged_in; + +/* Set if we have run the /etc/ppp/auth-up script. */ +static int did_authup; + +/* List of addresses which the peer may use. */ +static struct wordlist *addresses[NUM_PPP]; + +/* Number of network protocols which we have opened. */ +static int num_np_open; + +/* Number of network protocols which have come up. */ +static int num_np_up; + +#if PAP_SUPPORT || CHAP_SUPPORT +/* Set if we got the contents of passwd[] from the pap-secrets file. */ +static int passwd_from_file; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * An Open on LCP has requested a change from Dead to Establish phase. + * Do what's necessary to bring the physical layer up. + */ +void +link_required(int unit) +{ +  LWIP_UNUSED_ARG(unit); + +  AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit)); +} + +/* + * LCP has terminated the link; go to the Dead phase and take the + * physical layer down. + */ +void +link_terminated(int unit) +{ +  AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit)); +  if (lcp_phase[unit] == PHASE_DEAD) { +    return; +  } +  if (logged_in) { +    logout(); +  } +  lcp_phase[unit] = PHASE_DEAD; +  AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n")); +  pppLinkTerminated(unit); +} + +/* + * LCP has gone down; it will either die or try to re-establish. + */ +void +link_down(int unit) +{ +  int i; +  struct protent *protp; +   +  AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit)); +  if (did_authup) { +    /* XXX Do link down processing. */ +    did_authup = 0; +  } +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (!protp->enabled_flag) { +      continue; +    } +    if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) { +      (*protp->lowerdown)(unit); +    } +    if (protp->protocol < 0xC000 && protp->close != NULL) { +      (*protp->close)(unit, "LCP down"); +    } +  } +  num_np_open = 0; +  num_np_up = 0; +  if (lcp_phase[unit] != PHASE_DEAD) { +    lcp_phase[unit] = PHASE_TERMINATE; +  } +  pppLinkDown(unit); +} + +/* + * The link is established. + * Proceed to the Dead, Authenticate or Network phase as appropriate. + */ +void +link_established(int unit) +{ +  int auth; +  int i; +  struct protent *protp; +  lcp_options *wo = &lcp_wantoptions[unit]; +  lcp_options *go = &lcp_gotoptions[unit]; +#if PAP_SUPPORT || CHAP_SUPPORT +  lcp_options *ho = &lcp_hisoptions[unit]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +  AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit)); +  /* +   * Tell higher-level protocols that LCP is up. +   */ +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) { +      (*protp->lowerup)(unit); +    } +  } +  if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) { +    /* +     * We wanted the peer to authenticate itself, and it refused: +     * treat it as though it authenticated with PAP using a username +     * of "" and a password of "".  If that's not OK, boot it out. +     */ +    if (!wo->neg_upap || !null_login(unit)) { +      AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n")); +      lcp_close(unit, "peer refused to authenticate"); +      return; +    } +  } +     +  lcp_phase[unit] = PHASE_AUTHENTICATE; +  auth = 0; +#if CHAP_SUPPORT +  if (go->neg_chap) { +    ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype); +    auth |= CHAP_PEER; +  }  +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT +  else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT +  if (go->neg_upap) { +    upap_authpeer(unit); +    auth |= PAP_PEER; +  } +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +  if (ho->neg_chap) { +    ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype); +    auth |= CHAP_WITHPEER; +  } +#endif /* CHAP_SUPPORT */ +#if PAP_SUPPORT && CHAP_SUPPORT +  else +#endif /* PAP_SUPPORT && CHAP_SUPPORT */ +#if PAP_SUPPORT +  if (ho->neg_upap) { +    if (ppp_settings.passwd[0] == 0) { +      passwd_from_file = 1; +      if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { +        AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n")); +      } +    } +    upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); +    auth |= PAP_WITHPEER; +  } +#endif /* PAP_SUPPORT */ +  auth_pending[unit] = auth; + +  if (!auth) { +    network_phase(unit); +  } +} + +/* + * The peer has failed to authenticate himself using `protocol'. + */ +void +auth_peer_fail(int unit, u16_t protocol) +{ +  LWIP_UNUSED_ARG(protocol); + +  AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol)); +  /* +   * Authentication failure: take the link down +   */ +  lcp_close(unit, "Authentication failed"); +} + + +#if PAP_SUPPORT || CHAP_SUPPORT +/* + * The peer has been successfully authenticated using `protocol'. + */ +void +auth_peer_success(int unit, u16_t protocol, char *name, int namelen) +{ +  int pbit; +   +  AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol)); +  switch (protocol) { +    case PPP_CHAP: +      pbit = CHAP_PEER; +      break; +    case PPP_PAP: +      pbit = PAP_PEER; +      break; +    default: +      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); +      return; +  } +   +  /* +   * Save the authenticated name of the peer for later. +   */ +  if (namelen > sizeof(peer_authname) - 1) { +    namelen = sizeof(peer_authname) - 1; +  } +  BCOPY(name, peer_authname, namelen); +  peer_authname[namelen] = 0; +   +  /* +   * If there is no more authentication still to be done, +   * proceed to the network (or callback) phase. +   */ +  if ((auth_pending[unit] &= ~pbit) == 0) { +    network_phase(unit); +  } +} + +/* + * We have failed to authenticate ourselves to the peer using `protocol'. + */ +void +auth_withpeer_fail(int unit, u16_t protocol) +{ +  int errCode = PPPERR_AUTHFAIL; +   +  LWIP_UNUSED_ARG(protocol); + +  AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol)); +  if (passwd_from_file) { +    BZERO(ppp_settings.passwd, MAXSECRETLEN); +  } +  /*  +   * XXX Warning: the unit number indicates the interface which is +   * not necessarily the PPP connection.  It works here as long +   * as we are only supporting PPP interfaces. +   */ +  pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); + +  /* +   * We've failed to authenticate ourselves to our peer. +   * He'll probably take the link down, and there's not much +   * we can do except wait for that. +   */ +} + +/* + * We have successfully authenticated ourselves with the peer using `protocol'. + */ +void +auth_withpeer_success(int unit, u16_t protocol) +{ +  int pbit; +   +  AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol)); +  switch (protocol) { +    case PPP_CHAP: +      pbit = CHAP_WITHPEER; +      break; +    case PPP_PAP: +      if (passwd_from_file) { +        BZERO(ppp_settings.passwd, MAXSECRETLEN); +      } +      pbit = PAP_WITHPEER; +      break; +    default: +      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); +      pbit = 0; +  } +   +  /* +   * If there is no more authentication still being done, +   * proceed to the network (or callback) phase. +   */ +  if ((auth_pending[unit] &= ~pbit) == 0) { +    network_phase(unit); +  } +} +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + + +/* + * np_up - a network protocol has come up. + */ +void +np_up(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto)); +  if (num_np_up == 0) { +    AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); +    /* +     * At this point we consider that the link has come up successfully. +     */ +    if (ppp_settings.idle_time_limit > 0) { +      TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit); +    } +     +    /* +     * Set a timeout to close the connection once the maximum +     * connect time has expired. +     */ +    if (ppp_settings.maxconnect > 0) { +      TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect); +    } +  } +  ++num_np_up; +} + +/* + * np_down - a network protocol has gone down. + */ +void +np_down(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto)); +  if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) { +    UNTIMEOUT(check_idle, NULL); +  } +} + +/* + * np_finished - a network protocol has finished using the link. + */ +void +np_finished(int unit, u16_t proto) +{ +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(proto); + +  AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto)); +  if (--num_np_open <= 0) { +    /* no further use for the link: shut up shop. */ +    lcp_close(0, "No network protocols running"); +  } +} + +/* + * auth_reset - called when LCP is starting negotiations to recheck + * authentication options, i.e. whether we have appropriate secrets + * to use for authenticating ourselves and/or the peer. + */ +void +auth_reset(int unit) +{ +  lcp_options *go = &lcp_gotoptions[unit]; +  lcp_options *ao = &lcp_allowoptions[0]; +  ipcp_options *ipwo = &ipcp_wantoptions[0]; +  u32_t remote; + +  AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit)); +  ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL)); +  ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/; + +  if (go->neg_upap && !have_pap_secret()) { +    go->neg_upap = 0; +  } +  if (go->neg_chap) { +    remote = ipwo->accept_remote? 0: ipwo->hisaddr; +    if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) { +      go->neg_chap = 0; +    } +  } +} + +#if PAP_SUPPORT +/* + * check_passwd - Check the user name and passwd against the PAP secrets + * file.  If requested, also check against the system password database, + * and login the user if OK. + * + * returns: + *  UPAP_AUTHNAK: Authentication failed. + *  UPAP_AUTHACK: Authentication succeeded. + * In either case, msg points to an appropriate message. + */ +int +check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) +{ +#if 1 +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(auser); +  LWIP_UNUSED_ARG(userlen); +  LWIP_UNUSED_ARG(apasswd); +  LWIP_UNUSED_ARG(passwdlen); +  LWIP_UNUSED_ARG(msglen); +  *msg = (char *) 0; +  return UPAP_AUTHACK;     /* XXX Assume all entries OK. */ +#else +  int ret = 0; +  struct wordlist *addrs = NULL; +  char passwd[256], user[256]; +  char secret[MAXWORDLEN]; +  static u_short attempts = 0; +   +  /* +   * Make copies of apasswd and auser, then null-terminate them. +   */ +  BCOPY(apasswd, passwd, passwdlen); +  passwd[passwdlen] = '\0'; +  BCOPY(auser, user, userlen); +  user[userlen] = '\0'; +  *msg = (char *) 0; + +  /* XXX Validate user name and password. */ +  ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */ +       +  if (ret == UPAP_AUTHNAK) { +    if (*msg == (char *) 0) { +      *msg = "Login incorrect"; +    } +    *msglen = strlen(*msg); +    /* +     * Frustrate passwd stealer programs. +     * Allow 10 tries, but start backing off after 3 (stolen from login). +     * On 10'th, drop the connection. +     */ +    if (attempts++ >= 10) { +      AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user)); +      /*ppp_panic("Excess Bad Logins");*/ +    } +    if (attempts > 3) { +      sys_msleep((attempts - 3) * 5); +    } +    if (addrs != NULL) { +      free_wordlist(addrs); +    } +  } else { +    attempts = 0; /* Reset count */ +    if (*msg == (char *) 0) { +      *msg = "Login ok"; +    } +    *msglen = strlen(*msg); +    set_allowed_addrs(unit, addrs); +  } + +  BZERO(passwd, sizeof(passwd)); +  BZERO(secret, sizeof(secret)); + +  return ret; +#endif +} +#endif /* PAP_SUPPORT */ + + +/* + * auth_ip_addr - check whether the peer is authorized to use + * a given IP address.  Returns 1 if authorized, 0 otherwise. + */ +int +auth_ip_addr(int unit, u32_t addr) +{ +  return ip_addr_check(addr, addresses[unit]); +} + +/* + * bad_ip_adrs - return 1 if the IP address is one we don't want + * to use, such as an address in the loopback net or a multicast address. + * addr is in network byte order. + */ +int +bad_ip_adrs(u32_t addr) +{ +  addr = ntohl(addr); +  return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET +      || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + + +#if CHAP_SUPPORT +/* + * get_secret - open the CHAP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int get_secret( int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) +{ +#if 1 +  int len; +  struct wordlist *addrs; + +  LWIP_UNUSED_ARG(unit); +  LWIP_UNUSED_ARG(server); +  LWIP_UNUSED_ARG(save_addrs); + +  addrs = NULL; + +  if(!client || !client[0] || strcmp(client, ppp_settings.user)) { +    return 0; +  } + +  len = strlen(ppp_settings.passwd); +  if (len > MAXSECRETLEN) { +    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); +    len = MAXSECRETLEN; +  } + +  BCOPY(ppp_settings.passwd, secret, len); +  *secret_len = len; + +  return 1; +#else +  int ret = 0, len; +  struct wordlist *addrs; +  char secbuf[MAXWORDLEN]; +   +  addrs = NULL; +  secbuf[0] = 0; + +  /* XXX Find secret. */ +  if (ret < 0) { +    return 0; +  } + +  if (save_addrs) { +    set_allowed_addrs(unit, addrs); +  } + +  len = strlen(secbuf); +  if (len > MAXSECRETLEN) { +    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); +    len = MAXSECRETLEN; +  } + +  BCOPY(secbuf, secret, len); +  BZERO(secbuf, sizeof(secbuf)); +  *secret_len = len; + +  return 1; +#endif +} +#endif /* CHAP_SUPPORT */ + + +#if 0 /* UNUSED */ +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options(void) +{ +  lcp_options *wo = &lcp_wantoptions[0]; +  int can_auth; +  ipcp_options *ipwo = &ipcp_wantoptions[0]; +  u32_t remote; + +  /* Default our_name to hostname, and user to our_name */ +  if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { +      strcpy(ppp_settings.our_name, ppp_settings.hostname); +  } + +  if (ppp_settings.user[0] == 0) { +    strcpy(ppp_settings.user, ppp_settings.our_name); +  } + +  /* If authentication is required, ask peer for CHAP or PAP. */ +  if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { +    wo->neg_chap = 1; +    wo->neg_upap = 1; +  } +   +  /* +   * Check whether we have appropriate secrets to use +   * to authenticate the peer. +   */ +  can_auth = wo->neg_upap && have_pap_secret(); +  if (!can_auth && wo->neg_chap) { +    remote = ipwo->accept_remote? 0: ipwo->hisaddr; +    can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); +  } + +  if (ppp_settings.auth_required && !can_auth) { +    ppp_panic("No auth secret"); +  } +} +#endif + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * Proceed to the network phase. + */ +static void +network_phase(int unit) +{ +  int i; +  struct protent *protp; +  lcp_options *go = &lcp_gotoptions[unit]; +   +  /* +   * If the peer had to authenticate, run the auth-up script now. +   */ +  if ((go->neg_chap || go->neg_upap) && !did_authup) { +    /* XXX Do setup for peer authentication. */ +    did_authup = 1; +  } + +#if CBCP_SUPPORT +  /* +   * If we negotiated callback, do it now. +   */ +  if (go->neg_cbcp) { +    lcp_phase[unit] = PHASE_CALLBACK; +    (*cbcp_protent.open)(unit); +    return; +  } +#endif /* CBCP_SUPPORT */ + +  lcp_phase[unit] = PHASE_NETWORK; +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { +      (*protp->open)(unit); +      if (protp->protocol != PPP_CCP) { +        ++num_np_open; +      } +    } +  } + +  if (num_np_open == 0) { +    /* nothing to do */ +    lcp_close(0, "No network protocols running"); +  } +} + +/* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void +check_idle(void *arg) +{ +  struct ppp_idle idle; +  u_short itime; +   +  LWIP_UNUSED_ARG(arg); +  if (!get_idle_time(0, &idle)) { +    return; +  } +  itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); +  if (itime >= ppp_settings.idle_time_limit) { +    /* link is idle: shut it down. */ +    AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n")); +    lcp_close(0, "Link inactive"); +  } else { +    TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); +  } +} + +/* + * connect_time_expired - log a message and close the connection. + */ +static void +connect_time_expired(void *arg) +{ +  LWIP_UNUSED_ARG(arg); + +  AUTHDEBUG((LOG_INFO, "Connect time expired\n")); +  lcp_close(0, "Connect time expired");   /* Close connection */ +} + +#if 0 +/* + * login - Check the user name and password against the system + * password database, and login the user if OK. + * + * returns: + *  UPAP_AUTHNAK: Login failed. + *  UPAP_AUTHACK: Login succeeded. + * In either case, msg points to an appropriate message. + */ +static int +login(char *user, char *passwd, char **msg, int *msglen) +{ +  /* XXX Fail until we decide that we want to support logins. */ +  return (UPAP_AUTHNAK); +} +#endif + +/* + * logout - Logout the user. + */ +static void +logout(void) +{ +  logged_in = 0; +} + +/* + * null_login - Check if a username of "" and a password of "" are + * acceptable, and iff so, set the list of acceptable IP addresses + * and return 1. + */ +static int +null_login(int unit) +{ +  LWIP_UNUSED_ARG(unit); +  /* XXX Fail until we decide that we want to support logins. */ +  return 0; +} + +/* + * get_pap_passwd - get a password for authenticating ourselves with + * our peer using PAP.  Returns 1 on success, 0 if no suitable password + * could be found. + */ +static int +get_pap_passwd(int unit, char *user, char *passwd) +{ +  LWIP_UNUSED_ARG(unit); +/* normally we would reject PAP if no password is provided, +   but this causes problems with some providers (like CHT in Taiwan) +   who incorrectly request PAP and expect a bogus/empty password, so +   always provide a default user/passwd of "none"/"none" +*/ +  if(user) { +    strcpy(user, "none"); +  } +  if(passwd) { +    strcpy(passwd, "none"); +  } +  return 1; +} + +/* + * have_pap_secret - check whether we have a PAP file with any + * secrets that we could possibly use for authenticating the peer. + */ +static int +have_pap_secret(void) +{ +  /* XXX Fail until we set up our passwords. */ +  return 0; +} + +/* + * have_chap_secret - check whether we have a CHAP file with a + * secret that we could possibly use for authenticating `client' + * on `server'.  Either can be the null string, meaning we don't + * know the identity yet. + */ +static int +have_chap_secret(char *client, char *server, u32_t remote) +{ +  LWIP_UNUSED_ARG(client); +  LWIP_UNUSED_ARG(server); +  LWIP_UNUSED_ARG(remote); +  /* XXX Fail until we set up our passwords. */ +  return 0; +} + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * set_allowed_addrs() - set the list of allowed addresses. + */ +static void +set_allowed_addrs(int unit, struct wordlist *addrs) +{ +  if (addresses[unit] != NULL) { +    free_wordlist(addresses[unit]); +  } +  addresses[unit] = addrs; + +#if 0 +  /* +   * If there's only one authorized address we might as well +   * ask our peer for that one right away +   */ +  if (addrs != NULL && addrs->next == NULL) { +    char *p = addrs->word; +    struct ipcp_options *wo = &ipcp_wantoptions[unit]; +    u32_t a; +    struct hostent *hp; +     +    if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) { +      hp = gethostbyname(p); +      if (hp != NULL && hp->h_addrtype == AF_INET) { +        a = *(u32_t *)hp->h_addr; +      } else { +        a = inet_addr(p); +      } +      if (a != (u32_t) -1) { +        wo->hisaddr = a; +      } +    } +  } +#endif +} +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +static int +ip_addr_check(u32_t addr, struct wordlist *addrs) +{ +  /* don't allow loopback or multicast address */ +  if (bad_ip_adrs(addr)) { +    return 0; +  } + +  if (addrs == NULL) { +    return !ppp_settings.auth_required; /* no addresses authorized */ +  } + +  /* XXX All other addresses allowed. */ +  return 1; +} + +#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * free_wordlist - release memory allocated for a wordlist. + */ +static void +free_wordlist(struct wordlist *wp) +{ +  struct wordlist *next; +   +  while (wp != NULL) { +    next = wp->next; +    free(wp); +    wp = next; +  } +} +#endif  /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.h new file mode 100644 index 000000000..86ff04945 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/auth.h @@ -0,0 +1,111 @@ +/***************************************************************************** +* auth.h -  PPP Authentication and phase control header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original derived from BSD pppd.h. +*****************************************************************************/ +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ + +#ifndef AUTH_H +#define AUTH_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* we are starting to use the link */ +void link_required (int); + +/* we are finished with the link */ +void link_terminated (int); + +/* the LCP layer has left the Opened state */ +void link_down (int); + +/* the link is up; authenticate now */ +void link_established (int); + +/* a network protocol has come up */ +void np_up (int, u16_t); + +/* a network protocol has gone down */ +void np_down (int, u16_t); + +/* a network protocol no longer needs link */ +void np_finished (int, u16_t); + +/* peer failed to authenticate itself */ +void auth_peer_fail (int, u16_t); + +/* peer successfully authenticated itself */ +void auth_peer_success (int, u16_t, char *, int); + +/* we failed to authenticate ourselves */ +void auth_withpeer_fail (int, u16_t); + +/* we successfully authenticated ourselves */ +void auth_withpeer_success (int, u16_t); + +/* check authentication options supplied */ +void auth_check_options (void); + +/* check what secrets we have */ +void auth_reset (int); + +/* Check peer-supplied username/password */ +int  check_passwd (int, char *, int, char *, int, char **, int *); + +/* get "secret" for chap */ +int  get_secret (int, char *, char *, char *, int *, int); + +/* check if IP address is authorized */ +int  auth_ip_addr (int, u32_t); + +/* check if IP address is unreasonable */ +int  bad_ip_adrs (u32_t); + +#endif /* AUTH_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.c new file mode 100644 index 000000000..6d9c3c3ce --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.c @@ -0,0 +1,902 @@ +/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/ +/***************************************************************************** +* chap.c - Network Challenge Handshake Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD chap.c. +*****************************************************************************/ +/* + * chap.c - Challenge Handshake Authentication Protocol. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Gregory M. Christy.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "magic.h" +#include "randm.h" +#include "auth.h" +#include "md5.h" +#include "chap.h" +#include "chpms.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Protocol entry points. + */ +static void ChapInit (int); +static void ChapLowerUp (int); +static void ChapLowerDown (int); +static void ChapInput (int, u_char *, int); +static void ChapProtocolReject (int); +#if 0 +static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *); +#endif + +static void ChapChallengeTimeout (void *); +static void ChapResponseTimeout (void *); +static void ChapReceiveChallenge (chap_state *, u_char *, int, int); +static void ChapRechallenge (void *); +static void ChapReceiveResponse (chap_state *, u_char *, int, int); +static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapSendStatus (chap_state *, int); +static void ChapSendChallenge (chap_state *); +static void ChapSendResponse (chap_state *); +static void ChapGenChallenge (chap_state *); + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ + +struct protent chap_protent = { +  PPP_CHAP, +  ChapInit, +  ChapInput, +  ChapProtocolReject, +  ChapLowerUp, +  ChapLowerDown, +  NULL, +  NULL, +#if 0 +  ChapPrintPkt, +  NULL, +#endif +  1, +  "CHAP", +#if 0 +  NULL, +  NULL, +  NULL +#endif +}; + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * ChapAuthWithPeer - Authenticate us with our peer (start client). + * + */ +void +ChapAuthWithPeer(int unit, char *our_name, int digest) +{ +  chap_state *cstate = &chap[unit]; + +  cstate->resp_name = our_name; +  cstate->resp_type = digest; + +  if (cstate->clientstate == CHAPCS_INITIAL || +      cstate->clientstate == CHAPCS_PENDING) { +    /* lower layer isn't up - wait until later */ +    cstate->clientstate = CHAPCS_PENDING; +    return; +  } + +  /* +   * We get here as a result of LCP coming up. +   * So even if CHAP was open before, we will  +   * have to re-authenticate ourselves. +   */ +  cstate->clientstate = CHAPCS_LISTEN; +} + + +/* + * ChapAuthPeer - Authenticate our peer (start server). + */ +void +ChapAuthPeer(int unit, char *our_name, int digest) +{ +  chap_state *cstate = &chap[unit]; + +  cstate->chal_name = our_name; +  cstate->chal_type = digest; +   +  if (cstate->serverstate == CHAPSS_INITIAL || +      cstate->serverstate == CHAPSS_PENDING) { +    /* lower layer isn't up - wait until later */ +    cstate->serverstate = CHAPSS_PENDING; +    return; +  } + +  ChapGenChallenge(cstate); +  ChapSendChallenge(cstate);    /* crank it up dude! */ +  cstate->serverstate = CHAPSS_INITIAL_CHAL; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * ChapInit - Initialize a CHAP unit. + */ +static void +ChapInit(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  BZERO(cstate, sizeof(*cstate)); +  cstate->unit = unit; +  cstate->clientstate = CHAPCS_INITIAL; +  cstate->serverstate = CHAPSS_INITIAL; +  cstate->timeouttime = CHAP_DEFTIMEOUT; +  cstate->max_transmits = CHAP_DEFTRANSMITS; +  /* random number generator is initialized in magic_init */ +} + + +/* + * ChapChallengeTimeout - Timeout expired on sending challenge. + */ +static void +ChapChallengeTimeout(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; + +  /* if we aren't sending challenges, don't worry.  then again we */ +  /* probably shouldn't be here either */ +  if (cstate->serverstate != CHAPSS_INITIAL_CHAL && +      cstate->serverstate != CHAPSS_RECHALLENGE) { +    return; +  } + +  if (cstate->chal_transmits >= cstate->max_transmits) { +    /* give up on peer */ +    CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n")); +    cstate->serverstate = CHAPSS_BADAUTH; +    auth_peer_fail(cstate->unit, PPP_CHAP); +    return; +  } + +  ChapSendChallenge(cstate); /* Re-send challenge */ +} + + +/* + * ChapResponseTimeout - Timeout expired on sending response. + */ +static void +ChapResponseTimeout(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; + +  /* if we aren't sending a response, don't worry. */ +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    return; +  } + +  ChapSendResponse(cstate);    /* re-send response */ +} + + +/* + * ChapRechallenge - Time to challenge the peer again. + */ +static void +ChapRechallenge(void *arg) +{ +  chap_state *cstate = (chap_state *) arg; +   +  /* if we aren't sending a response, don't worry. */ +  if (cstate->serverstate != CHAPSS_OPEN) { +    return; +  } + +  ChapGenChallenge(cstate); +  ChapSendChallenge(cstate); +  cstate->serverstate = CHAPSS_RECHALLENGE; +} + + +/* + * ChapLowerUp - The lower layer is up. + * + * Start up if we have pending requests. + */ +static void +ChapLowerUp(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  if (cstate->clientstate == CHAPCS_INITIAL) { +    cstate->clientstate = CHAPCS_CLOSED; +  } else if (cstate->clientstate == CHAPCS_PENDING) { +    cstate->clientstate = CHAPCS_LISTEN; +  } + +  if (cstate->serverstate == CHAPSS_INITIAL) { +    cstate->serverstate = CHAPSS_CLOSED; +  } else if (cstate->serverstate == CHAPSS_PENDING) { +    ChapGenChallenge(cstate); +    ChapSendChallenge(cstate); +    cstate->serverstate = CHAPSS_INITIAL_CHAL; +  } +} + + +/* + * ChapLowerDown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +ChapLowerDown(int unit) +{ +  chap_state *cstate = &chap[unit]; + +  /* Timeout(s) pending?  Cancel if so. */ +  if (cstate->serverstate == CHAPSS_INITIAL_CHAL || +      cstate->serverstate == CHAPSS_RECHALLENGE) { +    UNTIMEOUT(ChapChallengeTimeout, cstate); +  } else if (cstate->serverstate == CHAPSS_OPEN +      && cstate->chal_interval != 0) { +    UNTIMEOUT(ChapRechallenge, cstate); +  } +  if (cstate->clientstate == CHAPCS_RESPONSE) { +    UNTIMEOUT(ChapResponseTimeout, cstate); +  } +  cstate->clientstate = CHAPCS_INITIAL; +  cstate->serverstate = CHAPSS_INITIAL; +} + + +/* + * ChapProtocolReject - Peer doesn't grok CHAP. + */ +static void +ChapProtocolReject(int unit) +{ +  chap_state *cstate = &chap[unit]; +   +  if (cstate->serverstate != CHAPSS_INITIAL && +      cstate->serverstate != CHAPSS_CLOSED) { +    auth_peer_fail(unit, PPP_CHAP); +  } +  if (cstate->clientstate != CHAPCS_INITIAL && +      cstate->clientstate != CHAPCS_CLOSED) { +    auth_withpeer_fail(unit, PPP_CHAP); +  } +  ChapLowerDown(unit); /* shutdown chap */ +} + + +/* + * ChapInput - Input CHAP packet. + */ +static void +ChapInput(int unit, u_char *inpacket, int packet_len) +{ +  chap_state *cstate = &chap[unit]; +  u_char *inp; +  u_char code, id; +  int len; +   +  /* +   * Parse header (code, id and length). +   * If packet too short, drop it. +   */ +  inp = inpacket; +  if (packet_len < CHAP_HEADERLEN) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < CHAP_HEADERLEN) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n")); +    return; +  } +  if (len > packet_len) { +    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n")); +    return; +  } +  len -= CHAP_HEADERLEN; +   +  /* +   * Action depends on code (as in fact it usually does :-). +   */ +  switch (code) { +    case CHAP_CHALLENGE: +      ChapReceiveChallenge(cstate, inp, id, len); +      break; +     +    case CHAP_RESPONSE: +      ChapReceiveResponse(cstate, inp, id, len); +      break; +     +    case CHAP_FAILURE: +      ChapReceiveFailure(cstate, inp, id, len); +      break; +     +    case CHAP_SUCCESS: +      ChapReceiveSuccess(cstate, inp, id, len); +      break; +     +    default:        /* Need code reject? */ +      CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code)); +      break; +  } +} + + +/* + * ChapReceiveChallenge - Receive Challenge and send Response. + */ +static void +ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len) +{ +  int rchallenge_len; +  u_char *rchallenge; +  int secret_len; +  char secret[MAXSECRETLEN]; +  char rhostname[256]; +  MD5_CTX mdContext; +  u_char hash[MD5_SIGNATURE_SIZE]; +   +  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id)); +  if (cstate->clientstate == CHAPCS_CLOSED || +    cstate->clientstate == CHAPCS_PENDING) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n", +         cstate->clientstate)); +    return; +  } + +  if (len < 2) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); +    return; +  } + +  GETCHAR(rchallenge_len, inp); +  len -= sizeof (u_char) + rchallenge_len;  /* now name field length */ +  if (len < 0) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); +    return; +  } +  rchallenge = inp; +  INCPTR(rchallenge_len, inp); + +  if (len >= sizeof(rhostname)) { +    len = sizeof(rhostname) - 1; +  } +  BCOPY(inp, rhostname, len); +  rhostname[len] = '\000'; + +  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname)); + +  /* Microsoft doesn't send their name back in the PPP packet */ +  if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) { +    strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname)); +    rhostname[sizeof(rhostname) - 1] = 0; +    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname)); +  } + +  /* get secret for authenticating ourselves with the specified host */ +  if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) { +    secret_len = 0;    /* assume null secret if can't find one */ +    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname)); +  } + +  /* cancel response send timeout if necessary */ +  if (cstate->clientstate == CHAPCS_RESPONSE) { +    UNTIMEOUT(ChapResponseTimeout, cstate); +  } + +  cstate->resp_id = id; +  cstate->resp_transmits = 0; + +  /*  generate MD based on negotiated type */ +  switch (cstate->resp_type) {  + +  case CHAP_DIGEST_MD5: +    MD5Init(&mdContext); +    MD5Update(&mdContext, &cstate->resp_id, 1); +    MD5Update(&mdContext, (u_char*)secret, secret_len); +    MD5Update(&mdContext, rchallenge, rchallenge_len); +    MD5Final(hash, &mdContext); +    BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE); +    cstate->resp_length = MD5_SIGNATURE_SIZE; +    break; +   +#ifdef CHAPMS +  case CHAP_MICROSOFT: +    ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); +    break; +#endif + +  default: +    CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type)); +    return; +  } + +  BZERO(secret, sizeof(secret)); +  ChapSendResponse(cstate); +} + + +/* + * ChapReceiveResponse - Receive and process response. + */ +static void +ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) +{ +  u_char *remmd, remmd_len; +  int secret_len, old_state; +  int code; +  char rhostname[256]; +  MD5_CTX mdContext; +  char secret[MAXSECRETLEN]; +  u_char hash[MD5_SIGNATURE_SIZE]; +   +  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id)); +   +  if (cstate->serverstate == CHAPSS_CLOSED || +      cstate->serverstate == CHAPSS_PENDING) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n", +    cstate->serverstate)); +    return; +  } + +  if (id != cstate->chal_id) { +    return;      /* doesn't match ID of last challenge */ +  } + +  /* +  * If we have received a duplicate or bogus Response, +  * we have to send the same answer (Success/Failure) +  * as we did for the first Response we saw. +  */ +  if (cstate->serverstate == CHAPSS_OPEN) { +    ChapSendStatus(cstate, CHAP_SUCCESS); +    return; +  } +  if (cstate->serverstate == CHAPSS_BADAUTH) { +    ChapSendStatus(cstate, CHAP_FAILURE); +    return; +  } +   +  if (len < 2) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); +    return; +  } +  GETCHAR(remmd_len, inp); /* get length of MD */ +  remmd = inp;             /* get pointer to MD */ +  INCPTR(remmd_len, inp); +   +  len -= sizeof (u_char) + remmd_len; +  if (len < 0) { +    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); +    return; +  } + +  UNTIMEOUT(ChapChallengeTimeout, cstate); +   +  if (len >= sizeof(rhostname)) { +    len = sizeof(rhostname) - 1; +  } +  BCOPY(inp, rhostname, len); +  rhostname[len] = '\000'; + +  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname)); + +  /* +  * Get secret for authenticating them with us, +  * do the hash ourselves, and compare the result. +  */ +  code = CHAP_FAILURE; +  if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) { +    /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */ +    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n", +    rhostname)); +  } else { +    /*  generate MD based on negotiated type */ +    switch (cstate->chal_type) { + +      case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */ +        if (remmd_len != MD5_SIGNATURE_SIZE) { +          break;      /* it's not even the right length */ +        } +        MD5Init(&mdContext); +        MD5Update(&mdContext, &cstate->chal_id, 1); +        MD5Update(&mdContext, (u_char*)secret, secret_len); +        MD5Update(&mdContext, cstate->challenge, cstate->chal_len); +        MD5Final(hash, &mdContext);  +         +        /* compare local and remote MDs and send the appropriate status */ +        if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) { +          code = CHAP_SUCCESS;  /* they are the same! */ +        } +        break; +       +      default: +        CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type)); +    } +  } +   +  BZERO(secret, sizeof(secret)); +  ChapSendStatus(cstate, code); + +  if (code == CHAP_SUCCESS) { +    old_state = cstate->serverstate; +    cstate->serverstate = CHAPSS_OPEN; +    if (old_state == CHAPSS_INITIAL_CHAL) { +      auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len); +    } +    if (cstate->chal_interval != 0) { +      TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); +    } +  } else { +    CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n")); +    cstate->serverstate = CHAPSS_BADAUTH; +    auth_peer_fail(cstate->unit, PPP_CHAP); +  } +} + +/* + * ChapReceiveSuccess - Receive Success + */ +static void +ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len) +{ +  LWIP_UNUSED_ARG(id); +  LWIP_UNUSED_ARG(inp); + +  CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id)); + +  if (cstate->clientstate == CHAPCS_OPEN) { +    /* presumably an answer to a duplicate response */ +    return; +  } + +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    /* don't know what this is */ +    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate)); +    return; +  } +   +  UNTIMEOUT(ChapResponseTimeout, cstate); +   +  /* +   * Print message. +   */ +  if (len > 0) { +    PRINTMSG(inp, len); +  } + +  cstate->clientstate = CHAPCS_OPEN; + +  auth_withpeer_success(cstate->unit, PPP_CHAP); +} + + +/* + * ChapReceiveFailure - Receive failure. + */ +static void +ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len) +{ +  LWIP_UNUSED_ARG(id); +  LWIP_UNUSED_ARG(inp); + +  CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id)); + +  if (cstate->clientstate != CHAPCS_RESPONSE) { +    /* don't know what this is */ +    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate)); +    return; +  } + +  UNTIMEOUT(ChapResponseTimeout, cstate); + +  /* +   * Print message. +   */ +  if (len > 0) { +    PRINTMSG(inp, len); +  } + +  CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n")); +  auth_withpeer_fail(cstate->unit, PPP_CHAP); +} + + +/* + * ChapSendChallenge - Send an Authenticate challenge. + */ +static void +ChapSendChallenge(chap_state *cstate) +{ +  u_char *outp; +  int chal_len, name_len; +  int outlen; +   +  chal_len = cstate->chal_len; +  name_len = strlen(cstate->chal_name); +  outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */ +   +  PUTCHAR(CHAP_CHALLENGE, outp); +  PUTCHAR(cstate->chal_id, outp); +  PUTSHORT(outlen, outp); +   +  PUTCHAR(chal_len, outp);    /* put length of challenge */ +  BCOPY(cstate->challenge, outp, chal_len); +  INCPTR(chal_len, outp); +   +  BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */ +   +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id)); +   +  TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); +  ++cstate->chal_transmits; +} + + +/* + * ChapSendStatus - Send a status response (ack or nak). + */ +static void +ChapSendStatus(chap_state *cstate, int code) +{ +  u_char *outp; +  int outlen, msglen; +  char msg[256]; +   +  if (code == CHAP_SUCCESS) { +    strcpy(msg, "Welcome!"); +  } else { +    strcpy(msg, "I don't like you.  Go 'way."); +  } +  msglen = strlen(msg); +   +  outlen = CHAP_HEADERLEN + msglen; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */ +   +  PUTCHAR(code, outp); +  PUTCHAR(cstate->chal_id, outp); +  PUTSHORT(outlen, outp); +  BCOPY(msg, outp, msglen); +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id)); +} + +/* + * ChapGenChallenge is used to generate a pseudo-random challenge string of + * a pseudo-random length between min_len and max_len.  The challenge + * string and its length are stored in *cstate, and various other fields of + * *cstate are initialized. + */ + +static void +ChapGenChallenge(chap_state *cstate) +{ +  int chal_len; +  u_char *ptr = cstate->challenge; +  int i; +   +  /* pick a random challenge length between MIN_CHALLENGE_LENGTH and  +     MAX_CHALLENGE_LENGTH */   +  chal_len = (unsigned) +        ((((magic() >> 16) * +              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16) +           + MIN_CHALLENGE_LENGTH); +  cstate->chal_len = chal_len; +  cstate->chal_id = ++cstate->id; +  cstate->chal_transmits = 0; +   +  /* generate a random string */ +  for (i = 0; i < chal_len; i++ ) { +    *ptr++ = (char) (magic() & 0xff); +  } +} + +/* + * ChapSendResponse - send a response packet with values as specified + * in *cstate. + */ +/* ARGSUSED */ +static void +ChapSendResponse(chap_state *cstate) +{ +  u_char *outp; +  int outlen, md_len, name_len; +   +  md_len = cstate->resp_length; +  name_len = strlen(cstate->resp_name); +  outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; +  outp = outpacket_buf[cstate->unit]; +   +  MAKEHEADER(outp, PPP_CHAP); +   +  PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */ +  PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */ +  PUTSHORT(outlen, outp);      /* packet length */ +   +  PUTCHAR(md_len, outp);      /* length of MD */ +  BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */ +  INCPTR(md_len, outp); +   +  BCOPY(cstate->resp_name, outp, name_len);  /* append our name */ +   +  /* send the packet */ +  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); +   +  cstate->clientstate = CHAPCS_RESPONSE; +  TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); +  ++cstate->resp_transmits; +} + +#if 0 +static char *ChapCodenames[] = { +  "Challenge", "Response", "Success", "Failure" +}; +/* + * ChapPrintPkt - print the contents of a CHAP packet. + */ +static int +ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  int code, id, len; +  int clen, nlen; +  u_char x; +   +  if (plen < CHAP_HEADERLEN) { +    return 0; +  } +  GETCHAR(code, p); +  GETCHAR(id, p); +  GETSHORT(len, p); +  if (len < CHAP_HEADERLEN || len > plen) { +    return 0; +  } +  if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) { +    printer(arg, " %s", ChapCodenames[code-1]); +  } else { +    printer(arg, " code=0x%x", code); +  } +  printer(arg, " id=0x%x", id); +  len -= CHAP_HEADERLEN; +  switch (code) { +    case CHAP_CHALLENGE: +    case CHAP_RESPONSE: +      if (len < 1) { +        break; +      } +      clen = p[0]; +      if (len < clen + 1) { +        break; +      } +      ++p; +      nlen = len - clen - 1; +      printer(arg, " <"); +      for (; clen > 0; --clen) { +        GETCHAR(x, p); +        printer(arg, "%.2x", x); +      } +      printer(arg, ">, name = %.*Z", nlen, p); +      break; +    case CHAP_FAILURE: +    case CHAP_SUCCESS: +      printer(arg, " %.*Z", len, p); +      break; +    default: +      for (clen = len; clen > 0; --clen) { +        GETCHAR(x, p); +        printer(arg, " %.2x", x); +      } +  } + +  return len + CHAP_HEADERLEN; +} +#endif + +#endif /* CHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.h new file mode 100644 index 000000000..83dafd734 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chap.h @@ -0,0 +1,166 @@ +/***************************************************************************** +* chap.h - Network Challenge Handshake Authentication Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1993 The Australian National University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the Australian National University.  The name of the University + * may not be used to endorse or promote products derived from this + * software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Copyright (c) 1991 Gregory M. Christy + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the author. + * + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $ + */ + +#ifndef CHAP_H +#define CHAP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* Code + ID + length */ +#define CHAP_HEADERLEN 4 + +/* + * CHAP codes. + */ + +#define CHAP_DIGEST_MD5      5    /* use MD5 algorithm */ +#define MD5_SIGNATURE_SIZE   16   /* 16 bytes in a MD5 message digest */ +#define CHAP_MICROSOFT       0x80 /* use Microsoft-compatible alg. */ +#define MS_CHAP_RESPONSE_LEN 49   /* Response length for MS-CHAP */ + +#define CHAP_CHALLENGE       1 +#define CHAP_RESPONSE        2 +#define CHAP_SUCCESS         3 +#define CHAP_FAILURE         4 + +/* + *  Challenge lengths (for challenges we send) and other limits. + */ +#define MIN_CHALLENGE_LENGTH 32 +#define MAX_CHALLENGE_LENGTH 64 +#define MAX_RESPONSE_LENGTH  64 /* sufficient for MD5 or MS-CHAP */ + +/* + * Client (peer) states. + */ +#define CHAPCS_INITIAL       0 /* Lower layer down, not opened */ +#define CHAPCS_CLOSED        1 /* Lower layer up, not opened */ +#define CHAPCS_PENDING       2 /* Auth us to peer when lower up */ +#define CHAPCS_LISTEN        3 /* Listening for a challenge */ +#define CHAPCS_RESPONSE      4 /* Sent response, waiting for status */ +#define CHAPCS_OPEN          5 /* We've received Success */ + +/* + * Server (authenticator) states. + */ +#define CHAPSS_INITIAL       0 /* Lower layer down, not opened */ +#define CHAPSS_CLOSED        1 /* Lower layer up, not opened */ +#define CHAPSS_PENDING       2 /* Auth peer when lower up */ +#define CHAPSS_INITIAL_CHAL  3 /* We've sent the first challenge */ +#define CHAPSS_OPEN          4 /* We've sent a Success msg */ +#define CHAPSS_RECHALLENGE   5 /* We've sent another challenge */ +#define CHAPSS_BADAUTH       6 /* We've sent a Failure msg */ + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Each interface is described by a chap structure. + */ + +typedef struct chap_state { +  int unit;                               /* Interface unit number */ +  int clientstate;                        /* Client state */ +  int serverstate;                        /* Server state */ +  u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */ +  u_char chal_len;                        /* challenge length */ +  u_char chal_id;                         /* ID of last challenge */ +  u_char chal_type;                       /* hash algorithm for challenges */ +  u_char id;                              /* Current id */ +  char *chal_name;                        /* Our name to use with challenge */ +  int chal_interval;                      /* Time until we challenge peer again */ +  int timeouttime;                        /* Timeout time in seconds */ +  int max_transmits;                      /* Maximum # of challenge transmissions */ +  int chal_transmits;                     /* Number of transmissions of challenge */ +  int resp_transmits;                     /* Number of transmissions of response */ +  u_char response[MAX_RESPONSE_LENGTH];   /* Response to send */ +  u_char resp_length;                     /* length of response */ +  u_char resp_id;                         /* ID for response messages */ +  u_char resp_type;                       /* hash algorithm for responses */ +  char *resp_name;                        /* Our name to send with response */ +} chap_state; + + +/****************** +*** PUBLIC DATA *** +******************/ +extern chap_state chap[]; + +extern struct protent chap_protent; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +void ChapAuthWithPeer (int, char *, int); +void ChapAuthPeer (int, char *, int); + +#endif /* CHAP_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.c new file mode 100644 index 000000000..0c7521f20 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.c @@ -0,0 +1,396 @@ +/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/ +/***************************************************************************** +* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD chap_ms.c. +*****************************************************************************/ +/* + * chap_ms.c - Microsoft MS-CHAP compatible implementation. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Eric Rosenquist.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997 + * + *   Implemented LANManager type password response to MS-CHAP challenges. + *   Now pppd provides both NT style and LANMan style blocks, and the + *   prefered is set by option "ms-lanman". Default is to use NT. + *   The hash text (StdText) was taken from Win95 RASAPI32.DLL. + * + *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80 + */ + +#define USE_CRYPT + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "md4.h" +#ifndef USE_CRYPT +#include "des.h" +#endif +#include "chap.h" +#include "chpms.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +typedef struct { +    u_char LANManResp[24]; +    u_char NTResp[24]; +    u_char UseNT; /* If 1, ignore the LANMan response field */ +} MS_ChapResponse; +/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse), +   in case this struct gets padded. */ + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ + +/* XXX Don't know what to do with these. */ +extern void setkey(const char *); +extern void encrypt(char *, int); + +static void DesEncrypt (u_char *, u_char *, u_char *); +static void MakeKey (u_char *, u_char *); + +#ifdef USE_CRYPT +static void Expand (u_char *, u_char *); +static void Collapse (u_char *, u_char *); +#endif + +static void ChallengeResponse( +  u_char *challenge, /* IN   8 octets */ +  u_char *pwHash,    /* IN  16 octets */ +  u_char *response   /* OUT 24 octets */ +); +static void ChapMS_NT( +  char *rchallenge, +  int rchallenge_len, +  char *secret, +  int secret_len, +  MS_ChapResponse *response +); +static u_char Get7Bits( +  u_char *input, +  int startBit +); + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +void +ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len) +{ +  MS_ChapResponse response; +#ifdef MSLANMAN +  extern int ms_lanman; +#endif + +#if 0 +  CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret)); +#endif +  BZERO(&response, sizeof(response)); + +  /* Calculate both always */ +  ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); + +#ifdef MSLANMAN +  ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); + +  /* prefered method is set by option  */ +  response.UseNT = !ms_lanman; +#else +  response.UseNT = 1; +#endif + +  BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); +  cstate->resp_length = MS_CHAP_RESPONSE_LEN; +} + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +static void +ChallengeResponse( u_char *challenge, /* IN   8 octets */ +                   u_char *pwHash,    /* IN  16 octets */ +                   u_char *response   /* OUT 24 octets */) +{ +  char    ZPasswordHash[21]; + +  BZERO(ZPasswordHash, sizeof(ZPasswordHash)); +  BCOPY(pwHash, ZPasswordHash, 16); + +#if 0 +  log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG); +#endif + +  DesEncrypt(challenge, ZPasswordHash +  0, response + 0); +  DesEncrypt(challenge, ZPasswordHash +  7, response + 8); +  DesEncrypt(challenge, ZPasswordHash + 14, response + 16); + +#if 0 +  log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG); +#endif +} + + +#ifdef USE_CRYPT +static void +DesEncrypt( u_char *clear, /* IN  8 octets */ +            u_char *key,   /* IN  7 octets */ +            u_char *cipher /* OUT 8 octets */) +{ +  u_char des_key[8]; +  u_char crypt_key[66]; +  u_char des_input[66]; + +  MakeKey(key, des_key); + +  Expand(des_key, crypt_key); +  setkey(crypt_key); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", +             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + +  Expand(clear, des_input); +  encrypt(des_input, 0); +  Collapse(des_input, cipher); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#else /* USE_CRYPT */ + +static void +DesEncrypt( u_char *clear, /* IN  8 octets */ +            u_char *key,   /* IN  7 octets */ +            u_char *cipher /* OUT 8 octets */) +{ +  des_cblock    des_key; +  des_key_schedule  key_schedule; + +  MakeKey(key, des_key); + +  des_set_key(&des_key, key_schedule); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", +             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); +#endif + +  des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); + +#if 0 +  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); +#endif +} + +#endif /* USE_CRYPT */ + + +static u_char +Get7Bits( u_char *input, int startBit) +{ +  register unsigned int  word; + +  word  = (unsigned)input[startBit / 8] << 8; +  word |= (unsigned)input[startBit / 8 + 1]; + +  word >>= 15 - (startBit % 8 + 7); + +  return word & 0xFE; +} + +#ifdef USE_CRYPT + +/* in == 8-byte string (expanded version of the 56-bit key) + * out == 64-byte string where each byte is either 1 or 0 + * Note that the low-order "bit" is always ignored by by setkey() + */ +static void +Expand(u_char *in, u_char *out) +{ +  int j, c; +  int i; + +  for(i = 0; i < 64; in++){ +    c = *in; +    for(j = 7; j >= 0; j--) { +      *out++ = (c >> j) & 01; +    } +    i += 8; +  } +} + +/* The inverse of Expand + */ +static void +Collapse(u_char *in, u_char *out) +{ +  int j; +  int i; +  unsigned int c; + +  for (i = 0; i < 64; i += 8, out++) { +    c = 0; +    for (j = 7; j >= 0; j--, in++) { +      c |= *in << j; +    } +    *out = c & 0xff; +  } +} +#endif + +static void +MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */ +         u_char *des_key /* OUT 64 bit DES key with parity bits added */) +{ +  des_key[0] = Get7Bits(key,  0); +  des_key[1] = Get7Bits(key,  7); +  des_key[2] = Get7Bits(key, 14); +  des_key[3] = Get7Bits(key, 21); +  des_key[4] = Get7Bits(key, 28); +  des_key[5] = Get7Bits(key, 35); +  des_key[6] = Get7Bits(key, 42); +  des_key[7] = Get7Bits(key, 49); +   +#ifndef USE_CRYPT +  des_set_odd_parity((des_cblock *)des_key); +#endif +   +#if 0 +  CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n", +             key[0], key[1], key[2], key[3], key[4], key[5], key[6])); +  CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n", +             des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); +#endif +} + +static void +ChapMS_NT( char *rchallenge, +           int rchallenge_len, +           char *secret, +           int secret_len, +           MS_ChapResponse *response) +{ +  int      i; +  MDstruct  md4Context; +  u_char    unicodePassword[MAX_NT_PASSWORD * 2]; +  static int  low_byte_first = -1; + +  /* Initialize the Unicode version of the secret (== password). */ +  /* This implicitly supports 8-bit ISO8859/1 characters. */ +  BZERO(unicodePassword, sizeof(unicodePassword)); +  for (i = 0; i < secret_len; i++) { +    unicodePassword[i * 2] = (u_char)secret[i]; +  } +  MDbegin(&md4Context); +  MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */ + +  if (low_byte_first == -1) { +    low_byte_first = (htons((unsigned short int)1) != 1); +  } +  if (low_byte_first == 0) { +    MDreverse((u_long *)&md4Context);  /*  sfb 961105 */ +  } + +  MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */ + +  ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp); +} + +#ifdef MSLANMAN +static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */ + +static void +ChapMS_LANMan( char *rchallenge, +               int rchallenge_len, +               char *secret, +               int secret_len, +               MS_ChapResponse  *response) +{ +  int      i; +  u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */ +  u_char    PasswordHash[16]; +   +  /* LANMan password is case insensitive */ +  BZERO(UcasePassword, sizeof(UcasePassword)); +  for (i = 0; i < secret_len; i++) { +    UcasePassword[i] = (u_char)toupper(secret[i]); +  } +  DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 ); +  DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 ); +  ChallengeResponse(rchallenge, PasswordHash, response->LANManResp); +} +#endif + +#endif /* MSCHAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.h new file mode 100644 index 000000000..df070fb35 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/chpms.h @@ -0,0 +1,64 @@ +/***************************************************************************** +* chpms.h - Network Microsoft Challenge Handshake Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original built from BSD network code. +******************************************************************************/ +/* + * chap.h - Challenge Handshake Authentication Protocol definitions. + * + * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited. + * http://www.strataware.com/ + * + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Eric Rosenquist.  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 ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef CHPMS_H +#define CHPMS_H + +#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */ + +void ChapMS (chap_state *, char *, int, char *, int); + +#endif /* CHPMS_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.c new file mode 100644 index 000000000..c073f1e36 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.c @@ -0,0 +1,906 @@ +/***************************************************************************** +* fsm.c - Network Control Protocol Finite State Machine program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD fsm.c. +*****************************************************************************/ +/* + * fsm.c - {Link, IP} Control Protocol Finite State Machine. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +/* + * TODO: + * Randomize fsm id on link/init. + * Deal with variable outgoing MTU. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +#if PPP_DEBUG + +static const char *ppperr_strerr[] = { +           "LS_INITIAL",  /* LS_INITIAL  0 */ +           "LS_STARTING", /* LS_STARTING 1 */ +           "LS_CLOSED",   /* LS_CLOSED   2 */ +           "LS_STOPPED",  /* LS_STOPPED  3 */ +           "LS_CLOSING",  /* LS_CLOSING  4 */ +           "LS_STOPPING", /* LS_STOPPING 5 */ +           "LS_REQSENT",  /* LS_REQSENT  6 */ +           "LS_ACKRCVD",  /* LS_ACKRCVD  7 */ +           "LS_ACKSENT",  /* LS_ACKSENT  8 */ +           "LS_OPENED"    /* LS_OPENED   9 */ +}; + +#endif /* PPP_DEBUG */ + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +static void fsm_timeout (void *); +static void fsm_rconfreq (fsm *, u_char, u_char *, int); +static void fsm_rconfack (fsm *, int, u_char *, int); +static void fsm_rconfnakrej (fsm *, int, int, u_char *, int); +static void fsm_rtermreq (fsm *, int, u_char *, int); +static void fsm_rtermack (fsm *); +static void fsm_rcoderej (fsm *, u_char *, int); +static void fsm_sconfreq (fsm *, int); + +#define PROTO_NAME(f) ((f)->callbacks->proto_name) + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +int peer_mru[NUM_PPP]; + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ + +/* + * fsm_init - Initialize fsm. + * + * Initialize fsm state. + */ +void +fsm_init(fsm *f) +{ +  f->state = LS_INITIAL; +  f->flags = 0; +  f->id = 0;        /* XXX Start with random id? */ +  f->timeouttime = FSM_DEFTIMEOUT; +  f->maxconfreqtransmits = FSM_DEFMAXCONFREQS; +  f->maxtermtransmits = FSM_DEFMAXTERMREQS; +  f->maxnakloops = FSM_DEFMAXNAKLOOPS; +  f->term_reason_len = 0; +} + + +/* + * fsm_lowerup - The lower layer is up. + */ +void +fsm_lowerup(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_INITIAL: +      f->state = LS_CLOSED; +      break; + +    case LS_STARTING: +      if( f->flags & OPT_SILENT ) { +        f->state = LS_STOPPED; +      } else { +        /* Send an initial configure-request */ +        fsm_sconfreq(f, 0); +        f->state = LS_REQSENT; +      } +    break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } +   +  FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_lowerdown - The lower layer is down. + * + * Cancel all timeouts and inform upper layers. + */ +void +fsm_lowerdown(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_CLOSED: +      f->state = LS_INITIAL; +      break; + +    case LS_STOPPED: +      f->state = LS_STARTING; +      if( f->callbacks->starting ) { +        (*f->callbacks->starting)(f); +      } +      break; + +    case LS_CLOSING: +      f->state = LS_INITIAL; +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      break; + +    case LS_STOPPING: +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      f->state = LS_STARTING; +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      break; + +    case LS_OPENED: +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f); +      } +      f->state = LS_STARTING; +      break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } + +  FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_open - Link is allowed to come up. + */ +void +fsm_open(fsm *f) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  switch( f->state ) { +    case LS_INITIAL: +      f->state = LS_STARTING; +      if( f->callbacks->starting ) { +        (*f->callbacks->starting)(f); +      } +      break; + +    case LS_CLOSED: +      if( f->flags & OPT_SILENT ) { +        f->state = LS_STOPPED; +      } else { +        /* Send an initial configure-request */ +        fsm_sconfreq(f, 0); +        f->state = LS_REQSENT; +      } +      break; +   +    case LS_CLOSING: +      f->state = LS_STOPPING; +      /* fall through */ +    case LS_STOPPED: +    case LS_OPENED: +      if( f->flags & OPT_RESTART ) { +        fsm_lowerdown(f); +        fsm_lowerup(f); +      } +      break; +  } + +  FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_close - Start closing connection. + * + * Cancel timeouts and either initiate close or possibly go directly to + * the LS_CLOSED state. + */ +void +fsm_close(fsm *f, char *reason) +{ +  int oldState = f->state; + +  LWIP_UNUSED_ARG(oldState); + +  f->term_reason = reason; +  f->term_reason_len = (reason == NULL? 0: strlen(reason)); +  switch( f->state ) { +    case LS_STARTING: +      f->state = LS_INITIAL; +      break; +    case LS_STOPPED: +      f->state = LS_CLOSED; +      break; +    case LS_STOPPING: +      f->state = LS_CLOSING; +      break; + +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +    case LS_OPENED: +      if( f->state != LS_OPENED ) { +        UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      } else if( f->callbacks->down ) { +        (*f->callbacks->down)(f);  /* Inform upper layers we're down */ +      } +      /* Init restart counter, send Terminate-Request */ +      f->retransmits = f->maxtermtransmits; +      fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      --f->retransmits; + +      f->state = LS_CLOSING; +      break; +  } + +  FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n", +      PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); +} + + +/* + * fsm_sdata - Send some data. + * + * Used for all packets sent to our peer by this module. + */ +void +fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen) +{ +  u_char *outp; +  int outlen; + +  /* Adjust length to be smaller than MTU */ +  outp = outpacket_buf[f->unit]; +  if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { +    datalen = peer_mru[f->unit] - HEADERLEN; +  } +  if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { +    BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); +  } +  outlen = datalen + HEADERLEN; +  MAKEHEADER(outp, f->protocol); +  PUTCHAR(code, outp); +  PUTCHAR(id, outp); +  PUTSHORT(outlen, outp); +  pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); +  FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n", +        PROTO_NAME(f), code, id, outlen)); +} + + +/* + * fsm_input - Input packet. + */ +void +fsm_input(fsm *f, u_char *inpacket, int l) +{ +  u_char *inp = inpacket; +  u_char code, id; +  int len; + +  /* +  * Parse header (code, id and length). +  * If packet too short, drop it. +  */ +  if (l < HEADERLEN) { +    FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n", +          f->protocol)); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < HEADERLEN) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n", +        f->protocol)); +    return; +  } +  if (len > l) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n", +        f->protocol)); +    return; +  } +  len -= HEADERLEN;    /* subtract header length */ + +  if( f->state == LS_INITIAL || f->state == LS_STARTING ) { +    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n", +        f->protocol, f->state, ppperr_strerr[f->state])); +    return; +  } +  FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); +  /* +   * Action depends on code. +   */ +  switch (code) { +    case CONFREQ: +      fsm_rconfreq(f, id, inp, len); +      break; +     +    case CONFACK: +      fsm_rconfack(f, id, inp, len); +      break; +     +    case CONFNAK: +    case CONFREJ: +      fsm_rconfnakrej(f, code, id, inp, len); +      break; +     +    case TERMREQ: +      fsm_rtermreq(f, id, inp, len); +      break; +     +    case TERMACK: +      fsm_rtermack(f); +      break; +     +    case CODEREJ: +      fsm_rcoderej(f, inp, len); +      break; +     +    default: +      if( !f->callbacks->extcode || +          !(*f->callbacks->extcode)(f, code, id, inp, len) ) { +        fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); +      } +      break; +  } +} + + +/* + * fsm_protreject - Peer doesn't speak this protocol. + * + * Treat this as a catastrophic error (RXJ-). + */ +void +fsm_protreject(fsm *f) +{ +  switch( f->state ) { +    case LS_CLOSING: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      /* fall through */ +    case LS_CLOSED: +      f->state = LS_CLOSED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; + +    case LS_STOPPING: +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      /* fall through */ +    case LS_STOPPED: +      f->state = LS_STOPPED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; +     +    case LS_OPENED: +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f); +      } +      /* Init restart counter, send Terminate-Request */ +      f->retransmits = f->maxtermtransmits; +      fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      --f->retransmits; +       +      f->state = LS_STOPPING; +      break; +     +    default: +      FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n", +            PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +    } +} + + + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +/* + * fsm_timeout - Timeout expired. + */ +static void +fsm_timeout(void *arg) +{ +  fsm *f = (fsm *) arg; + +  switch (f->state) { +    case LS_CLOSING: +    case LS_STOPPING: +      if( f->retransmits <= 0 ) { +        FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n", +             PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* +         * We've waited for an ack long enough.  Peer probably heard us. +         */ +        f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED; +        if( f->callbacks->finished ) { +          (*f->callbacks->finished)(f); +        } +      } else { +        FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n", +             PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* Send Terminate-Request */ +        fsm_sdata(f, TERMREQ, f->reqid = ++f->id, +            (u_char *) f->term_reason, f->term_reason_len); +        TIMEOUT(fsm_timeout, f, f->timeouttime); +        --f->retransmits; +      } +      break; + +    case LS_REQSENT: +    case LS_ACKRCVD: +    case LS_ACKSENT: +      if (f->retransmits <= 0) { +        FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n", +         PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        f->state = LS_STOPPED; +        if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) { +          (*f->callbacks->finished)(f); +        } +      } else { +        FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n", +         PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +        /* Retransmit the configure-request */ +        if (f->callbacks->retransmit) { +          (*f->callbacks->retransmit)(f); +        } +        fsm_sconfreq(f, 1);    /* Re-send Configure-Request */ +        if( f->state == LS_ACKRCVD ) { +          f->state = LS_REQSENT; +        } +      } +      break; + +    default: +      FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n", +          PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +  } +} + + +/* + * fsm_rconfreq - Receive Configure-Request. + */ +static void +fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) +{ +  int code, reject_if_disagree; + +  FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n",  +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); +  switch( f->state ) { +    case LS_CLOSED: +      /* Go away, we're closed */ +      fsm_sdata(f, TERMACK, id, NULL, 0); +      return; +    case LS_CLOSING: +    case LS_STOPPING: +      return; + +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if( f->callbacks->down ) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      break; + +    case LS_STOPPED: +      /* Negotiation started by our peer */ +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +   +  /* +  * Pass the requested configuration options +  * to protocol-specific code for checking. +  */ +  if (f->callbacks->reqci) {    /* Check CI */ +    reject_if_disagree = (f->nakloops >= f->maxnakloops); +    code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree); +  } else if (len) { +    code = CONFREJ;      /* Reject all CI */ +  } else { +    code = CONFACK; +  } +   +  /* send the Ack, Nak or Rej to the peer */ +  fsm_sdata(f, (u_char)code, id, inp, len); +   +  if (code == CONFACK) { +    if (f->state == LS_ACKRCVD) { +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      f->state = LS_OPENED; +      if (f->callbacks->up) { +        (*f->callbacks->up)(f);  /* Inform upper layers */ +      } +    } else { +      f->state = LS_ACKSENT; +    } +    f->nakloops = 0; +  } else { +    /* we sent CONFACK or CONFREJ */ +    if (f->state != LS_ACKRCVD) { +      f->state = LS_REQSENT; +    } +    if( code == CONFNAK ) { +      ++f->nakloops; +    } +  } +} + + +/* + * fsm_rconfack - Receive Configure-Ack. + */ +static void +fsm_rconfack(fsm *f, int id, u_char *inp, int len) +{ +  FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); +   +  if (id != f->reqid || f->seen_ack) {   /* Expected id? */ +    return; /* Nope, toss... */ +  } +  if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) { +    /* Ack is bad - ignore it */ +    FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n", +          PROTO_NAME(f), len)); +    return; +  } +  f->seen_ack = 1; +   +  switch (f->state) { +    case LS_CLOSED: +    case LS_STOPPED: +      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +      break; +     +    case LS_REQSENT: +      f->state = LS_ACKRCVD; +      f->retransmits = f->maxconfreqtransmits; +      break; +     +    case LS_ACKRCVD: +      /* Huh? an extra valid Ack? oh well... */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      fsm_sconfreq(f, 0); +      f->state = LS_REQSENT; +      break; +     +    case LS_ACKSENT: +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      f->state = LS_OPENED; +      f->retransmits = f->maxconfreqtransmits; +      if (f->callbacks->up) { +        (*f->callbacks->up)(f);  /* Inform upper layers */ +      } +      break; +     +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +} + + +/* + * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject. + */ +static void +fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) +{ +  int (*proc) (fsm *, u_char *, int); +  int ret; + +  FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + +  if (id != f->reqid || f->seen_ack) { /* Expected id? */ +    return;        /* Nope, toss... */ +  } +  proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; +  if (!proc || !((ret = proc(f, inp, len)))) { +    /* Nak/reject is bad - ignore it */ +    FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n", +          PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); +    return; +  } +  f->seen_ack = 1; + +  switch (f->state) { +    case LS_CLOSED: +    case LS_STOPPED: +      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +      break; +     +    case LS_REQSENT: +    case LS_ACKSENT: +      /* They didn't agree to what we wanted - try another request */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      if (ret < 0) { +        f->state = LS_STOPPED;    /* kludge for stopping CCP */ +      } else { +        fsm_sconfreq(f, 0);    /* Send Configure-Request */ +      } +      break; +     +    case LS_ACKRCVD: +      /* Got a Nak/reject when we had already had an Ack?? oh well... */ +      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */ +      fsm_sconfreq(f, 0); +      f->state = LS_REQSENT; +      break; +     +    case LS_OPENED: +      /* Go down and restart negotiation */ +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */ +      f->state = LS_REQSENT; +      break; +  } +} + + +/* + * fsm_rtermreq - Receive Terminate-Req. + */ +static void +fsm_rtermreq(fsm *f, int id, u_char *p, int len) +{ +  LWIP_UNUSED_ARG(p); + +  FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n", +        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); + +  switch (f->state) { +    case LS_ACKRCVD: +    case LS_ACKSENT: +      f->state = LS_REQSENT;    /* Start over but keep trying */ +      break; + +    case LS_OPENED: +      if (len > 0) { +        FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p)); +      } else { +        FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f))); +      } +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      f->retransmits = 0; +      f->state = LS_STOPPING; +      TIMEOUT(fsm_timeout, f, f->timeouttime); +      break; +  } + +  fsm_sdata(f, TERMACK, (u_char)id, NULL, 0); +} + + +/* + * fsm_rtermack - Receive Terminate-Ack. + */ +static void +fsm_rtermack(fsm *f) +{ +  FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n",  +        PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +   +  switch (f->state) { +    case LS_CLOSING: +      UNTIMEOUT(fsm_timeout, f); +      f->state = LS_CLOSED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; + +    case LS_STOPPING: +      UNTIMEOUT(fsm_timeout, f); +      f->state = LS_STOPPED; +      if( f->callbacks->finished ) { +        (*f->callbacks->finished)(f); +      } +      break; +     +    case LS_ACKRCVD: +      f->state = LS_REQSENT; +      break; +     +    case LS_OPENED: +      if (f->callbacks->down) { +        (*f->callbacks->down)(f);  /* Inform upper layers */ +      } +      fsm_sconfreq(f, 0); +      break; +  } +} + + +/* + * fsm_rcoderej - Receive an Code-Reject. + */ +static void +fsm_rcoderej(fsm *f, u_char *inp, int len) +{ +  u_char code, id; +   +  FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n",  +        PROTO_NAME(f), f->state, ppperr_strerr[f->state])); +   +  if (len < HEADERLEN) { +    FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n", +        PROTO_NAME(f), code, id)); +   +  if( f->state == LS_ACKRCVD ) { +    f->state = LS_REQSENT; +  } +} + + +/* + * fsm_sconfreq - Send a Configure-Request. + */ +static void +fsm_sconfreq(fsm *f, int retransmit) +{ +  u_char *outp; +  int cilen; +   +  if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) { +    /* Not currently negotiating - reset options */ +    if( f->callbacks->resetci ) { +      (*f->callbacks->resetci)(f); +    } +    f->nakloops = 0; +  } +   +  if( !retransmit ) { +    /* New request - reset retransmission counter, use new ID */ +    f->retransmits = f->maxconfreqtransmits; +    f->reqid = ++f->id; +  } +   +  f->seen_ack = 0; +   +  /* +   * Make up the request packet +   */ +  outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN; +  if( f->callbacks->cilen && f->callbacks->addci ) { +    cilen = (*f->callbacks->cilen)(f); +    if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) { +      cilen = peer_mru[f->unit] - HEADERLEN; +    } +    if (f->callbacks->addci) { +      (*f->callbacks->addci)(f, outp, &cilen); +    } +  } else { +    cilen = 0; +  } + +  /* send the request to our peer */ +  fsm_sdata(f, CONFREQ, f->reqid, outp, cilen); +   +  /* start the retransmit timer */ +  --f->retransmits; +  TIMEOUT(fsm_timeout, f, f->timeouttime); +   +  FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n", +        PROTO_NAME(f), f->reqid)); +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.h new file mode 100644 index 000000000..14034ec7f --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/fsm.h @@ -0,0 +1,169 @@ +/***************************************************************************** +* fsm.h - Network Control Protocol Finite State Machine header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original based on BSD code. +*****************************************************************************/ +/* + * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef FSM_H +#define FSM_H + +/***************************************************************************** +************************* PUBLIC DEFINITIONS ********************************* +*****************************************************************************/ +/* + * LCP Packet header = Code, id, length. + */ +#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + *  CP (LCP, IPCP, etc.) codes. + */ +#define CONFREQ     1 /* Configuration Request */ +#define CONFACK     2 /* Configuration Ack */ +#define CONFNAK     3 /* Configuration Nak */ +#define CONFREJ     4 /* Configuration Reject */ +#define TERMREQ     5 /* Termination Request */ +#define TERMACK     6 /* Termination Ack */ +#define CODEREJ     7 /* Code Reject */ + +/* + * Link states. + */ +#define LS_INITIAL  0 /* Down, hasn't been opened */ +#define LS_STARTING 1 /* Down, been opened */ +#define LS_CLOSED   2 /* Up, hasn't been opened */ +#define LS_STOPPED  3 /* Open, waiting for down event */ +#define LS_CLOSING  4 /* Terminating the connection, not open */ +#define LS_STOPPING 5 /* Terminating, but open */ +#define LS_REQSENT  6 /* We've sent a Config Request */ +#define LS_ACKRCVD  7 /* We've received a Config Ack */ +#define LS_ACKSENT  8 /* We've sent a Config Ack */ +#define LS_OPENED   9 /* Connection available */ + +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT  4 /* Wait for peer to speak first */ + + +/***************************************************************************** +************************* PUBLIC DATA TYPES ********************************** +*****************************************************************************/ +/* + * Each FSM is described by an fsm structure and fsm callbacks. + */ +typedef struct fsm { +  int unit;                        /* Interface unit number */ +  u_short protocol;                /* Data Link Layer Protocol field value */ +  int state;                       /* State */ +  int flags;                       /* Contains option bits */ +  u_char id;                       /* Current id */ +  u_char reqid;                    /* Current request id */ +  u_char seen_ack;                 /* Have received valid Ack/Nak/Rej to Req */ +  int timeouttime;                 /* Timeout time in milliseconds */ +  int maxconfreqtransmits;         /* Maximum Configure-Request transmissions */ +  int retransmits;                 /* Number of retransmissions left */ +  int maxtermtransmits;            /* Maximum Terminate-Request transmissions */ +  int nakloops;                    /* Number of nak loops since last ack */ +  int maxnakloops;                 /* Maximum number of nak loops tolerated */ +  struct fsm_callbacks* callbacks; /* Callback routines */ +  char* term_reason;               /* Reason for closing protocol */ +  int term_reason_len;             /* Length of term_reason */ +} fsm; + + +typedef struct fsm_callbacks { +  void (*resetci)(fsm*);                            /* Reset our Configuration Information */ +  int  (*cilen)(fsm*);                              /* Length of our Configuration Information */ +  void (*addci)(fsm*, u_char*, int*);               /* Add our Configuration Information */ +  int  (*ackci)(fsm*, u_char*, int);                /* ACK our Configuration Information */ +  int  (*nakci)(fsm*, u_char*, int);                /* NAK our Configuration Information */ +  int  (*rejci)(fsm*, u_char*, int);                /* Reject our Configuration Information */ +  int  (*reqci)(fsm*, u_char*, int*, int);          /* Request peer's Configuration Information */ +  void (*up)(fsm*);                                 /* Called when fsm reaches LS_OPENED state */ +  void (*down)(fsm*);                               /* Called when fsm leaves LS_OPENED state */ +  void (*starting)(fsm*);                           /* Called when we want the lower layer */ +  void (*finished)(fsm*);                           /* Called when we don't want the lower layer */ +  void (*protreject)(int);                          /* Called when Protocol-Reject received */ +  void (*retransmit)(fsm*);                         /* Retransmission is necessary */ +  int  (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */ +  char *proto_name;                                 /* String name for protocol (for messages) */ +} fsm_callbacks; + + +/***************************************************************************** +*********************** PUBLIC DATA STRUCTURES ******************************* +*****************************************************************************/ +/* + * Variables + */ +extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ + + +/***************************************************************************** +************************** PUBLIC FUNCTIONS ********************************** +*****************************************************************************/ + +/* + * Prototypes + */ +void fsm_init (fsm*); +void fsm_lowerup (fsm*); +void fsm_lowerdown (fsm*); +void fsm_open (fsm*); +void fsm_close (fsm*, char*); +void fsm_input (fsm*, u_char*, int); +void fsm_protreject (fsm*); +void fsm_sdata (fsm*, u_char, u_char, u_char*, int); + +#endif /* FSM_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c new file mode 100644 index 000000000..3a403a0a6 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.c @@ -0,0 +1,1440 @@ +/***************************************************************************** +* ipcp.c - Network PPP IP Control Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ +/* + * ipcp.c - PPP IP Control Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "auth.h" +#include "fsm.h" +#include "vj.h" +#include "ipcp.h" + +#include <string.h> + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ +/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */ + +/* + * Lengths of configuration options. + */ +#define CILEN_VOID     2 +#define CILEN_COMPRESS 4  /* min length for compression protocol opt. */ +#define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */ +#define CILEN_ADDR     6  /* new-style single address option */ +#define CILEN_ADDRS    10 /* old-style dual address option */ + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Callbacks for fsm code.  (CI = Configuration Information) + */ +static void ipcp_resetci (fsm *);                     /* Reset our CI */ +static int  ipcp_cilen (fsm *);                       /* Return length of our CI */ +static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */ +static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */ +static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */ +static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */ +static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */ +static void ipcp_up (fsm *);                          /* We're UP */ +static void ipcp_down (fsm *);                        /* We're DOWN */ +#if 0 +static void ipcp_script (fsm *, char *); /* Run an up/down script */ +#endif +static void ipcp_finished (fsm *);                    /* Don't need lower layer */ + +/* + * Protocol entry points from main code. + */ +static void ipcp_init (int); +static void ipcp_open (int); +static void ipcp_close (int, char *); +static void ipcp_lowerup (int); +static void ipcp_lowerdown (int); +static void ipcp_input (int, u_char *, int); +static void ipcp_protrej (int); + +static void ipcp_clear_addrs (int); + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ +                     (x) == CONFNAK ? "NAK" : "REJ") + + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +/* global vars */ +ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */ + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ + +struct protent ipcp_protent = { +  PPP_IPCP, +  ipcp_init, +  ipcp_input, +  ipcp_protrej, +  ipcp_lowerup, +  ipcp_lowerdown, +  ipcp_open, +  ipcp_close, +#if 0 +  ipcp_printpkt, +  NULL, +#endif +  1, +  "IPCP", +#if 0 +  ip_check_options, +  NULL, +  ip_active_pkt +#endif +}; + + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +/* local vars */ +static int cis_received[NUM_PPP];      /* # Conf-Reqs received */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ + +static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ +  ipcp_resetci,  /* Reset our Configuration Information */ +  ipcp_cilen,    /* Length of our Configuration Information */ +  ipcp_addci,    /* Add our Configuration Information */ +  ipcp_ackci,    /* ACK our Configuration Information */ +  ipcp_nakci,    /* NAK our Configuration Information */ +  ipcp_rejci,    /* Reject our Configuration Information */ +  ipcp_reqci,    /* Request peer's Configuration Information */ +  ipcp_up,       /* Called when fsm reaches LS_OPENED state */ +  ipcp_down,     /* Called when fsm leaves LS_OPENED state */ +  NULL,          /* Called when we want the lower layer up */ +  ipcp_finished, /* Called when we want the lower layer down */ +  NULL,          /* Called when Protocol-Reject received */ +  NULL,          /* Retransmission is necessary */ +  NULL,          /* Called to handle protocol-specific codes */ +  "IPCP"         /* String name of protocol */ +}; + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +/* + * Non-standard inet_ntoa left here for compat with original ppp + * sources. Assumes u32_t instead of struct in_addr. + */  + +char * +_inet_ntoa(u32_t n) +{ +  struct in_addr ia; +  ia.s_addr = n; +  return inet_ntoa(ia); +} + +#define inet_ntoa _inet_ntoa + +/* + * ipcp_init - Initialize IPCP. + */ +static void +ipcp_init(int unit) +{ +  fsm           *f = &ipcp_fsm[unit]; +  ipcp_options *wo = &ipcp_wantoptions[unit]; +  ipcp_options *ao = &ipcp_allowoptions[unit]; + +  f->unit      = unit; +  f->protocol  = PPP_IPCP; +  f->callbacks = &ipcp_callbacks; +  fsm_init(&ipcp_fsm[unit]); + +  memset(wo, 0, sizeof(*wo)); +  memset(ao, 0, sizeof(*ao)); + +  wo->neg_addr      = 1; +  wo->ouraddr       = 0; +#if VJ_SUPPORT +  wo->neg_vj        = 1; +#else  /* VJ_SUPPORT */ +  wo->neg_vj        = 0; +#endif /* VJ_SUPPORT */ +  wo->vj_protocol   = IPCP_VJ_COMP; +  wo->maxslotindex  = MAX_SLOTS - 1; +  wo->cflag         = 0; +  wo->default_route = 1; + +  ao->neg_addr      = 1; +#if VJ_SUPPORT +  ao->neg_vj        = 1; +#else  /* VJ_SUPPORT */ +  ao->neg_vj        = 0; +#endif /* VJ_SUPPORT */ +  ao->maxslotindex  = MAX_SLOTS - 1; +  ao->cflag         = 1; +  ao->default_route = 1; +} + + +/* + * ipcp_open - IPCP is allowed to come up. + */ +static void +ipcp_open(int unit) +{ +  fsm_open(&ipcp_fsm[unit]); +} + + +/* + * ipcp_close - Take IPCP down. + */ +static void +ipcp_close(int unit, char *reason) +{ +  fsm_close(&ipcp_fsm[unit], reason); +} + + +/* + * ipcp_lowerup - The lower layer is up. + */ +static void +ipcp_lowerup(int unit) +{ +  fsm_lowerup(&ipcp_fsm[unit]); +} + + +/* + * ipcp_lowerdown - The lower layer is down. + */ +static void +ipcp_lowerdown(int unit) +{ +  fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_input - Input IPCP packet. + */ +static void +ipcp_input(int unit, u_char *p, int len) +{ +  fsm_input(&ipcp_fsm[unit], p, len); +} + + +/* + * ipcp_protrej - A Protocol-Reject was received for IPCP. + * + * Pretend the lower layer went down, so we shut up. + */ +static void +ipcp_protrej(int unit) +{ +  fsm_lowerdown(&ipcp_fsm[unit]); +} + + +/* + * ipcp_resetci - Reset our CI. + */ +static void +ipcp_resetci(fsm *f) +{ +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +   +  wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr; +  if (wo->ouraddr == 0) { +    wo->accept_local = 1; +  } +  if (wo->hisaddr == 0) { +    wo->accept_remote = 1; +  } +  /* Request DNS addresses from the peer */ +  wo->req_dns1 = ppp_settings.usepeerdns; +  wo->req_dns2 = ppp_settings.usepeerdns; +  ipcp_gotoptions[f->unit] = *wo; +  cis_received[f->unit] = 0; +} + + +/* + * ipcp_cilen - Return length of our CI. + */ +static int +ipcp_cilen(fsm *f) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; + +#define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0) +#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0) +#define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0) + +  /* +   * First see if we want to change our options to the old +   * forms because we have received old forms from the peer. +   */ +  if (wo->neg_addr && !go->neg_addr && !go->old_addrs) { +    /* use the old style of address negotiation */ +    go->neg_addr = 1; +    go->old_addrs = 1; +  } +  if (wo->neg_vj && !go->neg_vj && !go->old_vj) { +    /* try an older style of VJ negotiation */ +    if (cis_received[f->unit] == 0) { +      /* keep trying the new style until we see some CI from the peer */ +      go->neg_vj = 1; +    } else { +      /* use the old style only if the peer did */ +      if (ho->neg_vj && ho->old_vj) { +        go->neg_vj = 1; +        go->old_vj = 1; +        go->vj_protocol = ho->vj_protocol; +      } +    } +  } + +  return (LENCIADDR(go->neg_addr, go->old_addrs) + +          LENCIVJ(go->neg_vj, go->old_vj) + +          LENCIDNS(go->req_dns1) + +          LENCIDNS(go->req_dns2)); +} + + +/* + * ipcp_addci - Add our desired CIs to a packet. + */ +static void +ipcp_addci(fsm *f, u_char *ucp, int *lenp) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  int len = *lenp; + +#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \ +  if (neg) { \ +    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ +    if (len >= vjlen) { \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(vjlen, ucp); \ +      PUTSHORT(val, ucp); \ +      if (!old) { \ +        PUTCHAR(maxslotindex, ucp); \ +        PUTCHAR(cflag, ucp); \ +      } \ +      len -= vjlen; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +#define ADDCIADDR(opt, neg, old, val1, val2) \ +  if (neg) { \ +    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ +    if (len >= addrlen) { \ +      u32_t l; \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(addrlen, ucp); \ +      l = ntohl(val1); \ +      PUTLONG(l, ucp); \ +      if (old) { \ +        l = ntohl(val2); \ +        PUTLONG(l, ucp); \ +      } \ +      len -= addrlen; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +#define ADDCIDNS(opt, neg, addr) \ +  if (neg) { \ +    if (len >= CILEN_ADDR) { \ +      u32_t l; \ +      PUTCHAR(opt, ucp); \ +      PUTCHAR(CILEN_ADDR, ucp); \ +      l = ntohl(addr); \ +      PUTLONG(l, ucp); \ +      len -= CILEN_ADDR; \ +    } else { \ +      neg = 0; \ +    } \ +  } + +  ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, +      go->old_addrs, go->ouraddr, go->hisaddr); + +  ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + +  ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + +  *lenp -= len; +} + + +/* + * ipcp_ackci - Ack our CIs. + * + * Returns: + *  0 - Ack was bad. + *  1 - Ack was good. + */ +static int +ipcp_ackci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_short cilen, citype, cishort; +  u32_t cilong; +  u_char cimaxslotindex, cicflag; + +  /* +   * CIs must be in exactly the same order that we sent... +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ + +#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \ +  if (neg) { \ +    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \ +    if ((len -= vjlen) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != vjlen || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETSHORT(cishort, p); \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    if (!old) { \ +      GETCHAR(cimaxslotindex, p); \ +      if (cimaxslotindex != maxslotindex) { \ +        goto bad; \ +      } \ +      GETCHAR(cicflag, p); \ +      if (cicflag != cflag) { \ +        goto bad; \ +      } \ +    } \ +  } +   +#define ACKCIADDR(opt, neg, old, val1, val2) \ +  if (neg) { \ +    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \ +    u32_t l; \ +    if ((len -= addrlen) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != addrlen || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    if (val1 != cilong) { \ +      goto bad; \ +    } \ +    if (old) { \ +      GETLONG(l, p); \ +      cilong = htonl(l); \ +      if (val2 != cilong) { \ +        goto bad; \ +      } \ +    } \ +  } + +#define ACKCIDNS(opt, neg, addr) \ +  if (neg) { \ +    u32_t l; \ +    if ((len -= CILEN_ADDR) < 0) { \ +      goto bad; \ +    } \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_ADDR || \ +        citype != opt) { \ +      goto bad; \ +    } \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    if (addr != cilong) { \ +      goto bad; \ +    } \ +  } + +  ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr, +        go->old_addrs, go->ouraddr, go->hisaddr); + +  ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]); + +  ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  return (1); +   +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n")); +  return (0); +} + +/* + * ipcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if IPCP is in the LS_OPENED state. + * + * Returns: + *  0 - Nak was bad. + *  1 - Nak was good. + */ +static int +ipcp_nakci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_char cimaxslotindex, cicflag; +  u_char citype, cilen, *next; +  u_short cishort; +  u32_t ciaddr1, ciaddr2, l, cidnsaddr; +  ipcp_options no;    /* options we've seen Naks for */ +  ipcp_options try;    /* options to request next time */ + +  BZERO(&no, sizeof(no)); +  try = *go; + +  /* +   * Any Nak'd CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define NAKCIADDR(opt, neg, old, code) \ +  if (go->neg && \ +      len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \ +      p[1] == cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    ciaddr1 = htonl(l); \ +    if (old) { \ +      GETLONG(l, p); \ +      ciaddr2 = htonl(l); \ +      no.old_addrs = 1; \ +    } else { \ +      ciaddr2 = 0; \ +    } \ +    no.neg = 1; \ +    code \ +  } + +#define NAKCIVJ(opt, neg, code) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    no.neg = 1; \ +    code \ +  } +   +#define NAKCIDNS(opt, neg, code) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_ADDR) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cidnsaddr = htonl(l); \ +    no.neg = 1; \ +    code \ +  } + +  /* +   * Accept the peer's idea of {our,his} address, if different +   * from our idea, only if the accept_{local,remote} flag is set. +   */ +  NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, +    if (go->accept_local && ciaddr1) { /* Do we know our address? */ +      try.ouraddr = ciaddr1; +      IPCPDEBUG((LOG_INFO, "local IP address %s\n", +           inet_ntoa(ciaddr1))); +    } +    if (go->accept_remote && ciaddr2) { /* Does he know his? */ +      try.hisaddr = ciaddr2; +      IPCPDEBUG((LOG_INFO, "remote IP address %s\n", +           inet_ntoa(ciaddr2))); +    } +  ); + +  /* +   * Accept the peer's value of maxslotindex provided that it +   * is less than what we asked for.  Turn off slot-ID compression +   * if the peer wants.  Send old-style compress-type option if +   * the peer wants. +   */ +  NAKCIVJ(CI_COMPRESSTYPE, neg_vj, +    if (cilen == CILEN_VJ) { +      GETCHAR(cimaxslotindex, p); +      GETCHAR(cicflag, p); +      if (cishort == IPCP_VJ_COMP) { +        try.old_vj = 0; +        if (cimaxslotindex < go->maxslotindex) { +          try.maxslotindex = cimaxslotindex; +        } +        if (!cicflag) { +          try.cflag = 0; +        } +      } else { +        try.neg_vj = 0; +      } +    } else { +      if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) { +        try.old_vj = 1; +        try.vj_protocol = cishort; +      } else { +        try.neg_vj = 0; +      } +    } +  ); + +  NAKCIDNS(CI_MS_DNS1, req_dns1, +      try.dnsaddr[0] = cidnsaddr; +        IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr))); +      ); + +  NAKCIDNS(CI_MS_DNS2, req_dns2, +      try.dnsaddr[1] = cidnsaddr; +        IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr))); +      ); + +  /* +  * There may be remaining CIs, if the peer is requesting negotiation +  * on an option that we didn't include in our request packet. +  * If they want to negotiate about IP addresses, we comply. +  * If they want us to ask for compression, we refuse. +  */ +  while (len > CILEN_VOID) { +    GETCHAR(citype, p); +    GETCHAR(cilen, p); +    if( (len -= cilen) < 0 ) { +      goto bad; +    } +    next = p + cilen - 2; + +    switch (citype) { +      case CI_COMPRESSTYPE: +        if (go->neg_vj || no.neg_vj || +            (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) { +          goto bad; +        } +        no.neg_vj = 1; +        break; +      case CI_ADDRS: +        if ((go->neg_addr && go->old_addrs) || no.old_addrs +            || cilen != CILEN_ADDRS) { +          goto bad; +        } +        try.neg_addr = 1; +        try.old_addrs = 1; +        GETLONG(l, p); +        ciaddr1 = htonl(l); +        if (ciaddr1 && go->accept_local) { +          try.ouraddr = ciaddr1; +        } +        GETLONG(l, p); +        ciaddr2 = htonl(l); +        if (ciaddr2 && go->accept_remote) { +          try.hisaddr = ciaddr2; +        } +        no.old_addrs = 1; +        break; +      case CI_ADDR: +        if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) { +          goto bad; +        } +        try.old_addrs = 0; +        GETLONG(l, p); +        ciaddr1 = htonl(l); +        if (ciaddr1 && go->accept_local) { +          try.ouraddr = ciaddr1; +        } +        if (try.ouraddr != 0) { +          try.neg_addr = 1; +        } +        no.neg_addr = 1; +        break; +    } +    p = next; +  } + +  /* If there is still anything left, this packet is bad. */ +  if (len != 0) { +    goto bad; +  } + +  /* +   * OK, the Nak is good.  Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } + +  return 1; + +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n")); +  return 0; +} + + +/* + * ipcp_rejci - Reject some of our CIs. + */ +static int +ipcp_rejci(fsm *f, u_char *p, int len) +{ +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  u_char cimaxslotindex, ciflag, cilen; +  u_short cishort; +  u32_t cilong; +  ipcp_options try;    /* options to request next time */ + +  try = *go; +  /* +   * Any Rejected CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define REJCIADDR(opt, neg, old, val1, val2) \ +  if (go->neg && \ +      len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \ +      p[1] == cilen && \ +      p[0] == opt) { \ +    u32_t l; \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    /* Check rejected value. */ \ +    if (cilong != val1) { \ +      goto bad; \ +    } \ +    if (old) { \ +      GETLONG(l, p); \ +      cilong = htonl(l); \ +      /* Check rejected value. */ \ +      if (cilong != val2) { \ +        goto bad; \ +      } \ +    } \ +    try.neg = 0; \ +  } + +#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \ +  if (go->neg && \ +      p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \ +      len >= p[1] && \ +      p[0] == opt) { \ +    len -= p[1]; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    /* Check rejected value. */  \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    if (!old) { \ +      GETCHAR(cimaxslotindex, p); \ +      if (cimaxslotindex != maxslot) { \ +        goto bad; \ +      } \ +      GETCHAR(ciflag, p); \ +      if (ciflag != cflag) { \ +        goto bad; \ +      } \ +    } \ +    try.neg = 0; \ +  } + +#define REJCIDNS(opt, neg, dnsaddr) \ +  if (go->neg && \ +      ((cilen = p[1]) == CILEN_ADDR) && \ +      len >= cilen && \ +      p[0] == opt) { \ +    u32_t l; \ +    len -= cilen; \ +    INCPTR(2, p); \ +    GETLONG(l, p); \ +    cilong = htonl(l); \ +    /* Check rejected value. */ \ +    if (cilong != dnsaddr) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +  } + +  REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, +        go->old_addrs, go->ouraddr, go->hisaddr); + +  REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj, +      go->maxslotindex, go->cflag); + +  REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]); + +  REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  /* +   * Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } +  return 1; + +bad: +  IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n")); +  return 0; +} + + +/* + * ipcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately.  If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + */ +static int +ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree) +{ +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; +  ipcp_options *ao = &ipcp_allowoptions[f->unit]; +#ifdef OLD_CI_ADDRS +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +#endif +  u_char *cip, *next;     /* Pointer to current and next CIs */ +  u_short cilen, citype;  /* Parsed len, type */ +  u_short cishort;        /* Parsed short value */ +  u32_t tl, ciaddr1;      /* Parsed address values */ +#ifdef OLD_CI_ADDRS +  u32_t ciaddr2;          /* Parsed address values */ +#endif +  int rc = CONFACK;       /* Final packet return code */ +  int orc;                /* Individual option return code */ +  u_char *p;              /* Pointer to next char to parse */ +  u_char *ucp = inp;      /* Pointer to current output char */ +  int l = *len;           /* Length left */ +  u_char maxslotindex, cflag; +  int d; + +  cis_received[f->unit] = 1; + +  /* +   * Reset all his options. +   */ +  BZERO(ho, sizeof(*ho)); + +  /* +   * Process all his options. +   */ +  next = inp; +  while (l) { +    orc = CONFACK;       /* Assume success */ +    cip = p = next;      /* Remember begining of CI */ +    if (l < 2 ||         /* Not enough data for CI header or */ +        p[1] < 2 ||      /*  CI length too small or */ +        p[1] > l) {      /*  CI length too big? */ +      IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n")); +      orc = CONFREJ;     /* Reject bad CI */ +      cilen = l;         /* Reject till end of packet */ +      l = 0;             /* Don't loop again */ +      goto endswitch; +    } +    GETCHAR(citype, p);  /* Parse CI type */ +    GETCHAR(cilen, p);   /* Parse CI length */ +    l -= cilen;          /* Adjust remaining length */ +    next += cilen;       /* Step to next CI */ + +    switch (citype) {      /* Check CI type */ +#ifdef OLD_CI_ADDRS /* Need to save space... */ +      case CI_ADDRS: +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n")); +        if (!ao->neg_addr || +            cilen != CILEN_ADDRS) {  /* Check CI length */ +          orc = CONFREJ;    /* Reject CI */ +          break; +        } + +        /* +         * If he has no address, or if we both have his address but +         * disagree about it, then NAK it with our idea. +         * In particular, if we don't know his address, but he does, +         * then accept it. +         */ +        GETLONG(tl, p);    /* Parse source address (his) */ +        ciaddr1 = htonl(tl); +        IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1))); +        if (ciaddr1 != wo->hisaddr +            && (ciaddr1 == 0 || !wo->accept_remote)) { +          orc = CONFNAK; +          if (!reject_if_disagree) { +            DECPTR(sizeof(u32_t), p); +            tl = ntohl(wo->hisaddr); +            PUTLONG(tl, p); +          } +        } else if (ciaddr1 == 0 && wo->hisaddr == 0) { +          /* +           * If neither we nor he knows his address, reject the option. +           */ +          orc = CONFREJ; +          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */ +          break; +        } + +        /* +         * If he doesn't know our address, or if we both have our address +         * but disagree about it, then NAK it with our idea. +         */ +        GETLONG(tl, p);    /* Parse desination address (ours) */ +        ciaddr2 = htonl(tl); +        IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2))); +        if (ciaddr2 != wo->ouraddr) { +          if (ciaddr2 == 0 || !wo->accept_local) { +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(sizeof(u32_t), p); +              tl = ntohl(wo->ouraddr); +              PUTLONG(tl, p); +            } +          } else { +            go->ouraddr = ciaddr2;  /* accept peer's idea */ +          } +        } + +        ho->neg_addr = 1; +        ho->old_addrs = 1; +        ho->hisaddr = ciaddr1; +        ho->ouraddr = ciaddr2; +        break; +#endif + +      case CI_ADDR: +        if (!ao->neg_addr) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n")); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } else if (cilen != CILEN_ADDR) {  /* Check CI length */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n")); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } + +        /* +         * If he has no address, or if we both have his address but +         * disagree about it, then NAK it with our idea. +         * In particular, if we don't know his address, but he does, +         * then accept it. +         */ +        GETLONG(tl, p);  /* Parse source address (his) */ +        ciaddr1 = htonl(tl); +        if (ciaddr1 != wo->hisaddr +            && (ciaddr1 == 0 || !wo->accept_remote)) { +          orc = CONFNAK; +          if (!reject_if_disagree) { +            DECPTR(sizeof(u32_t), p); +            tl = ntohl(wo->hisaddr); +            PUTLONG(tl, p); +          } +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1))); +        } else if (ciaddr1 == 0 && wo->hisaddr == 0) { +          /* +           * Don't ACK an address of 0.0.0.0 - reject it instead. +           */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1))); +          orc = CONFREJ; +          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */ +          break; +        } + +        ho->neg_addr = 1; +        ho->hisaddr = ciaddr1; +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1))); +        break; + +      case CI_MS_DNS1: +      case CI_MS_DNS2: +        /* Microsoft primary or secondary DNS request */ +        d = citype == CI_MS_DNS2; + +        /* If we do not have a DNS address then we cannot send it */ +        if (ao->dnsaddr[d] == 0 || +            cilen != CILEN_ADDR) {  /* Check CI length */ +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1)); +          orc = CONFREJ;        /* Reject CI */ +          break; +        } +        GETLONG(tl, p); +        if (htonl(tl) != ao->dnsaddr[d]) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n", +                d+1, inet_ntoa(tl))); +          DECPTR(sizeof(u32_t), p); +          tl = ntohl(ao->dnsaddr[d]); +          PUTLONG(tl, p); +          orc = CONFNAK; +        } +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1)); +        break; + +      case CI_MS_WINS1: +      case CI_MS_WINS2: +        /* Microsoft primary or secondary WINS request */ +        d = citype == CI_MS_WINS2; +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1)); + +        /* If we do not have a DNS address then we cannot send it */ +        if (ao->winsaddr[d] == 0 || +          cilen != CILEN_ADDR) {  /* Check CI length */ +          orc = CONFREJ;      /* Reject CI */ +          break; +        } +        GETLONG(tl, p); +        if (htonl(tl) != ao->winsaddr[d]) { +          DECPTR(sizeof(u32_t), p); +          tl = ntohl(ao->winsaddr[d]); +          PUTLONG(tl, p); +          orc = CONFNAK; +        } +        break; + +      case CI_COMPRESSTYPE: +        if (!ao->neg_vj) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n")); +          orc = CONFREJ; +          break; +        } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen)); +          orc = CONFREJ; +          break; +        } +        GETSHORT(cishort, p); + +        if (!(cishort == IPCP_VJ_COMP || +            (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { +          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort)); +          orc = CONFREJ; +          break; +        } + +        ho->neg_vj = 1; +        ho->vj_protocol = cishort; +        if (cilen == CILEN_VJ) { +          GETCHAR(maxslotindex, p); +          if (maxslotindex > ao->maxslotindex) {  +            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex)); +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(1, p); +              PUTCHAR(ao->maxslotindex, p); +            } +          } +          GETCHAR(cflag, p); +          if (cflag && !ao->cflag) { +            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag)); +            orc = CONFNAK; +            if (!reject_if_disagree) { +              DECPTR(1, p); +              PUTCHAR(wo->cflag, p); +            } +          } +          ho->maxslotindex = maxslotindex; +          ho->cflag = cflag; +        } else { +          ho->old_vj = 1; +          ho->maxslotindex = MAX_SLOTS - 1; +          ho->cflag = 1; +        } +        IPCPDEBUG((LOG_INFO,  +              "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n", +              ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag)); +        break; + +      default: +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype)); +        orc = CONFREJ; +        break; +    } + +endswitch: +    if (orc == CONFACK &&    /* Good CI */ +        rc != CONFACK) {     /*  but prior CI wasnt? */ +      continue;              /* Don't send this one */ +    } + +    if (orc == CONFNAK) {    /* Nak this CI? */ +      if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */ +        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n")); +        orc = CONFREJ;       /* Get tough if so */ +      } else { +        if (rc == CONFREJ) { /* Rejecting prior CI? */ +          continue;          /* Don't send this one */ +        } +        if (rc == CONFACK) { /* Ack'd all prior CIs? */ +          rc = CONFNAK;      /* Not anymore... */ +          ucp = inp;         /* Backup */ +        } +      } +    } + +    if (orc == CONFREJ &&    /* Reject this CI */ +        rc != CONFREJ) {  /*  but no prior ones? */ +      rc = CONFREJ; +      ucp = inp;        /* Backup */ +    } +     +    /* Need to move CI? */ +    if (ucp != cip) { +      BCOPY(cip, ucp, cilen);  /* Move it */ +    } + +    /* Update output pointer */ +    INCPTR(cilen, ucp); +  } + +  /* +   * If we aren't rejecting this packet, and we want to negotiate +   * their address, and they didn't send their address, then we +   * send a NAK with a CI_ADDR option appended.  We assume the +   * input buffer is long enough that we can append the extra +   * option safely. +   */ +  if (rc != CONFREJ && !ho->neg_addr && +      wo->req_addr && !reject_if_disagree) { +    IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n")); +    if (rc == CONFACK) { +      rc = CONFNAK; +      ucp = inp;        /* reset pointer */ +      wo->req_addr = 0;    /* don't ask again */ +    } +    PUTCHAR(CI_ADDR, ucp); +    PUTCHAR(CILEN_ADDR, ucp); +    tl = ntohl(wo->hisaddr); +    PUTLONG(tl, ucp); +  } + +  *len = (int)(ucp - inp);    /* Compute output length */ +  IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc))); +  return (rc);      /* Return final code */ +} + + +#if 0 +/* + * ip_check_options - check that any IP-related options are OK, + * and assign appropriate defaults. + */ +static void +ip_check_options(u_long localAddr) +{ +  ipcp_options *wo = &ipcp_wantoptions[0]; + +  /* +   * Load our default IP address but allow the remote host to give us +   * a new address. +   */ +  if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) { +    wo->accept_local = 1;  /* don't insist on this default value */ +    wo->ouraddr = htonl(localAddr); +  } +} +#endif + + +/* + * ipcp_up - IPCP has come UP. + * + * Configure the IP network interface appropriately and bring it up. + */ +static void +ipcp_up(fsm *f) +{ +  u32_t mask; +  ipcp_options *ho = &ipcp_hisoptions[f->unit]; +  ipcp_options *go = &ipcp_gotoptions[f->unit]; +  ipcp_options *wo = &ipcp_wantoptions[f->unit]; + +  np_up(f->unit, PPP_IP); +  IPCPDEBUG((LOG_INFO, "ipcp: up\n")); + +  /* +   * We must have a non-zero IP address for both ends of the link. +   */ +  if (!ho->neg_addr) { +    ho->hisaddr = wo->hisaddr; +  } + +  if (ho->hisaddr == 0) { +    IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n")); +    ipcp_close(f->unit, "Could not determine remote IP address"); +    return; +  } +  if (go->ouraddr == 0) { +    IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n")); +    ipcp_close(f->unit, "Could not determine local IP address"); +    return; +  } + +  if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) { +    /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/ +  } + +  /* +   * Check that the peer is allowed to use the IP address it wants. +   */ +  if (!auth_ip_addr(f->unit, ho->hisaddr)) { +    IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n", +        inet_ntoa(ho->hisaddr))); +    ipcp_close(f->unit, "Unauthorized remote IP address"); +    return; +  } + +  /* set tcp compression */ +  sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex); + +  /* +   * Set IP addresses and (if specified) netmask. +   */ +  mask = GetMask(go->ouraddr); + +  if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) { +    IPCPDEBUG((LOG_WARNING, "sifaddr failed\n")); +    ipcp_close(f->unit, "Interface configuration failed"); +    return; +  } + +  /* bring the interface up for IP */ +  if (!sifup(f->unit)) { +    IPCPDEBUG((LOG_WARNING, "sifup failed\n")); +    ipcp_close(f->unit, "Interface configuration failed"); +    return; +  } + +  sifnpmode(f->unit, PPP_IP, NPMODE_PASS); + +  /* assign a default route through the interface if required */ +  if (ipcp_wantoptions[f->unit].default_route) { +    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) { +      default_route_set[f->unit] = 1; +    } +  } + +  IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr))); +  IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr))); +  if (go->dnsaddr[0]) { +    IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0]))); +  } +  if (go->dnsaddr[1]) { +    IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1]))); +  } +} + + +/* + * ipcp_down - IPCP has gone DOWN. + * + * Take the IP network interface down, clear its addresses + * and delete routes through it. + */ +static void +ipcp_down(fsm *f) +{ +  IPCPDEBUG((LOG_INFO, "ipcp: down\n")); +  np_down(f->unit, PPP_IP); +  sifvjcomp(f->unit, 0, 0, 0); + +  sifdown(f->unit); +  ipcp_clear_addrs(f->unit); +} + + +/* + * ipcp_clear_addrs() - clear the interface addresses, routes, etc. + */ +static void +ipcp_clear_addrs(int unit) +{ +  u32_t ouraddr, hisaddr; + +  ouraddr = ipcp_gotoptions[unit].ouraddr; +  hisaddr = ipcp_hisoptions[unit].hisaddr; +  if (default_route_set[unit]) { +    cifdefaultroute(unit, ouraddr, hisaddr); +    default_route_set[unit] = 0; +  } +  cifaddr(unit, ouraddr, hisaddr); +} + + +/* + * ipcp_finished - possibly shut down the lower layers. + */ +static void +ipcp_finished(fsm *f) +{ +  np_finished(f->unit, PPP_IP); +} + +#if 0 +static int +ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  LWIP_UNUSED_ARG(p); +  LWIP_UNUSED_ARG(plen); +  LWIP_UNUSED_ARG(printer); +  LWIP_UNUSED_ARG(arg); +  return 0; +} + +/* + * ip_active_pkt - see if this IP packet is worth bringing the link up for. + * We don't bring the link up for IP fragments or for TCP FIN packets + * with no data. + */ +#define IP_HDRLEN   20  /* bytes */ +#define IP_OFFMASK  0x1fff +#define IPPROTO_TCP 6 +#define TCP_HDRLEN  20 +#define TH_FIN      0x01 + +/* + * We use these macros because the IP header may be at an odd address, + * and some compilers might use word loads to get th_off or ip_hl. + */ + +#define net_short(x)    (((x)[0] << 8) + (x)[1]) +#define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF) +#define get_ipoff(x)    net_short((unsigned char *)(x) + 6) +#define get_ipproto(x)  (((unsigned char *)(x))[9]) +#define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4) +#define get_tcpflags(x) (((unsigned char *)(x))[13]) + +static int +ip_active_pkt(u_char *pkt, int len) +{ +  u_char *tcp; +  int hlen; + +  len -= PPP_HDRLEN; +  pkt += PPP_HDRLEN; +  if (len < IP_HDRLEN) { +    return 0; +  } +  if ((get_ipoff(pkt) & IP_OFFMASK) != 0) { +    return 0; +  } +  if (get_ipproto(pkt) != IPPROTO_TCP) { +    return 1; +  } +  hlen = get_iphl(pkt) * 4; +  if (len < hlen + TCP_HDRLEN) { +    return 0; +  } +  tcp = pkt + hlen; +  if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) { +    return 0; +  } +  return 1; +} +#endif + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h new file mode 100644 index 000000000..dfcf4fba6 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ipcp.h @@ -0,0 +1,124 @@ +/***************************************************************************** +* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * ipcp.h - IP Control Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: ipcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef IPCP_H +#define IPCP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Options. + */ +#define CI_ADDRS            1      /* IP Addresses */ +#define CI_COMPRESSTYPE     2      /* Compression Type */ +#define CI_ADDR             3 + +#define CI_MS_WINS1         128    /* Primary WINS value */ +#define CI_MS_DNS1          129    /* Primary DNS value */ +#define CI_MS_WINS2         130    /* Secondary WINS value */ +#define CI_MS_DNS2          131    /* Secondary DNS value */ + +#define IPCP_VJMODE_OLD     1      /* "old" mode (option # = 0x0037) */ +#define IPCP_VJMODE_RFC1172 2      /* "old-rfc"mode (option # = 0x002d) */ +#define IPCP_VJMODE_RFC1332 3      /* "new-rfc"mode (option # = 0x002d, */ +                                   /*  maxslot and slot number compression) */ + +#define IPCP_VJ_COMP        0x002d /* current value for VJ compression option */ +#define IPCP_VJ_COMP_OLD    0x0037 /* "old" (i.e, broken) value for VJ */ +                                   /* compression option */  + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +typedef struct ipcp_options { +  u_int   neg_addr      : 1; /* Negotiate IP Address? */ +  u_int   old_addrs     : 1; /* Use old (IP-Addresses) option? */ +  u_int   req_addr      : 1; /* Ask peer to send IP address? */ +  u_int   default_route : 1; /* Assign default route through interface? */ +  u_int   proxy_arp     : 1; /* Make proxy ARP entry for peer? */ +  u_int   neg_vj        : 1; /* Van Jacobson Compression? */ +  u_int   old_vj        : 1; /* use old (short) form of VJ option? */ +  u_int   accept_local  : 1; /* accept peer's value for ouraddr */ +  u_int   accept_remote : 1; /* accept peer's value for hisaddr */ +  u_int   req_dns1      : 1; /* Ask peer to send primary DNS address? */ +  u_int   req_dns2      : 1; /* Ask peer to send secondary DNS address? */ +  u_short vj_protocol;       /* protocol value to use in VJ option */ +  u_char  maxslotindex;      /* VJ slots - 1. */ +  u_char  cflag;             /* VJ slot compression flag. */ +  u32_t   ouraddr, hisaddr;  /* Addresses in NETWORK BYTE ORDER */ +  u32_t   dnsaddr[2];        /* Primary and secondary MS DNS entries */ +  u32_t   winsaddr[2];       /* Primary and secondary MS WINS entries */ +} ipcp_options; + + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +extern fsm ipcp_fsm[]; +extern ipcp_options ipcp_wantoptions[]; +extern ipcp_options ipcp_gotoptions[]; +extern ipcp_options ipcp_allowoptions[]; +extern ipcp_options ipcp_hisoptions[]; + +extern struct protent ipcp_protent; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +#endif /* IPCP_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.c new file mode 100644 index 000000000..85a0add95 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.c @@ -0,0 +1,2035 @@ +/***************************************************************************** +* lcp.c - Network Link Control Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ + +/* + * lcp.c - PPP Link Control Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ +  + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "fsm.h" +#include "chap.h" +#include "magic.h" +#include "auth.h" +#include "lcp.h" + +#include <string.h> + +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#else +#define PPPOE_MAXMTU PPP_MAXMRU +#endif + + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID  2 +#define CILEN_CHAR  3 +#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ +#define CILEN_CHAP  5 /* CILEN_VOID + sizeof(short) + 1 */ +#define CILEN_LONG  6 /* CILEN_VOID + sizeof(long) */ +#define CILEN_LQR   8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ +#define CILEN_CBCP  3 + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Callbacks for fsm code.  (CI = Configuration Information) + */ +static void lcp_resetci (fsm*);                   /* Reset our CI */ +static int  lcp_cilen (fsm*);                     /* Return length of our CI */ +static void lcp_addci (fsm*, u_char*, int*);      /* Add our CI to pkt */ +static int  lcp_ackci (fsm*, u_char*, int);       /* Peer ack'd our CI */ +static int  lcp_nakci (fsm*, u_char*, int);       /* Peer nak'd our CI */ +static int  lcp_rejci (fsm*, u_char*, int);       /* Peer rej'd our CI */ +static int  lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */ +static void lcp_up (fsm*);                        /* We're UP */ +static void lcp_down (fsm*);                      /* We're DOWN */ +static void lcp_starting (fsm*);                  /* We need lower layer up */ +static void lcp_finished (fsm*);                  /* We need lower layer down */ +static int  lcp_extcode (fsm*, int, u_char, u_char*, int); + +static void lcp_rprotrej (fsm*, u_char*, int); + +/* + * routines to send LCP echos to peer + */ +static void lcp_echo_lowerup (int); +static void lcp_echo_lowerdown (int); +static void LcpEchoTimeout (void*); +static void lcp_received_echo_reply (fsm*, int, u_char*, int); +static void LcpSendEchoRequest (fsm*); +static void LcpLinkFailure (fsm*); +static void LcpEchoCheck (fsm*); + +/* + * Protocol entry points. + * Some of these are called directly. + */ +static void lcp_input (int, u_char *, int); +static void lcp_protrej (int); + +#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +/* global vars */ +LinkPhase lcp_phase[NUM_PPP];          /* Phase of link session (RFC 1661) */ +lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */ +lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */ +lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */ +ext_accm xmit_accm[NUM_PPP];           /* extended transmit ACCM */ + + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static fsm lcp_fsm[NUM_PPP];                            /* LCP fsm structure (global)*/ +static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ +static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ +static u32_t lcp_echos_pending      = 0;                /* Number of outstanding echo msgs */ +static u32_t lcp_echo_number        = 0;                /* ID number of next echo frame */ +static u32_t lcp_echo_timer_running = 0;                /* TRUE if a timer is running */ + +static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ + +static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ +  lcp_resetci,  /* Reset our Configuration Information */ +  lcp_cilen,    /* Length of our Configuration Information */ +  lcp_addci,    /* Add our Configuration Information */ +  lcp_ackci,    /* ACK our Configuration Information */ +  lcp_nakci,    /* NAK our Configuration Information */ +  lcp_rejci,    /* Reject our Configuration Information */ +  lcp_reqci,    /* Request peer's Configuration Information */ +  lcp_up,       /* Called when fsm reaches LS_OPENED state */ +  lcp_down,     /* Called when fsm leaves LS_OPENED state */ +  lcp_starting, /* Called when we want the lower layer up */ +  lcp_finished, /* Called when we want the lower layer down */ +  NULL,         /* Called when Protocol-Reject received */ +  NULL,         /* Retransmission is necessary */ +  lcp_extcode,  /* Called to handle LCP-specific codes */ +  "LCP"         /* String name of protocol */ +}; + +struct protent lcp_protent = { +    PPP_LCP, +    lcp_init, +    lcp_input, +    lcp_protrej, +    lcp_lowerup, +    lcp_lowerdown, +    lcp_open, +    lcp_close, +#if 0 +    lcp_printpkt, +    NULL, +#endif +    1, +    "LCP", +#if 0 +    NULL, +    NULL, +    NULL +#endif +}; + +int lcp_loopbackfail = DEFLOOPBACKFAIL; + + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * lcp_init - Initialize LCP. + */ +void +lcp_init(int unit) +{ +  fsm         *f  = &lcp_fsm[unit]; +  lcp_options *wo = &lcp_wantoptions[unit]; +  lcp_options *ao = &lcp_allowoptions[unit]; +   +  f->unit      = unit; +  f->protocol  = PPP_LCP; +  f->callbacks = &lcp_callbacks; +   +  fsm_init(f); +   +  wo->passive           = 0; +  wo->silent            = 0; +  wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */ +  wo->neg_mru           = 1; +  wo->mru               = PPP_DEFMRU; +  wo->neg_asyncmap      = 1; +  wo->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */ +  wo->neg_chap          = 0;               /* Set to 1 on server */ +  wo->neg_upap          = 0;               /* Set to 1 on server */ +  wo->chap_mdtype       = CHAP_DIGEST_MD5; +  wo->neg_magicnumber   = 1; +  wo->neg_pcompression  = 1; +  wo->neg_accompression = 1; +  wo->neg_lqr           = 0;               /* no LQR implementation yet */ +  wo->neg_cbcp          = 0; +   +  ao->neg_mru           = 1; +  ao->mru               = PPP_MAXMRU; +  ao->neg_asyncmap      = 1; +  ao->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */ +  ao->neg_chap          = (CHAP_SUPPORT != 0); +  ao->chap_mdtype       = CHAP_DIGEST_MD5; +  ao->neg_upap          = (PAP_SUPPORT != 0); +  ao->neg_magicnumber   = 1; +  ao->neg_pcompression  = 1; +  ao->neg_accompression = 1; +  ao->neg_lqr           = 0;               /* no LQR implementation yet */ +  ao->neg_cbcp          = (CBCP_SUPPORT != 0); + +  /*  +   * Set transmit escape for the flag and escape characters plus anything +   * set for the allowable options. +   */ +  memset(xmit_accm[unit], 0, sizeof(xmit_accm[0])); +  xmit_accm[unit][15] = 0x60; +  xmit_accm[unit][0]  = (u_char)((ao->asyncmap        & 0xFF)); +  xmit_accm[unit][1]  = (u_char)((ao->asyncmap >> 8)  & 0xFF); +  xmit_accm[unit][2]  = (u_char)((ao->asyncmap >> 16) & 0xFF); +  xmit_accm[unit][3]  = (u_char)((ao->asyncmap >> 24) & 0xFF); +  LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n", +        xmit_accm[unit][0], +        xmit_accm[unit][1], +        xmit_accm[unit][2], +        xmit_accm[unit][3])); +   +  lcp_phase[unit] = PHASE_INITIALIZE; +} + + +/* + * lcp_open - LCP is allowed to come up. + */ +void +lcp_open(int unit) +{ +  fsm         *f  = &lcp_fsm[unit]; +  lcp_options *wo = &lcp_wantoptions[unit]; + +  f->flags = 0; +  if (wo->passive) { +    f->flags |= OPT_PASSIVE; +  } +  if (wo->silent) { +    f->flags |= OPT_SILENT; +  } +  fsm_open(f); + +  lcp_phase[unit] = PHASE_ESTABLISH; +} + + +/* + * lcp_close - Take LCP down. + */ +void +lcp_close(int unit, char *reason) +{ +  fsm *f = &lcp_fsm[unit]; + +  if (lcp_phase[unit] != PHASE_DEAD) { +    lcp_phase[unit] = PHASE_TERMINATE; +  } +  if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) { +    /* +     * This action is not strictly according to the FSM in RFC1548, +     * but it does mean that the program terminates if you do an +     * lcp_close() in passive/silent mode when a connection hasn't +     * been established. +     */ +    f->state = LS_CLOSED; +    lcp_finished(f); +  } else { +    fsm_close(&lcp_fsm[unit], reason); +  } +} + + +/* + * lcp_lowerup - The lower layer is up. + */ +void +lcp_lowerup(int unit) +{ +  lcp_options *wo = &lcp_wantoptions[unit]; + +  /* +   * Don't use A/C or protocol compression on transmission, +   * but accept A/C and protocol compressed packets +   * if we are going to ask for A/C and protocol compression. +   */ +  ppp_set_xaccm(unit, &xmit_accm[unit]); +  ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0); +  ppp_recv_config(unit, PPP_MRU, 0x00000000l, +  wo->neg_pcompression, wo->neg_accompression); +  peer_mru[unit] = PPP_MRU; +  lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0] +                                 | ((u_long)xmit_accm[unit][1] << 8) +                                 | ((u_long)xmit_accm[unit][2] << 16) +                                 | ((u_long)xmit_accm[unit][3] << 24); +  LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n", +            xmit_accm[unit][3], +            xmit_accm[unit][2], +            xmit_accm[unit][1], +            xmit_accm[unit][0])); + +  fsm_lowerup(&lcp_fsm[unit]); +} + + +/* + * lcp_lowerdown - The lower layer is down. + */ +void +lcp_lowerdown(int unit) +{ +  fsm_lowerdown(&lcp_fsm[unit]); +} + +/* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void +lcp_sprotrej(int unit, u_char *p, int len) +{ +  /* +   * Send back the protocol and the information field of the +   * rejected packet.  We only get here if LCP is in the LS_OPENED state. +   */ + +  fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); +} + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * lcp_input - Input LCP packet. + */ +static void +lcp_input(int unit, u_char *p, int len) +{ +  fsm *f = &lcp_fsm[unit]; + +  fsm_input(f, p, len); +} + + +/* + * lcp_extcode - Handle a LCP-specific code. + */ +static int +lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) +{ +  u_char *magp; + +  switch( code ){ +    case PROTREJ: +      lcp_rprotrej(f, inp, len); +      break; +   +    case ECHOREQ: +      if (f->state != LS_OPENED) { +        break; +      } +      LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id)); +      magp = inp; +      PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); +      fsm_sdata(f, ECHOREP, id, inp, len); +      break; + +    case ECHOREP: +      lcp_received_echo_reply(f, id, inp, len); +      break; +     +    case DISCREQ: +      break; +     +    default: +      return 0; +  } +  return 1; +} + + +/* + * lcp_rprotrej - Receive an Protocol-Reject. + * + * Figure out which protocol is rejected and inform it. + */ +static void +lcp_rprotrej(fsm *f, u_char *inp, int len) +{ +  int i; +  struct protent *protp; +  u_short prot; + +  if (len < sizeof (u_short)) { +    LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); +    return; +  } + +  GETSHORT(prot, inp); + +  LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); + +  /* +   * Protocol-Reject packets received in any state other than the LCP +   * LS_OPENED state SHOULD be silently discarded. +   */ +  if( f->state != LS_OPENED ) { +    LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state)); +    return; +  } + +  /* +   * Upcall the proper Protocol-Reject routine. +   */ +  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +    if (protp->protocol == prot && protp->enabled_flag) { +      (*protp->protrej)(f->unit); +      return; +    } +  } + +  LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot)); +} + + +/* + * lcp_protrej - A Protocol-Reject was received. + */ +static void +lcp_protrej(int unit) +{ +  LWIP_UNUSED_ARG(unit); +  /* +   * Can't reject LCP! +   */ +  LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n")); +  fsm_protreject(&lcp_fsm[unit]); +} + + +/* + * lcp_resetci - Reset our CI. + */ +static void +lcp_resetci(fsm *f) +{ +  lcp_wantoptions[f->unit].magicnumber = magic(); +  lcp_wantoptions[f->unit].numloops = 0; +  lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit]; +  peer_mru[f->unit] = PPP_MRU; +  auth_reset(f->unit); +} + + +/* + * lcp_cilen - Return length of our CI. + */ +static int lcp_cilen(fsm *f) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; + +#define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0) +#define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0) +#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0) +#define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0) +#define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0) +#define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0) +  /* +   * NB: we only ask for one of CHAP and UPAP, even if we will +   * accept either. +   */ +  return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) + +          LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) + +          LENCICHAP(go->neg_chap) + +          LENCISHORT(!go->neg_chap && go->neg_upap) + +          LENCILQR(go->neg_lqr) + +          LENCICBCP(go->neg_cbcp) + +          LENCILONG(go->neg_magicnumber) + +          LENCIVOID(go->neg_pcompression) + +          LENCIVOID(go->neg_accompression)); +} + + +/* + * lcp_addci - Add our desired CIs to a packet. + */ +static void +lcp_addci(fsm *f, u_char *ucp, int *lenp) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char *start_ucp = ucp; + +#define ADDCIVOID(opt, neg) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_VOID, ucp); \ +  } +#define ADDCISHORT(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_SHORT, ucp); \ +    PUTSHORT(val, ucp); \ +  } +#define ADDCICHAP(opt, neg, val, digest) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_CHAP, ucp); \ +    PUTSHORT(val, ucp); \ +    PUTCHAR(digest, ucp); \ +  } +#define ADDCILONG(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_LONG, ucp); \ +    PUTLONG(val, ucp); \ +  } +#define ADDCILQR(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_LQR, ucp); \ +    PUTSHORT(PPP_LQR, ucp); \ +    PUTLONG(val, ucp); \ +  } +#define ADDCICHAR(opt, neg, val) \ +  if (neg) { \ +    LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ +    PUTCHAR(opt, ucp); \ +    PUTCHAR(CILEN_CHAR, ucp); \ +    PUTCHAR(val, ucp); \ +  } + +  ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); +  ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); +  ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); +  ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +  ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +  ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); +  ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); +  ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression); +  ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + +  if (ucp - start_ucp != *lenp) { +    /* this should never happen, because peer_mtu should be 1500 */ +    LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n")); +  } +} + + +/* + * lcp_ackci - Ack our CIs. + * This should not modify any state if the Ack is bad. + * + * Returns: + *  0 - Ack was bad. + *  1 - Ack was good. + */ +static int +lcp_ackci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char cilen, citype, cichar; +  u_short cishort; +  u32_t cilong; + +  /* +   * CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define ACKCIVOID(opt, neg) \ +  if (neg) { \ +    if ((len -= CILEN_VOID) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_VOID || citype != opt) \ +      goto bad; \ +  } +#define ACKCISHORT(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_SHORT) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_SHORT || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != val) \ +      goto bad; \ +  } +#define ACKCICHAR(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_CHAR) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_CHAR || citype != opt) \ +      goto bad; \ +    GETCHAR(cichar, p); \ +    if (cichar != val) \ +      goto bad; \ +  } +#define ACKCICHAP(opt, neg, val, digest) \ +  if (neg) { \ +    if ((len -= CILEN_CHAP) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_CHAP || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != val) \ +      goto bad; \ +    GETCHAR(cichar, p); \ +    if (cichar != digest) \ +      goto bad; \ +  } +#define ACKCILONG(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_LONG) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_LONG ||  citype != opt) \ +      goto bad; \ +    GETLONG(cilong, p); \ +    if (cilong != val) \ +      goto bad; \ +  } +#define ACKCILQR(opt, neg, val) \ +  if (neg) { \ +    if ((len -= CILEN_LQR) < 0) \ +      goto bad; \ +    GETCHAR(citype, p); \ +    GETCHAR(cilen, p); \ +    if (cilen != CILEN_LQR || citype != opt) \ +      goto bad; \ +    GETSHORT(cishort, p); \ +    if (cishort != PPP_LQR) \ +      goto bad; \ +    GETLONG(cilong, p); \ +    if (cilong != val) \ +      goto bad; \ +  } + +  ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru); +  ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap); +  ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype); +  ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP); +  ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period); +  ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT); +  ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber); +  ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression); +  ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression); + +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n")); +  return (1); +bad: +  LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n")); +  return (0); +} + + +/* + * lcp_nakci - Peer has sent a NAK for some of our CIs. + * This should not modify any state if the Nak is bad + * or if LCP is in the LS_OPENED state. + * + * Returns: + *  0 - Nak was bad. + *  1 - Nak was good. + */ +static int +lcp_nakci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *wo = &lcp_wantoptions[f->unit]; +  u_char citype, cichar, *next; +  u_short cishort; +  u32_t cilong; +  lcp_options no;     /* options we've seen Naks for */ +  lcp_options try;    /* options to request next time */ +  int looped_back = 0; +  int cilen; + +  BZERO(&no, sizeof(no)); +  try = *go; + +  /* +   * Any Nak'd CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define NAKCIVOID(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_VOID && \ +      p[1] == CILEN_VOID && \ +      p[0] == opt) { \ +    len -= CILEN_VOID; \ +    INCPTR(CILEN_VOID, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCICHAP(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_CHAP && \ +      p[1] == CILEN_CHAP && \ +      p[0] == opt) { \ +    len -= CILEN_CHAP; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETCHAR(cichar, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCICHAR(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_CHAR && \ +      p[1] == CILEN_CHAR && \ +      p[0] == opt) { \ +    len -= CILEN_CHAR; \ +    INCPTR(2, p); \ +    GETCHAR(cichar, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCISHORT(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_SHORT && \ +      p[1] == CILEN_SHORT && \ +      p[0] == opt) { \ +    len -= CILEN_SHORT; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCILONG(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_LONG && \ +      p[1] == CILEN_LONG && \ +      p[0] == opt) { \ +    len -= CILEN_LONG; \ +    INCPTR(2, p); \ +    GETLONG(cilong, p); \ +    no.neg = 1; \ +    code \ +  } +#define NAKCILQR(opt, neg, code) \ +  if (go->neg && \ +      len >= CILEN_LQR && \ +      p[1] == CILEN_LQR && \ +      p[0] == opt) { \ +    len -= CILEN_LQR; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETLONG(cilong, p); \ +    no.neg = 1; \ +    code \ +  } + +  /* +   * We don't care if they want to send us smaller packets than +   * we want.  Therefore, accept any MRU less than what we asked for, +   * but then ignore the new value when setting the MRU in the kernel. +   * If they send us a bigger MRU than what we asked, accept it, up to +   * the limit of the default MRU we'd get if we didn't negotiate. +   */ +  if (go->neg_mru && go->mru != PPP_DEFMRU) { +    NAKCISHORT(CI_MRU, neg_mru, +      if (cishort <= wo->mru || cishort < PPP_DEFMRU) { +        try.mru = cishort; +      } +    ); +  } + +  /* +   * Add any characters they want to our (receive-side) asyncmap. +   */ +  if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) { +    NAKCILONG(CI_ASYNCMAP, neg_asyncmap, +      try.asyncmap = go->asyncmap | cilong; +    ); +  } + +  /* +   * If they've nak'd our authentication-protocol, check whether +   * they are proposing a different protocol, or a different +   * hash algorithm for CHAP. +   */ +  if ((go->neg_chap || go->neg_upap) +      && len >= CILEN_SHORT +      && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) { +    cilen = p[1]; +    len -= cilen; +    no.neg_chap = go->neg_chap; +    no.neg_upap = go->neg_upap; +    INCPTR(2, p); +    GETSHORT(cishort, p); +    if (cishort == PPP_PAP && cilen == CILEN_SHORT) { +      /* +       * If we were asking for CHAP, they obviously don't want to do it. +       * If we weren't asking for CHAP, then we were asking for PAP, +       * in which case this Nak is bad. +       */ +      if (!go->neg_chap) { +        goto bad; +      } +      try.neg_chap = 0; +     +    } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) { +      GETCHAR(cichar, p); +      if (go->neg_chap) { +        /* +         * We were asking for CHAP/MD5; they must want a different +         * algorithm.  If they can't do MD5, we'll have to stop +         * asking for CHAP. +         */ +        if (cichar != go->chap_mdtype) { +          try.neg_chap = 0; +        } +      } else { +        /* +         * Stop asking for PAP if we were asking for it. +         */ +        try.neg_upap = 0; +      } +     +    } else { +      /* +       * We don't recognize what they're suggesting. +       * Stop asking for what we were asking for. +       */ +      if (go->neg_chap) { +        try.neg_chap = 0; +      } else { +        try.neg_upap = 0; +      } +      p += cilen - CILEN_SHORT; +    } +  } + +  /* +   * If they can't cope with our link quality protocol, we'll have +   * to stop asking for LQR.  We haven't got any other protocol. +   * If they Nak the reporting period, take their value XXX ? +   */ +  NAKCILQR(CI_QUALITY, neg_lqr, +    if (cishort != PPP_LQR) { +      try.neg_lqr = 0; +    } else { +      try.lqr_period = cilong; +    } +  ); + +  /* +   * Only implementing CBCP...not the rest of the callback options +   */ +  NAKCICHAR(CI_CALLBACK, neg_cbcp, +    try.neg_cbcp = 0; +  ); + +  /* +   * Check for a looped-back line. +   */ +  NAKCILONG(CI_MAGICNUMBER, neg_magicnumber, +    try.magicnumber = magic(); +    looped_back = 1; +  ); + +  /* +   * Peer shouldn't send Nak for protocol compression or +   * address/control compression requests; they should send +   * a Reject instead.  If they send a Nak, treat it as a Reject. +   */ +  NAKCIVOID(CI_PCOMPRESSION, neg_pcompression, +    try.neg_pcompression = 0; +  ); +  NAKCIVOID(CI_ACCOMPRESSION, neg_accompression, +    try.neg_accompression = 0; +  ); + +  /* +   * There may be remaining CIs, if the peer is requesting negotiation +   * on an option that we didn't include in our request packet. +   * If we see an option that we requested, or one we've already seen +   * in this packet, then this packet is bad. +   * If we wanted to respond by starting to negotiate on the requested +   * option(s), we could, but we don't, because except for the +   * authentication type and quality protocol, if we are not negotiating +   * an option, it is because we were told not to. +   * For the authentication type, the Nak from the peer means +   * `let me authenticate myself with you' which is a bit pointless. +   * For the quality protocol, the Nak means `ask me to send you quality +   * reports', but if we didn't ask for them, we don't want them. +   * An option we don't recognize represents the peer asking to +   * negotiate some option we don't support, so ignore it. +   */ +  while (len > CILEN_VOID) { +    GETCHAR(citype, p); +    GETCHAR(cilen, p); +    if (cilen < CILEN_VOID || (len -= cilen) < 0) { +      goto bad; +    } +    next = p + cilen - 2; + +    switch (citype) { +      case CI_MRU: +        if ((go->neg_mru && go->mru != PPP_DEFMRU) +            || no.neg_mru || cilen != CILEN_SHORT) { +          goto bad; +        } +        GETSHORT(cishort, p); +        if (cishort < PPP_DEFMRU) { +          try.mru = cishort; +        } +        break; +      case CI_ASYNCMAP: +        if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +            || no.neg_asyncmap || cilen != CILEN_LONG) { +          goto bad; +        } +        break; +      case CI_AUTHTYPE: +        if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) { +          goto bad; +        } +        break; +      case CI_MAGICNUMBER: +        if (go->neg_magicnumber || no.neg_magicnumber || +            cilen != CILEN_LONG) { +          goto bad; +        } +        break; +      case CI_PCOMPRESSION: +        if (go->neg_pcompression || no.neg_pcompression +            || cilen != CILEN_VOID) { +          goto bad; +        } +        break; +      case CI_ACCOMPRESSION: +        if (go->neg_accompression || no.neg_accompression +            || cilen != CILEN_VOID) { +          goto bad; +        } +        break; +      case CI_QUALITY: +        if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) { +          goto bad; +        } +        break; +    } +    p = next; +  } + +  /* If there is still anything left, this packet is bad. */ +  if (len != 0) { +    goto bad; +  } + +  /* +  * OK, the Nak is good.  Now we can update state. +  */ +  if (f->state != LS_OPENED) { +    if (looped_back) { +      if (++try.numloops >= lcp_loopbackfail) { +        LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n")); +        lcp_close(f->unit, "Loopback detected"); +      } +    } else { +      try.numloops = 0; +    } +    *go = try; +  } + +  return 1; + +bad: +  LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n")); +  return 0; +} + + +/* + * lcp_rejci - Peer has Rejected some of our CIs. + * This should not modify any state if the Reject is bad + * or if LCP is in the LS_OPENED state. + * + * Returns: + *  0 - Reject was bad. + *  1 - Reject was good. + */ +static int +lcp_rejci(fsm *f, u_char *p, int len) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  u_char cichar; +  u_short cishort; +  u32_t cilong; +  lcp_options try; /* options to request next time */ + +  try = *go; + +  /* +   * Any Rejected CIs must be in exactly the same order that we sent. +   * Check packet length and CI length at each step. +   * If we find any deviations, then this packet is bad. +   */ +#define REJCIVOID(opt, neg) \ +  if (go->neg && \ +      len >= CILEN_VOID && \ +      p[1] == CILEN_VOID && \ +      p[0] == opt) { \ +    len -= CILEN_VOID; \ +    INCPTR(CILEN_VOID, p); \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \ +  } +#define REJCISHORT(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_SHORT && \ +      p[1] == CILEN_SHORT && \ +      p[0] == opt) { \ +    len -= CILEN_SHORT; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    /* Check rejected value. */ \ +    if (cishort != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \ +  } +#define REJCICHAP(opt, neg, val, digest) \ +  if (go->neg && \ +      len >= CILEN_CHAP && \ +      p[1] == CILEN_CHAP && \ +      p[0] == opt) { \ +    len -= CILEN_CHAP; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETCHAR(cichar, p); \ +    /* Check rejected value. */ \ +    if (cishort != val || cichar != digest) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    try.neg_upap = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \ +  } +#define REJCILONG(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_LONG && \ +      p[1] == CILEN_LONG && \ +      p[0] == opt) { \ +    len -= CILEN_LONG; \ +    INCPTR(2, p); \ +    GETLONG(cilong, p); \ +    /* Check rejected value. */ \ +    if (cilong != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \ +  } +#define REJCILQR(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_LQR && \ +      p[1] == CILEN_LQR && \ +      p[0] == opt) { \ +    len -= CILEN_LQR; \ +    INCPTR(2, p); \ +    GETSHORT(cishort, p); \ +    GETLONG(cilong, p); \ +    /* Check rejected value. */ \ +    if (cishort != PPP_LQR || cilong != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \ +  } +#define REJCICBCP(opt, neg, val) \ +  if (go->neg && \ +      len >= CILEN_CBCP && \ +      p[1] == CILEN_CBCP && \ +      p[0] == opt) { \ +    len -= CILEN_CBCP; \ +    INCPTR(2, p); \ +    GETCHAR(cichar, p); \ +    /* Check rejected value. */ \ +    if (cichar != val) { \ +      goto bad; \ +    } \ +    try.neg = 0; \ +    LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \ +  } +   +  REJCISHORT(CI_MRU, neg_mru, go->mru); +  REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap); +  REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype); +  if (!go->neg_chap) { +    REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP); +  } +  REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period); +  REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT); +  REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber); +  REJCIVOID(CI_PCOMPRESSION, neg_pcompression); +  REJCIVOID(CI_ACCOMPRESSION, neg_accompression); +   +  /* +   * If there are any remaining CIs, then this packet is bad. +   */ +  if (len != 0) { +    goto bad; +  } +  /* +   * Now we can update state. +   */ +  if (f->state != LS_OPENED) { +    *go = try; +  } +  return 1; +   +bad: +  LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n")); +  return 0; +} + + +/* + * lcp_reqci - Check the peer's requested CIs and send appropriate response. + * + * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified + * appropriately.  If reject_if_disagree is non-zero, doesn't return + * CONFNAK; returns CONFREJ if it can't return CONFACK. + */ +static int +lcp_reqci(fsm *f,  +          u_char *inp,    /* Requested CIs */ +          int *lenp,      /* Length of requested CIs */ +          int reject_if_disagree) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *ho = &lcp_hisoptions[f->unit]; +  lcp_options *ao = &lcp_allowoptions[f->unit]; +  u_char *cip, *next;         /* Pointer to current and next CIs */ +  int cilen, citype, cichar;  /* Parsed len, type, char value */ +  u_short cishort;            /* Parsed short value */ +  u32_t cilong;               /* Parse long value */ +  int rc = CONFACK;           /* Final packet return code */ +  int orc;                    /* Individual option return code */ +  u_char *p;                  /* Pointer to next char to parse */ +  u_char *rejp;               /* Pointer to next char in reject frame */ +  u_char *nakp;               /* Pointer to next char in Nak frame */ +  int l = *lenp;              /* Length left */ +#if TRACELCP > 0 +  char traceBuf[80]; +  int traceNdx = 0; +#endif + +  /* +   * Reset all his options. +   */ +  BZERO(ho, sizeof(*ho)); + +  /* +   * Process all his options. +   */ +  next = inp; +  nakp = nak_buffer; +  rejp = inp; +  while (l) { +    orc = CONFACK;      /* Assume success */ +    cip = p = next;     /* Remember begining of CI */ +    if (l < 2 ||        /* Not enough data for CI header or */ +        p[1] < 2 ||     /*  CI length too small or */ +        p[1] > l) {     /*  CI length too big? */ +      LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n")); +      orc = CONFREJ;    /* Reject bad CI */ +      cilen = l;        /* Reject till end of packet */ +      l = 0;            /* Don't loop again */ +      citype = 0; +      goto endswitch; +    } +    GETCHAR(citype, p); /* Parse CI type */ +    GETCHAR(cilen, p);  /* Parse CI length */ +    l -= cilen;         /* Adjust remaining length */ +    next += cilen;      /* Step to next CI */ + +    switch (citype) {   /* Check CI type */ +      case CI_MRU: +        if (!ao->neg_mru) {    /* Allow option? */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n")); +          orc = CONFREJ;    /* Reject CI */ +          break; +        } else if (cilen != CILEN_SHORT) {  /* Check CI length */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n")); +          orc = CONFREJ;    /* Reject CI */ +          break; +        } +        GETSHORT(cishort, p);  /* Parse MRU */ + +        /* +         * He must be able to receive at least our minimum. +         * No need to check a maximum.  If he sends a large number, +         * we'll just ignore it. +         */ +        if (cishort < PPP_MINMRU) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n")); +          orc = CONFNAK;    /* Nak CI */ +          PUTCHAR(CI_MRU, nakp); +          PUTCHAR(CILEN_SHORT, nakp); +          PUTSHORT(PPP_MINMRU, nakp);  /* Give him a hint */ +          break; +        } +        ho->neg_mru = 1;    /* Remember he sent MRU */ +        ho->mru = cishort;    /* And remember value */ +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort); +        traceNdx = strlen(traceBuf); +#endif +        break; + +      case CI_ASYNCMAP: +        if (!ao->neg_asyncmap) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n")); +          orc = CONFREJ; +          break; +        } else if (cilen != CILEN_LONG) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n")); +          orc = CONFREJ; +          break; +        } +        GETLONG(cilong, p); +         +        /* +         * Asyncmap must have set at least the bits +         * which are set in lcp_allowoptions[unit].asyncmap. +         */ +        if ((ao->asyncmap & ~cilong) != 0) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n",  +                    cilong, ao->asyncmap)); +          orc = CONFNAK; +          PUTCHAR(CI_ASYNCMAP, nakp); +          PUTCHAR(CILEN_LONG, nakp); +          PUTLONG(ao->asyncmap | cilong, nakp); +          break; +        } +        ho->neg_asyncmap = 1; +        ho->asyncmap = cilong; +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong); +        traceNdx = strlen(traceBuf); +#endif +        break; + +      case CI_AUTHTYPE: +        if (cilen < CILEN_SHORT) { +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n")); +          orc = CONFREJ; +          break; +        } else if (!(ao->neg_upap || ao->neg_chap)) { +          /* +           * Reject the option if we're not willing to authenticate. +           */ +          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n")); +          orc = CONFREJ; +          break; +        } +        GETSHORT(cishort, p); +         +        /* +         * Authtype must be UPAP or CHAP. +         * +         * Note: if both ao->neg_upap and ao->neg_chap are set, +         * and the peer sends a Configure-Request with two +         * authenticate-protocol requests, one for CHAP and one +         * for UPAP, then we will reject the second request. +         * Whether we end up doing CHAP or UPAP depends then on +         * the ordering of the CIs in the peer's Configure-Request. +         */ +         +        if (cishort == PPP_PAP) { +          if (ho->neg_chap) {  /* we've already accepted CHAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); +            orc = CONFREJ; +            break; +          } else if (cilen != CILEN_SHORT) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n")); +            orc = CONFREJ; +            break; +          } +          if (!ao->neg_upap) {  /* we don't want to do PAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); +            orc = CONFNAK;  /* NAK it and suggest CHAP */ +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_CHAP, nakp); +            PUTSHORT(PPP_CHAP, nakp); +            PUTCHAR(ao->chap_mdtype, nakp); +            break; +          } +          ho->neg_upap = 1; +#if TRACELCP > 0 +          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort); +          traceNdx = strlen(traceBuf); +#endif +          break; +        } +        if (cishort == PPP_CHAP) { +          if (ho->neg_upap) {  /* we've already accepted PAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); +            orc = CONFREJ; +            break; +          } else if (cilen != CILEN_CHAP) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); +            orc = CONFREJ; +            break; +          } +          if (!ao->neg_chap) {  /* we don't want to do CHAP */ +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); +            orc = CONFNAK;  /* NAK it and suggest PAP */ +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_SHORT, nakp); +            PUTSHORT(PPP_PAP, nakp); +            break; +          } +          GETCHAR(cichar, p);  /* get digest type*/ +          if (cichar != CHAP_DIGEST_MD5 +#ifdef CHAPMS +              && cichar != CHAP_MICROSOFT +#endif +          ) { +            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar)); +            orc = CONFNAK; +            PUTCHAR(CI_AUTHTYPE, nakp); +            PUTCHAR(CILEN_CHAP, nakp); +            PUTSHORT(PPP_CHAP, nakp); +            PUTCHAR(ao->chap_mdtype, nakp); +            break; +          } +#if TRACELCP > 0 +          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar); +          traceNdx = strlen(traceBuf); +#endif +          ho->chap_mdtype = cichar; /* save md type */ +          ho->neg_chap = 1; +          break; +        } +         +        /* +         * We don't recognize the protocol they're asking for. +         * Nak it with something we're willing to do. +         * (At this point we know ao->neg_upap || ao->neg_chap.) +         */ +        orc = CONFNAK; +        PUTCHAR(CI_AUTHTYPE, nakp); +        if (ao->neg_chap) { +          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); +          PUTCHAR(CILEN_CHAP, nakp); +          PUTSHORT(PPP_CHAP, nakp); +          PUTCHAR(ao->chap_mdtype, nakp); +        } else { +          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); +          PUTCHAR(CILEN_SHORT, nakp); +          PUTSHORT(PPP_PAP, nakp); +        } +        break; +       +      case CI_QUALITY: +        GETSHORT(cishort, p); +        GETLONG(cilong, p); +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong); +        traceNdx = strlen(traceBuf); +#endif + +        if (!ao->neg_lqr || +            cilen != CILEN_LQR) { +          orc = CONFREJ; +          break; +        } +         +        /* +         * Check the protocol and the reporting period. +         * XXX When should we Nak this, and what with? +         */ +        if (cishort != PPP_LQR) { +          orc = CONFNAK; +          PUTCHAR(CI_QUALITY, nakp); +          PUTCHAR(CILEN_LQR, nakp); +          PUTSHORT(PPP_LQR, nakp); +          PUTLONG(ao->lqr_period, nakp); +          break; +        } +        break; +       +      case CI_MAGICNUMBER: +        if (!(ao->neg_magicnumber || go->neg_magicnumber) || +            cilen != CILEN_LONG) { +          orc = CONFREJ; +          break; +        } +        GETLONG(cilong, p); +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong); +        traceNdx = strlen(traceBuf); +#endif + +        /* +         * He must have a different magic number. +         */ +        if (go->neg_magicnumber && +            cilong == go->magicnumber) { +          cilong = magic();  /* Don't put magic() inside macro! */ +          orc = CONFNAK; +          PUTCHAR(CI_MAGICNUMBER, nakp); +          PUTCHAR(CILEN_LONG, nakp); +          PUTLONG(cilong, nakp); +          break; +        } +        ho->neg_magicnumber = 1; +        ho->magicnumber = cilong; +        break; +       +       +      case CI_PCOMPRESSION: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION"); +        traceNdx = strlen(traceBuf); +#endif +        if (!ao->neg_pcompression || +            cilen != CILEN_VOID) { +          orc = CONFREJ; +          break; +        } +        ho->neg_pcompression = 1; +        break; +       +      case CI_ACCOMPRESSION: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION"); +        traceNdx = strlen(traceBuf); +#endif +        if (!ao->neg_accompression || +            cilen != CILEN_VOID) { +          orc = CONFREJ; +          break; +        } +        ho->neg_accompression = 1; +        break; +       +      case CI_MRRU: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      case CI_SSNHF: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      case CI_EPDISC: +#if TRACELCP > 0 +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC"); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +       +      default: +#if TRACELCP +        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype); +        traceNdx = strlen(traceBuf); +#endif +        orc = CONFREJ; +        break; +    } + +  endswitch: +#if TRACELCP +    if (traceNdx >= 80 - 32) { +      LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf)); +      traceNdx = 0; +    } +#endif +    if (orc == CONFACK && /* Good CI */ +        rc != CONFACK) {  /*  but prior CI wasnt? */ +      continue;           /* Don't send this one */ +    } + +    if (orc == CONFNAK) {     /* Nak this CI? */ +      if (reject_if_disagree  /* Getting fed up with sending NAKs? */ +          && citype != CI_MAGICNUMBER) { +        orc = CONFREJ;        /* Get tough if so */ +      } else { +        if (rc == CONFREJ) {  /* Rejecting prior CI? */ +          continue;           /* Don't send this one */ +        } +        rc = CONFNAK; +      } +    } +    if (orc == CONFREJ) {        /* Reject this CI */ +      rc = CONFREJ; +      if (cip != rejp) {         /* Need to move rejected CI? */ +        BCOPY(cip, rejp, cilen); /* Move it */ +      } +      INCPTR(cilen, rejp);       /* Update output pointer */ +    } +  } + +  /* +   * If we wanted to send additional NAKs (for unsent CIs), the +   * code would go here.  The extra NAKs would go at *nakp. +   * At present there are no cases where we want to ask the +   * peer to negotiate an option. +   */ + +  switch (rc) { +    case CONFACK: +      *lenp = (int)(next - inp); +      break; +    case CONFNAK: +      /* +       * Copy the Nak'd options from the nak_buffer to the caller's buffer. +       */ +      *lenp = (int)(nakp - nak_buffer); +      BCOPY(nak_buffer, inp, *lenp); +      break; +    case CONFREJ: +      *lenp = (int)(rejp - inp); +      break; +  } + +#if TRACELCP > 0 +  if (traceNdx > 0) { +    LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf)); +  } +#endif +  LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc))); +  return (rc);      /* Return final code */ +} + + +/* + * lcp_up - LCP has come UP. + */ +static void +lcp_up(fsm *f) +{ +  lcp_options *wo = &lcp_wantoptions[f->unit]; +  lcp_options *ho = &lcp_hisoptions[f->unit]; +  lcp_options *go = &lcp_gotoptions[f->unit]; +  lcp_options *ao = &lcp_allowoptions[f->unit]; + +  if (!go->neg_magicnumber) { +    go->magicnumber = 0; +  } +  if (!ho->neg_magicnumber) { +    ho->magicnumber = 0; +  } + +  /* +   * Set our MTU to the smaller of the MTU we wanted and +   * the MRU our peer wanted.  If we negotiated an MRU, +   * set our MRU to the larger of value we wanted and +   * the value we got in the negotiation. +   */ +  ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)), +                 (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl), +                  ho->neg_pcompression, ho->neg_accompression); +  /* +   * If the asyncmap hasn't been negotiated, we really should +   * set the receive asyncmap to ffffffff, but we set it to 0 +   * for backwards contemptibility. +   */ +  ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU), +                 (go->neg_asyncmap? go->asyncmap: 0x00000000), +                  go->neg_pcompression, go->neg_accompression); + +  if (ho->neg_mru) { +    peer_mru[f->unit] = ho->mru; +  } + +  lcp_echo_lowerup(f->unit); /* Enable echo messages */ + +  link_established(f->unit); +} + + +/* + * lcp_down - LCP has gone DOWN. + * + * Alert other protocols. + */ +static void +lcp_down(fsm *f) +{ +  lcp_options *go = &lcp_gotoptions[f->unit]; + +  lcp_echo_lowerdown(f->unit); + +  link_down(f->unit); + +  ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0); +  ppp_recv_config(f->unit, PPP_MRU, +                  (go->neg_asyncmap? go->asyncmap: 0x00000000), +                   go->neg_pcompression, go->neg_accompression); +  peer_mru[f->unit] = PPP_MRU; +} + + +/* + * lcp_starting - LCP needs the lower layer up. + */ +static void +lcp_starting(fsm *f) +{ +  link_required(f->unit); +} + + +/* + * lcp_finished - LCP has finished with the lower layer. + */ +static void +lcp_finished(fsm *f) +{ +  link_terminated(f->unit); +} + + +#if 0 +/* + * print_string - print a readable representation of a string using + * printer. + */ +static void +print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg) +{ +  int c; +   +  printer(arg, "\""); +  for (; len > 0; --len) { +    c = *p++; +    if (' ' <= c && c <= '~') { +        if (c == '\\' || c == '"') { +          printer(arg, "\\"); +        } +        printer(arg, "%c", c); +    } else { +      switch (c) { +        case '\n': +          printer(arg, "\\n"); +          break; +        case '\r': +          printer(arg, "\\r"); +          break; +        case '\t': +          printer(arg, "\\t"); +          break; +        default: +          printer(arg, "\\%.3o", c); +        } +    } +  } +  printer(arg, "\""); +} + + +/* + * lcp_printpkt - print the contents of an LCP packet. + */ +static char *lcp_codenames[] = { +  "ConfReq", "ConfAck", "ConfNak", "ConfRej", +  "TermReq", "TermAck", "CodeRej", "ProtRej", +  "EchoReq", "EchoRep", "DiscReq" +}; + +static int +lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) +{ +  int code, id, len, olen; +  u_char *pstart, *optend; +  u_short cishort; +  u32_t cilong; + +  if (plen < HEADERLEN) { +    return 0; +  } +  pstart = p; +  GETCHAR(code, p); +  GETCHAR(id, p); +  GETSHORT(len, p); +  if (len < HEADERLEN || len > plen) { +    return 0; +  } + +  if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) { +    printer(arg, " %s", lcp_codenames[code-1]); +  } else { +    printer(arg, " code=0x%x", code); +  } +  printer(arg, " id=0x%x", id); +  len -= HEADERLEN; +  switch (code) { +    case CONFREQ: +    case CONFACK: +    case CONFNAK: +    case CONFREJ: +      /* print option list */ +      while (len >= 2) { +        GETCHAR(code, p); +        GETCHAR(olen, p); +        p -= 2; +        if (olen < 2 || olen > len) { +          break; +        } +        printer(arg, " <"); +        len -= olen; +        optend = p + olen; +        switch (code) { +          case CI_MRU: +            if (olen == CILEN_SHORT) { +              p += 2; +              GETSHORT(cishort, p); +              printer(arg, "mru %d", cishort); +            } +            break; +          case CI_ASYNCMAP: +            if (olen == CILEN_LONG) { +              p += 2; +              GETLONG(cilong, p); +              printer(arg, "asyncmap 0x%lx", cilong); +            } +            break; +          case CI_AUTHTYPE: +            if (olen >= CILEN_SHORT) { +              p += 2; +              printer(arg, "auth "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case PPP_PAP: +                  printer(arg, "pap"); +                  break; +                case PPP_CHAP: +                  printer(arg, "chap"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_QUALITY: +            if (olen >= CILEN_SHORT) { +              p += 2; +              printer(arg, "quality "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case PPP_LQR: +                  printer(arg, "lqr"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_CALLBACK: +            if (olen >= CILEN_CHAR) { +              p += 2; +              printer(arg, "callback "); +              GETSHORT(cishort, p); +              switch (cishort) { +                case CBCP_OPT: +                  printer(arg, "CBCP"); +                  break; +                default: +                  printer(arg, "0x%x", cishort); +              } +            } +            break; +          case CI_MAGICNUMBER: +            if (olen == CILEN_LONG) { +              p += 2; +              GETLONG(cilong, p); +              printer(arg, "magic 0x%x", cilong); +            } +            break; +          case CI_PCOMPRESSION: +            if (olen == CILEN_VOID) { +              p += 2; +              printer(arg, "pcomp"); +            } +            break; +          case CI_ACCOMPRESSION: +            if (olen == CILEN_VOID) { +              p += 2; +              printer(arg, "accomp"); +            } +            break; +        } +        while (p < optend) { +          GETCHAR(code, p); +          printer(arg, " %.2x", code); +        } +        printer(arg, ">"); +      } +      break; +     +    case TERMACK: +    case TERMREQ: +      if (len > 0 && *p >= ' ' && *p < 0x7f) { +        printer(arg, " "); +        print_string((char*)p, len, printer, arg); +        p += len; +        len = 0; +      } +      break; +     +    case ECHOREQ: +    case ECHOREP: +    case DISCREQ: +      if (len >= 4) { +        GETLONG(cilong, p); +        printer(arg, " magic=0x%x", cilong); +        p += 4; +        len -= 4; +      } +      break; +  } + +  /* print the rest of the bytes in the packet */ +  for (; len > 0; --len) { +    GETCHAR(code, p); +    printer(arg, " %.2x", code); +  } + +  return (int)(p - pstart); +} +#endif + +/* + * Time to shut down the link because there is nothing out there. + */ +static void +LcpLinkFailure (fsm *f) +{ +  if (f->state == LS_OPENED) { +    LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending)); +    LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n")); +    lcp_close(f->unit, "Peer not responding"); +  } +} + +/* + * Timer expired for the LCP echo requests from this process. + */ +static void +LcpEchoCheck (fsm *f) +{ +  LcpSendEchoRequest (f); + +  /* +   * Start the timer for the next interval. +   */ +  LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0); + +  TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval); +  lcp_echo_timer_running = 1; +} + +/* + * LcpEchoTimeout - Timer expired on the LCP echo + */ +static void +LcpEchoTimeout (void *arg) +{ +  if (lcp_echo_timer_running != 0) { +    lcp_echo_timer_running = 0; +    LcpEchoCheck ((fsm *) arg); +  } +} + +/* + * LcpEchoReply - LCP has received a reply to the echo + */ +static void +lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len) +{ +  u32_t magic; + +  LWIP_UNUSED_ARG(id); + +  /* Check the magic number - don't count replies from ourselves. */ +  if (len < 4) { +    LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len)); +    return; +  } +  GETLONG(magic, inp); +  if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { +    LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n")); +    return; +  } +   +  /* Reset the number of outstanding echo frames */ +  lcp_echos_pending = 0; +} + +/* + * LcpSendEchoRequest - Send an echo request frame to the peer + */ +static void +LcpSendEchoRequest (fsm *f) +{ +  u32_t lcp_magic; +  u_char pkt[4], *pktp; + +  /* +   * Detect the failure of the peer at this point. +   */ +  if (lcp_echo_fails != 0) { +    if (lcp_echos_pending++ >= lcp_echo_fails) { +      LcpLinkFailure(f); +      lcp_echos_pending = 0; +    } +  } + +  /* +   * Make and send the echo request frame. +   */ +  if (f->state == LS_OPENED) { +    lcp_magic = lcp_gotoptions[f->unit].magicnumber; +    pktp = pkt; +    PUTLONG(lcp_magic, pktp); +    fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt)); +  } +} + +/* + * lcp_echo_lowerup - Start the timer for the LCP frame + */ + +static void +lcp_echo_lowerup (int unit) +{ +  fsm *f = &lcp_fsm[unit]; + +  /* Clear the parameters for generating echo frames */ +  lcp_echos_pending      = 0; +  lcp_echo_number        = 0; +  lcp_echo_timer_running = 0; + +  /* If a timeout interval is specified then start the timer */ +  if (lcp_echo_interval != 0) { +    LcpEchoCheck (f); +  } +} + +/* + * lcp_echo_lowerdown - Stop the timer for the LCP frame + */ + +static void +lcp_echo_lowerdown (int unit) +{ +  fsm *f = &lcp_fsm[unit]; + +  if (lcp_echo_timer_running != 0) { +    UNTIMEOUT (LcpEchoTimeout, f); +    lcp_echo_timer_running = 0; +  } +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.h new file mode 100644 index 000000000..1a5e5a4c0 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/lcp.h @@ -0,0 +1,167 @@ +/***************************************************************************** +* lcp.h - Network Link Control Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * lcp.h - Link Control Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: lcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + */ + +#ifndef LCP_H +#define LCP_H + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Options. + */ +#define CI_MRU           1  /* Maximum Receive Unit */ +#define CI_ASYNCMAP      2  /* Async Control Character Map */ +#define CI_AUTHTYPE      3  /* Authentication Type */ +#define CI_QUALITY       4  /* Quality Protocol */ +#define CI_MAGICNUMBER   5  /* Magic Number */ +#define CI_PCOMPRESSION  7  /* Protocol Field Compression */ +#define CI_ACCOMPRESSION 8  /* Address/Control Field Compression */ +#define CI_CALLBACK      13 /* callback */ +#define CI_MRRU          17 /* max reconstructed receive unit; multilink */ +#define CI_SSNHF         18 /* short sequence numbers for multilink */ +#define CI_EPDISC        19 /* endpoint discriminator */ + +/* + * LCP-specific packet types. + */ +#define PROTREJ          8  /* Protocol Reject */ +#define ECHOREQ          9  /* Echo Request */ +#define ECHOREP          10 /* Echo Reply */ +#define DISCREQ          11 /* Discard Request */ +#define CBCP_OPT         6  /* Use callback control protocol */ + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * The state of options is described by an lcp_options structure. + */ +typedef struct lcp_options { +    u_int passive           : 1; /* Don't die if we don't get a response */ +    u_int silent            : 1; /* Wait for the other end to start first */ +    u_int restart           : 1; /* Restart vs. exit after close */ +    u_int neg_mru           : 1; /* Negotiate the MRU? */ +    u_int neg_asyncmap      : 1; /* Negotiate the async map? */ +    u_int neg_upap          : 1; /* Ask for UPAP authentication? */ +    u_int neg_chap          : 1; /* Ask for CHAP authentication? */ +    u_int neg_magicnumber   : 1; /* Ask for magic number? */ +    u_int neg_pcompression  : 1; /* HDLC Protocol Field Compression? */ +    u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */ +    u_int neg_lqr           : 1; /* Negotiate use of Link Quality Reports */ +    u_int neg_cbcp          : 1; /* Negotiate use of CBCP */ +#ifdef PPP_MULTILINK +    u_int neg_mrru          : 1; /* Negotiate multilink MRRU */ +    u_int neg_ssnhf         : 1; /* Negotiate short sequence numbers */ +    u_int neg_endpoint      : 1; /* Negotiate endpoint discriminator */ +#endif +    u_short mru;                 /* Value of MRU */ +#ifdef PPP_MULTILINK +    u_short mrru;                /* Value of MRRU, and multilink enable */ +#endif +    u_char chap_mdtype;          /* which MD type (hashing algorithm) */ +    u32_t asyncmap;              /* Value of async map */ +    u32_t magicnumber; +    int numloops;                /* Number of loops during magic number neg. */ +    u32_t lqr_period;            /* Reporting period for LQR 1/100ths second */ +#ifdef PPP_MULTILINK +    struct epdisc endpoint;      /* endpoint discriminator */ +#endif +} lcp_options; + +/* + * Values for phase from BSD pppd.h based on RFC 1661. + */ +typedef enum { +  PHASE_DEAD = 0, +  PHASE_INITIALIZE, +  PHASE_ESTABLISH, +  PHASE_AUTHENTICATE, +  PHASE_CALLBACK, +  PHASE_NETWORK, +  PHASE_TERMINATE +} LinkPhase; + + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ +extern lcp_options lcp_wantoptions[]; +extern lcp_options lcp_gotoptions[]; +extern lcp_options lcp_allowoptions[]; +extern lcp_options lcp_hisoptions[]; +extern ext_accm xmit_accm[]; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +void lcp_init     (int); +void lcp_open     (int); +void lcp_close    (int, char *); +void lcp_lowerup  (int); +void lcp_lowerdown(int); +void lcp_sprotrej (int, u_char *, int); /* send protocol reject */ + +extern struct protent lcp_protent; + +/* Default number of times we receive our magic number from the peer +   before deciding the link is looped-back. */ +#define DEFLOOPBACKFAIL 10 + +#endif /* LCP_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.c new file mode 100644 index 000000000..d3922bb56 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.c @@ -0,0 +1,82 @@ +/***************************************************************************** +* magic.c - Network Random Number Generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original based on BSD magic.c. +*****************************************************************************/ +/* + * magic.c - PPP Magic Number routines. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT + +#include "ppp.h" +#include "randm.h" +#include "magic.h" + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * magicInit - Initialize the magic number generator. + * + * Since we use another random number generator that has its own + * initialization, we do nothing here. + */ +void magicInit() +{ +  return; +} + +/* + * magic - Returns the next magic number. + */ +u32_t magic() +{ +  return avRandom(); +} + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.h new file mode 100644 index 000000000..bc5174993 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/magic.h @@ -0,0 +1,67 @@ +/***************************************************************************** +* magic.h - Network Random Number Generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * magic.h - PPP Magic Number definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * $Id: magic.h,v 1.2 2007/12/02 22:35:55 fbernon Exp $ + */ + +#ifndef MAGIC_H +#define MAGIC_H + +/***************************************************************************** +************************** PUBLIC FUNCTIONS ********************************** +*****************************************************************************/ + +/* Initialize the magic number generator */ +void  magicInit(void); + +/* Returns the next magic number */ +u32_t magic(void); + +#endif /* MAGIC_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.c new file mode 100644 index 000000000..d65ecedbf --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.c @@ -0,0 +1,318 @@ +/* + *********************************************************************** + ** md5.c -- the source code for MD5 routines                         ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              ** + ** Created: 2/17/90 RLR                                              ** + ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  ** + **                                                                   ** + ** License to copy and use this software is granted provided that    ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message-     ** + ** Digest Algorithm" in all material mentioning or referencing this  ** + ** software or this function.                                        ** + **                                                                   ** + ** License is also granted to make and use derivative works          ** + ** provided that such works are identified as "derived from the RSA  ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          ** + ** material mentioning or referencing the derived work.              ** + **                                                                   ** + ** RSA Data Security, Inc. makes no representations concerning       ** + ** either the merchantability of this software or the suitability    ** + ** of this software for any particular purpose.  It is provided "as  ** + ** is" without express or implied warranty of any kind.              ** + **                                                                   ** + ** These notices must be retained in any copies of any part of this  ** + ** documentation and/or software.                                    ** + *********************************************************************** + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if CHAP_SUPPORT || MD5_SUPPORT + +#include "ppp.h" +#include "pppdebug.h" + +#include "md5.h" + +/* + *********************************************************************** + **  Message-digest routines:                                         ** + **  To form the message digest for a message M                       ** + **    (1) Initialize a context buffer mdContext using MD5Init        ** + **    (2) Call MD5Update on mdContext and M                          ** + **    (3) Call MD5Final on mdContext                                 ** + **  The message digest is now in mdContext->digest[0...15]           ** + *********************************************************************** + */ + +/* forward declaration */ +static void Transform (u32_t *buf, u32_t *in); + +static unsigned char PADDING[64] = { +  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +}; + +/* F, G, H and I are basic MD5 functions */ +#define F(x, y, z) (((x) & (y)) | ((~x) & (z))) +#define G(x, y, z) (((x) & (z)) | ((y) & (~z))) +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define I(x, y, z) ((y) ^ ((x) | (~z))) + +/* ROTATE_LEFT rotates x left n bits */ +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n)))) + +/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */ +/* Rotation is separate from addition to prevent recomputation */ +#define FF(a, b, c, d, x, s, ac) \ +  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define GG(a, b, c, d, x, s, ac) \ +  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define HH(a, b, c, d, x, s, ac) \ +  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } +#define II(a, b, c, d, x, s, ac) \ +  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \ +   (a) = ROTATE_LEFT ((a), (s)); \ +   (a) += (b); \ +  } + +#ifdef __STDC__ +#define UL(x) x##UL +#else +#ifdef WIN32 +#define UL(x) x##UL +#else +#define UL(x) x +#endif +#endif + +/* The routine MD5Init initializes the message-digest context +   mdContext. All fields are set to zero. + */ +void +MD5Init (MD5_CTX *mdContext) +{ +  mdContext->i[0] = mdContext->i[1] = (u32_t)0; + +  /* Load magic initialization constants. */ +  mdContext->buf[0] = (u32_t)0x67452301UL; +  mdContext->buf[1] = (u32_t)0xefcdab89UL; +  mdContext->buf[2] = (u32_t)0x98badcfeUL; +  mdContext->buf[3] = (u32_t)0x10325476UL; +} + +/* The routine MD5Update updates the message-digest context to +   account for the presence of each of the characters inBuf[0..inLen-1] +   in the message whose digest is being computed. + */ +void +MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) +{ +  u32_t in[16]; +  int mdi; +  unsigned int i, ii; + +#if 0 +  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf); +  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf); +#endif +   +  /* compute number of bytes mod 64 */ +  mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + +  /* update number of bits */ +  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) { +    mdContext->i[1]++; +  } +  mdContext->i[0] += ((u32_t)inLen << 3); +  mdContext->i[1] += ((u32_t)inLen >> 29); + +  while (inLen--) { +    /* add new character to buffer, increment mdi */ +    mdContext->in[mdi++] = *inBuf++; + +    /* transform if necessary */ +    if (mdi == 0x40) { +      for (i = 0, ii = 0; i < 16; i++, ii += 4) { +        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | +                (((u32_t)mdContext->in[ii+2]) << 16) | +                (((u32_t)mdContext->in[ii+1]) << 8)  | +                ((u32_t)mdContext->in[ii]); +      } +      Transform (mdContext->buf, in); +      mdi = 0; +    } +  } +} + +/* The routine MD5Final terminates the message-digest computation and +   ends with the desired message digest in mdContext->digest[0...15]. + */ +void +MD5Final (unsigned char hash[], MD5_CTX *mdContext) +{ +  u32_t in[16]; +  int mdi; +  unsigned int i, ii; +  unsigned int padLen; + +  /* save number of bits */ +  in[14] = mdContext->i[0]; +  in[15] = mdContext->i[1]; + +  /* compute number of bytes mod 64 */ +  mdi = (int)((mdContext->i[0] >> 3) & 0x3F); + +  /* pad out to 56 mod 64 */ +  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi); +  MD5Update (mdContext, PADDING, padLen); + +  /* append length in bits and transform */ +  for (i = 0, ii = 0; i < 14; i++, ii += 4) { +    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) | +            (((u32_t)mdContext->in[ii+2]) << 16) | +            (((u32_t)mdContext->in[ii+1]) << 8)  | +            ((u32_t)mdContext->in[ii]); +  } +  Transform (mdContext->buf, in); + +  /* store buffer in digest */ +  for (i = 0, ii = 0; i < 4; i++, ii += 4) { +    mdContext->digest[ii]   = (unsigned char)(mdContext->buf[i] & 0xFF); +    mdContext->digest[ii+1] = +      (unsigned char)((mdContext->buf[i] >> 8)  & 0xFF); +    mdContext->digest[ii+2] = +      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF); +    mdContext->digest[ii+3] = +      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF); +  } +  SMEMCPY(hash, mdContext->digest, 16); +} + +/* Basic MD5 step. Transforms buf based on in. + */ +static void +Transform (u32_t *buf, u32_t *in) +{ +  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3]; + +  /* Round 1 */ +#define S11 7 +#define S12 12 +#define S13 17 +#define S14 22 +  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */ +  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */ +  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */ +  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */ +  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */ +  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */ +  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */ +  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */ +  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */ +  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */ +  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */ +  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */ +  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */ +  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */ +  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */ +  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */ + +  /* Round 2 */ +#define S21 5 +#define S22 9 +#define S23 14 +#define S24 20 +  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */ +  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */ +  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */ +  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */ +  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */ +  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */ +  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */ +  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */ +  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */ +  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */ +  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */ +  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */ +  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */ +  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */ +  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */ +  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */ + +  /* Round 3 */ +#define S31 4 +#define S32 11 +#define S33 16 +#define S34 23 +  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */ +  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */ +  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */ +  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */ +  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */ +  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */ +  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */ +  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */ +  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */ +  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */ +  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */ +  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */ +  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */ +  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */ +  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */ +  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */ + +  /* Round 4 */ +#define S41 6 +#define S42 10 +#define S43 15 +#define S44 21 +  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */ +  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */ +  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */ +  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */ +  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */ +  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */ +  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */ +  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */ +  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */ +  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */ +  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */ +  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */ +  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */ +  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */ +  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */ +  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */ + +  buf[0] += a; +  buf[1] += b; +  buf[2] += c; +  buf[3] += d; +} + +#endif /* CHAP_SUPPORT || MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.h new file mode 100644 index 000000000..e129533f3 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/md5.h @@ -0,0 +1,55 @@ +/* + *********************************************************************** + ** md5.h -- header file for implementation of MD5                    ** + ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              ** + ** Created: 2/17/90 RLR                                              ** + ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               ** + ** Revised (for MD5): RLR 4/27/91                                    ** + **   -- G modified to have y&~z instead of y&z                       ** + **   -- FF, GG, HH modified to add in last register done             ** + **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     ** + **   -- distinct additive constant for each step                     ** + **   -- round 4 added, working mod 7                                 ** + *********************************************************************** + */ + +/* + *********************************************************************** + ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  ** + **                                                                   ** + ** License to copy and use this software is granted provided that    ** + ** it is identified as the "RSA Data Security, Inc. MD5 Message-     ** + ** Digest Algorithm" in all material mentioning or referencing this  ** + ** software or this function.                                        ** + **                                                                   ** + ** License is also granted to make and use derivative works          ** + ** provided that such works are identified as "derived from the RSA  ** + ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          ** + ** material mentioning or referencing the derived work.              ** + **                                                                   ** + ** RSA Data Security, Inc. makes no representations concerning       ** + ** either the merchantability of this software or the suitability    ** + ** of this software for any particular purpose.  It is provided "as  ** + ** is" without express or implied warranty of any kind.              ** + **                                                                   ** + ** These notices must be retained in any copies of any part of this  ** + ** documentation and/or software.                                    ** + *********************************************************************** + */ + +#ifndef MD5_H +#define MD5_H + +/* Data structure for MD5 (Message-Digest) computation */ +typedef struct { +  u32_t i[2];               /* number of _bits_ handled mod 2^64 */ +  u32_t buf[4];             /* scratch buffer */ +  unsigned char in[64];     /* input buffer */ +  unsigned char digest[16]; /* actual digest after MD5Final call */ +} MD5_CTX; + +void MD5Init  ( MD5_CTX *mdContext); +void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen); +void MD5Final ( unsigned char hash[], MD5_CTX *mdContext); + +#endif /* MD5_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.c new file mode 100644 index 000000000..7c3fd7e4c --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.c @@ -0,0 +1,619 @@ +/***************************************************************************** +* pap.c - Network Password Authentication Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ +/* + * upap.c - User/Password Authentication Protocol. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "auth.h" +#include "pap.h" + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +/* + * Protocol entry points. + */ +static void upap_init      (int); +static void upap_lowerup   (int); +static void upap_lowerdown (int); +static void upap_input     (int, u_char *, int); +static void upap_protrej   (int); + +static void upap_timeout   (void *); +static void upap_reqtimeout(void *); +static void upap_rauthreq  (upap_state *, u_char *, int, int); +static void upap_rauthack  (upap_state *, u_char *, int, int); +static void upap_rauthnak  (upap_state *, u_char *, int, int); +static void upap_sauthreq  (upap_state *); +static void upap_sresp     (upap_state *, u_char, u_char, char *, int); + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +struct protent pap_protent = { +  PPP_PAP, +  upap_init, +  upap_input, +  upap_protrej, +  upap_lowerup, +  upap_lowerdown, +  NULL, +  NULL, +#if 0 +  upap_printpkt, +  NULL, +#endif +  1, +  "PAP", +#if 0 +  NULL, +  NULL, +  NULL +#endif +}; + +upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ + + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + *  Set the default login name and password for the pap sessions + */ +void +upap_setloginpasswd(int unit, const char *luser, const char *lpassword) +{ +  upap_state *u = &upap[unit]; +   +  /* Save the username and password we're given */ +  u->us_user = luser; +  u->us_userlen = strlen(luser); +  u->us_passwd = lpassword; +  u->us_passwdlen = strlen(lpassword); +} + + +/* + * upap_authwithpeer - Authenticate us with our peer (start client). + * + * Set new state and send authenticate's. + */ +void +upap_authwithpeer(int unit, char *user, char *password) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n", +             unit, user, password, u->us_clientstate)); + +  upap_setloginpasswd(unit, user, password); + +  u->us_transmits = 0; + +  /* Lower layer up yet? */ +  if (u->us_clientstate == UPAPCS_INITIAL || +      u->us_clientstate == UPAPCS_PENDING) { +    u->us_clientstate = UPAPCS_PENDING; +    return; +  } + +  upap_sauthreq(u);      /* Start protocol */ +} + + +/* + * upap_authpeer - Authenticate our peer (start server). + * + * Set new state. + */ +void +upap_authpeer(int unit) +{ +  upap_state *u = &upap[unit]; + +  /* Lower layer up yet? */ +  if (u->us_serverstate == UPAPSS_INITIAL || +      u->us_serverstate == UPAPSS_PENDING) { +    u->us_serverstate = UPAPSS_PENDING; +    return; +  } + +  u->us_serverstate = UPAPSS_LISTEN; +  if (u->us_reqtimeout > 0) { +    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); +  } +} + + + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ +/* + * upap_init - Initialize a UPAP unit. + */ +static void +upap_init(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit)); +  u->us_unit         = unit; +  u->us_user         = NULL; +  u->us_userlen      = 0; +  u->us_passwd       = NULL; +  u->us_passwdlen    = 0; +  u->us_clientstate  = UPAPCS_INITIAL; +  u->us_serverstate  = UPAPSS_INITIAL; +  u->us_id           = 0; +  u->us_timeouttime  = UPAP_DEFTIMEOUT; +  u->us_maxtransmits = 10; +  u->us_reqtimeout   = UPAP_DEFREQTIME; +} + +/* + * upap_timeout - Retransmission timer for sending auth-reqs expired. + */ +static void +upap_timeout(void *arg) +{ +  upap_state *u = (upap_state *) arg; + +  UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n",  +        u->us_unit, u->us_timeouttime, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { +    return; +  } + +  if (u->us_transmits >= u->us_maxtransmits) { +    /* give up in disgust */ +    UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n")); +    u->us_clientstate = UPAPCS_BADAUTH; +    auth_withpeer_fail(u->us_unit, PPP_PAP); +    return; +  } + +  upap_sauthreq(u);    /* Send Authenticate-Request */ +} + + +/* + * upap_reqtimeout - Give up waiting for the peer to send an auth-req. + */ +static void +upap_reqtimeout(void *arg) +{ +  upap_state *u = (upap_state *) arg; + +  if (u->us_serverstate != UPAPSS_LISTEN) { +    return; /* huh?? */ +  } + +  auth_peer_fail(u->us_unit, PPP_PAP); +  u->us_serverstate = UPAPSS_BADAUTH; +} + + +/* + * upap_lowerup - The lower layer is up. + * + * Start authenticating if pending. + */ +static void +upap_lowerup(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate)); + +  if (u->us_clientstate == UPAPCS_INITIAL) { +    u->us_clientstate = UPAPCS_CLOSED; +  } else if (u->us_clientstate == UPAPCS_PENDING) { +    upap_sauthreq(u);  /* send an auth-request */ +  } + +  if (u->us_serverstate == UPAPSS_INITIAL) { +    u->us_serverstate = UPAPSS_CLOSED; +  } else if (u->us_serverstate == UPAPSS_PENDING) { +    u->us_serverstate = UPAPSS_LISTEN; +    if (u->us_reqtimeout > 0) { +      TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout); +    } +  } +} + + +/* + * upap_lowerdown - The lower layer is down. + * + * Cancel all timeouts. + */ +static void +upap_lowerdown(int unit) +{ +  upap_state *u = &upap[unit]; + +  UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate)); + +  if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */ +    UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */ +  } +  if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) { +    UNTIMEOUT(upap_reqtimeout, u); +  } + +  u->us_clientstate = UPAPCS_INITIAL; +  u->us_serverstate = UPAPSS_INITIAL; +} + + +/* + * upap_protrej - Peer doesn't speak this protocol. + * + * This shouldn't happen.  In any case, pretend lower layer went down. + */ +static void +upap_protrej(int unit) +{ +  upap_state *u = &upap[unit]; + +  if (u->us_clientstate == UPAPCS_AUTHREQ) { +    UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n")); +    auth_withpeer_fail(unit, PPP_PAP); +  } +  if (u->us_serverstate == UPAPSS_LISTEN) { +    UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n")); +    auth_peer_fail(unit, PPP_PAP); +  } +  upap_lowerdown(unit); +} + + +/* + * upap_input - Input UPAP packet. + */ +static void +upap_input(int unit, u_char *inpacket, int l) +{ +  upap_state *u = &upap[unit]; +  u_char *inp; +  u_char code, id; +  int len; + +  /* +   * Parse header (code, id and length). +   * If packet too short, drop it. +   */ +  inp = inpacket; +  if (l < UPAP_HEADERLEN) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n")); +    return; +  } +  GETCHAR(code, inp); +  GETCHAR(id, inp); +  GETSHORT(len, inp); +  if (len < UPAP_HEADERLEN) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n")); +    return; +  } +  if (len > l) { +    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n")); +    return; +  } +  len -= UPAP_HEADERLEN; + +  /* +   * Action depends on code. +   */ +  switch (code) { +    case UPAP_AUTHREQ: +      upap_rauthreq(u, inp, id, len); +      break; + +    case UPAP_AUTHACK: +      upap_rauthack(u, inp, id, len); +      break; + +    case UPAP_AUTHNAK: +      upap_rauthnak(u, inp, id, len); +      break; + +    default:        /* XXX Need code reject */ +      break; +  } +} + + +/* + * upap_rauth - Receive Authenticate. + */ +static void +upap_rauthreq(upap_state *u, u_char *inp, int id, int len) +{ +  u_char ruserlen, rpasswdlen; +  char *ruser, *rpasswd; +  int retcode; +  char *msg; +  int msglen; + +  UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id)); + +  if (u->us_serverstate < UPAPSS_LISTEN) { +    return; +  } + +  /* +   * If we receive a duplicate authenticate-request, we are +   * supposed to return the same status as for the first request. +   */ +  if (u->us_serverstate == UPAPSS_OPEN) { +    upap_sresp(u, UPAP_AUTHACK, id, "", 0);  /* return auth-ack */ +    return; +  } +  if (u->us_serverstate == UPAPSS_BADAUTH) { +    upap_sresp(u, UPAP_AUTHNAK, id, "", 0);  /* return auth-nak */ +    return; +  } + +  /* +   * Parse user/passwd. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  GETCHAR(ruserlen, inp); +  len -= sizeof (u_char) + ruserlen + sizeof (u_char); +  if (len < 0) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  ruser = (char *) inp; +  INCPTR(ruserlen, inp); +  GETCHAR(rpasswdlen, inp); +  if (len < rpasswdlen) { +    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); +    return; +  } +  rpasswd = (char *) inp; + +  /* +   * Check the username and password given. +   */ +  retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen); +  BZERO(rpasswd, rpasswdlen); + +  upap_sresp(u, retcode, id, msg, msglen); + +  if (retcode == UPAP_AUTHACK) { +    u->us_serverstate = UPAPSS_OPEN; +    auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen); +  } else { +    u->us_serverstate = UPAPSS_BADAUTH; +    auth_peer_fail(u->us_unit, PPP_PAP); +  } + +  if (u->us_reqtimeout > 0) { +    UNTIMEOUT(upap_reqtimeout, u); +  } +} + + +/* + * upap_rauthack - Receive Authenticate-Ack. + */ +static void +upap_rauthack(upap_state *u, u_char *inp, int id, int len) +{ +  u_char msglen; +  char *msg; + +  LWIP_UNUSED_ARG(id); + +  UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ +    return; +  } + +  /* +   * Parse message. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); +    return; +  } +  GETCHAR(msglen, inp); +  len -= sizeof (u_char); +  if (len < msglen) { +    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); +    return; +  } +  msg = (char *) inp; +  PRINTMSG(msg, msglen); + +  u->us_clientstate = UPAPCS_OPEN; + +  auth_withpeer_success(u->us_unit, PPP_PAP); +} + + +/* + * upap_rauthnak - Receive Authenticate-Nakk. + */ +static void +upap_rauthnak(upap_state *u, u_char *inp, int id, int len) +{ +  u_char msglen; +  char *msg; + +  LWIP_UNUSED_ARG(id); + +  UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate)); + +  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ +    return; +  } + +  /* +   * Parse message. +   */ +  if (len < sizeof (u_char)) { +    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); +  } else { +    GETCHAR(msglen, inp); +    if(msglen > 0) { +      len -= sizeof (u_char); +      if (len < msglen) { +        UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); +        return; +      } +      msg = (char *) inp; +      PRINTMSG(msg, msglen); +    } +  } + +  u->us_clientstate = UPAPCS_BADAUTH; + +  UPAPDEBUG((LOG_ERR, "PAP authentication failed\n")); +  auth_withpeer_fail(u->us_unit, PPP_PAP); +} + + +/* + * upap_sauthreq - Send an Authenticate-Request. + */ +static void +upap_sauthreq(upap_state *u) +{ +  u_char *outp; +  int outlen; + +  outlen = UPAP_HEADERLEN + 2 * sizeof (u_char)  +         + u->us_userlen + u->us_passwdlen; +  outp = outpacket_buf[u->us_unit]; + +  MAKEHEADER(outp, PPP_PAP); + +  PUTCHAR(UPAP_AUTHREQ, outp); +  PUTCHAR(++u->us_id, outp); +  PUTSHORT(outlen, outp); +  PUTCHAR(u->us_userlen, outp); +  BCOPY(u->us_user, outp, u->us_userlen); +  INCPTR(u->us_userlen, outp); +  PUTCHAR(u->us_passwdlen, outp); +  BCOPY(u->us_passwd, outp, u->us_passwdlen); + +  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + +  UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id)); + +  TIMEOUT(upap_timeout, u, u->us_timeouttime); +  ++u->us_transmits; +  u->us_clientstate = UPAPCS_AUTHREQ; +} + + +/* + * upap_sresp - Send a response (ack or nak). + */ +static void +upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen) +{ +  u_char *outp; +  int outlen; + +  outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen; +  outp = outpacket_buf[u->us_unit]; +  MAKEHEADER(outp, PPP_PAP); + +  PUTCHAR(code, outp); +  PUTCHAR(id, outp); +  PUTSHORT(outlen, outp); +  PUTCHAR(msglen, outp); +  BCOPY(msg, outp, msglen); +  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); + +  UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate)); +} + +#if 0 +/* + * upap_printpkt - print the contents of a PAP packet. + */ +static int upap_printpkt( +  u_char *p, +  int plen, +  void (*printer) (void *, char *, ...), +  void *arg +) +{ +  LWIP_UNUSED_ARG(p); +  LWIP_UNUSED_ARG(plen); +  LWIP_UNUSED_ARG(printer); +  LWIP_UNUSED_ARG(arg); +  return 0; +} +#endif /* 0 */ + +#endif /* PAP_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.h new file mode 100644 index 000000000..0a09fc841 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pap.h @@ -0,0 +1,131 @@ +/***************************************************************************** +* pap.h -  PPP Password Authentication Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ +/* + * upap.h - User/Password Authentication Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#ifndef PAP_H +#define PAP_H + +#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ +/* + * Packet header = Code, id, length. + */ +#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short)) + + +/* + * UPAP codes. + */ +#define UPAP_AUTHREQ 1 /* Authenticate-Request */ +#define UPAP_AUTHACK 2 /* Authenticate-Ack */ +#define UPAP_AUTHNAK 3 /* Authenticate-Nak */ + +/* + * Client states. + */ +#define UPAPCS_INITIAL 0 /* Connection down */ +#define UPAPCS_CLOSED  1 /* Connection up, haven't requested auth */ +#define UPAPCS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */ +#define UPAPCS_OPEN    4 /* We've received an Ack */ +#define UPAPCS_BADAUTH 5 /* We've received a Nak */ + +/* + * Server states. + */ +#define UPAPSS_INITIAL 0 /* Connection down */ +#define UPAPSS_CLOSED  1 /* Connection up, haven't requested auth */ +#define UPAPSS_PENDING 2 /* Connection down, have requested auth */ +#define UPAPSS_LISTEN  3 /* Listening for an Authenticate */ +#define UPAPSS_OPEN    4 /* We've sent an Ack */ +#define UPAPSS_BADAUTH 5 /* We've sent a Nak */ + + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * Each interface is described by upap structure. + */ +typedef struct upap_state { +  int us_unit;           /* Interface unit number */ +  const char *us_user;   /* User */ +  int us_userlen;        /* User length */ +  const char *us_passwd; /* Password */ +  int us_passwdlen;      /* Password length */ +  int us_clientstate;    /* Client state */ +  int us_serverstate;    /* Server state */ +  u_char us_id;          /* Current id */ +  int us_timeouttime;    /* Timeout (seconds) for auth-req retrans. */ +  int us_transmits;      /* Number of auth-reqs sent */ +  int us_maxtransmits;   /* Maximum number of auth-reqs to send */ +  int us_reqtimeout;     /* Time to wait for auth-req from peer */ +} upap_state; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +extern upap_state upap[]; + +void upap_setloginpasswd(int unit, const char *luser, const char *lpassword); +void upap_authwithpeer  (int, char *, char *); +void upap_authpeer      (int); + +extern struct protent pap_protent; + +#endif /* PAP_SUPPORT */ + +#endif /* PAP_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.c new file mode 100644 index 000000000..8720c3368 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.c @@ -0,0 +1,1999 @@ +/***************************************************************************** +* ppp.c - Network Point to Point Protocol program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +*****************************************************************************/ + +/* + * ppp_defs.h - PPP definitions. + * + * if_pppvar.h - private structures and declarations for PPP. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies.  This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +/* + * if_ppp.h - Point-to-Point Protocol definitions. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/ip.h" /* for ip_input() */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "randm.h" +#include "fsm.h" +#if PAP_SUPPORT +#include "pap.h" +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +#include "chap.h" +#endif /* CHAP_SUPPORT */ +#include "ipcp.h" +#include "lcp.h" +#include "magic.h" +#include "auth.h" +#if VJ_SUPPORT +#include "vj.h" +#endif /* VJ_SUPPORT */ +#if PPPOE_SUPPORT +#include "netif/ppp_oe.h" +#endif /* PPPOE_SUPPORT */ + +#include <string.h> + +/*************************/ +/*** LOCAL DEFINITIONS ***/ +/*************************/ + +/* + * The basic PPP frame. + */ +#define PPP_ADDRESS(p)  (((u_char *)(p))[0]) +#define PPP_CONTROL(p)  (((u_char *)(p))[1]) +#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3]) + +/* PPP packet parser states.  Current state indicates operation yet to be + * completed. */ +typedef enum { +  PDIDLE = 0,  /* Idle state - waiting. */ +  PDSTART,     /* Process start flag. */ +  PDADDRESS,   /* Process address field. */ +  PDCONTROL,   /* Process control field. */ +  PDPROTOCOL1, /* Process protocol field 1. */ +  PDPROTOCOL2, /* Process protocol field 2. */ +  PDDATA       /* Process data byte. */ +} PPPDevStates; + +#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07]) + +/************************/ +/*** LOCAL DATA TYPES ***/ +/************************/ +/* + * PPP interface control block. + */ +typedef struct PPPControl_s { +  char openFlag;                /* True when in use. */ +#if PPPOE_SUPPORT +  struct netif *ethif; +  struct pppoe_softc *pppoe_sc; +#endif /* PPPOE_SUPPORT */ +  int  if_up;                   /* True when the interface is up. */ +  int  errCode;                 /* Code indicating why interface is down. */ +#if PPPOS_SUPPORT +  sio_fd_t fd;                  /* File device ID of port. */ +  int  kill_link;               /* Shut the link down. */ +  int  sig_hup;                 /* Carrier lost. */ +  struct pbuf *inHead, *inTail; /* The input packet. */ +  PPPDevStates inState;         /* The input process state. */ +  char inEscaped;               /* Escape next character. */ +  u16_t inProtocol;             /* The input protocol code. */ +  u16_t inFCS;                  /* Input Frame Check Sequence value. */ +#endif /* PPPOS_SUPPORT */ +  int  mtu;                     /* Peer's mru */ +  int  pcomp;                   /* Does peer accept protocol compression? */ +  int  accomp;                  /* Does peer accept addr/ctl compression? */ +  u_long lastXMit;              /* Time of last transmission. */ +  ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */ +  ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */ +#if PPPOS_SUPPORT && VJ_SUPPORT +  int  vjEnabled;               /* Flag indicating VJ compression enabled. */ +  struct vjcompress vjComp;     /* Van Jabobsen compression header. */ +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + +  struct netif netif; + +  struct ppp_addrs addrs; + +  void (*linkStatusCB)(void *ctx, int errCode, void *arg); +  void *linkStatusCtx; + +} PPPControl; + + +/* + * Ioctl definitions. + */ + +struct npioctl { +  int         protocol; /* PPP procotol, e.g. PPP_IP */ +  enum NPmode mode; +}; + + + +/***********************************/ +/*** LOCAL FUNCTION DECLARATIONS ***/ +/***********************************/ +#if PPPOS_SUPPORT +static void pppMain(void *pd); +static void pppDrop(PPPControl *pc); +static void pppInProc(int pd, u_char *s, int l); +#endif /* PPPOS_SUPPORT */ + + +/******************************/ +/*** PUBLIC DATA STRUCTURES ***/ +/******************************/ +u_long subnetMask; + +static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */ + +/* + * PPP Data Link Layer "protocol" table. + * One entry per supported protocol. + * The last entry must be NULL. + */ +struct protent *ppp_protocols[] = { +  &lcp_protent, +#if PAP_SUPPORT +  &pap_protent, +#endif /* PAP_SUPPORT */ +#if CHAP_SUPPORT +  &chap_protent, +#endif /* CHAP_SUPPORT */ +#if CBCP_SUPPORT +  &cbcp_protent, +#endif /* CBCP_SUPPORT */ +  &ipcp_protent, +#if CCP_SUPPORT +  &ccp_protent, +#endif /* CCP_SUPPORT */ +  NULL +}; + + +/* + * Buffers for outgoing packets.  This must be accessed only from the appropriate + * PPP task so that it doesn't need to be protected to avoid collisions. + */ +u_char *outpacket_buf[NUM_PPP];   + + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ + +#if PPPOS_SUPPORT +/* + * FCS lookup table as calculated by genfcstab. + */ +static const u_short fcstab[256] = { +  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, +  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7, +  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e, +  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876, +  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd, +  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5, +  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c, +  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974, +  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb, +  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3, +  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a, +  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72, +  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9, +  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1, +  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738, +  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70, +  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7, +  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff, +  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036, +  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e, +  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5, +  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd, +  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134, +  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c, +  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3, +  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb, +  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232, +  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a, +  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1, +  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9, +  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330, +  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78 +}; + +/* PPP's Asynchronous-Control-Character-Map.  The mask array is used + * to select the specific bit for a character. */ +static u_char pppACCMMask[] = { +  0x01, +  0x02, +  0x04, +  0x08, +  0x10, +  0x20, +  0x40, +  0x80 +}; + + +void +pppMainWakeup(int pd) +{ +  PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd)); +  sio_read_abort(pppControl[pd].fd); +} +#endif /* PPPOS_SUPPORT */ + +void +pppLinkTerminated(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +  PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd)); + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    pppoe_disconnect(pc->pppoe_sc); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +void +pppLinkDown(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +  PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd)); + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    pppoe_disconnect(pc->pppoe_sc); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +/* these callbacks are necessary because lcp_* functions +   must be called in the same context as pppInput(), +   namely the tcpip_thread(), essentially because +   they manipulate timeouts which are thread-private +*/ + +static void +pppStartCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd)); +  lcp_lowerup(pd); +  lcp_open(pd); /* Start protocol */ +} + +static void +pppStopCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd)); +  lcp_close(pd, "User request"); +} + +static void +pppHupCB(void *arg) +{ +  int pd = (int)arg; + +  PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd)); +  lcp_lowerdown(pd); +  link_terminated(pd); +} + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* Initialize the PPP subsystem. */ + +struct ppp_settings ppp_settings; + +err_t +pppInit(void) +{ +  struct protent *protp; +  int i, j; + +  memset(&ppp_settings, 0, sizeof(ppp_settings)); +  ppp_settings.usepeerdns = 1; +  pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL); + +  magicInit(); + +  for (i = 0; i < NUM_PPP; i++) { +    pppControl[i].openFlag = 0; + +    subnetMask = htonl(0xffffff00); + +    outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN); +    if(!outpacket_buf[i]) { +      return ERR_MEM; +    } + +    /* +     * Initialize to the standard option set. +     */ +    for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) { +      (*protp->init)(i); +    } +  } + +#if LINK_STATS +  /** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */ +  /* Clear the statistics. */ +  memset(&lwip_stats.link, 0, sizeof(lwip_stats.link)); +#endif /* LINK_STATS */ + +#if PPPOE_SUPPORT +  pppoe_init(); +#endif /* PPPOE_SUPPORT */ + +  return ERR_OK; +} + +void +pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) +{ +  switch(authType) { +    case PPPAUTHTYPE_NONE: +    default: +#ifdef LWIP_PPP_STRICT_PAP_REJECT +      ppp_settings.refuse_pap = 1; +#else  /* LWIP_PPP_STRICT_PAP_REJECT */ +      /* some providers request pap and accept an empty login/pw */ +      ppp_settings.refuse_pap = 0; +#endif /* LWIP_PPP_STRICT_PAP_REJECT */ +      ppp_settings.refuse_chap = 1; +      break; + +    case PPPAUTHTYPE_ANY: +      /* Warning: Using PPPAUTHTYPE_ANY might have security consequences. +       * RFC 1994 says: +       * +       * In practice, within or associated with each PPP server, there is a +       * database which associates "user" names with authentication +       * information ("secrets").  It is not anticipated that a particular +       * named user would be authenticated by multiple methods.  This would +       * make the user vulnerable to attacks which negotiate the least secure +       * method from among a set (such as PAP rather than CHAP).  If the same +       * secret was used, PAP would reveal the secret to be used later with +       * CHAP. +       * +       * Instead, for each user name there should be an indication of exactly +       * one method used to authenticate that user name.  If a user needs to +       * make use of different authentication methods under different +       * circumstances, then distinct user names SHOULD be employed, each of +       * which identifies exactly one authentication method. +       * +       */ +      ppp_settings.refuse_pap = 0; +      ppp_settings.refuse_chap = 0; +      break; + +    case PPPAUTHTYPE_PAP: +      ppp_settings.refuse_pap = 0; +      ppp_settings.refuse_chap = 1; +      break; + +    case PPPAUTHTYPE_CHAP: +      ppp_settings.refuse_pap = 1; +      ppp_settings.refuse_chap = 0; +      break; +  } + +  if(user) { +    strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1); +    ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0'; +  } else { +    ppp_settings.user[0] = '\0'; +  } + +  if(passwd) { +    strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1); +    ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0'; +  } else { +    ppp_settings.passwd[0] = '\0'; +  } +} + +#if PPPOS_SUPPORT +/* Open a new PPP connection using the given I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session.  If this port + * connects to a modem, the modem connection must be + * established before calling this. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure. */ +int +pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +{ +  PPPControl *pc; +  int pd; + +  /* Find a free PPP session descriptor. Critical region? */ +  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); + +  if (pd >= NUM_PPP) { +    pd = PPPERR_OPEN; +  } else { +    pppControl[pd].openFlag = !0; +  } + +  /* Launch a deamon thread. */ +  if (pd >= 0) { +    pppControl[pd].openFlag = 1; + +    lcp_init(pd); +    pc = &pppControl[pd]; +    pc->fd = fd; +#if PPPOE_SUPPORT +    pc->ethif= NULL; +#endif /* PPPOE_SUPPORT */ +    pc->kill_link = 0; +    pc->sig_hup = 0; +    pc->if_up = 0; +    pc->errCode = 0; +    pc->inState = PDIDLE; +    pc->inHead = NULL; +    pc->inTail = NULL; +    pc->inEscaped = 0; +    pc->lastXMit = 0; + +#if VJ_SUPPORT +    pc->vjEnabled = 0; +    vj_compress_init(&pc->vjComp); +#endif /* VJ_SUPPORT */ + +    /*  +     * Default the in and out accm so that escape and flag characters +     * are always escaped.  +     */ +    memset(pc->inACCM, 0, sizeof(ext_accm)); +    pc->inACCM[15] = 0x60; +    memset(pc->outACCM, 0, sizeof(ext_accm)); +    pc->outACCM[15] = 0x60; + +    pc->linkStatusCB = linkStatusCB; +    pc->linkStatusCtx = linkStatusCtx; + +    sys_thread_new(PPP_THREAD_NAME, pppMain, (void*)pd, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); +    if(!linkStatusCB) { +      while(pd >= 0 && !pc->if_up) { +        sys_msleep(500); +        if (lcp_phase[pd] == PHASE_DEAD) { +          pppClose(pd); +          if (pc->errCode) { +            pd = pc->errCode; +          } else { +            pd = PPPERR_CONNECT; +          } +        } +      } +    } +  } + +  return pd; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static void pppOverEthernetLinkStatusCB(int pd, int up); + +void +pppOverEthernetClose(int pd) +{ +  PPPControl* pc = &pppControl[pd]; + +  /* *TJL* There's no lcp_deinit */ +  lcp_close(pd, NULL); + +  pppoe_destroy(&pc->netif); +} + +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) +{ +  PPPControl *pc; +  int pd; + +  LWIP_UNUSED_ARG(service_name); +  LWIP_UNUSED_ARG(concentrator_name); + +  /* Find a free PPP session descriptor. Critical region? */ +  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); +  if (pd >= NUM_PPP) { +    pd = PPPERR_OPEN; +  } else { +    pppControl[pd].openFlag = !0; +  } + +  /* Launch a deamon thread. */ +  if (pd >= 0) { + +    pppControl[pd].openFlag = 1; + +    lcp_init(pd); + +    lcp_wantoptions[pd].mru = PPPOE_MAXMTU; +    lcp_wantoptions[pd].neg_asyncmap = 0; +    lcp_wantoptions[pd].neg_pcompression = 0; +    lcp_wantoptions[pd].neg_accompression = 0; + +    lcp_allowoptions[pd].mru = PPPOE_MAXMTU; +    lcp_allowoptions[pd].neg_asyncmap = 0; +    lcp_allowoptions[pd].neg_pcompression = 0; +    lcp_allowoptions[pd].neg_accompression = 0; + +    pc = &pppControl[pd]; +    pc->if_up = 0; +    pc->errCode = 0; +    pc->lastXMit = 0; +#if PPPOS_SUPPORT +    pc->kill_link = 0; +    pc->sig_hup = 0; +    pc->inState = PDIDLE; +    pc->inHead = NULL; +    pc->inTail = NULL; +    pc->inEscaped = 0; +#if VJ_SUPPORT +    pc->vjEnabled = 0; +#endif /* VJ_SUPPORT */ +#endif /* PPPOS_SUPPORT */ +    pc->ethif= ethif; + +    memset(pc->inACCM,  0, sizeof(ext_accm)); +    memset(pc->outACCM, 0, sizeof(ext_accm)); + +    pc->linkStatusCB  = linkStatusCB; +    pc->linkStatusCtx = linkStatusCtx; + +    if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) { +      pc->openFlag = 0; +      return PPPERR_OPEN; +    } + +    pppoe_connect(pc->pppoe_sc); + +    if(!linkStatusCB) { +      while(pd >= 0 && !pc->if_up) { +        sys_msleep(500); +        if (lcp_phase[pd] == PHASE_DEAD) { +          pppClose(pd); +          if (pc->errCode) { +            pd = pc->errCode; +          } else { +            pd = PPPERR_CONNECT; +          } +        } +      } +    } +  } + +  return pd; +} +#endif /* PPPOE_SUPPORT */ + + +/* Close a PPP connection and release the descriptor.  + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure. */ +int +pppClose(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 0; + +  /* Disconnect */ +#if PPPOE_SUPPORT +  if(pc->ethif) { +    PPPDEBUG((LOG_DEBUG, "pppClose: unit %d kill_link -> pppStopCB\n", pd)); +    pc->errCode = PPPERR_USER; +    /* This will leave us at PHASE_DEAD. */ +    tcpip_callback(pppStopCB, (void*)pd); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pc->kill_link = !0; +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } + +  if(!pc->linkStatusCB) { +    while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) { +      sys_msleep(500); +      break; +    } +  } + +  return st; +} + +/* This function is called when carrier is lost on the PPP channel. */ +void +pppSigHUP(int pd) +{ +  PPPControl *pc = &pppControl[pd]; + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    PPPDEBUG((LOG_DEBUG, "pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd)); +    tcpip_callback(pppHupCB, (void*)pd); +  } else +#endif /* PPPOE_SUPPORT */ +  { +#if PPPOS_SUPPORT +    pc->sig_hup = 1; +    pppMainWakeup(pd); +#endif /* PPPOS_SUPPORT */ +  } +} + +#if PPPOS_SUPPORT +static void +nPut(PPPControl *pc, struct pbuf *nb) +{ +  struct pbuf *b; +  int c; + +  for(b = nb; b != NULL; b = b->next) { +    if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) { +      PPPDEBUG((LOG_WARNING, +               "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c)); +      LINK_STATS_INC(link.err); +      pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */ +      break; +    } +  } + +  pbuf_free(nb); +  LINK_STATS_INC(link.xmit); +} + +/*  + * pppAppend - append given character to end of given pbuf.  If outACCM + * is not NULL and the character needs to be escaped, do so. + * If pbuf is full, append another. + * Return the current pbuf. + */ +static struct pbuf * +pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM) +{ +  struct pbuf *tb = nb; +   +  /* Make sure there is room for the character and an escape code. +   * Sure we don't quite fill the buffer if the character doesn't +   * get escaped but is one character worth complicating this? */ +  /* Note: We assume no packet header. */ +  if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) { +    tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +    if (tb) { +      nb->next = tb; +    } else { +      LINK_STATS_INC(link.memerr); +    } +    nb = tb; +  } + +  if (nb) { +    if (outACCM && ESCAPE_P(*outACCM, c)) { +      *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE; +      *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS; +    } else { +      *((u_char*)nb->payload + nb->len++) = c; +    } +  } + +  return tb; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +static err_t +pppifOutputOverEthernet(int pd, struct pbuf *p) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *pb; +  u_short protocol = PPP_IP; +  int i=0; + +  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + sizeof(protocol), PBUF_RAM); +  if(!pb) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return ERR_MEM; +  } + +  pbuf_header(pb, -pppoe_hdrlen); + +  pc->lastXMit = sys_jiffies(); + +  if (!pc->pcomp || protocol > 0xFF) { +    *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF; +  } +  *((u_char*)pb->payload + i) = protocol & 0xFF; + +  pbuf_chain(pb, p); + +  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { +    LINK_STATS_INC(link.err); +    return PPPERR_DEVICE; +  } + +  LINK_STATS_INC(link.xmit); +  return ERR_OK; +} +#endif /* PPPOE_SUPPORT */ + +/* Send a packet on the given connection. */ +static err_t +pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) +{ +  int pd = (int)netif->state; +  u_short protocol = PPP_IP; +  PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT +  u_int fcsOut = PPP_INITFCS; +  struct pbuf *headMB = NULL, *tailMB = NULL, *p; +  u_char c; +#endif /* PPPOS_SUPPORT */ + +  LWIP_UNUSED_ARG(ipaddr); + +  /* Validate parameters. */ +  /* We let any protocol value go through - it can't hurt us +   * and the peer will just drop it if it's not accepting it. */ +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) { +    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n", +              pd, protocol, pb)); +    LINK_STATS_INC(link.opterr); +    LINK_STATS_INC(link.drop); +    return ERR_ARG; +  } + +  /* Check that the link is up. */ +  if (lcp_phase[pd] == PHASE_DEAD) { +    PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd)); +    LINK_STATS_INC(link.rterr); +    LINK_STATS_INC(link.drop); +    return ERR_RTE; +  } + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    return pppifOutputOverEthernet(pd, pb); +  } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT +  /* Grab an output buffer. */ +  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +  if (headMB == NULL) { +    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd)); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +    return ERR_MEM; +  } + +#if VJ_SUPPORT +  /*  +   * Attempt Van Jacobson header compression if VJ is configured and +   * this is an IP packet.  +   */ +  if (protocol == PPP_IP && pc->vjEnabled) { +    switch (vj_compress_tcp(&pc->vjComp, pb)) { +      case TYPE_IP: +        /* No change... +           protocol = PPP_IP_PROTOCOL; */ +        break; +      case TYPE_COMPRESSED_TCP: +        protocol = PPP_VJC_COMP; +        break; +      case TYPE_UNCOMPRESSED_TCP: +        protocol = PPP_VJC_UNCOMP; +        break; +      default: +        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd)); +        LINK_STATS_INC(link.proterr); +        LINK_STATS_INC(link.drop); +        pbuf_free(headMB); +        return ERR_VAL; +    } +  } +#endif /* VJ_SUPPORT */ + +  tailMB = headMB; + +  /* Build the PPP header. */ +  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { +    tailMB = pppAppend(PPP_FLAG, tailMB, NULL); +  } + +  pc->lastXMit = sys_jiffies(); +  if (!pc->accomp) { +    fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS); +    tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM); +    fcsOut = PPP_FCS(fcsOut, PPP_UI); +    tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM); +  } +  if (!pc->pcomp || protocol > 0xFF) { +    c = (protocol >> 8) & 0xFF; +    fcsOut = PPP_FCS(fcsOut, c); +    tailMB = pppAppend(c, tailMB, &pc->outACCM); +  } +  c = protocol & 0xFF; +  fcsOut = PPP_FCS(fcsOut, c); +  tailMB = pppAppend(c, tailMB, &pc->outACCM); + +  /* Load packet. */ +  for(p = pb; p; p = p->next) { +    int n; +    u_char *sPtr; + +    sPtr = (u_char*)p->payload; +    n = p->len; +    while (n-- > 0) { +      c = *sPtr++; + +      /* Update FCS before checking for special characters. */ +      fcsOut = PPP_FCS(fcsOut, c); +       +      /* Copy to output buffer escaping special characters. */ +      tailMB = pppAppend(c, tailMB, &pc->outACCM); +    } +  } + +  /* Add FCS and trailing flag. */ +  c = ~fcsOut & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  c = (~fcsOut >> 8) & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + +  /* If we failed to complete the packet, throw it away. */ +  if (!tailMB) { +    PPPDEBUG((LOG_WARNING, +             "pppifOutput[%d]: Alloc err - dropping proto=%d\n",  +              pd, protocol)); +    pbuf_free(headMB); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +    return ERR_MEM; +  } + +  /* Send it. */ +  PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol)); + +  nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + +  return ERR_OK; +} + +/* Get and set parameters for the given connection. + * Return 0 on success, an error code on failure. */ +int +pppIOCtl(int pd, int cmd, void *arg) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 0; + +  if (pd < 0 || pd >= NUM_PPP) { +    st = PPPERR_PARAM; +  } else { +    switch(cmd) { +    case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */ +      if (arg) { +        *(int *)arg = (int)(pc->if_up); +      } else { +        st = PPPERR_PARAM; +      } +      break; +    case PPPCTLS_ERRCODE:       /* Set the PPP error code. */ +      if (arg) { +        pc->errCode = *(int *)arg; +      } else { +        st = PPPERR_PARAM; +      } +      break; +    case PPPCTLG_ERRCODE:       /* Get the PPP error code. */ +      if (arg) { +        *(int *)arg = (int)(pc->errCode); +      } else { +        st = PPPERR_PARAM; +      } +      break; +#if PPPOS_SUPPORT +    case PPPCTLG_FD: +      if (arg) { +        *(sio_fd_t *)arg = pc->fd; +      } else { +        st = PPPERR_PARAM; +      } +      break; +#endif /* PPPOS_SUPPORT */ +    default: +      st = PPPERR_PARAM; +      break; +    } +  } + +  return st; +} + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_int +pppMTU(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  u_int st; + +  /* Validate parameters. */ +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +  } else { +    st = pc->mtu; +  } + +  return st; +} + +#if PPPOE_SUPPORT +int +pppWriteOverEthernet(int pd, const u_char *s, int n) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *pb; + +  /* skip address & flags */ +  s += 2; +  n -= 2; + +  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + n, PBUF_RAM); +  if(!pb) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  pbuf_header(pb, -pppoe_hdrlen); + +  pc->lastXMit = sys_jiffies(); + +  MEMCPY(pb->payload, s, n); + +  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { +    LINK_STATS_INC(link.err); +    return PPPERR_DEVICE; +  } + +  LINK_STATS_INC(link.xmit); +  return PPPERR_NONE; +} +#endif /* PPPOE_SUPPORT */ + +/* + * Write n characters to a ppp link. + *  RETURN: >= 0 Number of characters written + *           -1 Failed to write to device + */ +int +pppWrite(int pd, const u_char *s, int n) +{ +  PPPControl *pc = &pppControl[pd]; +#if PPPOS_SUPPORT +  u_char c; +  u_int fcsOut; +  struct pbuf *headMB, *tailMB; +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +  if(pc->ethif) { +    return pppWriteOverEthernet(pd, s, n); +  } +#endif /* PPPOE_SUPPORT */ + +#if PPPOS_SUPPORT +  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +  if (headMB == NULL) { +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  tailMB = headMB; + +  /* If the link has been idle, we'll send a fresh flag character to +   * flush any noise. */ +  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) { +    tailMB = pppAppend(PPP_FLAG, tailMB, NULL); +  } +  pc->lastXMit = sys_jiffies(); + +  fcsOut = PPP_INITFCS; +  /* Load output buffer. */ +  while (n-- > 0) { +    c = *s++; + +    /* Update FCS before checking for special characters. */ +    fcsOut = PPP_FCS(fcsOut, c); + +    /* Copy to output buffer escaping special characters. */ +    tailMB = pppAppend(c, tailMB, &pc->outACCM); +  } +     +  /* Add FCS and trailing flag. */ +  c = ~fcsOut & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  c = (~fcsOut >> 8) & 0xFF; +  tailMB = pppAppend(c, tailMB, &pc->outACCM); +  tailMB = pppAppend(PPP_FLAG, tailMB, NULL); + +  /* If we failed to complete the packet, throw it away. +   * Otherwise send it. */ +  if (!tailMB) { +    PPPDEBUG((LOG_WARNING, +             "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len)); +           /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ +    pbuf_free(headMB); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.proterr); +    return PPPERR_ALLOC; +  } + +  PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len)); +                   /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ +  nPut(pc, headMB); +#endif /* PPPOS_SUPPORT */ + +  return PPPERR_NONE; +} + +/* + * ppp_send_config - configure the transmit characteristics of + * the ppp interface. + */ +void +ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp) +{ +  PPPControl *pc = &pppControl[unit]; +  int i; +   +  pc->mtu = mtu; +  pc->pcomp = pcomp; +  pc->accomp = accomp; +   +  /* Load the ACCM bits for the 32 control codes. */ +  for (i = 0; i < 32/8; i++) { +    pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF); +  } +  PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n", +            unit, +            pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3])); +} + + +/* + * ppp_set_xaccm - set the extended transmit ACCM for the interface. + */ +void +ppp_set_xaccm(int unit, ext_accm *accm) +{ +  SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm)); +  PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n", +            unit, +            pppControl[unit].outACCM[0], +            pppControl[unit].outACCM[1], +            pppControl[unit].outACCM[2], +            pppControl[unit].outACCM[3])); +} + + +/* + * ppp_recv_config - configure the receive-side characteristics of + * the ppp interface. + */ +void +ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp) +{ +  PPPControl *pc = &pppControl[unit]; +  int i; + +  LWIP_UNUSED_ARG(accomp); +  LWIP_UNUSED_ARG(pcomp); +  LWIP_UNUSED_ARG(mru); + +  /* Load the ACCM bits for the 32 control codes. */ +  for (i = 0; i < 32 / 8; i++) { +    pc->inACCM[i] = (u_char)(asyncmap >> (i * 8)); +  } +  PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n", +            unit, +            pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3])); +} + +#if 0 +/* + * ccp_test - ask kernel whether a given compression method + * is acceptable for use.  Returns 1 if the method and parameters + * are OK, 0 if the method is known but the parameters are not OK + * (e.g. code size should be reduced), or -1 if the method is unknown. + */ +int +ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr) +{ +  return 0; /* XXX Currently no compression. */ +} + +/* + * ccp_flags_set - inform kernel about the current state of CCP. + */ +void +ccp_flags_set(int unit, int isopen, int isup) +{ +  /* XXX */ +} + +/* + * ccp_fatal_error - returns 1 if decompression was disabled as a + * result of an error detected after decompression of a packet, + * 0 otherwise.  This is necessary because of patent nonsense. + */ +int +ccp_fatal_error(int unit) +{ +  /* XXX */ +  return 0; +} +#endif + +/* + * get_idle_time - return how long the link has been idle. + */ +int +get_idle_time(int u, struct ppp_idle *ip) +{ +  /* XXX */ +  LWIP_UNUSED_ARG(u); +  LWIP_UNUSED_ARG(ip); + +  return 0; +} + + +/* + * Return user specified netmask, modified by any mask we might determine + * for address `addr' (in network byte order). + * Here we scan through the system's list of interfaces, looking for + * any non-point-to-point interfaces which might appear to be on the same + * network as `addr'.  If we find any, we OR in their netmask to the + * user-specified netmask. + */ +u32_t +GetMask(u32_t addr) +{ +  u32_t mask, nmask; + +  htonl(addr); +  if (IN_CLASSA(addr)) { /* determine network mask for address class */ +    nmask = IN_CLASSA_NET; +  } else if (IN_CLASSB(addr)) { +    nmask = IN_CLASSB_NET; +  } else {  +    nmask = IN_CLASSC_NET; +  } + +  /* class D nets are disallowed by bad_ip_adrs */ +  mask = subnetMask | htonl(nmask); +   +  /* XXX +   * Scan through the system's network interfaces. +   * Get each netmask and OR them into our mask. +   */ + +  return mask; +} + +/* + * sifvjcomp - config tcp header compression + */ +int +sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid) +{ +#if PPPOS_SUPPORT && VJ_SUPPORT +  PPPControl *pc = &pppControl[pd]; +   +  pc->vjEnabled = vjcomp; +  pc->vjComp.compressSlot = cidcomp; +  pc->vjComp.maxSlotIndex = maxcid; +  PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", +            vjcomp, cidcomp, maxcid)); +#endif /* PPPOS_SUPPORT && VJ_SUPPORT */ + +  return 0; +} + +/* + * pppifNetifInit - netif init callback + */ +static err_t +pppifNetifInit(struct netif *netif) +{ +  netif->name[0] = 'p'; +  netif->name[1] = 'p'; +  netif->output = pppifOutput; +  netif->mtu = pppMTU((int)netif->state); +  return ERR_OK; +} + + +/* + * sifup - Config the interface up and enable IP packets to pass. + */ +int +sifup(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_remove(&pc->netif); +    if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) { +      netif_set_up(&pc->netif); +      pc->if_up = 1; +      pc->errCode = PPPERR_NONE; + +      PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +      if(pc->linkStatusCB) { +        pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs); +      } +    } else { +      st = 0; +      PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd)); +    } +  } + +  return st; +} + +/* + * sifnpmode - Set the mode for handling packets for a given NP. + */ +int +sifnpmode(int u, int proto, enum NPmode mode) +{ +  LWIP_UNUSED_ARG(u); +  LWIP_UNUSED_ARG(proto); +  LWIP_UNUSED_ARG(mode); +  return 0; +} + +/* + * sifdown - Config the interface down and disable IP. + */ +int +sifdown(int pd) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd)); +  } else { +    pc->if_up = 0; +    netif_remove(&pc->netif); +    PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +    if(pc->linkStatusCB) { +      pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL); +    } +  } +  return st; +} + +/** + * sifaddr - Config the interface IP addresses and netmask. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h His IP address ??? + * @param m IP subnet mask ??? + * @param ns1 Primary DNS + * @param ns2 Secondary DNS + */ +int +sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o)); +    SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h)); +    SMEMCPY(&pc->addrs.netmask, &m, sizeof(m)); +    SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1)); +    SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2)); +  } +  return st; +} + +/** + * cifaddr - Clear the interface IP addresses, and delete routes + * through the interface if possible. + * @param pd Interface unit ??? + * @param o Our IP address ??? + * @param h IP broadcast address ??? + */ +int +cifaddr( int pd, u32_t o, u32_t h) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; +   +  LWIP_UNUSED_ARG(o); +  LWIP_UNUSED_ARG(h); +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0); +    IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0); +    IP4_ADDR(&pc->addrs.netmask, 255,255,255,0); +    IP4_ADDR(&pc->addrs.dns1, 0,0,0,0); +    IP4_ADDR(&pc->addrs.dns2, 0,0,0,0); +  } +  return st; +} + +/* + * sifdefaultroute - assign a default route through the address given. + */ +int +sifdefaultroute(int pd, u32_t l, u32_t g) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; + +  LWIP_UNUSED_ARG(l); +  LWIP_UNUSED_ARG(g); + +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_set_default(&pc->netif); +  } + +  /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */ + +  return st; +} + +/* + * cifdefaultroute - delete a default route through the address given. + */ +int +cifdefaultroute(int pd, u32_t l, u32_t g) +{ +  PPPControl *pc = &pppControl[pd]; +  int st = 1; + +  LWIP_UNUSED_ARG(l); +  LWIP_UNUSED_ARG(g); + +  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { +    st = 0; +    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); +  } else { +    netif_set_default(NULL); +  } + +  return st; +} + +/**********************************/ +/*** LOCAL FUNCTION DEFINITIONS ***/ +/**********************************/ + +#if PPPOS_SUPPORT +/* The main PPP process function.  This implements the state machine according + * to section 4 of RFC 1661: The Point-To-Point Protocol. */ +static void +pppMain(void *arg) +{ +  int pd = (int)arg; +  struct pbuf *p; +  PPPControl* pc; +  int c; + +  pc = &pppControl[pd]; + +  p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM); +  if (!p) { +    LWIP_ASSERT("p != NULL", p); +    pc->errCode = PPPERR_ALLOC; +    goto out; +  } + +  /* +   * Start the connection and handle incoming events (packet or timeout). +   */ +  PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); +  tcpip_callback(pppStartCB, arg); +  while (lcp_phase[pd] != PHASE_DEAD) { +    if (pc->kill_link) { +      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d kill_link -> pppStopCB\n", pd)); +      pc->errCode = PPPERR_USER; +      /* This will leave us at PHASE_DEAD. */ +      tcpip_callback(pppStopCB, arg); +      pc->kill_link = 0; +    } else if (pc->sig_hup) { +      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sig_hup -> pppHupCB\n", pd)); +      pc->sig_hup = 0; +      tcpip_callback(pppHupCB, arg); +    } else { +      c = sio_read(pc->fd, p->payload, p->len); +      if(c > 0) { +        pppInProc(pd, p->payload, c); +      } else { +        PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c)); +        sys_msleep(1); /* give other tasks a chance to run */ +      } +    } +  } +  PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd)); +  pppDrop(pc); /* bug fix #17726 */ +  pbuf_free(p); + +out: +  PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); +  if(pc->linkStatusCB) { +    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); +  } + +  pc->openFlag = 0; +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT + +void +pppOverEthernetInitFailed(void* arg) +{ +  PPPControl* pc; +  int pd = (int)arg; + +  pppHupCB(arg); +  pppStopCB(arg); + +  pc = &pppControl[pd]; +  pppoe_destroy(&pc->netif); +  pc->openFlag = 0; + +  if(pc->linkStatusCB) { +    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); +  } +} + +static void +pppOverEthernetLinkStatusCB(int pd, int up) +{ +  if(up) { +    PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); +    tcpip_callback(pppStartCB, (void*)pd); +  } else { +    PPPControl* pc; +    pc = &pppControl[pd]; +    tcpip_callback(pppOverEthernetInitFailed, (void*)pd); +  } +} +#endif /* PPPOE_SUPPORT */ + +struct pbuf * +pppSingleBuf(struct pbuf *p) +{ +  struct pbuf *q, *b; +  u_char *pl; + +  if(p->tot_len == p->len) { +    return p; +  } + +  q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); +  if(!q) { +    PPPDEBUG((LOG_ERR, +             "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len)); +    return p; /* live dangerously */ +  } + +  for(b = p, pl = q->payload; b != NULL; b = b->next) { +    MEMCPY(pl, b->payload, b->len); +    pl += b->len; +  } + +  pbuf_free(p); + +  return q; +} + +struct pppInputHeader { +  int unit; +  u16_t proto; +}; + +/* + * Pass the processed input packet to the appropriate handler. + * This function and all handlers run in the context of the tcpip_thread + */ +static void +pppInput(void *arg) +{ +  struct pbuf *nb = (struct pbuf *)arg; +  u16_t protocol; +  int pd; + +  pd = ((struct pppInputHeader *)nb->payload)->unit; +  protocol = ((struct pppInputHeader *)nb->payload)->proto; +     +  if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) { +    LWIP_ASSERT("pbuf_header failed\n", 0); +    goto drop; +  } + +  LINK_STATS_INC(link.recv); + +  /* +   * Toss all non-LCP packets unless LCP is OPEN. +   * Until we get past the authentication phase, toss all packets +   * except LCP, LQR and authentication packets. +   */ +  if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) { +    if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) || +        (lcp_phase[pd] != PHASE_AUTHENTICATE)) { +      PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd])); +      goto drop; +    } +  } + +  switch(protocol) { +    case PPP_VJC_COMP:      /* VJ compressed TCP */ +#if VJ_SUPPORT +      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len)); +      /* +       * Clip off the VJ header and prepend the rebuilt TCP/IP header and +       * pass the result to IP. +       */ +      if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      /* Something's wrong so drop it. */ +      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd)); +#else  /* VJ_SUPPORT */ +      /* No handler for this protocol so drop the packet. */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload)); +#endif /* VJ_SUPPORT */ +      break; + +    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */ +#if VJ_SUPPORT +      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len)); +      /* +       * Process the TCP/IP header for VJ header compression and then pass +       * the packet to IP. +       */ +      if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      /* Something's wrong so drop it. */ +      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd)); +#else  /* VJ_SUPPORT */ +      /* No handler for this protocol so drop the packet. */ +      PPPDEBUG((LOG_INFO, +               "pppInput[%d]: drop VJ UnComp in %d:.*H\n",  +                pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload)); +#endif /* VJ_SUPPORT */ +      break; + +    case PPP_IP:            /* Internet Protocol */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); +      if (pppControl[pd].netif.input) { +        pppControl[pd].netif.input(nb, &pppControl[pd].netif); +        return; +      } +      break; + +    default: { +      struct protent *protp; +      int i; + +      /* +       * Upcall the proper protocol input routine. +       */ +      for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { +        if (protp->protocol == protocol && protp->enabled_flag) { +          PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len)); +          nb = pppSingleBuf(nb); +          (*protp->input)(pd, nb->payload, nb->len); +          goto out; +        } +      } + +      /* No handler for this protocol so reject the packet. */ +      PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len)); +      if (pbuf_header(nb, sizeof(protocol))) { +        LWIP_ASSERT("pbuf_header failed\n", 0); +        goto drop; +      } +#if BYTE_ORDER == LITTLE_ENDIAN +      protocol = htons(protocol); +      SMEMCPY(nb->payload, &protocol, sizeof(protocol)); +#endif /* BYTE_ORDER == LITTLE_ENDIAN */ +      lcp_sprotrej(pd, nb->payload, nb->len); +    } +    break; +  } + +drop: +  LINK_STATS_INC(link.drop); + +out: +  pbuf_free(nb); +  return; +} + +#if PPPOS_SUPPORT +/* + * Drop the input packet. + */ +static void +pppDrop(PPPControl *pc) +{ +  if (pc->inHead != NULL) { +#if 0 +    PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload)); +#endif +    PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len)); +    if (pc->inTail && (pc->inTail != pc->inHead)) { +      pbuf_free(pc->inTail); +    } +    pbuf_free(pc->inHead); +    pc->inHead = NULL; +    pc->inTail = NULL; +  } +#if VJ_SUPPORT +  vj_uncompress_err(&pc->vjComp); +#endif /* VJ_SUPPORT */ + +  LINK_STATS_INC(link.drop); +} + +/** + * Process a received octet string. + */ +static void +pppInProc(int pd, u_char *s, int l) +{ +  PPPControl *pc = &pppControl[pd]; +  struct pbuf *nextNBuf; +  u_char curChar; + +  PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l)); +  while (l-- > 0) { +    curChar = *s++; +     +    /* Handle special characters. */ +    if (ESCAPE_P(pc->inACCM, curChar)) { +      /* Check for escape sequences. */ +      /* XXX Note that this does not handle an escaped 0x5d character which +       * would appear as an escape character.  Since this is an ASCII ']' +       * and there is no reason that I know of to escape it, I won't complicate +       * the code to handle this case. GLL */ +      if (curChar == PPP_ESCAPE) { +        pc->inEscaped = 1; +      /* Check for the flag character. */ +      } else if (curChar == PPP_FLAG) { +         /* If this is just an extra flag character, ignore it. */ +         if (pc->inState <= PDADDRESS) { +           /* ignore it */; +         /* If we haven't received the packet header, drop what has come in. */ +         } else if (pc->inState < PDDATA) { +           PPPDEBUG((LOG_WARNING, +                    "pppInProc[%d]: Dropping incomplete packet %d\n",  +                     pd, pc->inState)); +           LINK_STATS_INC(link.lenerr); +           pppDrop(pc); +         /* If the fcs is invalid, drop the packet. */ +         } else if (pc->inFCS != PPP_GOODFCS) { +           PPPDEBUG((LOG_INFO, +                    "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n",  +                     pd, pc->inFCS, pc->inProtocol)); +           LINK_STATS_INC(link.chkerr); +           pppDrop(pc); +         /* Otherwise it's a good packet so pass it on. */ +         } else { +           /* Trim off the checksum. */ +           if(pc->inTail->len >= 2) { +             pc->inTail->len -= 2; + +             pc->inTail->tot_len = pc->inTail->len; +             if (pc->inTail != pc->inHead) { +               pbuf_cat(pc->inHead, pc->inTail); +             } +           } else { +             pc->inTail->tot_len = pc->inTail->len; +             if (pc->inTail != pc->inHead) { +               pbuf_cat(pc->inHead, pc->inTail); +             } + +             pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2); +           } + +           /* Dispatch the packet thereby consuming it. */ +           if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) { +             PPPDEBUG((LOG_ERR, "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd)); +             pbuf_free(pc->inHead); +             LINK_STATS_INC(link.drop); +           } +           pc->inHead = NULL; +           pc->inTail = NULL; +         } + +         /* Prepare for a new packet. */ +         pc->inFCS = PPP_INITFCS; +         pc->inState = PDADDRESS; +         pc->inEscaped = 0; +      /* Other characters are usually control characters that may have +       * been inserted by the physical layer so here we just drop them. */ +      } else { +        PPPDEBUG((LOG_WARNING, +                 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar)); +      } +    /* Process other characters. */ +    } else { +      /* Unencode escaped characters. */ +      if (pc->inEscaped) { +        pc->inEscaped = 0; +        curChar ^= PPP_TRANS; +      } + +      /* Process character relative to current state. */ +      switch(pc->inState) { +        case PDIDLE:                    /* Idle state - waiting. */ +          /* Drop the character if it's not 0xff +           * we would have processed a flag character above. */ +          if (curChar != PPP_ALLSTATIONS) { +            break; +          } + +        /* Fall through */ +        case PDSTART:                   /* Process start flag. */ +          /* Prepare for a new packet. */ +          pc->inFCS = PPP_INITFCS; + +        /* Fall through */ +        case PDADDRESS:                 /* Process address field. */ +          if (curChar == PPP_ALLSTATIONS) { +            pc->inState = PDCONTROL; +            break; +          } +          /* Else assume compressed address and control fields so +           * fall through to get the protocol... */ +        case PDCONTROL:                 /* Process control field. */ +          /* If we don't get a valid control code, restart. */ +          if (curChar == PPP_UI) { +            pc->inState = PDPROTOCOL1; +            break; +          } +#if 0 +          else { +            PPPDEBUG((LOG_WARNING, +                     "pppInProc[%d]: Invalid control <%d>\n", pd, curChar)); +                      pc->inState = PDSTART; +          } +#endif +        case PDPROTOCOL1:               /* Process protocol field 1. */ +          /* If the lower bit is set, this is the end of the protocol +           * field. */ +          if (curChar & 1) { +            pc->inProtocol = curChar; +            pc->inState = PDDATA; +          } else { +            pc->inProtocol = (u_int)curChar << 8; +            pc->inState = PDPROTOCOL2; +          } +          break; +        case PDPROTOCOL2:               /* Process protocol field 2. */ +          pc->inProtocol |= curChar; +          pc->inState = PDDATA; +          break; +        case PDDATA:                    /* Process data byte. */ +          /* Make space to receive processed data. */ +          if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) { +            if(pc->inTail) { +              pc->inTail->tot_len = pc->inTail->len; +              if (pc->inTail != pc->inHead) { +                pbuf_cat(pc->inHead, pc->inTail); +              } +            } +            /* If we haven't started a packet, we need a packet header. */ +            nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); +            if (nextNBuf == NULL) { +              /* No free buffers.  Drop the input packet and let the +               * higher layers deal with it.  Continue processing +               * the received pbuf chain in case a new packet starts. */ +              PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd)); +              LINK_STATS_INC(link.memerr); +              pppDrop(pc); +              pc->inState = PDSTART;  /* Wait for flag sequence. */ +              break; +            } +            if (pc->inHead == NULL) { +              struct pppInputHeader *pih = nextNBuf->payload; + +              pih->unit = pd; +              pih->proto = pc->inProtocol; + +              nextNBuf->len += sizeof(*pih); + +              pc->inHead = nextNBuf; +            } +            pc->inTail = nextNBuf; +          } +          /* Load character into buffer. */ +          ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar; +          break; +      } + +      /* update the frame check sequence number. */ +      pc->inFCS = PPP_FCS(pc->inFCS, curChar); +    } +  } + +  avRandomize(); +} +#endif /* PPPOS_SUPPORT */ + +#if PPPOE_SUPPORT +void +pppInProcOverEthernet(int pd, struct pbuf *pb) +{ +  struct pppInputHeader *pih; +  u16_t inProtocol; + +  if(pb->len < sizeof(inProtocol)) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: too small for protocol field\n")); +    goto drop; +  } + +  inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1]; + +  /* make room for pppInputHeader - should not fail */ +  if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: could not allocate room for header\n")); +    goto drop; +  } + +  pih = pb->payload; + +  pih->unit = pd; +  pih->proto = inProtocol; + +  /* Dispatch the packet thereby consuming it. */ +  if(tcpip_callback(pppInput, pb) != ERR_OK) { +    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet[%d]: tcpip_callback() failed, dropping packet\n", pd)); +    goto drop; +  } + +  return; + +drop: +  LINK_STATS_INC(link.drop); +  pbuf_free(pb); +  return; +} +#endif /* PPPOE_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.h new file mode 100644 index 000000000..d5caa0a7e --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp.h @@ -0,0 +1,465 @@ +/***************************************************************************** +* ppp.h - Network Point to Point Protocol header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1997 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Original derived from BSD codes. +*****************************************************************************/ + +#ifndef PPP_H +#define PPP_H + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/def.h" +#include "lwip/sio.h" +#include "lwip/api.h" +#include "lwip/sockets.h" +#include "lwip/stats.h" +#include "lwip/mem.h" +#include "lwip/tcpip.h" +#include "lwip/netif.h" + +/* + * pppd.h - PPP daemon global declarations. + * + * Copyright (c) 1989 Carnegie Mellon University. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by Carnegie Mellon University.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + */ +/* + * ppp_defs.h - PPP definitions. + * + * Copyright (c) 1994 The Australian National University. + * All rights reserved. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation is hereby granted, provided that the above copyright + * notice appears in all copies.  This software is provided without any + * warranty, express or implied. The Australian National University + * makes no representations about the suitability of this software for + * any purpose. + * + * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY + * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES + * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF + * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES, + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS + * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO + * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, + * OR MODIFICATIONS. + */ + +#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a)) +#define UNTIMEOUT(f, a)     sys_untimeout((f), (a)) + + +#ifndef __u_char_defined + +/* Type definitions for BSD code. */ +typedef unsigned long  u_long; +typedef unsigned int   u_int; +typedef unsigned short u_short; +typedef unsigned char  u_char; + +#endif + +/* + * Constants and structures defined by the internet system, + * Per RFC 790, September 1981, and numerous additions. + */ + +/* + * The basic PPP frame. + */ +#define PPP_HDRLEN      4       /* octets for standard ppp header */ +#define PPP_FCSLEN      2       /* octets for FCS */ + + +/* + * Significant octet values. + */ +#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */ +#define PPP_UI          0x03    /* Unnumbered Information */ +#define PPP_FLAG        0x7e    /* Flag Sequence */ +#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */ +#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */ + +/* + * Protocol field values. + */ +#define PPP_IP          0x21    /* Internet Protocol */ +#define PPP_AT          0x29    /* AppleTalk Protocol */ +#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */ +#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */ +#define PPP_COMP        0xfd    /* compressed packet */ +#define PPP_IPCP        0x8021  /* IP Control Protocol */ +#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */ +#define PPP_CCP         0x80fd  /* Compression Control Protocol */ +#define PPP_LCP         0xc021  /* Link Control Protocol */ +#define PPP_PAP         0xc023  /* Password Authentication Protocol */ +#define PPP_LQR         0xc025  /* Link Quality Report protocol */ +#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */ +#define PPP_CBCP        0xc029  /* Callback Control Protocol */ + +/* + * Values for FCS calculations. + */ +#define PPP_INITFCS     0xffff  /* Initial FCS value */ +#define PPP_GOODFCS     0xf0b8  /* Good final FCS value */ +#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff]) + +/* + * Extended asyncmap - allows any character to be escaped. + */ +typedef u_char  ext_accm[32]; + +/* + * What to do with network protocol (NP) packets. + */ +enum NPmode { +  NPMODE_PASS,        /* pass the packet through */ +  NPMODE_DROP,        /* silently drop the packet */ +  NPMODE_ERROR,       /* return an error */ +  NPMODE_QUEUE        /* save it up for later. */ +}; + +/* + * Inline versions of get/put char/short/long. + * Pointer is advanced; we assume that both arguments + * are lvalues and will already be in registers. + * cp MUST be u_char *. + */ +#define GETCHAR(c, cp) { \ +    (c) = *(cp)++; \ +} +#define PUTCHAR(c, cp) { \ +    *(cp)++ = (u_char) (c); \ +} + + +#define GETSHORT(s, cp) { \ +    (s) = *(cp); (cp)++; (s) <<= 8; \ +    (s) |= *(cp); (cp)++; \ +} +#define PUTSHORT(s, cp) { \ +    *(cp)++ = (u_char) ((s) >> 8); \ +    *(cp)++ = (u_char) (s & 0xff); \ +} + +#define GETLONG(l, cp) { \ +    (l) = *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; (l) <<= 8; \ +    (l) |= *(cp); (cp)++; \ +} +#define PUTLONG(l, cp) { \ +    *(cp)++ = (u_char) ((l) >> 24); \ +    *(cp)++ = (u_char) ((l) >> 16); \ +    *(cp)++ = (u_char) ((l) >> 8); \ +    *(cp)++ = (u_char) (l); \ +} + + +#define INCPTR(n, cp)   ((cp) += (n)) +#define DECPTR(n, cp)   ((cp) -= (n)) + +#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l)) +#define BCOPY(s, d, l)      MEMCPY((d), (s), (l)) +#define BZERO(s, n)         memset(s, 0, n) + +#if PPP_DEBUG +#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); } +#else  /* PPP_DEBUG */ +#define PRINTMSG(m, l) +#endif /* PPP_DEBUG */ + +/* + * MAKEHEADER - Add PPP Header fields to a packet. + */ +#define MAKEHEADER(p, t) { \ +    PUTCHAR(PPP_ALLSTATIONS, p); \ +    PUTCHAR(PPP_UI, p); \ +    PUTSHORT(t, p); } + +/************************* +*** PUBLIC DEFINITIONS *** +*************************/ + +/* Error codes. */ +#define PPPERR_NONE      0 /* No error. */ +#define PPPERR_PARAM    -1 /* Invalid parameter. */ +#define PPPERR_OPEN     -2 /* Unable to open PPP session. */ +#define PPPERR_DEVICE   -3 /* Invalid I/O device for PPP. */ +#define PPPERR_ALLOC    -4 /* Unable to allocate resources. */ +#define PPPERR_USER     -5 /* User interrupt. */ +#define PPPERR_CONNECT  -6 /* Connection lost. */ +#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */ +#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */ + +/* + * PPP IOCTL commands. + */ +/* + * Get the up status - 0 for down, non-zero for up.  The argument must + * point to an int. + */ +#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */ +#define PPPCTLS_ERRCODE  101 /* Set the error code */ +#define PPPCTLG_ERRCODE  102 /* Get the error code */ +#define PPPCTLG_FD       103 /* Get the fd associated with the ppp */ + +/************************ +*** PUBLIC DATA TYPES *** +************************/ + +/* + * The following struct gives the addresses of procedures to call + * for a particular protocol. + */ +struct protent { +    u_short protocol;       /* PPP protocol number */ +    /* Initialization procedure */ +    void (*init) (int unit); +    /* Process a received packet */ +    void (*input) (int unit, u_char *pkt, int len); +    /* Process a received protocol-reject */ +    void (*protrej) (int unit); +    /* Lower layer has come up */ +    void (*lowerup) (int unit); +    /* Lower layer has gone down */ +    void (*lowerdown) (int unit); +    /* Open the protocol */ +    void (*open) (int unit); +    /* Close the protocol */ +    void (*close) (int unit, char *reason); +#if 0 +    /* Print a packet in readable form */ +    int  (*printpkt) (u_char *pkt, int len, +              void (*printer) (void *, char *, ...), +              void *arg); +    /* Process a received data packet */ +    void (*datainput) (int unit, u_char *pkt, int len); +#endif +    int  enabled_flag;      /* 0 iff protocol is disabled */ +    char *name;         /* Text name of protocol */ +#if 0 +    /* Check requested options, assign defaults */ +    void (*check_options) (u_long); +    /* Configure interface for demand-dial */ +    int  (*demand_conf) (int unit); +    /* Say whether to bring up link for this pkt */ +    int  (*active_pkt) (u_char *pkt, int len); +#endif +}; + +/* + * The following structure records the time in seconds since + * the last NP packet was sent or received. + */ +struct ppp_idle { +  u_short xmit_idle;      /* seconds since last NP packet sent */ +  u_short recv_idle;      /* seconds since last NP packet received */ +}; + +struct ppp_settings { + +  u_int  disable_defaultip : 1;       /* Don't use hostname for default IP addrs */ +  u_int  auth_required     : 1;       /* Peer is required to authenticate */ +  u_int  explicit_remote   : 1;       /* remote_name specified with remotename opt */ +  u_int  refuse_pap        : 1;       /* Don't wanna auth. ourselves with PAP */ +  u_int  refuse_chap       : 1;       /* Don't wanna auth. ourselves with CHAP */ +  u_int  usehostname       : 1;       /* Use hostname for our_name */ +  u_int  usepeerdns        : 1;       /* Ask peer for DNS adds */ + +  u_short idle_time_limit;            /* Shut down link if idle for this long */ +  int  maxconnect;                    /* Maximum connect time (seconds) */ + +  char user       [MAXNAMELEN   + 1]; /* Username for PAP */ +  char passwd     [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */ +  char our_name   [MAXNAMELEN   + 1]; /* Our name for authentication purposes */ +  char remote_name[MAXNAMELEN   + 1]; /* Peer's name for authentication */ +}; + +struct ppp_addrs { +  struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2; +}; + +/***************************** +*** PUBLIC DATA STRUCTURES *** +*****************************/ + +/* Buffers for outgoing packets. */ +extern u_char *outpacket_buf[NUM_PPP]; + +extern struct ppp_settings ppp_settings; + +extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */ + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ + +/* Initialize the PPP subsystem. */ +err_t pppInit(void); + +/* Warning: Using PPPAUTHTYPE_ANY might have security consequences. + * RFC 1994 says: + * + * In practice, within or associated with each PPP server, there is a + * database which associates "user" names with authentication + * information ("secrets").  It is not anticipated that a particular + * named user would be authenticated by multiple methods.  This would + * make the user vulnerable to attacks which negotiate the least secure + * method from among a set (such as PAP rather than CHAP).  If the same + * secret was used, PAP would reveal the secret to be used later with + * CHAP. + * + * Instead, for each user name there should be an indication of exactly + * one method used to authenticate that user name.  If a user needs to + * make use of different authentication methods under different + * circumstances, then distinct user names SHOULD be employed, each of + * which identifies exactly one authentication method. + * + */ +enum pppAuthType { +    PPPAUTHTYPE_NONE, +    PPPAUTHTYPE_ANY, +    PPPAUTHTYPE_PAP, +    PPPAUTHTYPE_CHAP +}; + +void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd); + +/* + * Open a new PPP connection using the given serial I/O device. + * This initializes the PPP control block but does not + * attempt to negotiate the LCP session. + * Return a new PPP connection descriptor on success or + * an error code (negative) on failure.  + */ +int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); + +/* + * Open a new PPP Over Ethernet (PPPOE) connection. + */ +int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx); + +/* for source code compatibility */ +#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls) + +/* + * Close a PPP connection and release the descriptor.  + * Any outstanding packets in the queues are dropped. + * Return 0 on success, an error code on failure.  + */ +int pppClose(int pd); + +/* + * Indicate to the PPP process that the line has disconnected. + */ +void pppSigHUP(int pd); + +/* + * Get and set parameters for the given connection. + * Return 0 on success, an error code on failure.  + */ +int  pppIOCtl(int pd, int cmd, void *arg); + +/* + * Return the Maximum Transmission Unit for the given PPP connection. + */ +u_int pppMTU(int pd); + +/* + * Write n characters to a ppp link. + * RETURN: >= 0 Number of characters written, -1 Failed to write to device. + */ +int pppWrite(int pd, const u_char *s, int n); + +void pppInProcOverEthernet(int pd, struct pbuf *pb); + +struct pbuf *pppSingleBuf(struct pbuf *p); + +void pppLinkTerminated(int pd); + +void pppLinkDown(int pd); + +void pppMainWakeup(int pd); + +/* Configure i/f transmit parameters */ +void ppp_send_config (int, int, u32_t, int, int); +/* Set extended transmit ACCM */ +void ppp_set_xaccm (int, ext_accm *); +/* Configure i/f receive parameters */ +void ppp_recv_config (int, int, u32_t, int, int); +/* Find out how long link has been idle */ +int  get_idle_time (int, struct ppp_idle *); + +/* Configure VJ TCP header compression */ +int  sifvjcomp (int, int, int, int); +/* Configure i/f down (for IP) */ +int  sifup (int); +/* Set mode for handling packets for proto */ +int  sifnpmode (int u, int proto, enum NPmode mode); +/* Configure i/f down (for IP) */ +int  sifdown (int); +/* Configure IP addresses for i/f */ +int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t); +/* Reset i/f IP addresses */ +int  cifaddr (int, u32_t, u32_t); +/* Create default route through i/f */ +int  sifdefaultroute (int, u32_t, u32_t); +/* Delete default route through i/f */ +int  cifdefaultroute (int, u32_t, u32_t); + +/* Get appropriate netmask for address */ +u32_t GetMask (u32_t);  + +#endif /* PPP_SUPPORT */ + +#endif /* PPP_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c new file mode 100644 index 000000000..c34c529b6 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/ppp_oe.c @@ -0,0 +1,1227 @@ +/***************************************************************************** +* ppp_oe.c - PPP Over Ethernet implementation for lwIP. +* +* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 06-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +*****************************************************************************/ + + + +/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */ + +/*- + * Copyright (c) 2002 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Martin Husemann <martin@NetBSD.org>. + * + * 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. All advertising materials mentioning features or use of this software + *    must display the following acknowledgement: + *        This product includes software developed by the NetBSD + *        Foundation, Inc. and its contributors. + * 4. Neither the name of The NetBSD Foundation 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 THE NETBSD FOUNDATION, INC. 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 THE FOUNDATION 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. + */ + +#include "lwip/opt.h" + +#if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "lwip/sys.h" + +#include "netif/ppp_oe.h" +#include "netif/etharp.h" + +#include <string.h> +#include <stdio.h> + +/** @todo Replace this part with a simple list like other lwIP lists */ +#ifndef _SYS_QUEUE_H_ +#define _SYS_QUEUE_H_ + +/* + * A list is headed by a single forward pointer (or an array of forward + * pointers for a hash table header). The elements are doubly linked + * so that an arbitrary element can be removed without a need to + * traverse the list. New elements can be added to the list before + * or after an existing element or at the head of the list. A list + * may only be traversed in the forward direction. + * + * For details on the use of these macros, see the queue(3) manual page. + */ + +/* + * List declarations. + */ +#define  LIST_HEAD(name, type)                                                 \ +struct name {                                                                  \ +  struct type *lh_first;  /* first element */                                  \ +} + +#define  LIST_HEAD_INITIALIZER(head)                                           \ +  { NULL } + +#define  LIST_ENTRY(type)                                                      \ +struct {                                                                       \ +  struct type *le_next;  /* next element */                                    \ +  struct type **le_prev; /* address of previous next element */                \ +} + +/* + * List functions. + */ + +#define  LIST_EMPTY(head)  ((head)->lh_first == NULL) + +#define  LIST_FIRST(head)  ((head)->lh_first) + +#define  LIST_FOREACH(var, head, field)                                        \ +  for ((var) = LIST_FIRST((head));                                             \ +      (var);                                                                   \ +      (var) = LIST_NEXT((var), field)) + +#define  LIST_INIT(head) do {                                                  \ +  LIST_FIRST((head)) = NULL;                                                   \ +} while (0) + +#define  LIST_INSERT_AFTER(listelm, elm, field) do {                           \ +  if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)         \ +    LIST_NEXT((listelm), field)->field.le_prev =                               \ +        &LIST_NEXT((elm), field);                                              \ +  LIST_NEXT((listelm), field) = (elm);                                         \ +  (elm)->field.le_prev = &LIST_NEXT((listelm), field);                         \ +} while (0) + +#define  LIST_INSERT_BEFORE(listelm, elm, field) do {                          \ +  (elm)->field.le_prev = (listelm)->field.le_prev;                             \ +  LIST_NEXT((elm), field) = (listelm);                                         \ +  *(listelm)->field.le_prev = (elm);                                           \ +  (listelm)->field.le_prev = &LIST_NEXT((elm), field);                         \ +} while (0) + +#define  LIST_INSERT_HEAD(head, elm, field) do {                               \ +  if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)                  \ +    LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);              \ +  LIST_FIRST((head)) = (elm);                                                  \ +  (elm)->field.le_prev = &LIST_FIRST((head));                                  \ +} while (0) + +#define  LIST_NEXT(elm, field)  ((elm)->field.le_next) + +#define  LIST_REMOVE(elm, field) do {                                          \ +  if (LIST_NEXT((elm), field) != NULL)                                         \ +    LIST_NEXT((elm), field)->field.le_prev =                                   \ +        (elm)->field.le_prev;                                                  \ +  *(elm)->field.le_prev = LIST_NEXT((elm), field);                             \ +} while (0) + +#endif /* !_SYS_QUEUE_H_ */ + + +/* Add a 16 bit unsigned value to a buffer pointed to by PTR */ +#define PPPOE_ADD_16(PTR, VAL) \ +    *(PTR)++ = (VAL) / 256;    \ +    *(PTR)++ = (VAL) % 256 + +/* Add a complete PPPoE header to the buffer pointed to by PTR */ +#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \ +    *(PTR)++ = PPPOE_VERTYPE;  \ +    *(PTR)++ = (CODE);         \ +    PPPOE_ADD_16(PTR, SESS);   \ +    PPPOE_ADD_16(PTR, LEN) + +#define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */ +#define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */ +#define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */ +#define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */ + +#ifdef PPPOE_SERVER +/* from if_spppsubr.c */ +#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ +#endif + +struct pppoe_softc { +  LIST_ENTRY(pppoe_softc) sc_list; +  struct netif *sc_ethif;      /* ethernet interface we are using */ +  int sc_pd;                   /* ppp unit number */ +  void (*sc_linkStatusCB)(int pd, int up); + +  int sc_state;                /* discovery phase or session connected */ +  struct eth_addr sc_dest;     /* hardware address of concentrator */ +  u16_t sc_session;            /* PPPoE session id */ + +  char *sc_service_name;       /* if != NULL: requested name of service */ +  char *sc_concentrator_name;  /* if != NULL: requested concentrator id */ +  u8_t *sc_ac_cookie;          /* content of AC cookie we must echo back */ +  size_t sc_ac_cookie_len;     /* length of cookie data */ +#ifdef PPPOE_SERVER +  u8_t *sc_hunique;            /* content of host unique we must echo back */ +  size_t sc_hunique_len;       /* length of host unique */ +#endif +  int sc_padi_retried;         /* number of PADI retries already done */ +  int sc_padr_retried;         /* number of PADR retries already done */ +}; + +/* input routines */ +static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *); + +/* management routines */ +static int pppoe_do_disconnect(struct pppoe_softc *); +static void pppoe_abort_connect(struct pppoe_softc *); +static void pppoe_clear_softc(struct pppoe_softc *, const char *); + +/* internal timeout handling */ +static void pppoe_timeout(void *); + +/* sending actual protocol controll packets */ +static err_t pppoe_send_padi(struct pppoe_softc *); +static err_t pppoe_send_padr(struct pppoe_softc *); +#ifdef PPPOE_SERVER +static err_t pppoe_send_pado(struct pppoe_softc *); +static err_t pppoe_send_pads(struct pppoe_softc *); +#endif +static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); + +/* internal helper functions */ +static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *); +static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *); + +static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list; + +int pppoe_hdrlen; + +void +pppoe_init(void) +{ +  pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN; +  LIST_INIT(&pppoe_softc_list); +} + +err_t +pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr) +{ +  struct pppoe_softc *sc; + +  sc = mem_malloc(sizeof(struct pppoe_softc)); +  if(!sc) { +    *scptr = NULL; +    return ERR_MEM; +  } +  memset(sc, 0, sizeof(struct pppoe_softc)); + +  /* changed to real address later */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); + +  sc->sc_pd = pd; +  sc->sc_linkStatusCB = linkStatusCB; +  sc->sc_ethif = ethif; + +  LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list); + +  *scptr = sc; + +  return ERR_OK; +} + +err_t +pppoe_destroy(struct netif *ifp) +{ +  struct pppoe_softc * sc; + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_ethif == ifp) { +      break; +    } +  } + +  if(!(sc && (sc->sc_ethif == ifp))) { +    return ERR_IF; +  } + +  tcpip_untimeout(pppoe_timeout, sc); +  LIST_REMOVE(sc, sc_list); + +  if (sc->sc_concentrator_name) { +    mem_free(sc->sc_concentrator_name); +  } +  if (sc->sc_service_name) { +    mem_free(sc->sc_service_name); +  } +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +  } +  mem_free(sc); + +  return ERR_OK; +} + +/* + * Find the interface handling the specified session. + * Note: O(number of sessions open), this is a client-side only, mean + * and lean implementation, so number of open sessions typically should + * be 1. + */ +static struct pppoe_softc * +pppoe_find_softc_by_session(u_int session, struct netif *rcvif) +{ +  struct pppoe_softc *sc; + +  if (session == 0) { +    return NULL; +  } + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_state == PPPOE_STATE_SESSION +        && sc->sc_session == session) { +      if (sc->sc_ethif == rcvif) { +        return sc; +      } else { +        return NULL; +      } +    } +  } +  return NULL; +} + +/* Check host unique token passed and return appropriate softc pointer, + * or NULL if token is bogus. */ +static struct pppoe_softc * +pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) +{ +  struct pppoe_softc *sc, *t; + +  if (LIST_EMPTY(&pppoe_softc_list)) { +    return NULL; +  } + +  if (len != sizeof sc) { +    return NULL; +  } +  MEMCPY(&t, token, len); + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc == t) { +      break; +    } +  } + +  if (sc == NULL) { +    PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n")); +    return NULL; +  } + +  /* should be safe to access *sc now */ +  if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) { +    printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state); +    return NULL; +  } +  if (sc->sc_ethif != rcvif) { +    printf("%c%c%"U16_F": wrong interface, not accepting host unique\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +    return NULL; +  } +  return sc; +} + +static void +pppoe_linkstatus_up(void *arg) +{ +  struct pppoe_softc *sc = (struct pppoe_softc*)arg; + +  sc->sc_linkStatusCB(sc->sc_pd, 1); +} + +/* analyze and handle a single received packet while not in session state */ +static void +pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) +{ +  u16_t tag, len; +  u16_t session, plen; +  struct pppoe_softc *sc; +  const char *err_msg; +  char devname[6]; +  char *error; +  u8_t *ac_cookie; +  size_t ac_cookie_len; +#ifdef PPPOE_SERVER +  u8_t *hunique; +  size_t hunique_len; +#endif +  struct pppoehdr *ph; +  struct pppoetag pt; +  int off = 0, err, errortag; +  struct eth_hdr *ethhdr; + +  pb = pppSingleBuf(pb); + +  strcpy(devname, "pppoe");  /* as long as we don't know which instance */ +  err_msg = NULL; +  errortag = 0; +  if (pb->len < sizeof(*ethhdr)) { +    goto done; +  } +  ethhdr = (struct eth_hdr *)pb->payload; +  off += sizeof(*ethhdr); + +  ac_cookie = NULL; +  ac_cookie_len = 0; +#ifdef PPPOE_SERVER +  hunique = NULL; +  hunique_len = 0; +#endif +  session = 0; +  if (pb->len - off <= PPPOE_HEADERLEN) { +    printf("pppoe: packet too short: %d\n", pb->len); +    goto done; +  } + +  ph = (struct pppoehdr *) (ethhdr + 1); +  if (ph->vertype != PPPOE_VERTYPE) { +    printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype); +    goto done; +  } +  session = ntohs(ph->session); +  plen = ntohs(ph->plen); +  off += sizeof(*ph); + +  if (plen + off > pb->len) { +    printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n", +        pb->len - off, plen); +    goto done; +  } +  if(pb->tot_len == pb->len) { +    pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */ +  } +  tag = 0; +  len = 0; +  sc = NULL; +  while (off + sizeof(pt) <= pb->len) { +    MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt)); +    tag = ntohs(pt.tag); +    len = ntohs(pt.len); +    if (off + sizeof(pt) + len > pb->len) { +      printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len); +      goto done; +    } +    switch (tag) { +      case PPPOE_TAG_EOL: +        goto breakbreak; +      case PPPOE_TAG_SNAME: +        break;  /* ignored */ +      case PPPOE_TAG_ACNAME: +        break;  /* ignored */ +      case PPPOE_TAG_HUNIQUE: +        if (sc != NULL) { +          break; +        } +#ifdef PPPOE_SERVER +        hunique = (u8_t*)pb->payload + off + sizeof(pt); +        hunique_len = len; +#endif +        sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif); +        if (sc != NULL) { +          snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        } +        break; +      case PPPOE_TAG_ACCOOKIE: +        if (ac_cookie == NULL) { +          ac_cookie = (u8_t*)pb->payload + off + sizeof(pt); +          ac_cookie_len = len; +        } +        break; +      case PPPOE_TAG_SNAME_ERR: +        err_msg = "SERVICE NAME ERROR"; +        errortag = 1; +        break; +      case PPPOE_TAG_ACSYS_ERR: +        err_msg = "AC SYSTEM ERROR"; +        errortag = 1; +        break; +      case PPPOE_TAG_GENERIC_ERR: +        err_msg = "GENERIC ERROR"; +        errortag = 1; +        break; +    } +    if (err_msg) { +      error = NULL; +      if (errortag && len) { +        error = mem_malloc(len+1); +        if (error) { +          strncpy(error, (char*)pb->payload + off + sizeof(pt), len); +          error[len-1] = '\0'; +        } +      } +      if (error) { +        printf("%s: %s: %s\n", devname, err_msg, error); +        mem_free(error); +      } else { +        printf("%s: %s\n", devname, err_msg); +      } +      if (errortag) { +        goto done; +      } +    } +    off += sizeof(pt) + len; +  } + +breakbreak:; +  switch (ph->code) { +    case PPPOE_CODE_PADI: +#ifdef PPPOE_SERVER +      /* +       * got service name, concentrator name, and/or host unique. +       * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP. +       */ +      if (LIST_EMPTY(&pppoe_softc_list)) { +        goto done; +      } +      LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +        if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) { +          continue; +        } +        if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { +          continue; +        } +        if (sc->sc_state == PPPOE_STATE_INITIAL) { +          break; +        } +      } +      if (sc == NULL) { +        /* printf("pppoe: free passive interface is not found\n"); */ +        goto done; +      } +      if (hunique) { +        if (sc->sc_hunique) { +          mem_free(sc->sc_hunique); +        } +        sc->sc_hunique = mem_malloc(hunique_len); +        if (sc->sc_hunique == NULL) { +          goto done; +        } +        sc->sc_hunique_len = hunique_len; +        MEMCPY(sc->sc_hunique, hunique, hunique_len); +      } +      MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest); +      sc->sc_state = PPPOE_STATE_PADO_SENT; +      pppoe_send_pado(sc); +      break; +  #endif /* PPPOE_SERVER */ +    case PPPOE_CODE_PADR: +  #ifdef PPPOE_SERVER +      /* +       * get sc from ac_cookie if IFF_PASSIVE +       */ +      if (ac_cookie == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        printf("pppoe: received PADR but not includes ac_cookie\n"); +        goto done; +      } +      sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif); +      if (sc == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        if (!LIST_EMPTY(&pppoe_softc_list)) { +          printf("pppoe: received PADR but could not find request for it\n"); +        } +        goto done; +      } +      if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +        printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        goto done; +      } +      if (hunique) { +        if (sc->sc_hunique) { +          mem_free(sc->sc_hunique); +        } +        sc->sc_hunique = mem_malloc(hunique_len); +        if (sc->sc_hunique == NULL) { +          goto done; +        } +        sc->sc_hunique_len = hunique_len; +        MEMCPY(sc->sc_hunique, hunique, hunique_len); +      } +      pppoe_send_pads(sc); +      sc->sc_state = PPPOE_STATE_SESSION; +      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ +      break; +  #else +      /* ignore, we are no access concentrator */ +      goto done; +  #endif /* PPPOE_SERVER */ +    case PPPOE_CODE_PADO: +      if (sc == NULL) { +        /* be quiet if there is not a single pppoe instance */ +        if (!LIST_EMPTY(&pppoe_softc_list)) { +          printf("pppoe: received PADO but could not find request for it\n"); +        } +        goto done; +      } +      if (sc->sc_state != PPPOE_STATE_PADI_SENT) { +        printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +        goto done; +      } +      if (ac_cookie) { +        if (sc->sc_ac_cookie) { +          mem_free(sc->sc_ac_cookie); +        } +        sc->sc_ac_cookie = mem_malloc(ac_cookie_len); +        if (sc->sc_ac_cookie == NULL) { +          goto done; +        } +        sc->sc_ac_cookie_len = ac_cookie_len; +        MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); +      } +      MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); +      tcpip_untimeout(pppoe_timeout, sc); +      sc->sc_padr_retried = 0; +      sc->sc_state = PPPOE_STATE_PADR_SENT; +      if ((err = pppoe_send_padr(sc)) != 0) { +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); +      break; +    case PPPOE_CODE_PADS: +      if (sc == NULL) { +        goto done; +      } +      sc->sc_session = session; +      tcpip_untimeout(pppoe_timeout, sc); +      PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); +      sc->sc_state = PPPOE_STATE_SESSION; +      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ +      break; +    case PPPOE_CODE_PADT: +      if (sc == NULL) { +        goto done; +      } +      pppoe_clear_softc(sc, "received PADT"); +      break; +    default: +      if(sc) { +        printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n", +            sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, +            ph->code, session); +      } else { +        printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session); +      } +      break; +  } + +done: +  pbuf_free(pb); +  return; +} + +void +pppoe_disc_input(struct netif *netif, struct pbuf *p) +{ +  /* avoid error messages if there is not a single pppoe instance */ +  if (!LIST_EMPTY(&pppoe_softc_list)) { +    pppoe_dispatch_disc_pkt(netif, p); +  } else { +    pbuf_free(p); +  } +} + +void +pppoe_data_input(struct netif *netif, struct pbuf *pb) +{ +  u16_t session, plen; +  struct pppoe_softc *sc; +  struct pppoehdr *ph; +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +  u8_t shost[ETHER_ADDR_LEN]; +#endif + +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +  MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost)); +#endif +  if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n")); +    LINK_STATS_INC(link.lenerr); +    goto drop; +  }  + +  pb = pppSingleBuf (pb); + +  if (pb->len <= PPPOE_HEADERLEN) { +    printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len); +    goto drop; +  } + +  if (pb->len < sizeof(*ph)) { +    printf("pppoe_data_input: could not get PPPoE header\n"); +    goto drop; +  } +  ph = (struct pppoehdr *)pb->payload; + +  if (ph->vertype != PPPOE_VERTYPE) { +    printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype); +    goto drop; +  } +  if (ph->code != 0) { +    goto drop; +  } + +  session = ntohs(ph->session); +  sc = pppoe_find_softc_by_session(session, netif); +  if (sc == NULL) { +#ifdef PPPOE_TERM_UNKNOWN_SESSIONS +    printf("pppoe: input for unknown session 0x%x, sending PADT\n", session); +    pppoe_send_padt(netif, session, shost); +#endif +    goto drop; +  } + +  plen = ntohs(ph->plen); + +  if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); +    LINK_STATS_INC(link.lenerr); +    goto drop; +  }  + +  PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", +        sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, +        pb->len, plen)); + +  if (pb->len < plen) { +    goto drop; +  } + +  pppInProcOverEthernet(sc->sc_pd, pb); + +  return; + +drop: +  pbuf_free(pb); +} + +static err_t +pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) +{ +  struct eth_hdr *ethhdr; +  u16_t etype; +  err_t res; + +  if (!sc->sc_ethif) { +    pbuf_free(pb); +    return ERR_IF; +  } + +  ethhdr = (struct eth_hdr *)pb->payload; +  etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC; +  ethhdr->type = htons(etype); +  MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); +  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr)); + +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", +      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, +      sc->sc_state, sc->sc_session, +      sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], +      pb->tot_len)); + +  res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb); + +  pbuf_free(pb); + +  return res; +} + +static err_t +pppoe_send_padi(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  int len, l1 = 0, l2 = 0; /* XXX: gcc */ + +  if (sc->sc_state >PPPOE_STATE_PADI_SENT) { +    PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state)); +  } + +  /* calculate length of frame (excluding ethernet header + pppoe header) */ +  len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */ +  if (sc->sc_service_name != NULL) { +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  if (sc->sc_concentrator_name != NULL) { +    l2 = strlen(sc->sc_concentrator_name); +    len += 2 + 2 + l2; +  } + +  /* allocate a buffer */ +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } + +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  /* fill in pkt */ +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  if (sc->sc_concentrator_name != NULL) { +    PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); +    PPPOE_ADD_16(p, l2); +    MEMCPY(p, sc->sc_concentrator_name, l2); +    p += l2; +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof sc); + +  /* send pkt */ +  return pppoe_output(sc, pb); +} + +static void +pppoe_timeout(void *arg) +{ +  int retry_wait, err; +  struct pppoe_softc *sc = (struct pppoe_softc*)arg; + +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + +  switch (sc->sc_state) { +    case PPPOE_STATE_PADI_SENT: +      /* +       * We have two basic ways of retrying: +       *  - Quick retry mode: try a few times in short sequence +       *  - Slow retry mode: we already had a connection successfully +       *    established and will try infinitely (without user +       *    intervention) +       * We only enter slow retry mode if IFF_LINK1 (aka autodial) +       * is not set. +       */ + +      /* initialize for quick retry mode */ +      retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried); + +      sc->sc_padi_retried++; +      if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) { +#if 0 +        if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) { +          /* slow retry mode */ +          retry_wait = PPPOE_SLOW_RETRY; +        } else +#endif +        { +          pppoe_abort_connect(sc); +          return; +        } +      } +      if ((err = pppoe_send_padi(sc)) != 0) { +        sc->sc_padi_retried--; +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(retry_wait, pppoe_timeout, sc); +      break; + +    case PPPOE_STATE_PADR_SENT: +      sc->sc_padr_retried++; +      if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) { +        MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +        sc->sc_state = PPPOE_STATE_PADI_SENT; +        sc->sc_padr_retried = 0; +        if ((err = pppoe_send_padi(sc)) != 0) { +          PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +        } +        tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); +        return; +      } +      if ((err = pppoe_send_padr(sc)) != 0) { +        sc->sc_padr_retried--; +        PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +      } +      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); +      break; +    case PPPOE_STATE_CLOSING: +      pppoe_do_disconnect(sc); +      break; +    default: +      return;  /* all done, work in peace */ +  } +} + +/* Start a connection (i.e. initiate discovery phase) */ +int +pppoe_connect(struct pppoe_softc *sc) +{ +  int err; + +  if (sc->sc_state != PPPOE_STATE_INITIAL) { +    return EBUSY; +  } + +#ifdef PPPOE_SERVER +  /* wait PADI if IFF_PASSIVE */ +  if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) { +    return 0; +  } +#endif +  /* save state, in case we fail to send PADI */ +  sc->sc_state = PPPOE_STATE_PADI_SENT; +  sc->sc_padr_retried = 0; +  err = pppoe_send_padi(sc); +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); +  tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); +  return err; +} + +/* disconnect */ +void +pppoe_disconnect(struct pppoe_softc *sc) +{ +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    return; +  } +  /* +   * Do not call pppoe_disconnect here, the upper layer state +   * machine gets confused by this. We must return from this +   * function and defer disconnecting to the timeout handler. +   */ +  sc->sc_state = PPPOE_STATE_CLOSING; +  tcpip_timeout(20, pppoe_timeout, sc); +} + +static int +pppoe_do_disconnect(struct pppoe_softc *sc) +{ +  int err; + +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    err = EBUSY; +  } else { +    PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); +    err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); +  } + +  /* cleanup softc */ +  sc->sc_state = PPPOE_STATE_INITIAL; +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +    sc->sc_ac_cookie = NULL; +  } +  sc->sc_ac_cookie_len = 0; +#ifdef PPPOE_SERVER +  if (sc->sc_hunique) { +    mem_free(sc->sc_hunique); +    sc->sc_hunique = NULL; +  } +  sc->sc_hunique_len = 0; +#endif +  sc->sc_session = 0; + +  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + +  return err; +} + +/* Connection attempt aborted */ +static void +pppoe_abort_connect(struct pppoe_softc *sc) +{ +  printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +  sc->sc_state = PPPOE_STATE_CLOSING; + +  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */ + +  /* clear connection state */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  sc->sc_state = PPPOE_STATE_INITIAL; +} + +/* Send a PADR packet */ +static err_t +pppoe_send_padr(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len, l1 = 0; /* XXX: gcc */ + +  if (sc->sc_state != PPPOE_STATE_PADR_SENT) { +    return ERR_CONN; +  } + +  len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */ +  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */ +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  if (sc->sc_ac_cookie_len > 0) { +    len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */ +  } +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  if (sc->sc_ac_cookie_len > 0) { +    PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); +    PPPOE_ADD_16(p, sc->sc_ac_cookie_len); +    MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len); +    p += sc->sc_ac_cookie_len; +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof sc); + +  return pppoe_output(sc, pb); +} + +/* send a PADT packet */ +static err_t +pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) +{ +  struct pbuf *pb; +  struct eth_hdr *ethhdr; +  err_t res; +  u8_t *p; + +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } + +  ethhdr = (struct eth_hdr *)pb->payload; +  ethhdr->type = htons(ETHTYPE_PPPOEDISC); +  MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); +  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr)); + +  p = (u8_t*)(ethhdr + 1); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0); + +  res = outgoing_if->linkoutput(outgoing_if, pb); + +  pbuf_free(pb); + +  return res; +} + +#ifdef PPPOE_SERVER +static err_t +pppoe_send_pado(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len; + +  if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +    return ERR_CONN; +  } + +  /* calc length */ +  len = 0; +  /* include ac_cookie */ +  len += 2 + 2 + sizeof(sc); +  /* include hunique */ +  len += 2 + 2 + sc->sc_hunique_len; +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); +  PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); +  PPPOE_ADD_16(p, sizeof(sc)); +  MEMCPY(p, &sc, sizeof(sc)); +  p += sizeof(sc); +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sc->sc_hunique_len); +  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); +  return pppoe_output(sc, pb); +} + +static err_t +pppoe_send_pads(struct pppoe_softc *sc) +{ +  struct pbuf *pb; +  u8_t *p; +  size_t len, l1 = 0;  /* XXX: gcc */ + +  if (sc->sc_state != PPPOE_STATE_PADO_SENT) { +    return ERR_CONN; +  } + +  sc->sc_session = mono_time.tv_sec % 0xff + 1; +  /* calc length */ +  len = 0; +  /* include hunique */ +  len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/ +  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */ +    l1 = strlen(sc->sc_service_name); +    len += l1; +  } +  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); +  if (!pb) { +    return ERR_MEM; +  } +  p = (u8_t*)pb->payload + sizeof (struct eth_hdr); +  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); +  PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +  if (sc->sc_service_name != NULL) { +    PPPOE_ADD_16(p, l1); +    MEMCPY(p, sc->sc_service_name, l1); +    p += l1; +  } else { +    PPPOE_ADD_16(p, 0); +  } +  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); +  PPPOE_ADD_16(p, sc->sc_hunique_len); +  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len); +  return pppoe_output(sc, pb); +} +#endif + +err_t +pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) +{ +  u8_t *p; +  size_t len; + +  /* are we ready to process data yet? */ +  if (sc->sc_state < PPPOE_STATE_SESSION) { +    /*sppp_flush(&sc->sc_sppp.pp_if);*/ +    pbuf_free(pb); +    return ERR_CONN; +  } + +  len = pb->tot_len; + +  /* make room for Ethernet header - should not fail */ +  if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) { +    /* bail out */ +    PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); +    LINK_STATS_INC(link.lenerr); +    pbuf_free(pb); +    return ERR_BUF; +  }  + +  p = (u8_t*)pb->payload + sizeof(struct eth_hdr); +  PPPOE_ADD_HEADER(p, 0, sc->sc_session, len); + +  return pppoe_output(sc, pb); +} + +#if 0 /*def PFIL_HOOKS*/ +static int +pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir) +{ +  struct pppoe_softc *sc; +  int s; + +  if (mp != (struct pbuf **)PFIL_IFNET_DETACH) { +    return 0; +  } + +  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { +    if (sc->sc_ethif != ifp) { +      continue; +    } +    if (sc->sc_sppp.pp_if.if_flags & IFF_UP) { +      sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING); +      printf("%c%c%"U16_F": ethernet interface detached, going down\n", +          sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num); +    } +    sc->sc_ethif = NULL; +    pppoe_clear_softc(sc, "ethernet interface detached"); +  } + +  return 0; +} +#endif + +static void +pppoe_clear_softc(struct pppoe_softc *sc, const char *message) +{ +  LWIP_UNUSED_ARG(message); + +  /* stop timer */ +  tcpip_untimeout(pppoe_timeout, sc); +  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + +  /* fix our state */ +  sc->sc_state = PPPOE_STATE_INITIAL; + +  /* notify upper layers */ +  sc->sc_linkStatusCB(sc->sc_pd, 0); + +  /* clean up softc */ +  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); +  if (sc->sc_ac_cookie) { +    mem_free(sc->sc_ac_cookie); +    sc->sc_ac_cookie = NULL; +  } +  sc->sc_ac_cookie_len = 0; +  sc->sc_session = 0; +} + +#endif /* PPPOE_SUPPORT */ + diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h new file mode 100644 index 000000000..6253863c9 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/pppdebug.h @@ -0,0 +1,86 @@ +/***************************************************************************** +* pppdebug.h - System debugging utilities. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* portions Copyright (c) 1998 Global Election Systems Inc. +* portions Copyright (c) 2001 by Cognizant Pty Ltd. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY (please don't use tabs!) +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Original. +* +***************************************************************************** +*/ +#ifndef PPPDEBUG_H +#define PPPDEBUG_H + +/************************ +*** PUBLIC DATA TYPES *** +************************/ +/* Trace levels. */ +typedef enum { +LOG_CRITICAL = 0, +LOG_ERR      = 1, +LOG_NOTICE   = 2, +LOG_WARNING  = 3, +LOG_INFO     = 5, +LOG_DETAIL   = 6, +LOG_DEBUG    = 7 +} LogCodes; + + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ +/* + * ppp_trace - a form of printf to send tracing information to stderr + */ +void ppp_trace(int level, const char *format,...); + +#define TRACELCP PPP_DEBUG + +#if PPP_DEBUG + +#define AUTHDEBUG(a) ppp_trace a +#define IPCPDEBUG(a) ppp_trace a +#define UPAPDEBUG(a) ppp_trace a +#define LCPDEBUG(a)  ppp_trace a +#define FSMDEBUG(a)  ppp_trace a +#define CHAPDEBUG(a) ppp_trace a +#define PPPDEBUG(a)  ppp_trace a + +#else /* PPP_DEBUG */ + +#define AUTHDEBUG(a) +#define IPCPDEBUG(a) +#define UPAPDEBUG(a) +#define LCPDEBUG(a) +#define FSMDEBUG(a) +#define CHAPDEBUG(a) +#define PPPDEBUG(a) + +#endif /* PPP_DEBUG */ + +#endif /* PPPDEBUG_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.c new file mode 100644 index 000000000..0c622a0b0 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.c @@ -0,0 +1,248 @@ +/***************************************************************************** +* randm.c - Random number generator program file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 by Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc. +*   Extracted from avos. +*****************************************************************************/ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "md5.h" +#include "randm.h" + +#include "ppp.h" +#include "pppdebug.h" + + +#if MD5_SUPPORT /* this module depends on MD5 */ +#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static char randPool[RANDPOOLSZ];   /* Pool of randomness. */ +static long randCount = 0;      /* Pseudo-random incrementer */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * Initialize the random number generator. + * + * Since this is to be called on power up, we don't have much + *  system randomess to work with.  Here all we use is the + *  real-time clock.  We'll accumulate more randomness as soon + *  as things start happening. + */ +void +avRandomInit() +{ +  avChurnRand(NULL, 0); +} + +/* + * Churn the randomness pool on a random event.  Call this early and often + *  on random and semi-random system events to build randomness in time for + *  usage.  For randomly timed events, pass a null pointer and a zero length + *  and this will use the system timer and other sources to add randomness. + *  If new random data is available, pass a pointer to that and it will be + *  included. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + */ +void +avChurnRand(char *randData, u32_t randLen) +{ +  MD5_CTX md5; + +  /* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */ +  MD5Init(&md5); +  MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); +  if (randData) { +    MD5Update(&md5, (u_char *)randData, randLen); +  } else { +    struct { +      /* INCLUDE fields for any system sources of randomness */ +      char foobar; +    } sysData; + +    /* Load sysData fields here. */ +    MD5Update(&md5, (u_char *)&sysData, sizeof(sysData)); +  } +  MD5Final((u_char *)randPool, &md5); +/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */ +} + +/* + * Use the random pool to generate random data.  This degrades to pseudo + *  random when used faster than randomness is supplied using churnRand(). + * Note: It's important that there be sufficient randomness in randPool + *  before this is called for otherwise the range of the result may be + *  narrow enough to make a search feasible. + * + * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427 + * + * XXX Why does he not just call churnRand() for each block?  Probably + *  so that you don't ever publish the seed which could possibly help + *  predict future values. + * XXX Why don't we preserve md5 between blocks and just update it with + *  randCount each time?  Probably there is a weakness but I wish that + *  it was documented. + */ +void +avGenRand(char *buf, u32_t bufLen) +{ +  MD5_CTX md5; +  u_char tmp[16]; +  u32_t n; + +  while (bufLen > 0) { +    n = LWIP_MIN(bufLen, RANDPOOLSZ); +    MD5Init(&md5); +    MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); +    MD5Update(&md5, (u_char *)&randCount, sizeof(randCount)); +    MD5Final(tmp, &md5); +    randCount++; +    MEMCPY(buf, tmp, n); +    buf += n; +    bufLen -= n; +  } +} + +/* + * Return a new random number. + */ +u32_t +avRandom() +{ +  u32_t newRand; + +  avGenRand((char *)&newRand, sizeof(newRand)); + +  return newRand; +} + +#else /* MD5_SUPPORT */ + +/*****************************/ +/*** LOCAL DATA STRUCTURES ***/ +/*****************************/ +static int  avRandomized = 0;       /* Set when truely randomized. */ +static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */ + + +/***********************************/ +/*** PUBLIC FUNCTION DEFINITIONS ***/ +/***********************************/ +/* + * Initialize the random number generator. + * + * Here we attempt to compute a random number seed but even if + * it isn't random, we'll randomize it later. + * + * The current method uses the fields from the real time clock, + * the idle process counter, the millisecond counter, and the + * hardware timer tick counter.  When this is invoked + * in startup(), then the idle counter and timer values may + * repeat after each boot and the real time clock may not be + * operational.  Thus we call it again on the first random + * event. + */ +void +avRandomInit() +{ +#if 0 +  /* Get a pointer into the last 4 bytes of clockBuf. */ +  u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]); + +  /* +   * Initialize our seed using the real-time clock, the idle +   * counter, the millisecond timer, and the hardware timer +   * tick counter.  The real-time clock and the hardware +   * tick counter are the best sources of randomness but +   * since the tick counter is only 16 bit (and truncated +   * at that), the idle counter and millisecond timer +   * (which may be small values) are added to help +   * randomize the lower 16 bits of the seed. +   */ +  readClk(); +  avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr +           + ppp_mtime() + ((u32_t)TM1 << 16) + TM1; +#else +  avRandomSeed += sys_jiffies(); /* XXX */ +#endif + +  /* Initialize the Borland random number generator. */ +  srand((unsigned)avRandomSeed); +} + +/* + * Randomize our random seed value.  Here we use the fact that + * this function is called at *truely random* times by the polling + * and network functions.  Here we only get 16 bits of new random + * value but we use the previous value to randomize the other 16 + * bits. + */ +void +avRandomize(void) +{ +  static u32_t last_jiffies; + +  if (!avRandomized) { +    avRandomized = !0; +    avRandomInit(); +    /* The initialization function also updates the seed. */ +  } else { +    /* avRandomSeed += (avRandomSeed << 16) + TM1; */ +    avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */ +  } +  last_jiffies = sys_jiffies(); +} + +/* + * Return a new random number. + * Here we use the Borland rand() function to supply a pseudo random + * number which we make truely random by combining it with our own + * seed which is randomized by truely random events.  + * Thus the numbers will be truely random unless there have been no + * operator or network events in which case it will be pseudo random + * seeded by the real time clock. + */ +u32_t +avRandom() +{ +  return ((((u32_t)rand() << 16) + rand()) + avRandomSeed); +} + +#endif /* MD5_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.h new file mode 100644 index 000000000..a0984b020 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/randm.h @@ -0,0 +1,81 @@ +/***************************************************************************** +* randm.h - Random number generator header file. +* +* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc. +* Copyright (c) 1998 Global Election Systems Inc. +* +* The authors hereby grant permission to use, copy, modify, distribute, +* and license this software and its documentation for any purpose, provided +* that existing copyright notices are retained in all copies and that this +* notice and the following disclaimer are included verbatim in any  +* distributions. No written agreement, license, or royalty fee is required +* for any of the authorized uses. +* +* THIS SOFTWARE IS PROVIDED BY THE 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 THE 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. +* +****************************************************************************** +* REVISION HISTORY +* +* 03-01-01 Marc Boucher <marc@mbsi.ca> +*   Ported to lwIP. +* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc. +*   Extracted from avos. +*****************************************************************************/ + +#ifndef RANDM_H +#define RANDM_H + +/*********************** +*** PUBLIC FUNCTIONS *** +***********************/ +/* + * Initialize the random number generator. + */ +void avRandomInit(void); + +/* + * Churn the randomness pool on a random event.  Call this early and often + * on random and semi-random system events to build randomness in time for + * usage.  For randomly timed events, pass a null pointer and a zero length + * and this will use the system timer and other sources to add randomness. + * If new random data is available, pass a pointer to that and it will be + * included. + */ +void avChurnRand(char *randData, u32_t randLen); + +/* + * Randomize our random seed value.  To be called for truely random events + * such as user operations and network traffic. + */ +#if MD5_SUPPORT +#define avRandomize() avChurnRand(NULL, 0) +#else  /* MD5_SUPPORT */ +void avRandomize(void); +#endif /* MD5_SUPPORT */ + +/* + * Use the random pool to generate random data.  This degrades to pseudo + * random when used faster than randomness is supplied using churnRand(). + * Thus it's important to make sure that the results of this are not + * published directly because one could predict the next result to at + * least some degree.  Also, it's important to get a good seed before + * the first use. + */ +void avGenRand(char *buf, u32_t bufLen); + +/* + * Return a new random number. + */ +u32_t avRandom(void); + + +#endif /* RANDM_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.c new file mode 100644 index 000000000..814ea72c5 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.c @@ -0,0 +1,660 @@ +/* + * Routines to compress and uncompess tcp packets (for transmission + * over low speed serial lines. + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + *   Initial distribution. + * + * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au, + * so that the entire packet being decompressed doesn't have + * to be in contiguous memory (just the compressed header). + * + * Modified March 1998 by Guy Lancaster, glanca@gesn.com, + * for a 16 bit processor. + */ + +#include "lwip/opt.h" + +#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */ + +#include "ppp.h" +#include "pppdebug.h" + +#include "vj.h" + +#include <string.h> + +#if VJ_SUPPORT + +#if LINK_STATS +#define INCR(counter) ++comp->stats.counter +#else +#define INCR(counter) +#endif + +#if defined(NO_CHAR_BITFIELDS) +#define getip_hl(base)  ((base).ip_hl_v&0xf) +#define getth_off(base) (((base).th_x2_off&0xf0)>>4) +#else +#define getip_hl(base)  ((base).ip_hl) +#define getth_off(base) ((base).th_off) +#endif + +void +vj_compress_init(struct vjcompress *comp) +{ +  register u_int i; +  register struct cstate *tstate = comp->tstate; +   +#if MAX_SLOTS == 0 +  memset((char *)comp, 0, sizeof(*comp)); +#endif +  comp->maxSlotIndex = MAX_SLOTS - 1; +  comp->compressSlot = 0;    /* Disable slot ID compression by default. */ +  for (i = MAX_SLOTS - 1; i > 0; --i) { +    tstate[i].cs_id = i; +    tstate[i].cs_next = &tstate[i - 1]; +  } +  tstate[0].cs_next = &tstate[MAX_SLOTS - 1]; +  tstate[0].cs_id = 0; +  comp->last_cs = &tstate[0]; +  comp->last_recv = 255; +  comp->last_xmit = 255; +  comp->flags = VJF_TOSS; +} + + +/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ + * checks for zero (since zero has to be encoded in the long, 3 byte + * form). + */ +#define ENCODE(n) { \ +  if ((u_short)(n) >= 256) { \ +    *cp++ = 0; \ +    cp[1] = (n); \ +    cp[0] = (n) >> 8; \ +    cp += 2; \ +  } else { \ +    *cp++ = (n); \ +  } \ +} +#define ENCODEZ(n) { \ +  if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ +    *cp++ = 0; \ +    cp[1] = (n); \ +    cp[0] = (n) >> 8; \ +    cp += 2; \ +  } else { \ +    *cp++ = (n); \ +  } \ +} + +#define DECODEL(f) { \ +  if (*cp == 0) {\ +    u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \ +    (f) = htonl(tmp); \ +    cp += 3; \ +  } else { \ +    u32_t tmp = ntohl(f) + (u32_t)*cp++; \ +    (f) = htonl(tmp); \ +  } \ +} + +#define DECODES(f) { \ +  if (*cp == 0) {\ +    u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \ +    (f) = htons(tmp); \ +    cp += 3; \ +  } else { \ +    u_short tmp = ntohs(f) + (u_short)*cp++; \ +    (f) = htons(tmp); \ +  } \ +} + +#define DECODEU(f) { \ +  if (*cp == 0) {\ +    (f) = htons(((u_short)cp[1] << 8) | cp[2]); \ +    cp += 3; \ +  } else { \ +    (f) = htons((u_short)*cp++); \ +  } \ +} + +/* + * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a + * packet.  This assumes that nb and comp are not null and that the first + * buffer of the chain contains a valid IP header. + * Return the VJ type code indicating whether or not the packet was + * compressed. + */ +u_int +vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) +{ +  register struct ip *ip = (struct ip *)pb->payload; +  register struct cstate *cs = comp->last_cs->cs_next; +  register u_short hlen = getip_hl(*ip); +  register struct tcphdr *oth; +  register struct tcphdr *th; +  register u_short deltaS, deltaA; +  register u_long deltaL; +  register u_int changes = 0; +  u_char new_seq[16]; +  register u_char *cp = new_seq; + +  /*   +   * Check that the packet is IP proto TCP. +   */ +  if (ip->ip_p != IPPROTO_TCP) { +    return (TYPE_IP); +  } + +  /* +   * Bail if this is an IP fragment or if the TCP packet isn't +   * `compressible' (i.e., ACK isn't set or some other control bit is +   * set).   +   */ +  if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) { +    return (TYPE_IP); +  } +  th = (struct tcphdr *)&((long *)ip)[hlen]; +  if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { +    return (TYPE_IP); +  } +  /* +   * Packet is compressible -- we're going to send either a +   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need +   * to locate (or create) the connection state.  Special case the +   * most recently used connection since it's most likely to be used +   * again & we don't have to do any reordering if it's used. +   */ +  INCR(vjs_packets); +  if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr  +      || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr  +      || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { +    /* +     * Wasn't the first -- search for it. +     * +     * States are kept in a circularly linked list with +     * last_cs pointing to the end of the list.  The +     * list is kept in lru order by moving a state to the +     * head of the list whenever it is referenced.  Since +     * the list is short and, empirically, the connection +     * we want is almost always near the front, we locate +     * states via linear search.  If we don't find a state +     * for the datagram, the oldest state is (re-)used. +     */ +    register struct cstate *lcs; +    register struct cstate *lastcs = comp->last_cs; +     +    do { +      lcs = cs; cs = cs->cs_next; +      INCR(vjs_searches); +      if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr +          && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr +          && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { +        goto found; +      } +    } while (cs != lastcs); + +    /* +     * Didn't find it -- re-use oldest cstate.  Send an +     * uncompressed packet that tells the other side what +     * connection number we're using for this conversation. +     * Note that since the state list is circular, the oldest +     * state points to the newest and we only need to set +     * last_cs to update the lru linkage. +     */ +    INCR(vjs_misses); +    comp->last_cs = lcs; +    hlen += getth_off(*th); +    hlen <<= 2; +    /* Check that the IP/TCP headers are contained in the first buffer. */ +    if (hlen > pb->len) { +      return (TYPE_IP); +    } +    goto uncompressed; + +    found: +    /* +     * Found it -- move to the front on the connection list. +     */ +    if (cs == lastcs) { +      comp->last_cs = lcs; +    } else { +      lcs->cs_next = cs->cs_next; +      cs->cs_next = lastcs->cs_next; +      lastcs->cs_next = cs; +    } +  } + +  oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen]; +  deltaS = hlen; +  hlen += getth_off(*th); +  hlen <<= 2; +  /* Check that the IP/TCP headers are contained in the first buffer. */ +  if (hlen > pb->len) { +    PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen)); +    return (TYPE_IP); +  } + +  /* +   * Make sure that only what we expect to change changed. The first +   * line of the `if' checks the IP protocol version, header length & +   * type of service.  The 2nd line checks the "Don't fragment" bit. +   * The 3rd line checks the time-to-live and protocol (the protocol +   * check is unnecessary but costless).  The 4th line checks the TCP +   * header length.  The 5th line checks IP options, if any.  The 6th +   * line checks TCP options, if any.  If any of these things are +   * different between the previous & current datagram, we send the +   * current datagram `uncompressed'. +   */ +  if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0]  +      || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3]  +      || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4]  +      || getth_off(*th) != getth_off(*oth)  +      || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2))  +      || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) { +    goto uncompressed; +  } + +  /* +   * Figure out which of the changing fields changed.  The +   * receiver expects changes in the order: urgent, window, +   * ack, seq (the order minimizes the number of temporaries +   * needed in this section of code). +   */ +  if (th->th_flags & TCP_URG) { +    deltaS = ntohs(th->th_urp); +    ENCODEZ(deltaS); +    changes |= NEW_U; +  } else if (th->th_urp != oth->th_urp) { +    /* argh! URG not set but urp changed -- a sensible +     * implementation should never do this but RFC793 +     * doesn't prohibit the change so we have to deal +     * with it. */ +    goto uncompressed; +  } + +  if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) { +    ENCODE(deltaS); +    changes |= NEW_W; +  } + +  if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) { +    if (deltaL > 0xffff) { +      goto uncompressed; +    } +    deltaA = (u_short)deltaL; +    ENCODE(deltaA); +    changes |= NEW_A; +  } + +  if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) { +    if (deltaL > 0xffff) { +      goto uncompressed; +    } +    deltaS = (u_short)deltaL; +    ENCODE(deltaS); +    changes |= NEW_S; +  } + +  switch(changes) { +  case 0: +    /* +     * Nothing changed. If this packet contains data and the +     * last one didn't, this is probably a data packet following +     * an ack (normal on an interactive connection) and we send +     * it compressed.  Otherwise it's probably a retransmit, +     * retransmitted ack or window probe.  Send it uncompressed +     * in case the other side missed the compressed version. +     */ +    if (ip->ip_len != cs->cs_ip.ip_len && +      ntohs(cs->cs_ip.ip_len) == hlen) { +      break; +    } + +  /* (fall through) */ + +  case SPECIAL_I: +  case SPECIAL_D: +    /* +     * actual changes match one of our special case encodings -- +     * send packet uncompressed. +     */ +    goto uncompressed; + +  case NEW_S|NEW_A: +    if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { +      /* special case for echoed terminal traffic */ +      changes = SPECIAL_I; +      cp = new_seq; +    } +    break; + +  case NEW_S: +    if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { +      /* special case for data xfer */ +      changes = SPECIAL_D; +      cp = new_seq; +    } +    break; +  } + +  deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id)); +  if (deltaS != 1) { +    ENCODEZ(deltaS); +    changes |= NEW_I; +  } +  if (th->th_flags & TCP_PSH) { +    changes |= TCP_PUSH_BIT; +  } +  /* +   * Grab the cksum before we overwrite it below.  Then update our +   * state with this packet's header. +   */ +  deltaA = ntohs(th->th_sum); +  BCOPY(ip, &cs->cs_ip, hlen); + +  /* +   * We want to use the original packet as our compressed packet. +   * (cp - new_seq) is the number of bytes we need for compressed +   * sequence numbers.  In addition we need one byte for the change +   * mask, one for the connection id and two for the tcp checksum. +   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how +   * many bytes of the original packet to toss so subtract the two to +   * get the new packet size. +   */ +  deltaS = (u_short)(cp - new_seq); +  if (!comp->compressSlot || comp->last_xmit != cs->cs_id) { +    comp->last_xmit = cs->cs_id; +    hlen -= deltaS + 4; +    if(pbuf_header(pb, -hlen)){ +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +    } +    cp = (u_char *)pb->payload; +    *cp++ = changes | NEW_C; +    *cp++ = cs->cs_id; +  } else { +    hlen -= deltaS + 3; +    if(pbuf_header(pb, -hlen)) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +    } +    cp = (u_char *)pb->payload; +    *cp++ = changes; +  } +  *cp++ = deltaA >> 8; +  *cp++ = deltaA; +  BCOPY(new_seq, cp, deltaS); +  INCR(vjs_compressed); +  return (TYPE_COMPRESSED_TCP); + +  /* +   * Update connection state cs & send uncompressed packet (that is, +   * a regular ip/tcp packet but with the 'conversation id' we hope +   * to use on future compressed packets in the protocol field). +   */ +uncompressed: +  BCOPY(ip, &cs->cs_ip, hlen); +  ip->ip_p = cs->cs_id; +  comp->last_xmit = cs->cs_id; +  return (TYPE_UNCOMPRESSED_TCP); +} + +/* + * Called when we may have missed a packet. + */ +void +vj_uncompress_err(struct vjcompress *comp) +{ +  comp->flags |= VJF_TOSS; +  INCR(vjs_errorin); +} + +/* + * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP. + * Return 0 on success, -1 on failure. + */ +int +vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) +{ +  register u_int hlen; +  register struct cstate *cs; +  register struct ip *ip; +   +  ip = (struct ip *)nb->payload; +  hlen = getip_hl(*ip) << 2; +  if (ip->ip_p >= MAX_SLOTS +      || hlen + sizeof(struct tcphdr) > nb->len +      || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2) +          > nb->len +      || hlen > MAX_HDR) { +    PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n",  +          ip->ip_p, hlen, nb->len)); +    comp->flags |= VJF_TOSS; +    INCR(vjs_errorin); +    return -1; +  } +  cs = &comp->rstate[comp->last_recv = ip->ip_p]; +  comp->flags &=~ VJF_TOSS; +  ip->ip_p = IPPROTO_TCP; +  BCOPY(ip, &cs->cs_ip, hlen); +  cs->cs_hlen = hlen; +  INCR(vjs_uncompressedin); +  return 0; +} + +/* + * Uncompress a packet of type TYPE_COMPRESSED_TCP. + * The packet is composed of a buffer chain and the first buffer + * must contain an accurate chain length. + * The first buffer must include the entire compressed TCP/IP header.  + * This procedure replaces the compressed header with the uncompressed + * header and returns the length of the VJ header. + */ +int +vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) +{ +  u_char *cp; +  struct tcphdr *th; +  struct cstate *cs; +  u_short *bp; +  struct pbuf *n0 = *nb; +  u32_t tmp; +  u_int vjlen, hlen, changes; + +  INCR(vjs_compressedin); +  cp = (u_char *)n0->payload; +  changes = *cp++; +  if (changes & NEW_C) { +    /*  +     * Make sure the state index is in range, then grab the state. +     * If we have a good state index, clear the 'discard' flag.  +     */ +    if (*cp >= MAX_SLOTS) { +      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp)); +      goto bad; +    } + +    comp->flags &=~ VJF_TOSS; +    comp->last_recv = *cp++; +  } else { +    /*  +     * this packet has an implicit state index.  If we've +     * had a line error since the last time we got an +     * explicit state index, we have to toss the packet.  +     */ +    if (comp->flags & VJF_TOSS) { +      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n")); +      INCR(vjs_tossed); +      return (-1); +    } +  } +  cs = &comp->rstate[comp->last_recv]; +  hlen = getip_hl(cs->cs_ip) << 2; +  th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; +  th->th_sum = htons((*cp << 8) | cp[1]); +  cp += 2; +  if (changes & TCP_PUSH_BIT) { +    th->th_flags |= TCP_PSH; +  } else { +    th->th_flags &=~ TCP_PSH; +  } + +  switch (changes & SPECIALS_MASK) { +  case SPECIAL_I: +    { +      register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; +      /* some compilers can't nest inline assembler.. */ +      tmp = ntohl(th->th_ack) + i; +      th->th_ack = htonl(tmp); +      tmp = ntohl(th->th_seq) + i; +      th->th_seq = htonl(tmp); +    } +    break; + +  case SPECIAL_D: +    /* some compilers can't nest inline assembler.. */ +    tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; +    th->th_seq = htonl(tmp); +    break; + +  default: +    if (changes & NEW_U) { +      th->th_flags |= TCP_URG; +      DECODEU(th->th_urp); +    } else { +      th->th_flags &=~ TCP_URG; +    } +    if (changes & NEW_W) { +      DECODES(th->th_win); +    } +    if (changes & NEW_A) { +      DECODEL(th->th_ack); +    } +    if (changes & NEW_S) { +      DECODEL(th->th_seq); +    } +    break; +  } +  if (changes & NEW_I) { +    DECODES(cs->cs_ip.ip_id); +  } else { +    cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1; +    cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); +  } + +  /* +   * At this point, cp points to the first byte of data in the +   * packet.  Fill in the IP total length and update the IP +   * header checksum. +   */ +  vjlen = (u_short)(cp - (u_char*)n0->payload); +  if (n0->len < vjlen) { +    /*  +     * We must have dropped some characters (crc should detect +     * this but the old slip framing won't)  +     */ +    PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n",  +          n0->len, vjlen)); +    goto bad; +  } + +#if BYTE_ORDER == LITTLE_ENDIAN +  tmp = n0->tot_len - vjlen + cs->cs_hlen; +  cs->cs_ip.ip_len = htons(tmp); +#else +  cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen); +#endif + +  /* recompute the ip header checksum */ +  bp = (u_short *) &cs->cs_ip; +  cs->cs_ip.ip_sum = 0; +  for (tmp = 0; hlen > 0; hlen -= 2) { +    tmp += *bp++; +  } +  tmp = (tmp & 0xffff) + (tmp >> 16); +  tmp = (tmp & 0xffff) + (tmp >> 16); +  cs->cs_ip.ip_sum = (u_short)(~tmp); +   +  /* Remove the compressed header and prepend the uncompressed header. */ +  if(pbuf_header(n0, -((s16_t)(vjlen)))) { +    /* Can we cope with this failing?  Just assert for now */ +    LWIP_ASSERT("pbuf_header failed\n", 0); +    goto bad; +  } + +  if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) { +    struct pbuf *np, *q; +    u8_t *bufptr; + +    np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); +    if(!np) { +      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n")); +      goto bad; +    } + +    if(pbuf_header(np, -cs->cs_hlen)) { +      /* Can we cope with this failing?  Just assert for now */ +      LWIP_ASSERT("pbuf_header failed\n", 0); +      goto bad; +    } + +    bufptr = n0->payload; +    for(q = np; q != NULL; q = q->next) { +      MEMCPY(q->payload, bufptr, q->len); +      bufptr += q->len; +    } + +    if(n0->next) { +      pbuf_chain(np, n0->next); +      pbuf_dechain(n0); +    } +    pbuf_free(n0); +    n0 = np; +  } + +  if(pbuf_header(n0, cs->cs_hlen)) { +    struct pbuf *np; + +    LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); +    np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); +    if(!np) { +      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n")); +      goto bad; +    } +    pbuf_cat(np, n0); +    n0 = np; +  } +  LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen); +  MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen); + +  *nb = n0; + +  return vjlen; + +bad: +  comp->flags |= VJF_TOSS; +  INCR(vjs_errorin); +  return (-1); +} + +#endif /* VJ_SUPPORT */ + +#endif /* PPP_SUPPORT */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.h new file mode 100644 index 000000000..b9617da4d --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vj.h @@ -0,0 +1,155 @@ +/* + * Definitions for tcp compression routines. + * + * $Id: vj.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley.  The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + */ + +#ifndef VJ_H +#define VJ_H + +#include "vjbsdhdr.h" + +#define MAX_SLOTS 16 /* must be > 2 and < 256 */ +#define MAX_HDR   128 + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits).  The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet.  The next two octets are the TCP checksum + * from the original datagram.  The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + *  + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID.  (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.)  Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0.  (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type.  There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows.  Top + * three bits are actual packet type.  For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* packet types */ +#define TYPE_IP               0x40 +#define TYPE_UNCOMPRESSED_TCP 0x70 +#define TYPE_COMPRESSED_TCP   0x80 +#define TYPE_ERROR            0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + + +/* + * "state" data for each active tcp conversation on the wire.  This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { +  struct cstate *cs_next; /* next most recently used state (xmit only) */ +  u_short cs_hlen;        /* size of hdr (receive only) */ +  u_char cs_id;           /* connection # associated with this state */ +  u_char cs_filler; +  union { +    char csu_hdr[MAX_HDR]; +    struct ip csu_ip;     /* ip/tcp hdr from most recent packet */ +  } vjcs_u; +}; +#define cs_ip vjcs_u.csu_ip +#define cs_hdr vjcs_u.csu_hdr + + +struct vjstat { +  unsigned long vjs_packets;        /* outbound packets */ +  unsigned long vjs_compressed;     /* outbound compressed packets */ +  unsigned long vjs_searches;       /* searches for connection state */ +  unsigned long vjs_misses;         /* times couldn't find conn. state */ +  unsigned long vjs_uncompressedin; /* inbound uncompressed packets */ +  unsigned long vjs_compressedin;   /* inbound compressed packets */ +  unsigned long vjs_errorin;        /* inbound unknown type packets */ +  unsigned long vjs_tossed;         /* inbound packets tossed because of error */ +}; + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct vjcompress { +  struct cstate *last_cs;          /* most recently used tstate */ +  u_char last_recv;                /* last rcvd conn. id */ +  u_char last_xmit;                /* last sent conn. id */ +  u_short flags; +  u_char maxSlotIndex; +  u_char compressSlot;             /* Flag indicating OK to compress slot ID. */ +#if LINK_STATS +  struct vjstat stats; +#endif +  struct cstate tstate[MAX_SLOTS]; /* xmit connection states */ +  struct cstate rstate[MAX_SLOTS]; /* receive connection states */ +}; + +/* flag values */ +#define VJF_TOSS 1U /* tossing rcvd frames because of input err */ + +extern void  vj_compress_init    (struct vjcompress *comp); +extern u_int vj_compress_tcp     (struct vjcompress *comp, struct pbuf *pb); +extern void  vj_uncompress_err   (struct vjcompress *comp); +extern int   vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp); +extern int   vj_uncompress_tcp   (struct pbuf **nb, struct vjcompress *comp); + +#endif /* VJ_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h new file mode 100644 index 000000000..f46267614 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/ppp/vjbsdhdr.h @@ -0,0 +1,75 @@ +#ifndef VJBSDHDR_H +#define VJBSDHDR_H + +#include "lwip/tcp.h" + +/* + * Structure of an internet header, naked of options. + * + * We declare ip_len and ip_off to be short, rather than u_short + * pragmatically since otherwise unsigned comparisons can result + * against negative integers quite easily, and fail in subtle ways. + */ +PACK_STRUCT_BEGIN +struct ip +{ +#if defined(NO_CHAR_BITFIELDS) +  u_char   ip_hl_v;  /* bug in GCC for mips means the bitfield stuff will sometimes break - so we use a char for both and get round it with macro's instead... */ +#else +#if BYTE_ORDER == LITTLE_ENDIAN +  unsigned ip_hl:4,              /* header length */ +           ip_v :4;              /* version */ +#elif BYTE_ORDER == BIG_ENDIAN  +  unsigned ip_v :4,              /* version */ +           ip_hl:4;              /* header length */ +#else +  COMPLAIN - NO BYTE ORDER SELECTED! +#endif +#endif +  u_char  ip_tos;                /* type of service */ +  u_short ip_len;                /* total length */ +  u_short ip_id;                 /* identification */ +  u_short ip_off;                /* fragment offset field */ +#define  IP_DF 0x4000            /* dont fragment flag */ +#define  IP_MF 0x2000            /* more fragments flag */ +#define  IP_OFFMASK 0x1fff       /* mask for fragmenting bits */ +  u_char  ip_ttl;                /* time to live */ +  u_char  ip_p;                  /* protocol */ +  u_short ip_sum;                /* checksum */ +  struct  in_addr ip_src,ip_dst; /* source and dest address */ +}; +PACK_STRUCT_END + +typedef u32_t tcp_seq; + +/* + * TCP header. + * Per RFC 793, September, 1981. + */ +PACK_STRUCT_BEGIN +struct tcphdr   +{ +  u_short  th_sport;    /* source port */ +  u_short  th_dport;    /* destination port */ +  tcp_seq  th_seq;      /* sequence number */ +  tcp_seq  th_ack;      /* acknowledgement number */ +#if defined(NO_CHAR_BITFIELDS) +  u_char   th_x2_off; +#else +#if BYTE_ORDER == LITTLE_ENDIAN +  unsigned th_x2 :4,    /* (unused) */ +           th_off:4;    /* data offset */ +#endif +#if BYTE_ORDER == BIG_ENDIAN  +  unsigned th_off:4,    /* data offset */ +           th_x2 :4;    /* (unused) */ +#endif +#endif +  u_char   th_flags; +  u_short  th_win;      /* window */ +  u_short  th_sum;      /* checksum */ +  u_short  th_urp;      /* urgent pointer */ +}; +PACK_STRUCT_END + +#endif /* VJBSDHDR_H */ diff --git a/firmware/usrp3/lwip/lwip-1.3.1/src/netif/slipif.c b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/slipif.c new file mode 100644 index 000000000..6cb2db442 --- /dev/null +++ b/firmware/usrp3/lwip/lwip-1.3.1/src/netif/slipif.c @@ -0,0 +1,279 @@ +/** + * @file + * SLIP Interface + * + */ + +/* + * 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. Neither the name of the Institute 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 THE INSTITUTE 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 THE INSTITUTE 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 built upon the file: src/arch/rtxc/netif/sioslip.c + * + * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com>  + */ + +/*  + * This is an arch independent SLIP netif. The specific serial hooks must be + * provided by another file. They are sio_open, sio_recv and sio_send + */ + +#include "netif/slipif.h" +#include "lwip/opt.h" + +#if LWIP_HAVE_SLIPIF + +#include "lwip/def.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include "lwip/stats.h" +#include "lwip/snmp.h" +#include "lwip/sio.h" + +#define SLIP_END     0300 /* 0xC0 */ +#define SLIP_ESC     0333 /* 0xDB */ +#define SLIP_ESC_END 0334 /* 0xDC */ +#define SLIP_ESC_ESC 0335 /* 0xDD */ + +#define MAX_SIZE     1500 + +/** + * Send a pbuf doing the necessary SLIP encapsulation + * + * Uses the serial layer's sio_send() + * + * @param netif the lwip network interface structure for this slipif + * @param p the pbuf chaing packet to send + * @param ipaddr the ip address to send the packet to (not used for slipif) + * @return always returns ERR_OK since the serial layer does not provide return values + */ +err_t +slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +{ +  struct pbuf *q; +  u16_t i; +  u8_t c; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); +  LWIP_ASSERT("p != NULL", (p != NULL)); + +  LWIP_UNUSED_ARG(ipaddr); + +  /* Send pbuf out on the serial I/O device. */ +  sio_send(SLIP_END, netif->state); + +  for (q = p; q != NULL; q = q->next) { +    for (i = 0; i < q->len; i++) { +      c = ((u8_t *)q->payload)[i]; +      switch (c) { +      case SLIP_END: +        sio_send(SLIP_ESC, netif->state); +        sio_send(SLIP_ESC_END, netif->state); +        break; +      case SLIP_ESC: +        sio_send(SLIP_ESC, netif->state); +        sio_send(SLIP_ESC_ESC, netif->state); +        break; +      default: +        sio_send(c, netif->state); +        break; +      } +    } +  } +  sio_send(SLIP_END, netif->state); +  return ERR_OK; +} + +/** + * Handle the incoming SLIP stream character by character + * + * Poll the serial layer by calling sio_recv() + * + * @param netif the lwip network interface structure for this slipif + * @return The IP packet when SLIP_END is received  + */ +static struct pbuf * +slipif_input(struct netif *netif) +{ +  u8_t c; +  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */ +  struct pbuf *p, *q; +  u16_t recved; +  u16_t i; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL)); + +  q = p = NULL; +  recved = i = 0; +  c = 0; + +  while (1) { +    c = sio_recv(netif->state); +    switch (c) { +    case SLIP_END: +      if (recved > 0) { +        /* Received whole packet. */ +        /* Trim the pbuf to the size of the received packet. */ +        pbuf_realloc(q, recved); +         +        LINK_STATS_INC(link.recv); +         +        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n")); +        return q; +      } +      break; + +    case SLIP_ESC: +      c = sio_recv(netif->state); +      switch (c) { +      case SLIP_ESC_END: +        c = SLIP_END; +        break; +      case SLIP_ESC_ESC: +        c = SLIP_ESC; +        break; +      } +      /* FALLTHROUGH */ + +    default: +      /* byte received, packet not yet completely received */ +      if (p == NULL) { +        /* allocate a new pbuf */ +        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n")); +        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL); + +        if (p == NULL) { +          LINK_STATS_INC(link.drop); +          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n")); +          /* don't process any further since we got no pbuf to receive to */ +          break; +        } + +        if (q != NULL) { +          /* 'chain' the pbuf to the existing chain */ +          pbuf_cat(q, p); +        } else { +          /* p is the first pbuf in the chain */ +          q = p; +        } +      } + +      /* this automatically drops bytes if > MAX_SIZE */ +      if ((p != NULL) && (recved <= MAX_SIZE)) { +        ((u8_t *)p->payload)[i] = c; +        recved++; +        i++; +        if (i >= p->len) { +          /* on to the next pbuf */ +          i = 0; +          if (p->next != NULL && p->next->len > 0) { +            /* p is a chain, on to the next in the chain */ +            p = p->next; +          } else { +            /* p is a single pbuf, set it to NULL so next time a new +             * pbuf is allocated */ +            p = NULL; +          } +        } +      } +      break; +    } +  } +  return NULL; +} + +#if !NO_SYS +/** + * The SLIP input thread. + * + * Feed the IP layer with incoming packets + * + * @param nf the lwip network interface structure for this slipif + */ +static void +slipif_loop(void *nf) +{ +  struct pbuf *p; +  struct netif *netif = (struct netif *)nf; + +  while (1) { +    p = slipif_input(netif); +    if (p != NULL) { +      if (netif->input(p, netif) != ERR_OK) { +        pbuf_free(p); +        p = NULL; +      } +    } +  } +} +#endif /* !NO_SYS */ + +/** + * SLIP netif initialization + * + * Call the arch specific sio_open and remember + * the opened device in the state field of the netif. + * + * @param netif the lwip network interface structure for this slipif + * @return ERR_OK if serial line could be opened, + *         ERR_IF is serial line couldn't be opened + * + * @note netif->num must contain the number of the serial port to open + *       (0 by default) + */ +err_t +slipif_init(struct netif *netif) +{ + +  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num)); + +  netif->name[0] = 's'; +  netif->name[1] = 'l'; +  netif->output = slipif_output; +  netif->mtu = MAX_SIZE; +  netif->flags = NETIF_FLAG_POINTTOPOINT; + +  /* Try to open the serial port (netif->num contains the port number). */ +  netif->state = sio_open(netif->num); +  if (!netif->state) { +    /* Opening the serial port failed. */ +    return ERR_IF; +  } + +  /* initialize the snmp variables and counters inside the struct netif +   * ifSpeed: no assumption can be made without knowing more about the +   * serial line! +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0); + +  /* Create a thread to poll the serial line. */ +  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO); +  return ERR_OK; +} +#endif /* LWIP_HAVE_SLIPIF */ diff --git a/firmware/usrp3/lwip/lwipopts.h b/firmware/usrp3/lwip/lwipopts.h new file mode 100644 index 000000000..3839eea83 --- /dev/null +++ b/firmware/usrp3/lwip/lwipopts.h @@ -0,0 +1,196 @@ +/* -*- c++ -*- */ +/* + * Copyright 2009 Free Software Foundation, Inc. + *  + * This file is part of GNU Radio + *  + * GNU Radio is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3, or (at your option) + * any later version. + *  + * GNU Radio is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + *  + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +/* + * Our lwip options + */ + +#define NO_SYS				1 + + +// ---------- Memory options ---------- +/** + * MEM_ALIGNMENT: should be set to the alignment of the CPU + *    4 byte alignment -> #define MEM_ALIGNMENT 4 + *    2 byte alignment -> #define MEM_ALIGNMENT 2 + */ +#define MEM_ALIGNMENT      		4 + +/** + * MEM_SIZE: the size of the heap memory. If the application will send + * a lot of data that needs to be copied, this should be set high. + */ +#define MEM_SIZE        		256 + +/** + * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set + * of memory pools of various sizes. When mem_malloc is called, an element of + * the smallest pool that can provide the lenght needed is returned. + */ +#define MEM_USE_POOLS                   0 + +/** + * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h + * that defines additional pools beyond the "standard" ones required + * by lwIP. If you set this to 1, you must have lwippools.h in your  + * inlude path somewhere.  + */ +#define MEMP_USE_CUSTOM_POOLS           0 + +// ---------- Internal Memory Pool Sizes ---------- +/** + * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF). + * If the application sends a lot of data out of ROM (or other static memory), + * this should be set high. + */ +#define MEMP_NUM_PBUF                   8 + +/** + * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One + * per active UDP "connection". + * (requires the LWIP_UDP option) + */ +#define MEMP_NUM_UDP_PCB                4 + +/** + * PBUF_LINK_HLEN: the number of bytes that should be allocated for a + * link level header. The default is 14, the standard value for + * Ethernet. + */ +#define PBUF_LINK_HLEN                  16 +#define	ETH_PAD_SIZE			2 + +/** + * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.  + */ +#define PBUF_POOL_SIZE                  8 + +/** + * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is + * designed to accomodate single full size TCP frame in one pbuf, including + * TCP_MSS, IP header, and link header. + */ +//#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN) +#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(128+28+PBUF_LINK_HLEN) + + +// ---------- ARP options ---------- +/** + * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached. + */ +#define ARP_TABLE_SIZE                  5 + +/** + * ARP_QUEUEING==1: Outgoing packets are queued during hardware address + * resolution. + */ +#define ARP_QUEUEING                    0 + +/** + * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing + * packets (pbufs) that are waiting for an ARP request (to resolve + * their destination address) to finish. + * (requires the ARP_QUEUEING option) + */ +#define MEMP_NUM_ARP_QUEUE              5 + +// ---------- IP options ---------- +/** + * IP_OPTIONS_ALLOWED: Defines the behavior for IP options. + *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped. + *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed). + */ +#define IP_OPTIONS_ALLOWED              0 + +/** + * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that + * this option does not affect outgoing packet sizes, which can be controlled + * via IP_FRAG. + */ +#define IP_REASSEMBLY                   0 + +/** + * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note + * that this option does not affect incoming packet sizes, which can be + * controlled via IP_REASSEMBLY. + */ +#define IP_FRAG                         0 + +/** + * LWIP_DHCP==1: Enable DHCP module. + */ +#define LWIP_DHCP                       0 + +/** + * LWIP_IGMP==1: Turn on IGMP module.  + */ +#define LWIP_IGMP                       0 + +/** + * LWIP_UDP==1: Turn on UDP. + */ +#define LWIP_UDP                        1 + +/** + * LWIP_TCP==1: Turn on TCP. + */ +#define LWIP_TCP                        0 + +/** + * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) + */ +#define LWIP_NETCONN                    0 + +/** + * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c) + */ +#define LWIP_SOCKET                     0 + +/** + * LWIP_STATS==1: Enable statistics collection in lwip_stats. + */ +#define LWIP_STATS                      0 + +/** + * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets. + */ +#define CHECKSUM_GEN_IP                 0 +  +/** + * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets. + */ +#define CHECKSUM_GEN_UDP                0 +  +/** + * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets. + */ +#define CHECKSUM_CHECK_IP               0 + +/** + * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets. + */ +#define CHECKSUM_CHECK_UDP              0 + +/** + * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface + * whenever the link changes (i.e., link down) + */ +#define LWIP_NETIF_LINK_CALLBACK        1 diff --git a/firmware/usrp3/lwip/lwippools.h b/firmware/usrp3/lwip/lwippools.h new file mode 100644 index 000000000..caee23c82 --- /dev/null +++ b/firmware/usrp3/lwip/lwippools.h @@ -0,0 +1,24 @@ +#ifndef INCLUDED_LWIPPOOLS_H +#define INCLUDED_LWIPPOOLS_H + +/* + * from comment at top of mem.c: + * + * 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 + */ + +LWIP_MALLOC_MEMPOOL_START +LWIP_MALLOC_MEMPOOL(2, 256) +LWIP_MALLOC_MEMPOOL_END + +#endif /* INCLUDED_LWIPPOOLS_H */ diff --git a/firmware/usrp3/lwip_port/arch/cc.h b/firmware/usrp3/lwip_port/arch/cc.h new file mode 100644 index 000000000..d8d53ecf8 --- /dev/null +++ b/firmware/usrp3/lwip_port/arch/cc.h @@ -0,0 +1,65 @@ +#ifndef INCLUDED_ARCH_CC_H +#define INCLUDED_ARCH_CC_H + +#define BYTE_ORDER BIG_ENDIAN + + +#if 1 +#include <stdint.h> + +typedef uint8_t    u8_t; +typedef int8_t     s8_t; +typedef uint16_t   u16_t; +typedef int16_t    s16_t; +typedef uint32_t   u32_t; +typedef int32_t    s32_t; + +#else + +typedef unsigned   char    u8_t; +typedef signed     char    s8_t; +typedef unsigned   short   u16_t; +typedef signed     short   s16_t; +typedef unsigned   long    u32_t; +typedef signed     long    s32_t; +#endif + +typedef u32_t mem_ptr_t; + +#if 1   /* minimal printf */ +#define U16_F "u" +#define S16_F "d" +#define X16_F "x" +#define U32_F "u" +#define S32_F "d" +#define X32_F "x" + +#else + +#define U16_F "hu" +#define S16_F "hd" +#define X16_F "hx" +#define U32_F "lu" +#define S32_F "ld" +#define X32_F "lx" +#endif + +#if 1	// gcc: don't pack +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END +#else	// gcc: do pack +#define PACK_STRUCT_FIELD(x) x +#define PACK_STRUCT_STRUCT __attribute__((packed)) +#define PACK_STRUCT_BEGIN +#define PACK_STRUCT_END +#endif + +//#define LWIP_PLATFORM_ASSERT(msg) ((void)0) +void abort(void); +#define LWIP_PLATFORM_ASSERT(msg) abort() + + +#endif /* INCLUDED_ARCH_CC_H */ + diff --git a/firmware/usrp3/lwip_port/arch/perf.h b/firmware/usrp3/lwip_port/arch/perf.h new file mode 100644 index 000000000..f0906d03f --- /dev/null +++ b/firmware/usrp3/lwip_port/arch/perf.h @@ -0,0 +1,2 @@ +#define PERF_START     ((void) 0) +#define PERF_STOP(msg) ((void) 0) diff --git a/firmware/usrp3/lwip_port/netif/eth_driver.c b/firmware/usrp3/lwip_port/netif/eth_driver.c new file mode 100644 index 000000000..18c6eaf3e --- /dev/null +++ b/firmware/usrp3/lwip_port/netif/eth_driver.c @@ -0,0 +1,303 @@ +/** + * @file + * Ethernet Interface for quadradio + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * Copyright (c) 2010 Ettus Research LLC + * 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/mem.h" +#include "lwip/pbuf.h" +#include "lwip/sys.h" +#include <lwip/stats.h> +#include <lwip/snmp.h> +#include "netif/etharp.h" +#include "netif/ppp_oe.h" +#include "eth_driver.h" + +#if 0	// don't build + +/* Define those to better describe your network interface. */ +#define IFNAME0 'e' +#define IFNAME1 'n' + +/** + * Helper struct to hold private data used to operate your ethernet interface. + */ +struct quadradioif { +  int	ethno; +}; + +/* Forward declarations. */ +static void  quadradioif_input(struct netif *netif); + +/** + * In this function, the hardware should be initialized. + * Called from quadradioif_init(). + * + * @param netif the already initialized lwip network interface structure + *        for this quadradioif + */ +static void +low_level_init(struct netif *netif) +{ +  struct quadradioif *quadradioif = netif->state; +   +  /* set MAC hardware address length */ +  netif->hwaddr_len = ETHARP_HWADDR_LEN; + +  /* set MAC hardware address */ +  netif->hwaddr[0] = ; +  ... +  netif->hwaddr[5] = ; + +  /* maximum transfer unit */ +  netif->mtu = 1500; +   +  /* device capabilities */ +  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */ +  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP; +  +  /* Do whatever else is needed to initialize interface. */   +} + +/** + * This function should do the actual transmission of the packet. The packet is + * contained in the pbuf that is passed to the function. This pbuf + * might be chained. + * + * @param netif the lwip network interface structure for this quadradioif + * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type) + * @return ERR_OK if the packet could be sent + *         an err_t value if the packet couldn't be sent + * + * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to + *       strange results. You might consider waiting for space in the DMA queue + *       to become availale since the stack doesn't retry to send a packet + *       dropped because of memory failure (except for the TCP timers). + */ + +static err_t +low_level_output(struct netif *netif, struct pbuf *p) +{ +  struct quadradioif *quadradioif = netif->state; +  struct pbuf *q; + +  initiate transfer(); +   +#if ETH_PAD_SIZE +  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +  for(q = p; q != NULL; q = q->next) { +    /* Send the data from the pbuf to the interface, one pbuf at a +       time. The size of the data in each pbuf is kept in the ->len +       variable. */ +    send data from(q->payload, q->len); +  } + +  signal that packet should be sent(); + +#if ETH_PAD_SIZE +  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif +   +  LINK_STATS_INC(link.xmit); + +  return ERR_OK; +} + +/** + * Should allocate a pbuf and transfer the bytes of the incoming + * packet from the interface into the pbuf. + * + * @param netif the lwip network interface structure for this quadradioif + * @return a pbuf filled with the received packet (including MAC header) + *         NULL on memory error + */ +static struct pbuf * +low_level_input(struct netif *netif) +{ +  struct quadradioif *quadradioif = netif->state; +  struct pbuf *p, *q; +  u16_t len; + +  /* Obtain the size of the packet and put it into the "len" +     variable. */ +  len = ; + +#if ETH_PAD_SIZE +  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */ +#endif + +  /* We allocate a pbuf chain of pbufs from the pool. */ +  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL); +   +  if (p != NULL) { + +#if ETH_PAD_SIZE +    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */ +#endif + +    /* We iterate over the pbuf chain until we have read the entire +     * packet into the pbuf. */ +    for(q = p; q != NULL; q = q->next) { +      /* Read enough bytes to fill this pbuf in the chain. The +       * available data in the pbuf is given by the q->len +       * variable. */ +      read data into(q->payload, q->len); +    } +    acknowledge that packet has been read(); + +#if ETH_PAD_SIZE +    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */ +#endif + +    LINK_STATS_INC(link.recv); +  } else { +    drop packet(); +    LINK_STATS_INC(link.memerr); +    LINK_STATS_INC(link.drop); +  } + +  return p;   +} + +/** + * This function should be called when a packet is ready to be read + * from the interface. It uses the function low_level_input() that + * should handle the actual reception of bytes from the network + * interface. Then the type of the received packet is determined and + * the appropriate input function is called. + * + * @param netif the lwip network interface structure for this quadradioif + */ +static void +quadradioif_input(struct netif *netif) +{ +  struct quadradioif *quadradioif; +  struct eth_hdr *ethhdr; +  struct pbuf *p; + +  quadradioif = netif->state; + +  /* move received packet into a new pbuf */ +  p = low_level_input(netif); +  /* no packet could be read, silently ignore this */ +  if (p == NULL) return; +  /* points to packet payload, which starts with an Ethernet header */ +  ethhdr = p->payload; + +  switch (htons(ethhdr->type)) { +  /* IP or ARP packet? */ +  case ETHTYPE_IP: +  case ETHTYPE_ARP: +#if PPPOE_SUPPORT +  /* PPPoE packet? */ +  case ETHTYPE_PPPOEDISC: +  case ETHTYPE_PPPOE: +#endif /* PPPOE_SUPPORT */ +    /* full packet send to tcpip_thread to process */ +    if (netif->input(p, netif)!=ERR_OK) +     { LWIP_DEBUGF(NETIF_DEBUG, ("quadradioif_input: IP input error\n")); +       pbuf_free(p); +       p = NULL; +     } +    break; + +  default: +    pbuf_free(p); +    p = NULL; +    break; +  } +} + +/** + * Should be called at the beginning of the program to set up the + * network interface. It calls the function low_level_init() to do the + * actual setup of the hardware. + * + * This function should be passed as a parameter to netif_add(). + * + * @param netif the lwip network interface structure for this quadradioif + * @return ERR_OK if the loopif is initialized + *         ERR_MEM if private data couldn't be allocated + *         any other err_t on error + */ +err_t +quadradioif_init(struct netif *netif) +{ +  struct quadradioif *quadradioif; + +  LWIP_ASSERT("netif != NULL", (netif != NULL)); +     +  quadradioif = mem_malloc(sizeof(struct quadradioif)); +  if (quadradioif == NULL) { +    LWIP_DEBUGF(NETIF_DEBUG, ("quadradioif_init: out of memory\n")); +    return ERR_MEM; +  } + +#if LWIP_NETIF_HOSTNAME +  /* Initialize interface hostname */ +  netif->hostname = "lwip"; +#endif /* LWIP_NETIF_HOSTNAME */ + +  /* +   * Initialize the snmp variables and counters inside the struct netif. +   * The last argument should be replaced with your link speed, in units +   * of bits per second. +   */ +  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, LINK_SPEED_OF_YOUR_NETIF_IN_BPS); + +  netif->state = quadradioif; +  netif->name[0] = IFNAME0; +  netif->name[1] = IFNAME1; +  /* We directly use etharp_output() here to save a function call. +   * You can instead declare your own function an call etharp_output() +   * from it if you have to do some checks before sending (e.g. if link +   * is available...) */ +  netif->output = etharp_output; +  netif->linkoutput = low_level_output; +   +  quadradioif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]); +   +  /* initialize the hardware */ +  low_level_init(netif); + +  return ERR_OK; +} + +#endif /* 0 */ diff --git a/firmware/usrp3/lwip_port/netif/eth_driver.h b/firmware/usrp3/lwip_port/netif/eth_driver.h new file mode 100644 index 000000000..72a212091 --- /dev/null +++ b/firmware/usrp3/lwip_port/netif/eth_driver.h @@ -0,0 +1,23 @@ +/* -*- c -*- */ +/* + * Copyright 2010 Ettus Research LLC + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program.  If not, see <http://www.gnu.org/licenses/>. + */ + +#include "qpn_port.h" + +void eth_driver_init(QActive *); +void eth_driver_handle_input(int ethno, int bufno, size_t nbytes); +void eth_driver_buffer_sig(int bufno); diff --git a/firmware/usrp3/utils/bin_to_coe.py b/firmware/usrp3/utils/bin_to_coe.py new file mode 100755 index 000000000..332c705ae --- /dev/null +++ b/firmware/usrp3/utils/bin_to_coe.py @@ -0,0 +1,18 @@ +#!/usr/bin/python + +import sys +import binascii + +if __name__ == '__main__': +    bin_file = sys.argv[1] +    coe_file = sys.argv[2] + +    #parse bin file into hex lines +    h = binascii.hexlify(open(bin_file).read()) + '0'*7 +    d = [h[i*8:(i+1)*8] for i in range(len(h)/8)] + +    #write output coe file +    out = open(coe_file, 'w') +    out.write('memory_initialization_radix=16;\n') +    out.write('memory_initialization_vector=\n') +    out.write(',\n'.join([h[i*8:(i+1)*8] for i in range(len(h)/8)]) + ';') diff --git a/firmware/usrp3/x300/CMakeLists.txt b/firmware/usrp3/x300/CMakeLists.txt new file mode 100644 index 000000000..5e6134885 --- /dev/null +++ b/firmware/usrp3/x300/CMakeLists.txt @@ -0,0 +1,36 @@ +# +# Copyright 2010-2014 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +######################################################################## +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) +include_directories(${CMAKE_SOURCE_DIR}/../../host/lib/usrp/x300) + +list(APPEND x300_sources x300_init.c x300_main.c) + +######################################################################## +set(GEN_OUTPUTS_BIN_SIZE 0x7fff) +SET(CMAKE_C_FLAGS_DEBUG -DX300_DEBUG_UART) + +add_executable(x300_main.elf ${x300_sources}) +target_link_libraries(x300_main.elf usrp3fw) +GEN_OUTPUTS(x300_main.elf x300) + +INSTALL( +    FILES ${CMAKE_CURRENT_BINARY_DIR}/x300_main.bin +    DESTINATION share/uhd/images +    RENAME usrp_x300_fw.bin +) diff --git a/firmware/usrp3/x300/x300_debug.py b/firmware/usrp3/x300/x300_debug.py new file mode 100755 index 000000000..c9bcbb138 --- /dev/null +++ b/firmware/usrp3/x300/x300_debug.py @@ -0,0 +1,167 @@ +#!/usr/bin/env python +# +# Copyright 2010-2011 Ettus Research LLC +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program.  If not, see <http://www.gnu.org/licenses/>. +# + +import optparse +import math +import socket +import struct + + +######################################################################## +# constants +######################################################################## +B250_FW_COMMS_UDP_PORT = 49152 + +B250_FW_COMMS_FLAGS_ACK = 1 +B250_FW_COMMS_FLAGS_ERROR = 2 +B250_FW_COMMS_FLAGS_POKE32 = 4 +B250_FW_COMMS_FLAGS_PEEK32 = 8 + +#UDP_CTRL_PORT = 49183 +UDP_MAX_XFER_BYTES = 1024 +UDP_TIMEOUT = 3 +#USRP2_FW_PROTO_VERSION = 11 #should be unused after r6 + +#REG_ARGS_FMT = '!LLLLLB15x' +#REG_IP_FMT = '!LLLL20x' +REG_PEEK_POKE_FMT = '!LLLL' + + +_seq = -1 +def seq(): +    global _seq +    _seq = _seq+1 +    return _seq + + +######################################################################## +# helper functions +######################################################################## + +def unpack_reg_peek_poke_fmt(s): +    return struct.unpack(REG_PEEK_POKE_FMT,s) #(flags, seq, addr, data) + +def pack_reg_peek_poke_fmt(flags, seq, addr, data): +    return struct.pack(REG_PEEK_POKE_FMT, flags, seq, addr, data); + +######################################################################## +# Burner class, holds a socket and send/recv routines +######################################################################## +class ctrl_socket(object): +    def __init__(self, addr): +        self._sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) +        self._sock.settimeout(UDP_TIMEOUT) +        self._sock.connect((addr, B250_FW_COMMS_UDP_PORT)) +        self.set_callbacks(lambda *a: None, lambda *a: None) +        #self.init_update() #check that the device is there + +    def set_callbacks(self, progress_cb, status_cb): +        self._progress_cb = progress_cb +        self._status_cb = status_cb + +    def send_and_recv(self, pkt): +        self._sock.send(pkt) +        return self._sock.recv(UDP_MAX_XFER_BYTES) + +    def read_router_stats(self): +        print +        print("            "), +        ports = ['        eth0','        eth1','      radio0','      radio1','    compute0','    compute1','    compute2','        pcie'] +        for in_prt in ports: +            print("%s" % in_prt), +        print("   Egress Port") +        print("             "), +        for in_prt in range (0, 8): +            print("____________"), +        print +        for in_prt in range (0, 8): +            print("%s |" % ports[in_prt]), +            for out_prt in range (0, 8): +                out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_PEEK32|B250_FW_COMMS_FLAGS_ACK, seq(), 0xA000+256+((in_prt*8+out_prt)*4), 0) +                in_pkt = self.send_and_recv(out_pkt) +                (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) +                if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: +                    raise Exception("B250 peek returns error code") +                print("%10d  " % (data)), +            print +        print +        print("Ingress Port") +        print + + +    def peek(self,peek_addr): +        out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_PEEK32|B250_FW_COMMS_FLAGS_ACK, seq(), peek_addr, 0) +        in_pkt = self.send_and_recv(out_pkt) +        (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) +        if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: +            raise Exception("B250 peek of address %d returns error code" % (addr)) +        print("PEEK of address %d(0x%x) reads %d(0x%x)" % (addr,addr,data,data)) + +    def poke(self,poke_addr,poke_data): +        out_pkt = pack_reg_peek_poke_fmt(B250_FW_COMMS_FLAGS_POKE32|B250_FW_COMMS_FLAGS_ACK, seq(), poke_addr, poke_data) +        in_pkt = self.send_and_recv(out_pkt) +        (flags, rxseq, addr, data) = unpack_reg_peek_poke_fmt(in_pkt) +        if flags & B250_FW_COMMS_FLAGS_ERROR == B250_FW_COMMS_FLAGS_ERROR: +            raise Exception("B250 peek of address %d returns error code" % (addr)) +        print("POKE of address %d(0x%x) with %d(0x%x)" % (poke_addr,poke_addr,poke_data,poke_data)  ) + + +######################################################################## +# command line options +######################################################################## +def get_options(): +    parser = optparse.OptionParser() +    parser.add_option("--addr", type="string",                 help="USRP-N2XX device address",       default='') +    parser.add_option("--list", action="store_true",           help="list possible network devices", default=False) +    parser.add_option("--peek", type="int",                 help="Read from memory map",     default=None) +    parser.add_option("--poke", type="int",                 help="Write to memory map",     default=None) +    parser.add_option("--data", type="int",                 help="Data for poke",     default=None) +    parser.add_option("--stats", action="store_true",           help="Display SuperMIMO Network Stats", default=False) +    (options, args) = parser.parse_args() + +    return options + + +######################################################################## +# main +######################################################################## +if __name__=='__main__': +    options = get_options() + + +    if options.list: +        print('Possible network devices:') +        print('  ' + '\n  '.join(enumerate_devices())) +        exit() + +    if not options.addr: raise Exception('no address specified') + +    status = ctrl_socket(addr=options.addr) + +    if options.stats: +        status.read_router_stats() + + +    if options.peek is not None: +        addr = options.peek +        status.peek(addr) + +    if options.poke is not None and options.data is not None: +        addr = options.poke +        data = options.data +        status.poke(addr,data) diff --git a/firmware/usrp3/x300/x300_defs.h b/firmware/usrp3/x300/x300_defs.h new file mode 100644 index 000000000..65c5d5a23 --- /dev/null +++ b/firmware/usrp3/x300/x300_defs.h @@ -0,0 +1,75 @@ + +// Copyright 2014 Ettus Research LLC + +#ifndef INCLUDED_X300_DEFS_H +#define INCLUDED_X300_DEFS_H + +#define CPU_CLOCK 166666667 +#define MAIN_RAM_BASE 0x0000 +#define PKT_RAM0_BASE 0x8000 +#define XGE0_BASE 0xC000 +#define XGE1_BASE 0xD000 +#define BOOT_LDR_BASE 0xFC00 +#define UART0_BASE 0xfd00 +#define UART0_BAUD 115200 +#define UART1_BASE 0xf900 +#define UART1_BAUD 115200 +#define I2C0_BASE 0xfe00 +#define I2C1_BASE 0xff00 +#define I2C2_BASE 0xfc00 +#define SET0_BASE 0xa000 +#define RB0_BASE 0xa000 //same as set +#define SETXB_BASE 0xb000 + +#define ETH1G +//#define ETH10G  + +//eeprom map for mboard addrs +#define MBOARD_EEPROM_ADDR 0x50 + +// Setting Regs Memeory Map +static const int SR_LEDS       = 0; +static const int SR_SW_RST     = 1; +static const int SR_CLOCK_CTRL = 2; +static const int SR_XB_LOCAL   = 3; +static const int SR_SFPP_CTRL  = 4; +static const int SR_SPI        = 32; +static const int SR_ETHINT0    = 40; +static const int SR_ETHINT1    = 56; + +//led shifts for SR_LEDS +static const int LED_ACT1 = (1 << 5); +static const int LED_ACT2 = (1 << 4); +static const int LED_LINK1 = (1 << 3); +static const int LED_LINK2 = (1 << 2); +static const int LED_LINKSTAT = (1 << 1); +static const int LED_LINKACT = (1 << 0); + +// Readback Memory Map +static const int RB_COUNTER      = 0; +static const int RB_SPI_RDY      = 1; +static const int RB_SPI_DATA     = 2; +static const int RB_ETH_TYPE0    = 4; +static const int RB_ETH_TYPE1    = 5; +static const int RB_SFPP_STATUS0 = 8; +static const int RB_SFPP_STATUS1 = 9; + +// Bootloader Memory Map +static const int BL_ADDRESS     = 0; +static const int BL_DATA        = 1; + +#define SW_RST_PHY 0x01 +#define SW_RST_RADIO 0x02 +#define SW_RST_RADIO_PLL 0x04 + +//eth framer constants +#define ETH_FRAMER_SRC_MAC_HI 0 +#define ETH_FRAMER_SRC_MAC_LO 1 +#define ETH_FRAMER_SRC_IP_ADDR 2 +#define ETH_FRAMER_SRC_UDP_PORT 3 +#define ETH_FRAMER_DST_RAM_ADDR 4 +#define ETH_FRAMER_DST_IP_ADDR 5 +#define ETH_FRAMER_DST_UDP_MAC 6 +#define ETH_FRAMER_DST_MAC_LO 7 + +#endif /* INCLUDED_X300_DEFS_H */ diff --git a/firmware/usrp3/x300/x300_init.c b/firmware/usrp3/x300/x300_init.c new file mode 100644 index 000000000..66fb120f3 --- /dev/null +++ b/firmware/usrp3/x300/x300_init.c @@ -0,0 +1,168 @@ +#include "x300_init.h" +#include "x300_defs.h" +#include "ethernet.h" +#include "mdelay.h" +#include <wb_utils.h> +#include <wb_uart.h> +#include <wb_i2c.h> +#include <stdint.h> +#include <stdbool.h> +#include <printf.h> +#include <wb_pkt_iface64.h> +#include <u3_net_stack.h> +#include <link_state_route_proto.h> +#include <udp_uart.h> +#include "x300_fw_common.h" +#include <print_addrs.h> + +static wb_pkt_iface64_config_t pkt_config; + +struct x300_eeprom_map +{ +    //indentifying numbers +    unsigned char revision[2]; +    unsigned char product[2]; +    uint8_t _pad0[4]; + +    //all the mac addrs +    uint8_t mac_addr0[6]; +    uint8_t _pad1[2]; +    uint8_t mac_addr1[6]; +    uint8_t _pad2[2]; + +    //all the IP addrs +    uint32_t gateway; +    uint32_t subnet[4]; +    uint32_t ip_addr[4]; +    uint8_t _pad3[16]; +}; + +static struct x300_eeprom_map default_map = { +    .mac_addr0 = X300_DEFAULT_MAC_ADDR_0, +    .mac_addr1 = X300_DEFAULT_MAC_ADDR_1, +    .gateway = X300_DEFAULT_GATEWAY, +    .subnet = { +        X300_DEFAULT_NETMASK_ETH0_1G, +        X300_DEFAULT_NETMASK_ETH1_1G, +        X300_DEFAULT_NETMASK_ETH0_10G, +        X300_DEFAULT_NETMASK_ETH1_10G +    }, +    .ip_addr = { +        X300_DEFAULT_IP_ETH0_1G, +        X300_DEFAULT_IP_ETH1_1G, +        X300_DEFAULT_IP_ETH0_10G, +        X300_DEFAULT_IP_ETH1_10G +    }, +}; + +const void *pick_inited_field(const void *eeprom, const void *def, const size_t len) +{ +    bool all_ones = true; +    bool all_zeros = true; +    for (size_t i = 0; i < len; i++) +    { +        const uint8_t b = ((const uint8_t *)eeprom)[i]; +        if (b != 0x00) all_zeros = false; +        if (b != 0xff) all_ones = false; +    } +    if (all_zeros) return def; +    if (all_ones) return def; +    return eeprom; +} + +static void init_network(void) +{ +    pkt_config = wb_pkt_iface64_init(PKT_RAM0_BASE, 0x1ffc); +    printf("PKT RAM0 BASE 0x%x\n", (&pkt_config)->base); +    u3_net_stack_init(&pkt_config); + +    link_state_route_proto_init(); + +    //read everything from eeprom +    static const uint8_t eeprom_cmd[2] = {0, 0}; //the command is 16 bits of address offset +    struct x300_eeprom_map eeprom_map = default_map; +    wb_i2c_write(I2C1_BASE, MBOARD_EEPROM_ADDR, eeprom_cmd, 2); +    wb_i2c_read(I2C1_BASE, MBOARD_EEPROM_ADDR, (uint8_t *)(&eeprom_map), sizeof(eeprom_map)); + +    //determine interface number +    const size_t eth0no = wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))? 2 : 0; +    const size_t eth1no = wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))? 3 : 1; + +    //pick the address from eeprom or default +    const eth_mac_addr_t *my_mac0 = (const eth_mac_addr_t *)pick_inited_field(&eeprom_map.mac_addr0, &default_map.mac_addr0, 6); +    const eth_mac_addr_t *my_mac1 = (const eth_mac_addr_t *)pick_inited_field(&eeprom_map.mac_addr1, &default_map.mac_addr1, 6); +    const struct ip_addr *my_ip0 = (const struct ip_addr *)pick_inited_field(&eeprom_map.ip_addr[eth0no], &default_map.ip_addr[eth0no], 4); +    const struct ip_addr *subnet0 = (const struct ip_addr *)pick_inited_field(&eeprom_map.subnet[eth0no], &default_map.subnet[eth0no], 4); +    const struct ip_addr *my_ip1 = (const struct ip_addr *)pick_inited_field(&eeprom_map.ip_addr[eth1no], &default_map.ip_addr[eth1no], 4); +    const struct ip_addr *subnet1 = (const struct ip_addr *)pick_inited_field(&eeprom_map.subnet[eth1no], &default_map.subnet[eth1no], 4); + +    //init eth0 +    u3_net_stack_init_eth(0, my_mac0, my_ip0, subnet0); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 0), (my_mac0->addr[5] << 0) | (my_mac0->addr[4] << 8) | (my_mac0->addr[3] << 16) | (my_mac0->addr[2] << 24)); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 1), (my_mac0->addr[1] << 0) | (my_mac0->addr[0] << 8)); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 2), my_ip0->addr); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 4), 0/*nofwd*/); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT0 + 8 + 5), (ICMP_IRQ << 8) | 0); //no fwd: type, code + +    //init eth1 +    u3_net_stack_init_eth(1, my_mac1, my_ip1, subnet1); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 0), (my_mac1->addr[5] << 0) | (my_mac1->addr[4] << 8) | (my_mac1->addr[3] << 16) | (my_mac1->addr[2] << 24)); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 1), (my_mac1->addr[1] << 0) | (my_mac1->addr[0] << 8)); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 2), my_ip1->addr); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 4), 0/*nofwd*/); +    wb_poke32(SR_ADDR(SET0_BASE, SR_ETHINT1 + 8 + 5), (ICMP_IRQ << 8) | 0); //no fwd: type, code +} + +static void putc(void *p, char c) +{ +#ifdef X300_DEBUG_UART +    wb_uart_putc(UART1_BASE, c); +#endif +} + +void x300_init(void) +{ +    //first - uart +    wb_uart_init(UART0_BASE, CPU_CLOCK/UART0_BAUD); +    wb_uart_init(UART1_BASE, CPU_CLOCK/UART1_BAUD); +    init_printf(NULL,putc); +    //udp_uart_init(UART0_BASE, X300_GPSDO_UDP_PORT); + +    //now we can init the rest with prints +    printf("X300 ZPU Init Begin -- CPU CLOCK is %d MHz\n", CPU_CLOCK/1000000); + +    //i2c rate init +    wb_i2c_init(I2C0_BASE, CPU_CLOCK); +    wb_i2c_init(I2C1_BASE, CPU_CLOCK); +    wb_i2c_init(I2C2_BASE, CPU_CLOCK); + +    //hold phy in reset +    wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), SW_RST_PHY); + +    printf("DEBUG: eth0 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0))==1) ? 10 : 1); +    printf("DEBUG: eth1 is %2dG\n",(wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1))==1) ? 10 : 1); + +    //setup net stack and eth state machines +    init_network(); + +    //phy reset release +    wb_poke32(SR_ADDR(SET0_BASE, SR_SW_RST), 0); + +    // For eth interfaces, initialize the PHY's +    mdelay(100); +    if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE0)) == 1) { +        xge_ethernet_init(0); +    } +    if (wb_peek32(SR_ADDR(RB0_BASE, RB_ETH_TYPE1)) == 1) { +        xge_ethernet_init(1); +    } + +    //print network summary +    for (uint8_t e = 0; e < ethernet_ninterfaces(); e++) +    { +        printf("  MAC%u:     %s\n", (int)e, mac_addr_to_str(u3_net_stack_get_mac_addr(e))); +        printf("    IP%u:      %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_ip_addr(e))); +        printf("    SUBNET%u:  %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_subnet(e))); +        printf("    BCAST%u:   %s\n", (int)e, ip_addr_to_str(u3_net_stack_get_bcast(e))); +    } +} diff --git a/firmware/usrp3/x300/x300_init.h b/firmware/usrp3/x300/x300_init.h new file mode 100644 index 000000000..324033779 --- /dev/null +++ b/firmware/usrp3/x300/x300_init.h @@ -0,0 +1,18 @@ + +// Copyright 2012 Ettus Research LLC + +#ifndef INCLUDED_B250_INIT_H +#define INCLUDED_B250_INIT_H + +void x300_init(void); + +void x300_serial_loader_run1(void); + +typedef enum +  { +    DCO_156p25, +    DCO_125, +    DCO_10 +  } dco_freq_t; + +#endif /* INCLUDED_B250_INIT_H */ diff --git a/firmware/usrp3/x300/x300_main.c b/firmware/usrp3/x300/x300_main.c new file mode 100644 index 000000000..d865e1d09 --- /dev/null +++ b/firmware/usrp3/x300/x300_main.c @@ -0,0 +1,470 @@ +// Copyright 2013-2014 Ettus Research LLC + +#include "x300_init.h" +#include "x300_defs.h" +#include "x300_fw_common.h" +#include "xge_phy.h" +#include "ethernet.h" +#include "chinch.h" +#include "mdelay.h" + +#include <wb_utils.h> +#include <wb_uart.h> +#include <udp_uart.h> +#include <u3_net_stack.h> +#include <link_state_route_proto.h> +#include <printf.h> +#include <string.h> +#include <print_addrs.h> + +static uint32_t *shmem = (uint32_t *) X300_FW_SHMEM_BASE; + +/*********************************************************************** + * Setup call for udp framer + **********************************************************************/ +void program_udp_framer( +    const uint8_t ethno, +    const uint32_t sid, +    const struct ip_addr *dst_ip, +    const uint16_t dst_port, +    const uint16_t src_port +) +{ +    const eth_mac_addr_t *dst_mac = u3_net_stack_arp_cache_lookup(dst_ip); +    const size_t ethbase = (ethno == 0)? SR_ETHINT0 : SR_ETHINT1; +    const size_t vdest = (sid >> 16) & 0xff; +    printf("handle_udp_prog_framer sid %u vdest %u\n", sid, vdest); + +    //setup source framer +    const eth_mac_addr_t *src_mac = u3_net_stack_get_mac_addr(ethno); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_MAC_HI), +        (((uint32_t)src_mac->addr[0]) << 8) | (((uint32_t)src_mac->addr[1]) << 0)); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_MAC_LO), +        (((uint32_t)src_mac->addr[2]) << 24) | (((uint32_t)src_mac->addr[3]) << 16) | +        (((uint32_t)src_mac->addr[4]) << 8) | (((uint32_t)src_mac->addr[5]) << 0)); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_IP_ADDR), u3_net_stack_get_ip_addr(ethno)->addr); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_SRC_UDP_PORT), src_port); + +    //setup destination framer +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_RAM_ADDR), vdest); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_IP_ADDR), dst_ip->addr); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_UDP_MAC), +        (((uint32_t)dst_port) << 16) | +        (((uint32_t)dst_mac->addr[0]) << 8) | (((uint32_t)dst_mac->addr[1]) << 0)); +    wb_poke32(SR_ADDR(SET0_BASE, ethbase + ETH_FRAMER_DST_MAC_LO), +        (((uint32_t)dst_mac->addr[2]) << 24) | (((uint32_t)dst_mac->addr[3]) << 16) | +        (((uint32_t)dst_mac->addr[4]) << 8) | (((uint32_t)dst_mac->addr[5]) << 0)); +} + +/*********************************************************************** + * Handler for UDP framer program packets + **********************************************************************/ +void handle_udp_prog_framer( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t src_port, const uint16_t dst_port, +    const void *buff, const size_t num_bytes +) +{ +  if (buff == NULL) { +    /* We got here from ICMP_DUR undeliverable packet */ +    /* Future space for hooks to tear down streaming radios etc */ +  } +  else { +    const uint32_t sid = ((const uint32_t *)buff)[1]; +    program_udp_framer(ethno, sid, src, src_port, dst_port); +  } +} + +/*********************************************************************** + * Handler for peek and poke host packets + **********************************************************************/ +void handle_udp_fw_comms( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t src_port, const uint16_t dst_port, +    const void *buff, const size_t num_bytes +) +{ +    if (buff == NULL) { +     /* We got here from ICMP_DUR undeliverable packet */ +    /* Future space for hooks to tear down streaming radios etc */ +    } else { +        const x300_fw_comms_t *request = (const x300_fw_comms_t *)buff; +        x300_fw_comms_t reply; memcpy(&reply, buff, sizeof(reply)); + +        //check for error and set error flag +        if (num_bytes < sizeof(x300_fw_comms_t)) { +           reply.flags |= X300_FW_COMMS_FLAGS_ERROR; +        } +        //otherwise, run the actions set by the flags +        else { +            if (request->flags & X300_FW_COMMS_FLAGS_PEEK32) +            { +                if (request->addr & 0x00100000) { +                    chinch_peek32(request->addr & 0x000FFFFF, &reply.data); +                } else { +                    reply.data = wb_peek32(request->addr); +                } +            } +            if (request->flags & X300_FW_COMMS_FLAGS_POKE32) +            { +                if (request->addr & 0x00100000) { +                    chinch_poke32(request->addr & 0x000FFFFF, request->data); +                } else { +                    wb_poke32(request->addr, request->data); +                } +            } +        } + +        //send a reply if ack requested +        if (request->flags & X300_FW_COMMS_FLAGS_ACK) { +            u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, sizeof(reply)); +        } +    } +} + +/*********************************************************************** + * Handler for FPGA programming packets + **********************************************************************/ +void handle_udp_fpga_prog( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t src_port, const uint16_t dst_port, +    const void *buff, const size_t num_bytes +) +{ +    const x300_fpga_prog_t *request = (const x300_fpga_prog_t *)buff; +    x300_fpga_prog_flags_t reply = {0}; +    bool status = true; + +    if (buff == NULL) { +        return; +    } else if (num_bytes < offsetof(x300_fpga_prog_t, data)) { +        reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; +    } else { +        if (request->flags & X300_FPGA_PROG_FLAGS_INIT) { +            STATUS_MERGE(chinch_flash_init(), status); +        } else if (request->flags & X300_FPGA_PROG_FLAGS_CLEANUP) { +            chinch_flash_cleanup(); +        } else if (request->flags & X300_FPGA_PROG_CONFIGURE) { +            //This is a self-destructive operation and will most likely not return an ack. +            chinch_start_config(); +        } else if (request->flags & X300_FPGA_PROG_CONFIG_STATUS) { +            if (chinch_get_config_status() != CHINCH_CONFIG_COMPLETED) +                reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; +        } else { +            STATUS_MERGE(chinch_flash_select_sector(request->sector), status); +            if (request->flags & X300_FPGA_PROG_FLAGS_ERASE) +                STATUS_CHAIN(chinch_flash_erase_sector(), status); + +            uint32_t num_buff_writes = (request->size / CHINCH_FLASH_MAX_BUF_WRITES) + +                                       (request->size % CHINCH_FLASH_MAX_BUF_WRITES == 0 ? 0 : 1); +            uint32_t data_idx = 0; +            for (uint32_t buf_wr_i = 0; (buf_wr_i < num_buff_writes) && status; buf_wr_i++) { +                uint32_t wr_len = (request->size - data_idx) >= CHINCH_FLASH_MAX_BUF_WRITES ? +                    CHINCH_FLASH_MAX_BUF_WRITES : (request->size - data_idx); + +                STATUS_MERGE(chinch_flash_write_buf((request->index + data_idx)*2, +                    (uint16_t*)request->data+data_idx, wr_len), status); +                data_idx += wr_len; +            } + +            if (request->flags & X300_FPGA_PROG_FLAGS_VERIFY) { +                uint16_t data[request->size]; +                STATUS_MERGE(chinch_flash_read_buf(request->index*2, data, request->size), status); +                for (uint32_t i = 0; i < request->size; i++) { +                    status &= (data[i] == request->data[i]); +                } +            } +        } +    } +    if (!status) reply.flags |= X300_FPGA_PROG_FLAGS_ERROR; + +    //send a reply if ack requested +    if (request->flags & X300_FPGA_PROG_FLAGS_ACK) +    { +        u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, sizeof(reply)); +    } +} + +/*********************************************************************** + * Handler for MTU detection + **********************************************************************/ +void handle_udp_mtu_detect( +    const uint8_t ethno, +    const struct ip_addr *src, const struct ip_addr *dst, +    const uint16_t src_port, const uint16_t dst_port, +    const void *buff, const size_t num_bytes +) +{ +    const x300_mtu_t *request = (const x300_mtu_t *) buff; +    x300_mtu_t reply; + +    if (buff == NULL) { +        return; +    } else if (!(request->flags & X300_MTU_DETECT_ECHO_REQUEST)) { +        printf("DEBUG: MTU detect got unknown request\n"); +        reply.flags |= X300_MTU_DETECT_ERROR; +    } + +    reply.flags |= X300_MTU_DETECT_ECHO_REPLY; +    reply.size = num_bytes; + +    u3_net_stack_send_udp_pkt(ethno, src, dst_port, src_port, &reply, request->size); +} + + +/*********************************************************************** + * Deal with host claims and claim timeout + **********************************************************************/ +static void handle_claim(void) +{ +    static uint32_t last_time = 0; +    static size_t timeout = 0; + +    //time is 0 if the claim was forfeit +    if (shmem[X300_FW_SHMEM_CLAIM_TIME] == 0) +    { +        shmem[X300_FW_SHMEM_CLAIM_STATUS] = 0; +    } +    //if the time changes, reset timeout +    else if (last_time != shmem[X300_FW_SHMEM_CLAIM_TIME]) +    { +        shmem[X300_FW_SHMEM_CLAIM_STATUS] = 1; +        timeout = 0; +    } +    //otherwise increment for timeout +    else timeout++; + +    //always stash the last seen time +    last_time = shmem[X300_FW_SHMEM_CLAIM_TIME]; + +    //the claim has timed out after 2 seconds +    if (timeout > 2000) shmem[X300_FW_SHMEM_CLAIM_STATUS] = 0; +} + +/*********************************************************************** + * LED blinky logic and support utilities + **********************************************************************/ +static uint32_t get_xbar_total(const uint8_t port) +{ +    #define get_xbar_stat(in_prt, out_prt) \ +        wb_peek32(RB0_BASE+256+(((in_prt)*8+(out_prt))*4)) +    uint32_t total = 0; +    for (size_t i = 0; i < 8; i++) +    { +        total += get_xbar_stat(port, i); +    } +    for (size_t i = 0; i < 8; i++) +    { +        total += get_xbar_stat(i, port); +    } +    if (port < 2) //also netstack if applicable +    { +        total += u3_net_stack_get_stat_counts(port); +    } +    return total; +} + +static size_t popcntll(uint64_t num) +{ +    size_t total = 0; +    for (size_t i = 0; i < sizeof(num)*8; i++) +    { +        total += (num >> i) & 0x1; +    } +    return total; +} + +static void update_leds(void) +{ +    //update activity status for all ports +    uint64_t activity_shreg[8]; +    for (size_t i = 0; i < 8; i++) +    { +        static uint32_t last_total[8]; +        const uint32_t total = get_xbar_total(i); +        activity_shreg[i] <<= 1; +        activity_shreg[i] |= (total == last_total[i])? 0 : 1; +        last_total[i] = total; +    } + +    static uint32_t counter = 0; +    counter++; + +    const size_t cnt0 = popcntll(activity_shreg[0]); +    const size_t cnt1 = popcntll(activity_shreg[1]); +    const bool act0 = cnt0*8 > (counter % 64); +    const bool act1 = cnt1*8 > (counter % 64); +    const bool link0 = ethernet_get_link_up(0); +    const bool link1 = ethernet_get_link_up(1); +    const bool claimed = shmem[X300_FW_SHMEM_CLAIM_STATUS]; + +    wb_poke32(SET0_BASE + SR_LEDS*4, 0 +        | (link0? LED_LINK2 : 0) +        | (link1? LED_LINK1 : 0) +        | (act0? LED_ACT2 : 0) +        | (act1? LED_ACT1 : 0) +        | ((act0 || act1)? LED_LINKACT : 0) +        | (claimed? LED_LINKSTAT : 0) +    ); +} + +/*********************************************************************** + * Send periodic GARPs to keep network hardware informed + **********************************************************************/ +static void garp(void) +{ +    static size_t count = 0; +    if (count++ < 60000) return; //60 seconds +    count = 0; +    for (size_t e = 0; e < ethernet_ninterfaces(); e++) +    { +        if (!ethernet_get_link_up(e)) continue; +        u3_net_stack_send_arp_request(e, u3_net_stack_get_ip_addr(e)); +    } +} + +/*********************************************************************** + * UART handlers - interacts between UART and SHMEM + **********************************************************************/ +static void handle_uarts(void) +{ +    //pool allocations - always update shmem with location +    #define NUM_POOL_WORDS32 64 +    static uint32_t rxpool[NUM_POOL_WORDS32]; +    static uint32_t txpool[NUM_POOL_WORDS32]; +    shmem[X300_FW_SHMEM_UART_RX_ADDR] = (uint32_t)rxpool; +    shmem[X300_FW_SHMEM_UART_TX_ADDR] = (uint32_t)txpool; +    shmem[X300_FW_SHMEM_UART_WORDS32] = NUM_POOL_WORDS32; + +    //////////////////////////////////////////////////////////////////// +    // RX UART - get available characters and post to the shmem buffer +    //////////////////////////////////////////////////////////////////// +    static uint32_t rxoffset = 0; +    for (int rxch = wb_uart_getc(UART0_BASE); rxch != -1; rxch = wb_uart_getc(UART0_BASE)) +    { +        rxoffset++; +        const int shift = ((rxoffset%4) * 8); +        static uint32_t rxword32 = 0; +        if (shift == 0) rxword32 = 0; +        rxword32 |= ((uint32_t) rxch & 0xFF) << shift; +        rxpool[(rxoffset/4) % NUM_POOL_WORDS32] = rxword32; +        shmem[X300_FW_SHMEM_UART_RX_INDEX] = rxoffset; +    } + +    //////////////////////////////////////////////////////////////////// +    // TX UART - check for characters in the shmem buffer and send them +    //////////////////////////////////////////////////////////////////// +    static uint32_t txoffset = 0; +    while (txoffset != shmem[X300_FW_SHMEM_UART_TX_INDEX]) +    { +        const int shift = ((txoffset%4) * 8); +        const int txch = txpool[txoffset/4] >> shift; +        wb_uart_putc(UART0_BASE, txch); +        txoffset = (txoffset+1) % (NUM_POOL_WORDS32*4); +    } +} + +/*********************************************************************** + * update the link state periodic update + **********************************************************************/ +static void update_forwarding(const uint8_t e) +{ +    /* FIXME: This code is broken. +     * It blindly enables forwarding without regard to whether or not +     * packets can be forwarded.  If one of the Ethernet interfaces is not +     * connected, data backs up until the first interface becomes unresponsive. +     * +     * //update forwarding rules +     * uint32_t forward = 0; +     * if (!link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) +     * { +     *     forward |= (1 << 0); //forward bcast +     *     forward |= (1 << 1); //forward not mac dest +     * } +     * const uint32_t eth_base = (e == 0)? SR_ETHINT0 : SR_ETHINT1; +     * wb_poke32(SR_ADDR(SET0_BASE, eth_base + 8 + 4), forward); +     */ + +} + +static void handle_link_state(void) +{ +    //update shmem entries to keep it persistent +    size_t map_len = 0; +    shmem[X300_FW_SHMEM_ROUTE_MAP_ADDR] = (uint32_t)link_state_route_get_node_mapping(&map_len); +    shmem[X300_FW_SHMEM_ROUTE_MAP_LEN] = map_len; + +    static size_t count = 0; +    if (count--) return; +    count = 2000;  //repeat every ~2 seconds + +    link_state_route_proto_tick(); +    for (size_t e = 0; e < ethernet_ninterfaces(); e++) +    { +        if (ethernet_get_link_up(e)) +        { +            link_state_route_proto_update(e); +            link_state_route_proto_flood(e); +        } + +        //update forwarding if something changed +        bool before = link_state_route_proto_causes_cycle_cached(e, (e+1)%2); +        link_state_route_proto_update_cycle_cache(e); +        if (before != link_state_route_proto_causes_cycle_cached(e, (e+1)%2)) +            update_forwarding(e); +        /* +        printf("is there a cycle %s -> %s? %s\n", +            ip_addr_to_str(u3_net_stack_get_ip_addr(e)), +            ip_addr_to_str(u3_net_stack_get_ip_addr((e+1)%2)), +            link_state_route_proto_causes_cycle_cached(e, (e+1)%2)? "YES" : "no"); +        //*/ +    } +} + +/*********************************************************************** + * Main loop runs all the handlers + **********************************************************************/ +int main(void) +{ +    x300_init(); +    u3_net_stack_register_udp_handler(X300_FW_COMMS_UDP_PORT, &handle_udp_fw_comms); +    u3_net_stack_register_udp_handler(X300_VITA_UDP_PORT, &handle_udp_prog_framer); +    u3_net_stack_register_udp_handler(X300_FPGA_PROG_UDP_PORT, &handle_udp_fpga_prog); +    u3_net_stack_register_udp_handler(X300_MTU_DETECT_UDP_PORT, &handle_udp_mtu_detect); + +    uint32_t last_cronjob = 0; + +    while(true) +    { +        //jobs that happen once every ms +        const uint32_t ticks_now = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); +        const uint32_t ticks_passed = ticks_now - last_cronjob; +        static const uint32_t tick_delta = CPU_CLOCK/1000; +        if (ticks_passed > tick_delta) +        { +            handle_link_state(); //deal with router table update +            handle_claim(); //deal with the host claim register +            update_leds(); //run the link and activity leds +            garp(); //send periodic garps +            xge_poll_sfpp_status(0); // Every so often poll XGE Phy to look for SFP+ hotplug events. +            xge_poll_sfpp_status(1); // Every so often poll XGE Phy to look for SFP+ hotplug events. +            last_cronjob = wb_peek32(SR_ADDR(RB0_BASE, RB_COUNTER)); +        } + +        //run the network stack - poll and handle +        u3_net_stack_handle_one(); + +        //run the PCIe listener - poll and fwd to wishbone +        forward_pcie_user_xact_to_wb(); + +        //run the udp uart handler for incoming serial data +        handle_uarts(); //udp_uart_poll(); + +        //always reload the compat number into the shmem to keep it persistent +        shmem[X300_FW_SHMEM_COMPAT_NUM] = (X300_FW_COMPAT_MAJOR << 16) | X300_FW_COMPAT_MINOR; +    } +    return 0; +}  | 
