]> git.sur5r.net Git - freertos/commitdiff
Add lwIP V1.3 files.
authorrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 11 Aug 2008 14:49:32 +0000 (14:49 +0000)
committerrichardbarry <richardbarry@1d2547de-c912-0410-9cb9-b8ca96c0e9e2>
Mon, 11 Aug 2008 14:49:32 +0000 (14:49 +0000)
git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@447 1d2547de-c912-0410-9cb9-b8ca96c0e9e2

139 files changed:
Demo/Common/ethernet/lwIP_130/CHANGELOG [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/COPYING [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/README [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cc.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cpu.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/init.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/lib.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/perf.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/sys_arch.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/sys_arch.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/contrib.txt [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/rawapi.txt [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/savannah.txt [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/snmp_agent.txt [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/doc/sys_arch.txt [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/api_lib.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/api_msg.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/err.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/netbuf.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/netdb.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/netifapi.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/sockets.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/api/tcpip.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/dhcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/dns.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/init.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv6/README [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/mem.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/memp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/netif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/pbuf.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/raw.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/stats.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/sys.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/tcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/core/udp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/FILES [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/etharp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/loopif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/slipif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c [new file with mode: 0644]
Demo/Common/ethernet/lwIP_130/sys [new file with mode: 0644]

diff --git a/Demo/Common/ethernet/lwIP_130/CHANGELOG b/Demo/Common/ethernet/lwIP_130/CHANGELOG
new file mode 100644 (file)
index 0000000..bc0ca0e
--- /dev/null
@@ -0,0 +1,1881 @@
+FUTURE\r
+\r
+  * TODO: The lwIP source code makes some invalid assumptions on processor\r
+    word-length, storage sizes and alignment. See the mailing lists for\r
+    problems with exoteric (/DSP) architectures showing these problems.\r
+    We still have to fix some of these issues neatly.\r
+\r
+  * TODO: the PPP code is broken in a few ways. There are namespace\r
+    collisions on BSD systems and many assumptions on word-length\r
+    (sizeof(int)). In ppp.c an assumption is made on the availability of\r
+    a thread subsystem. Either PPP needs to be moved to contrib/ports/???\r
+    or rearranged to be more generic.\r
+\r
+HISTORY\r
+\r
+(CVS HEAD)\r
+\r
+  * [Enter new changes just after this line - do not remove this line]\r
+\r
+  ++ New features:\r
+\r
+\r
+  ++ Bugfixes:\r
+\r
+\r
+(STABLE-1.3.0)\r
+\r
+  ++ New features:\r
+\r
+  2008-03-10 Jonathan Larmour\r
+  * inet_chksum.c: Allow choice of one of the sample algorithms to be\r
+    made from lwipopts.h. Fix comment on how to override LWIP_CHKSUM.\r
+\r
+  2008-01-22 Frédéric Bernon\r
+  * tcp.c, tcp_in.c, tcp.h, opt.h: Rename LWIP_CALCULATE_EFF_SEND_MSS in \r
+    TCP_CALCULATE_EFF_SEND_MSS to have coherent TCP options names.\r
+\r
+  2008-01-14 Frédéric Bernon\r
+  * rawapi.txt, api_msg.c, tcp.c, tcp_in.c, tcp.h: changes for task #7675 "Enable\r
+    to refuse data on a TCP_EVENT_RECV call". Important, behavior changes for the\r
+    tcp_recv callback (see rawapi.txt).\r
+\r
+  2008-01-14 Frédéric Bernon, Marc Chaland\r
+  * ip.c: Integrate patch #6369" ip_input : checking before realloc".\r
+  \r
+  2008-01-12 Frédéric Bernon\r
+  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field\r
+    netconn::sem per netconn::op_completed like suggested for the task #7490\r
+    "Add return value to sys_mbox_post".\r
+\r
+  2008-01-12 Frédéric Bernon\r
+  * api_msg.c, opt.h: replace DEFAULT_RECVMBOX_SIZE per DEFAULT_TCP_RECVMBOX_SIZE,\r
+    DEFAULT_UDP_RECVMBOX_SIZE and DEFAULT_RAW_RECVMBOX_SIZE (to optimize queues\r
+    sizes), like suggested for the task #7490 "Add return value to sys_mbox_post".\r
+\r
+  2008-01-10 Frédéric Bernon\r
+  * tcpip.h, tcpip.c: add tcpip_callback_with_block function for the task #7490\r
+    "Add return value to sys_mbox_post". tcpip_callback is always defined as\r
+    "blocking" ("block" parameter = 1).\r
+\r
+  2008-01-10 Frédéric Bernon\r
+  * tcpip.h, tcpip.c, api.h, api_lib.c, api_msg.c, sockets.c: replace the field\r
+    netconn::mbox (sys_mbox_t) per netconn::sem (sys_sem_t) for the task #7490\r
+    "Add return value to sys_mbox_post".\r
+\r
+  2008-01-05 Frédéric Bernon\r
+  * sys_arch.txt, api.h, api_lib.c, api_msg.h, api_msg.c, tcpip.c, sys.h, opt.h:\r
+    Introduce changes for task #7490 "Add return value to sys_mbox_post" with some\r
+    modifications in the sys_mbox api: sys_mbox_new take a "size" parameters which\r
+    indicate the number of pointers query by the mailbox. There is three defines\r
+    in opt.h to indicate sizes for tcpip::mbox, netconn::recvmbox, and for the \r
+    netconn::acceptmbox. Port maintainers, you can decide to just add this new \r
+    parameter in your implementation, but to ignore it to keep the previous behavior.\r
+    The new sys_mbox_trypost function return a value to know if the mailbox is\r
+    full or if the message is posted. Take a look to sys_arch.txt for more details.\r
+    This new function is used in tcpip_input (so, can be called in an interrupt\r
+    context since the function is not blocking), and in recv_udp and recv_raw.\r
+\r
+  2008-01-04 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour\r
+  * rawapi.txt, api.h, api_lib.c, api_msg.h, api_msg.c, sockets.c, tcp.h, tcp.c,\r
+    tcp_in.c, init.c, opt.h: rename backlog options with TCP_ prefix, limit the\r
+    "backlog" parameter in an u8_t, 0 is interpreted as "smallest queue", add\r
+    documentation in the rawapi.txt file.\r
+\r
+  2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm)\r
+  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer\r
+\r
+  2007-12-31 Frédéric Bernon, Luca Ceresoli\r
+  * autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets\r
+    in autoip". The change in etharp_raw could be removed, since all calls to\r
+    etharp_raw use ethbroadcast for the "ethdst_addr" parameter. But it could be\r
+    wrong in the future.\r
+\r
+  2007-12-30 Frédéric Bernon, Tom Evans\r
+  * ip.c: Fix bug #21846 "LwIP doesn't appear to perform any IP Source Address\r
+    Filtering" reported by Tom Evans.\r
+\r
+  2007-12-21 Frédéric Bernon, Simon Goldschmidt, Jonathan Larmour\r
+  * tcp.h, opt.h, api.h, api_msg.h, tcp.c, tcp_in.c, api_lib.c, api_msg.c,\r
+    sockets.c, init.c: task #7252: Implement TCP listen backlog: Warning: raw API\r
+    applications have to call 'tcp_accepted(pcb)' in their accept callback to\r
+    keep accepting new connections.\r
+\r
+  2007-12-13 Frédéric Bernon\r
+  * api_msg.c, err.h, err.c, sockets.c, dns.c, dns.h: replace "enum dns_result"\r
+    by err_t type. Add a new err_t code "ERR_INPROGRESS".\r
+\r
+  2007-12-12 Frédéric Bernon\r
+  * dns.h, dns.c, opt.h: move DNS options to the "right" place. Most visibles\r
+    are the one which have ram usage.\r
+\r
+  2007-12-05 Frédéric Bernon\r
+  * netdb.c: add a LWIP_DNS_API_HOSTENT_STORAGE option to decide to use a static\r
+    set of variables (=0) or a local one (=1). In this last case, your port should\r
+    provide a function "struct hostent* sys_thread_hostent( struct hostent* h)"\r
+    which have to do a copy of "h" and return a pointer ont the "per-thread" copy.\r
+\r
+  2007-12-03 Simon Goldschmidt\r
+  * ip.c: ip_input: check if a packet is for inp first before checking all other\r
+    netifs on netif_list (speeds up packet receiving in most cases)\r
+\r
+  2007-11-30 Simon Goldschmidt\r
+  * udp.c, raw.c: task #7497: Sort lists (pcb, netif, ...) for faster access\r
+    UDP: move a (connected) pcb selected for input to the front of the list of\r
+    pcbs so that it is found faster next time. Same for RAW pcbs that have eaten\r
+    a packet.\r
+\r
+  2007-11-28 Simon Goldschmidt\r
+  * etharp.c, stats.c, stats.h, opt.h: Introduced ETHARP_STATS\r
+\r
+  2007-11-25 Simon Goldschmidt\r
+  * dhcp.c: dhcp_unfold_reply() uses pbuf_copy_partial instead of its own copy\r
+    algorithm.\r
+\r
+  2007-11-24 Simon Goldschmidt\r
+  * netdb.h, netdb.c, sockets.h/.c: Moved lwip_gethostbyname from sockets.c\r
+    to the new file netdb.c; included lwip_getaddrinfo.\r
+\r
+  2007-11-21 Simon Goldschmidt\r
+  * tcp.h, opt.h, tcp.c, tcp_in.c: implemented calculating the effective send-mss\r
+    based on the MTU of the netif used to send. Enabled by default. Disable by\r
+    setting LWIP_CALCULATE_EFF_SEND_MSS to 0. This fixes bug #21492.\r
+\r
+  2007-11-19 Frédéric Bernon\r
+  * api_msg.c, dns.h, dns.c: Implement DNS_DOES_NAME_CHECK option (check if name\r
+    received match the name query), implement DNS_USES_STATIC_BUF (the place where\r
+    copy dns payload to parse the response), return an error if there is no place\r
+    for a new query, and fix some minor problems.\r
+\r
+  2007-11-16 Simon Goldschmidt\r
+  * new files: ipv4/inet.c, ipv4/inet_chksum.c, ipv6/inet6.c\r
+    removed files: core/inet.c, core/inet6.c\r
+    Moved inet files into ipv4/ipv6 directory; splitted inet.c/inet.h into\r
+    inet and chksum part; changed includes in all lwIP files as appropriate\r
+\r
+  2007-11-16 Simon Goldschmidt\r
+  * api.h, api_msg.h, api_lib.c, api_msg.c, socket.h, socket.c: Added sequential\r
+    dns resolver function for netconn api (netconn_gethostbyname) and socket api\r
+    (gethostbyname/gethostbyname_r).\r
+\r
+  2007-11-15 Jim Pettinato, Frédéric Bernon\r
+  * opt.h, init.c, tcpip.c, dhcp.c, dns.h, dns.c: add DNS client for simple name\r
+    requests with RAW api interface. Initialization is done in lwip_init() with\r
+    build time options. DNS timer is added in tcpip_thread context. DHCP can set\r
+    DNS server ip addresses when options are received. You need to set LWIP_DNS=1\r
+    in your lwipopts.h file (LWIP_DNS=0 in opt.h). DNS_DEBUG can be set to get\r
+    some traces with LWIP_DEBUGF. Sanity check have been added. There is a "todo"\r
+    list with points to improve.\r
+\r
+  2007-11-06 Simon Goldschmidt\r
+  * opt.h, mib2.c: Patch #6215: added ifAdminStatus write support (if explicitly\r
+    enabled by defining SNMP_SAFE_REQUESTS to 0); added code to check link status\r
+    for ifOperStatus if LWIP_NETIF_LINK_CALLBACK is defined.\r
+\r
+  2007-11-06 Simon Goldschmidt\r
+  * api.h, api_msg.h and dependent files: Task #7410: Removed the need to include\r
+    core header files in api.h (ip/tcp/udp/raw.h) to hide the internal\r
+    implementation from netconn api applications.\r
+\r
+  2007-11-03 Frédéric Bernon\r
+  * api.h, api_lib.c, api_msg.c, sockets.c, opt.h: add SO_RCVBUF option for UDP &\r
+    RAW netconn. You need to set LWIP_SO_RCVBUF=1 in your lwipopts.h (it's disabled\r
+    by default). Netconn API users can use the netconn_recv_bufsize macro to access\r
+    it. This is a first release which have to be improve for TCP. Note it used the\r
+    netconn::recv_avail which need to be more "thread-safe" (note there is already\r
+    the problem for FIONREAD with lwip_ioctl/ioctlsocket).\r
+\r
+  2007-11-01 Frédéric Bernon, Marc Chaland\r
+  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, tcp.h, tcp_out.c:\r
+    Integrate "patch #6250 : MSG_MORE flag for send". MSG_MORE is used at socket api\r
+    layer, NETCONN_MORE at netconn api layer, and TCP_WRITE_FLAG_MORE at raw api\r
+    layer. This option enable to delayed TCP PUSH flag on multiple "write" calls.\r
+    Note that previous "copy" parameter for "write" APIs is now called "apiflags".\r
+\r
+  2007-10-24 Frédéric Bernon\r
+  * api.h, api_lib.c, api_msg.c: Add macro API_EVENT in the same spirit than \r
+    TCP_EVENT_xxx macros to get a code more readable. It could also help to remove\r
+    some code (like we have talk in "patch #5919 : Create compile switch to remove\r
+    select code"), but it could be done later.\r
+\r
+  2007-10-08 Simon Goldschmidt\r
+  * many files: Changed initialization: many init functions are not needed any\r
+    more since we now rely on the compiler initializing global and static\r
+    variables to zero!\r
+\r
+  2007-10-06 Simon Goldschmidt\r
+  * ip_frag.c, memp.c, mib2.c, ip_frag.h, memp_std.h, opt.h: Changed IP_REASSEMBLY\r
+    to enqueue the received pbufs so that multiple packets can be reassembled\r
+    simultaneously and no static reassembly buffer is needed.\r
+\r
+  2007-10-05 Simon Goldschmidt\r
+  * tcpip.c, etharp.h, etharp.c: moved ethernet_input from tcpip.c to etharp.c so\r
+    all netifs (or ports) can use it.\r
+\r
+  2007-10-05 Frédéric Bernon\r
+  * netifapi.h, netifapi.c: add function netifapi_netif_set_default. Change the \r
+    common function to reduce a little bit the footprint (for all functions using\r
+    only the "netif" parameter).\r
+\r
+  2007-10-03 Frédéric Bernon\r
+  * netifapi.h, netifapi.c: add functions netifapi_netif_set_up, netifapi_netif_set_down,\r
+    netifapi_autoip_start and netifapi_autoip_stop. Use a common function to reduce\r
+    a little bit the footprint (for all functions using only the "netif" parameter).\r
+\r
+  2007-09-15 Frédéric Bernon\r
+  * udp.h, udp.c, sockets.c: Changes for "#20503 IGMP Improvement". Add IP_MULTICAST_IF\r
+    option in socket API, and a new field "multicast_ip" in "struct udp_pcb" (for\r
+    netconn and raw API users), only if LWIP_IGMP=1. Add getsockopt processing for\r
+    IP_MULTICAST_TTL and IP_MULTICAST_IF.\r
+\r
+  2007-09-10 Frédéric Bernon\r
+  * snmp.h, mib2.c: enable to remove SNMP timer (which consumne several cycles\r
+    even when it's not necessary). snmp_agent.txt tell to call snmp_inc_sysuptime()\r
+    each 10ms (but, it's intrusive if you use sys_timeout feature). Now, you can\r
+    decide to call snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but\r
+    call to a lower frequency). Or, you can decide to not call snmp_inc_sysuptime()\r
+    or snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.\r
+    This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside\r
+    snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only\r
+    when it's queried (any direct call to "sysuptime" is changed by a call to \r
+    snmp_get_sysuptime).\r
+\r
+  2007-09-09 Frédéric Bernon, Bill Florac\r
+  * igmp.h, igmp.c, netif.h, netif.c, ip.c: To enable to have interfaces with IGMP,\r
+    and others without it, there is a new NETIF_FLAG_IGMP flag to set in netif->flags\r
+    if you want IGMP on an interface. igmp_stop() is now called inside netif_remove().\r
+    igmp_report_groups() is now called inside netif_set_link_up() (need to have\r
+    LWIP_NETIF_LINK_CALLBACK=1) to resend reports once the link is up (avoid to wait\r
+    the next query message to receive the matching multicast streams).\r
+\r
+  2007-09-08 Frédéric Bernon\r
+  * sockets.c, ip.h, api.h, tcp.h: declare a "struct ip_pcb" which only contains\r
+    IP_PCB. Add in the netconn's "pcb" union a "struct ip_pcb *ip;" (no size change).\r
+    Use this new field to access to common pcb fields (ttl, tos, so_options, etc...).\r
+    Enable to access to these fields with LWIP_TCP=0.\r
+\r
+  2007-09-05 Frédéric Bernon\r
+  * udp.c, ipv4/icmp.c, ipv4/ip.c, ipv6/icmp.c, ipv6/ip6.c, ipv4/icmp.h,\r
+    ipv6/icmp.h, opt.h: Integrate "task #7272 : LWIP_ICMP option". The new option\r
+    LWIP_ICMP enable/disable ICMP module inside the IP stack (enable per default).\r
+    Be careful, disabling ICMP make your product non-compliant to RFC1122, but\r
+    help to reduce footprint, and to reduce "visibility" on the Internet.\r
+\r
+  2007-09-05 Frédéric Bernon, Bill Florac\r
+  * opt.h, sys.h, tcpip.c, slipif.c, ppp.c, sys_arch.txt: Change parameters list\r
+    for sys_thread_new (see "task #7252 : Create sys_thread_new_ex()"). Two new\r
+    parameters have to be provided: a task name, and a task stack size. For this\r
+    one, since it's platform dependant, you could define the best one for you in\r
+    your lwipopts.h. For port maintainers, you can just add these new parameters\r
+    in your sys_arch.c file, and but it's not mandatory, use them in your OS\r
+    specific functions.\r
+\r
+  2007-09-05 Frédéric Bernon\r
+  * inet.c, autoip.c, msg_in.c, msg_out.c, init.c: Move some build time checkings\r
+    inside init.c for task #7142 "Sanity check user-configurable values".\r
+\r
+  2007-09-04 Frédéric Bernon, Bill Florac\r
+  * igmp.h, igmp.c, memp_std.h, memp.c, init.c, opt.h: Replace mem_malloc call by\r
+    memp_malloc, and use a new MEMP_NUM_IGMP_GROUP option (see opt.h to define the\r
+    value). It will avoid potential fragmentation problems, use a counter to know\r
+    how many times a group is used on an netif, and free it when all applications\r
+    leave it. MEMP_NUM_IGMP_GROUP got 8 as default value (and init.c got a sanity\r
+    check if LWIP_IGMP!=0).\r
+\r
+  2007-09-03 Frédéric Bernon\r
+  * igmp.h, igmp.c, sockets.c, api_msg.c: Changes for "#20503 IGMP Improvement".\r
+    Initialize igmp_mac_filter to NULL in netif_add (this field should be set in\r
+    the netif's "init" function). Use the "imr_interface" field (for socket layer)\r
+    and/or the "interface" field (for netconn layer), for join/leave operations.\r
+    The igmp_join/leavegroup first parameter change from a netif to an ipaddr.\r
+    This field could be a netif's ipaddr, or "any" (same meaning than ip_addr_isany).\r
+\r
+  2007-08-30 Frédéric Bernon\r
+  * Add netbuf.h, netbuf.c, Change api.h, api_lib.c: #7249 "Split netbuf functions\r
+    from api/api_lib". Now netbuf API is independant of netconn, and can be used\r
+    with other API (application based on raw API, or future "socket2" API). Ports\r
+    maintainers just have to add src/api/netbuf.c in their makefile/projects.\r
+\r
+  2007-08-30 Frédéric Bernon, Jonathan Larmour\r
+  * init.c: Add first version of lwip_sanity_check for task #7142 "Sanity check\r
+    user-configurable values".\r
+\r
+  2007-08-29 Frédéric Bernon\r
+  * igmp.h, igmp.c, tcpip.c, init.c, netif.c: change igmp_init and add igmp_start.\r
+    igmp_start is call inside netif_add. Now, igmp initialization is in the same\r
+    spirit than the others modules. Modify some IGMP debug traces.\r
+\r
+  2007-08-29 Frédéric Bernon\r
+  * Add init.h, init.c, Change opt.h, tcpip.c: Task  #7213 "Add a lwip_init function"\r
+    Add lwip_init function to regroup all modules initializations, and to provide\r
+    a place to add code for task #7142 "Sanity check user-configurable values".\r
+    Ports maintainers should remove direct initializations calls from their code,\r
+    and add init.c in their makefiles. Note that lwip_init() function is called\r
+    inside tcpip_init, but can also be used by raw api users since all calls are\r
+    disabled when matching options are disabled. Also note that their is new options\r
+    in opt.h, you should configure in your lwipopts.h (they are enabled per default).\r
+\r
+  2007-08-26 Marc Boucher\r
+  * api_msg.c: do_close_internal(): Reset the callbacks and arg (conn) to NULL\r
+    since they can under certain circumstances be called with an invalid conn\r
+    pointer after the connection has been closed (and conn has been freed). \r
+\r
+  2007-08-25 Frédéric Bernon (Artem Migaev's Patch)\r
+  * netif.h, netif.c: Integrate "patch #6163 : Function to check if link layer is up".\r
+    Add a netif_is_link_up() function if LWIP_NETIF_LINK_CALLBACK option is set.\r
+\r
+  2007-08-22 Frédéric Bernon\r
+  * netif.h, netif.c, opt.h: Rename LWIP_NETIF_CALLBACK in LWIP_NETIF_STATUS_CALLBACK\r
+    to be coherent with new LWIP_NETIF_LINK_CALLBACK option before next release.\r
+\r
+  2007-08-22 Frédéric Bernon\r
+  * tcpip.h, tcpip.c, ethernetif.c, opt.h: remove options ETHARP_TCPIP_INPUT &\r
+    ETHARP_TCPIP_ETHINPUT, now, only "ethinput" code is supported, even if the \r
+    name is tcpip_input (we keep the name of 1.2.0 function).\r
+\r
+  2007-08-17 Jared Grubb\r
+  * memp_std.h, memp.h, memp.c, mem.c, stats.c: (Task #7136) Centralize mempool \r
+    settings into new memp_std.h and optional user file lwippools.h. This adds\r
+    more dynamic mempools, and allows the user to create an arbitrary number of\r
+    mempools for mem_malloc.\r
+\r
+  2007-08-16 Marc Boucher\r
+  * api_msg.c: Initialize newconn->state to NETCONN_NONE in accept_function;\r
+    otherwise it was left to NETCONN_CLOSE and sent_tcp() could prematurely\r
+    close the connection.\r
+\r
+  2007-08-16 Marc Boucher\r
+  * sockets.c: lwip_accept(): check netconn_peer() error return.\r
+\r
+  2007-08-16 Marc Boucher\r
+  * mem.c, mem.h: Added mem_calloc().\r
+\r
+  2007-08-16 Marc Boucher\r
+  * tcpip.c, tcpip.h memp.c, memp.h: Added distinct memp (MEMP_TCPIP_MSG_INPKT)\r
+    for input packets to prevent floods from consuming all of MEMP_TCPIP_MSG\r
+    and starving other message types.\r
+    Renamed MEMP_TCPIP_MSG to MEMP_TCPIP_MSG_API\r
+\r
+  2007-08-16 Marc Boucher\r
+  * pbuf.c, pbuf.h, etharp.c, tcp_in.c, sockets.c: Split pbuf flags in pbuf\r
+    type and flgs (later renamed to flags).\r
+    Use enum pbuf_flag as pbuf_type.  Renumber PBUF_FLAG_*.\r
+    Improved lwip_recvfrom().  TCP push now propagated.\r
+\r
+  2007-08-16 Marc Boucher\r
+  * ethernetif.c, contrib/ports/various: ethbroadcast now a shared global\r
+    provided by etharp.\r
+\r
+  2007-08-16 Marc Boucher\r
+  * ppp_oe.c ppp_oe.h, auth.c chap.c fsm.c lcp.c ppp.c ppp.h,\r
+    etharp.c ethernetif.c, etharp.h, opt.h tcpip.h, tcpip.c:\r
+    Added PPPoE support and various PPP improvements.\r
+\r
+  2007-07-25 Simon Goldschmidt\r
+  * api_lib.c, ip_frag.c, pbuf.c, api.h, pbuf.h: Introduced pbuf_copy_partial,\r
+    making netbuf_copy_partial use this function.\r
+\r
+  2007-07-25 Simon Goldschmidt\r
+  * tcp_in.c: Fix bug #20506: Slow start / initial congestion window starts with\r
+    2 * mss (instead of 1 * mss previously) to comply with some newer RFCs and\r
+    other stacks.\r
+\r
+  2007-07-13 Jared Grubb (integrated by Frédéric Bernon)\r
+  * opt.h, netif.h, netif.c, ethernetif.c: Add new configuration option to add\r
+    a link callback in the netif struct, and functions to handle it. Be carefull\r
+    for port maintainers to add the NETIF_FLAG_LINK_UP flag (like in ethernetif.c)\r
+    if you want to be sure to be compatible with future changes...\r
+\r
+  2007-06-30 Frédéric Bernon\r
+  * sockets.h, sockets.c: Implement MSG_PEEK flag for recv/recvfrom functions.\r
+\r
+  2007-06-21 Simon Goldschmidt\r
+  * etharp.h, etharp.c: Combined etharp_request with etharp_raw for both\r
+    LWIP_AUTOIP =0 and =1 to remove redundant code.\r
+\r
+  2007-06-21 Simon Goldschmidt\r
+  * mem.c, memp.c, mem.h, memp.h, opt.h: task #6863: Introduced the option\r
+    MEM_USE_POOLS to use 4 pools with different sized elements instead of a\r
+    heap. This both prevents memory fragmentation and gives a higher speed\r
+    at the cost of more memory consumption. Turned off by default.\r
+\r
+  2007-06-21 Simon Goldschmidt\r
+  * api_lib.c, api_msg.c, api.h, api_msg.h: Converted the length argument of\r
+    netconn_write (and therefore also api_msg_msg.msg.w.len) from u16_t into\r
+    int to be able to send a bigger buffer than 64K with one time (mainly\r
+    used from lwip_send).\r
+\r
+  2007-06-21 Simon Goldschmidt\r
+  * tcp.h, api_msg.c: Moved the nagle algorithm from netconn_write/do_write\r
+    into a define (tcp_output_nagle) in tcp.h to provide it to raw api users, too.\r
+\r
+  2007-06-21 Simon Goldschmidt\r
+  * api.h, api_lib.c, api_msg.c: Fixed bug #20021: Moved sendbuf-processing in\r
+    netconn_write from api_lib.c to api_msg.c to also prevent multiple context-\r
+    changes on low memory or empty send-buffer.\r
+\r
+  2007-06-18 Simon Goldschmidt\r
+  * etharp.c, etharp.h: Changed etharp to use a defined hardware address length\r
+    of 6 to avoid loading netif->hwaddr_len every time (since this file is only\r
+    used for ethernet and struct eth_addr already had a defined length of 6).\r
+\r
+  2007-06-17 Simon Goldschmidt\r
+  * sockets.c, sockets.h: Implemented socket options SO_NO_CHECK for UDP sockets\r
+    to disable UDP checksum generation on transmit.\r
+\r
+  2007-06-13 Frédéric Bernon, Simon Goldschmidt\r
+  * debug.h, api_msg.c: change LWIP_ERROR to use it to check errors like invalid\r
+    pointers or parameters, and let the possibility to redefined it in cc.h. Use\r
+    this macro to check "conn" parameter in api_msg.c functions.\r
+\r
+  2007-06-11 Simon Goldschmidt\r
+  * sockets.c, sockets.h: Added UDP lite support for sockets\r
+\r
+  2007-06-10 Simon Goldschmidt\r
+  * udp.h, opt.h, api_msg.c, ip.c, udp.c: Included switch LWIP_UDPLITE (enabled\r
+    by default) to switch off UDP-Lite support if not needed (reduces udp.c code\r
+    size)\r
+\r
+  2007-06-09 Dominik Spies (integrated by Frédéric Bernon)\r
+  * autoip.h, autoip.c, dhcp.h, dhcp.c, netif.h, netif.c, etharp.h, etharp.c, opt.h:\r
+    AutoIP implementation available for IPv4, with new options LWIP_AUTOIP and\r
+    LWIP_DHCP_AUTOIP_COOP if you want to cooperate with DHCP. Some tips to adapt\r
+    (see TODO mark in the source code).\r
+\r
+  2007-06-09 Simon Goldschmidt\r
+  * etharp.h, etharp.c, ethernetif.c: Modified order of parameters for\r
+    etharp_output() to match netif->output so etharp_output() can be used\r
+    directly as netif->output to save one function call.\r
+\r
+  2007-06-08 Simon Goldschmidt\r
+  * netif.h, ethernetif.c, slipif.c, loopif.c: Added define\r
+    NETIF_INIT_SNMP(netif, type, speed) to initialize per-netif snmp variables,\r
+    added initialization of those to ethernetif, slipif and loopif.\r
+\r
+  2007-05-18 Simon Goldschmidt\r
+  * opt.h, ip_frag.c, ip_frag.h, ip.c: Added option IP_FRAG_USES_STATIC_BUF\r
+    (defaulting to off for now) that can be set to 0 to send fragmented\r
+    packets by passing PBUF_REFs down the stack.\r
+\r
+  2007-05-23 Frédéric Bernon\r
+  * api_lib.c: Implement SO_RCVTIMEO for accept and recv on TCP\r
+    connections, such present in patch #5959.\r
+\r
+  2007-05-23 Frédéric Bernon\r
+  * api.h, api_lib.c, api_msg.c, sockets.c: group the different NETCONN_UDPxxx\r
+    code in only one part...\r
+\r
+  2007-05-18 Simon Goldschmidt\r
+  * opt.h, memp.h, memp.c: Added option MEMP_OVERFLOW_CHECK to check for memp\r
+    elements to overflow. This is achieved by adding some bytes before and after\r
+    each pool element (increasing their size, of course), filling them with a\r
+    prominent value and checking them on freeing the element.\r
+    Set it to 2 to also check every element in every pool each time memp_malloc()\r
+    or memp_free() is called (slower but more helpful).\r
+\r
+  2007-05-10 Simon Goldschmidt\r
+  * opt.h, memp.h, memp.c, pbuf.c (see task #6831): use a new memp pool for\r
+    PBUF_POOL pbufs instead of the old pool implementation in pbuf.c to reduce\r
+    code size.\r
+\r
+  2007-05-11 Frédéric Bernon\r
+  * sockets.c, api_lib.c, api_msg.h, api_msg.c, netifapi.h, netifapi.c, tcpip.c:\r
+    Include a function pointer instead of a table index in the message to reduce\r
+    footprint. Disable some part of lwip_send and lwip_sendto if some options are\r
+    not set (LWIP_TCP, LWIP_UDP, LWIP_RAW).\r
+\r
+  2007-05-10 Simon Goldschmidt\r
+  * *.h (except netif/ppp/*.h): Included patch #5448: include '#ifdef __cplusplus\r
+    \ extern "C" {' in all header files. Now you can write your application using\r
+    the lwIP stack in C++ and simply #include the core files. Note I have left\r
+    out the netif/ppp/*h header files for now, since I don't know which files are\r
+    included by applications and which are for internal use only.\r
+\r
+  2007-05-09 Simon Goldschmidt\r
+  * opt.h, *.c/*.h: Included patch #5920: Create define to override C-library\r
+    memcpy. 2 Defines are created: MEMCPY() for normal memcpy, SMEMCPY() for\r
+    situations where some compilers might inline the copy and save a function\r
+    call. Also replaced all calls to memcpy() with calls to (S)MEMCPY().\r
+\r
+  2007-05-08 Simon Goldschmidt\r
+  * mem.h: If MEM_LIBC_MALLOC==1, allow the defines (e.g. mem_malloc() -> malloc())\r
+    to be overriden in case the C-library malloc implementation is not protected\r
+    against concurrent access.\r
+\r
+  2007-05-04 Simon Goldschmidt (Atte Kojo)\r
+  * etharp.c: Introduced fast one-entry-cache to speed up ARP lookup when sending\r
+    multiple packets to the same host.\r
+\r
+  2007-05-04 Frédéric Bernon, Jonathan Larmour\r
+  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fix bug #19162 "lwip_sento: a possible\r
+    to corrupt remote addr/port connection state". Reduce problems "not enought memory" with\r
+    netbuf (if we receive lot of datagrams). Improve lwip_sendto (only one exchange between\r
+    sockets api and api_msg which run in tcpip_thread context). Add netconn_sento function.\r
+    Warning, if you directly access to "fromaddr" & "fromport" field from netbuf struct,\r
+    these fields are now renamed "addr" & "port".\r
+\r
+  2007-04-11 Jonathan Larmour\r
+  * sys.h, api_lib.c: Provide new sys_mbox_tryfetch function. Require ports to provide new\r
+    sys_arch_mbox_tryfetch function to get a message if one is there, otherwise return\r
+    with SYS_MBOX_EMPTY. sys_arch_mbox_tryfetch can be implemented as a function-like macro\r
+    by the port in sys_arch.h if desired.\r
+\r
+  2007-04-06 Frédéric Bernon, Simon Goldschmidt\r
+  * opt.h, tcpip.h, tcpip.c, netifapi.h, netifapi.c: New configuration option LWIP_NETIF_API\r
+    allow to use thread-safe functions to add/remove netif in list, and to start/stop dhcp\r
+    clients, using new functions from netifapi.h. Disable as default (no port change to do).\r
+\r
+  2007-04-05 Frédéric Bernon\r
+  * sockets.c: remplace ENOBUFS errors on alloc_socket by ENFILE to be more BSD compliant.\r
+\r
+  2007-04-04 Simon Goldschmidt\r
+  * arch.h, api_msg.c, dhcp.c, msg_in.c, sockets.c: Introduced #define LWIP_UNUSED_ARG(x)\r
+    use this for and architecture-independent form to tell the compiler you intentionally\r
+    are not using this variable. Can be overriden in cc.h.\r
+\r
+  2007-03-28 Frédéric Bernon\r
+  * opt.h, netif.h, dhcp.h, dhcp.c: New configuration option LWIP_NETIF_HOSTNAME allow to\r
+    define a hostname in netif struct (this is just a pointer, so, you can use a hardcoded\r
+    string, point on one of your's ethernetif field, or alloc a string you will free yourself).\r
+    It will be used by DHCP to register a client hostname, but can also be use when you call\r
+    snmp_set_sysname.\r
+\r
+  2007-03-28 Frédéric Bernon\r
+  * netif.h, netif.c: A new NETIF_FLAG_ETHARP flag is defined in netif.h, to allow to \r
+    initialize a network interface's flag with. It tell this interface is an ethernet\r
+    device, and we can use ARP with it to do a "gratuitous ARP" (RFC 3220 "IP Mobility\r
+    Support for IPv4" section 4.6) when interface is "up" with netif_set_up().\r
+\r
+  2007-03-26 Frédéric Bernon, Jonathan Larmour\r
+  * opt.h, tcpip.c: New configuration option LWIP_ARP allow to disable ARP init at build\r
+    time if you only use PPP or SLIP. The default is enable. Note we don't have to call \r
+    etharp_init in your port's initilization sequence if you use tcpip.c, because this call\r
+    is done in tcpip_init function.\r
+\r
+  2007-03-22 Frédéric Bernon\r
+  * stats.h, stats.c, msg_in.c: Stats counters can be change to u32_t if necessary with the\r
+    new option LWIP_STATS_LARGE. If you need this option, define LWIP_STATS_LARGE to 1 in\r
+    your lwipopts.h. More, unused counters are not defined in the stats structs, and not \r
+    display by stats_display(). Note that some options (SYS_STATS and RAW_STATS) are defined\r
+    but never used. Fix msg_in.c with the correct #if test for a stat display.\r
+\r
+  2007-03-21 Kieran Mansley\r
+  * netif.c, netif.h: Apply patch#4197 with some changes (originator: rireland@hmgsl.com). \r
+    Provides callback on netif up/down state change.\r
+\r
+  2007-03-11 Frédéric Bernon, Mace Gael, Steve Reynolds\r
+  * sockets.h, sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c, igmp.h, igmp.c,\r
+    ip.c, netif.h, tcpip.c, opt.h:\r
+    New configuration option LWIP_IGMP to enable IGMP processing. Based on only one \r
+    filter per all network interfaces. Declare a new function in netif to enable to\r
+    control the MAC filter (to reduce lwIP traffic processing).\r
+\r
+  2007-03-11 Frédéric Bernon\r
+  * tcp.h, tcp.c, sockets.c, tcp_out.c, tcp_in.c, opt.h: Keepalive values can\r
+    be configured at run time with LWIP_TCP_KEEPALIVE, but don't change this\r
+    unless you know what you're doing (default are RFC1122 compliant). Note\r
+    that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set in seconds.\r
+\r
+  2007-03-08 Frédéric Bernon\r
+  * tcp.h: Keepalive values can be configured at compile time, but don't change\r
+    this unless you know what you're doing (default are RFC1122 compliant).\r
+\r
+  2007-03-08 Frédéric Bernon\r
+  * sockets.c, api.h, api_lib.c, tcpip.c, sys.h, sys.c, err.c, opt.h:\r
+    Implement LWIP_SO_RCVTIMEO configuration option to enable/disable SO_RCVTIMEO\r
+    on UDP sockets/netconn.\r
+\r
+  2007-03-08 Simon Goldschmidt\r
+  * snmp_msg.h, msg_in.c: SNMP UDP ports can be configured at compile time.\r
+\r
+  2007-03-06 Frédéric Bernon\r
+  * api.h, api_lib.c, sockets.h, sockets.c, tcpip.c, sys.h, sys.c, err.h: \r
+    Implement SO_RCVTIMEO on UDP sockets/netconn.\r
+\r
+  2007-02-28 Kieran Mansley (based on patch from Simon Goldschmidt)\r
+  * api_lib.c, tcpip.c, memp.c, memp.h: make API msg structs allocated\r
+    on the stack and remove the API msg type from memp\r
+\r
+  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt)\r
+  * sockets.h, sockets.c: Move socket initialization to new\r
+    lwip_socket_init() function.\r
+    NOTE: this changes the API with ports. Ports will have to be\r
+    updated to call lwip_socket_init() now.\r
+\r
+  2007-02-26 Jonathan Larmour (based on patch from Simon Goldschmidt)\r
+  * api_lib.c: Use memcpy in netbuf_copy_partial.\r
+\r
+\r
+  ++ Bug fixes:\r
+\r
+  2008-03-17 Frédéric Bernon, Ed Kerekes\r
+  * igmp.h, igmp.c: Fix bug #22613 "IGMP iphdr problem" (could have\r
+    some problems to fill the IP header on some targets, use now the\r
+    ip.h macros to do it).\r
+\r
+  2008-03-13 Frédéric Bernon\r
+  * sockets.c: Fix bug #22435 "lwip_recvfrom with TCP break;". Using\r
+    (lwip_)recvfrom with valid "from" and "fromlen" parameters, on a\r
+    TCP connection caused a crash. Note that using (lwip_)recvfrom\r
+    like this is a bit slow and that using (lwip)getpeername is the\r
+    good lwip way to do it (so, using recv is faster on tcp sockets).\r
+\r
+  2008-03-12 Frédéric Bernon, Jonathan Larmour\r
+  * api_msg.c, contrib/apps/ping.c: Fix bug #22530 "api_msg.c's\r
+    recv_raw() does not consume data", and the ping sample (with\r
+    LWIP_SOCKET=1, the code did the wrong supposition that lwip_recvfrom\r
+    returned the IP payload, without the IP header).\r
+\r
+  2008-03-04 Jonathan Larmour\r
+  * mem.c, stats.c, mem.h: apply patch #6414 to avoid compiler errors\r
+  and/or warnings on some systems where mem_size_t and size_t differ.\r
+  * pbuf.c, ppp.c: Fix warnings on some systems with mem_malloc.\r
+\r
+  2008-03-04 Kieran Mansley (contributions by others) \r
+  * Numerous small compiler error/warning fixes from contributions to\r
+    mailing list after 1.3.0 release candidate made.\r
+\r
+  2008-01-25 Cui hengbin (integrated by Frédéric Bernon)\r
+  * dns.c: Fix bug #22108 "DNS problem" caused by unaligned structures.\r
+\r
+  2008-01-15 Kieran Mansley\r
+  * tcp_out.c: BUG20511.  Modify persist timer to start when we are\r
+    prevented from sending by a small send window, not just a zero\r
+    send window.\r
+\r
+  2008-01-09 Jonathan Larmour\r
+  * opt.h, ip.c: Rename IP_OPTIONS define to IP_OPTIONS_ALLOWED to avoid\r
+    conflict with Linux system headers.\r
+\r
+  2008-01-06 Jonathan Larmour\r
+  * dhcp.c: fix bug #19927: "DHCP NACK problem" by clearing any existing set IP\r
+    address entirely on receiving a DHCPNAK, and restarting discovery.\r
+\r
+  2007-12-21 Simon Goldschmidt\r
+  * sys.h, api_lib.c, api_msg.c, sockets.c: fix bug #21698: "netconn->recv_avail\r
+    is not protected" by using new macros for interlocked access to modify/test\r
+    netconn->recv_avail.\r
+\r
+  2007-12-20 Kieran Mansley (based on patch from Oleg Tyshev)\r
+  * tcp_in.c: fix bug# 21535 (nrtx not reset correctly in SYN_SENT state)\r
+\r
+  2007-12-20 Kieran Mansley (based on patch from Per-Henrik Lundbolm)\r
+  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: fix bug #20199 (better handling\r
+    of silly window avoidance and prevent lwIP from shrinking the window)\r
+\r
+  2007-12-04 Simon Goldschmidt\r
+  * tcp.c, tcp_in.c: fix bug #21699 (segment leak in ooseq processing when last\r
+    data packet was lost): add assert that all segment lists are empty in\r
+    tcp_pcb_remove before setting pcb to CLOSED state; don't directly set CLOSED\r
+    state from LAST_ACK in tcp_process\r
+\r
+  2007-12-02 Simon Goldschmidt\r
+  * sockets.h: fix bug #21654: exclude definition of struct timeval from #ifndef FD_SET\r
+    If including <sys/time.h> for system-struct timeval, LWIP_TIMEVAL_PRIVATE now\r
+    has to be set to 0 in lwipopts.h\r
+\r
+  2007-12-02 Simon Goldschmidt\r
+  * api_msg.c, api_lib.c: fix bug #21656 (recvmbox problem in netconn API): always\r
+    allocate a recvmbox in netconn_new_with_proto_and_callback. For a tcp-listen\r
+    netconn, this recvmbox is later freed and a new mbox is allocated for acceptmbox.\r
+    This is a fix for thread-safety and allocates all items needed for a netconn\r
+    when the netconn is created.\r
+\r
+  2007-11-30 Simon Goldschmidt\r
+  * udp.c: first attempt to fix bug #21655 (DHCP doesn't work reliably with multiple\r
+    netifs): if LWIP_DHCP is enabled, UDP packets to DHCP_CLIENT_PORT are passed\r
+    to netif->dhcp->pcb only (if that exists) and not to any other pcb for the same\r
+    port (only solution to let UDP pcbs 'bind' to a netif instead of an IP address)\r
+\r
+  2007-11-27 Simon Goldschmidt\r
+  * ip.c: fixed bug #21643 (udp_send/raw_send don't fail if netif is down) by\r
+    letting ip_route only use netifs that are up.\r
+\r
+  2007-11-27 Simon Goldschmidt\r
+  * err.h, api_lib.c, api_msg.c, sockets.c: Changed error handling: ERR_MEM, ERR_BUF\r
+    and ERR_RTE are seen as non-fatal, all other errors are fatal. netconns and\r
+    sockets block most operations once they have seen a fatal error.\r
+\r
+  2007-11-27 Simon Goldschmidt\r
+  * udp.h, udp.c, dhcp.c: Implemented new function udp_sendto_if which takes the\r
+    netif to send as an argument (to be able to send on netifs that are down).\r
+\r
+  2007-11-26 Simon Goldschmidt\r
+  * tcp_in.c: Fixed bug #21582: pcb->acked accounting can be wrong when ACKs\r
+    arrive out-of-order\r
+\r
+  2007-11-21 Simon Goldschmidt\r
+  * tcp.h, tcp_out.c, api_msg.c: Fixed bug #20287: tcp_output_nagle sends too early\r
+    Fixed the nagle algorithm; nagle now also works for all raw API applications\r
+    and has to be explicitly disabled with 'tcp_pcb->flags |= TF_NODELAY'\r
+\r
+  2007-11-12 Frédéric Bernon\r
+  * sockets.c, api.h, api_lib.c, api_msg.h, api_msg.c: Fixed bug #20900. Now, most\r
+    of the netconn_peer and netconn_addr processing is done inside tcpip_thread\r
+    context in do_getaddr.\r
+\r
+  2007-11-10 Simon Goldschmidt\r
+  * etharp.c: Fixed bug: assert fired when MEMP_ARP_QUEUE was empty (which can\r
+    happen any time). Now the packet simply isn't enqueued when out of memory.\r
+\r
+  2007-11-01 Simon Goldschmidt\r
+  * tcp.c, tcp_in.c: Fixed bug #21494: The send mss (pcb->mss) is set to 536 (or\r
+    TCP_MSS if that is smaller) as long as no MSS option is received from the\r
+    remote host.\r
+\r
+  2007-11-01 Simon Goldschmidt\r
+  * tcp.h, tcp.c, tcp_in.c: Fixed bug #21491: The MSS option sent (with SYN)\r
+    is now based on TCP_MSS instead of pcb->mss (on passive open now effectively\r
+    sending our configured TCP_MSS instead of the one received).\r
+\r
+  2007-11-01 Simon Goldschmidt\r
+  * tcp_in.c: Fixed bug #21181: On active open, the initial congestion window was\r
+    calculated based on the configured TCP_MSS, not on the MSS option received\r
+    with SYN+ACK.\r
+\r
+  2007-10-09 Simon Goldschmidt\r
+  * udp.c, inet.c, inet.h: Fixed UDPLite: send: Checksum was always generated too\r
+    short and also was generated wrong if checksum coverage != tot_len;\r
+    receive: checksum was calculated wrong if checksum coverage != tot_len\r
+\r
+  2007-10-08 Simon Goldschmidt\r
+  * mem.c: lfree was not updated in mem_realloc!\r
+\r
+  2007-10-07 Frédéric Bernon\r
+  * sockets.c, api.h, api_lib.c: First step to fix "bug #20900 : Potential\r
+    crash error problem with netconn_peer & netconn_addr". VERY IMPORTANT:\r
+    this change cause an API breakage for netconn_addr, since a parameter\r
+    type change. Any compiler should cause an error without any changes in\r
+    yours netconn_peer calls (so, it can't be a "silent change"). It also\r
+    reduce a little bit the footprint for socket layer (lwip_getpeername &\r
+    lwip_getsockname use now a common lwip_getaddrname function since \r
+    netconn_peer & netconn_addr have the same parameters).\r
+\r
+  2007-09-20 Simon Goldschmidt\r
+  * tcp.c: Fixed bug #21080 (tcp_bind without check pcbs in TIME_WAIT state)\r
+    by checking  tcp_tw_pcbs also\r
+\r
+  2007-09-19 Simon Goldschmidt\r
+  * icmp.c: Fixed bug #21107 (didn't reset IP TTL in ICMP echo replies)\r
+\r
+  2007-09-15 Mike Kleshov\r
+  * mem.c: Fixed bug #21077 (inaccuracy in calculation of lwip_stat.mem.used)\r
+\r
+  2007-09-06 Frédéric Bernon\r
+  * several-files: replace some #include "arch/cc.h" by "lwip/arch.h", or simply remove\r
+    it as long as "lwip/opt.h" is included before (this one include "lwip/debug.h" which\r
+    already include "lwip/arch.h"). Like that, default defines are provided by "lwip/arch.h"\r
+    if they are not defined in cc.h, in the same spirit than "lwip/opt.h" for lwipopts.h.\r
+\r
+  2007-08-30 Frédéric Bernon\r
+  * igmp.h, igmp.c: Some changes to remove some redundant code, add some traces, \r
+    and fix some coding style.\r
+\r
+  2007-08-28 Frédéric Bernon\r
+  * tcpip.c: Fix TCPIP_MSG_INPKT processing: now, tcpip_input can be used for any\r
+    kind of packets. These packets are considered like Ethernet packets (payload \r
+    pointing to ethhdr) if the netif got the NETIF_FLAG_ETHARP flag. Else, packets \r
+    are considered like IP packets (payload pointing to iphdr).\r
+\r
+  2007-08-27 Frédéric Bernon\r
+  * api.h, api_lib.c, api_msg.c: First fix for "bug #20900 : Potential crash error\r
+    problem with netconn_peer & netconn_addr". Introduce NETCONN_LISTEN netconn_state\r
+    and remove obsolete ones (NETCONN_RECV & NETCONN_ACCEPT).\r
+\r
+  2007-08-24 Kieran Mansley\r
+  * inet.c Modify (acc >> 16) test to ((acc >> 16) != 0) to help buggy\r
+    compiler (Paradigm C++)\r
+\r
+  2007-08-09 Frédéric Bernon, Bill Florac\r
+  * stats.h, stats.c, igmp.h, igmp.c, opt.h: Fix for bug #20503 : IGMP Improvement.\r
+    Introduce IGMP_STATS to centralize statistics management.\r
+\r
+  2007-08-09 Frédéric Bernon, Bill Florac\r
+  * udp.c: Fix for bug #20503 : IGMP Improvement. Enable to receive a multicast\r
+    packet on a udp pcb binded on an netif's IP address, and not on "any".\r
+\r
+  2007-08-09 Frédéric Bernon, Bill Florac\r
+  * igmp.h, igmp.c, ip.c: Fix minor changes from bug #20503 : IGMP Improvement.\r
+    This is mainly on using lookup/lookfor, and some coding styles...\r
+\r
+  2007-07-26 Frédéric Bernon (and "thedoctor")\r
+  * igmp.c: Fix bug #20595 to accept IGMPv3 "Query" messages.\r
+\r
+  2007-07-25 Simon Goldschmidt\r
+  * api_msg.c, tcp.c: Another fix for bug #20021: by not returning an error if\r
+    tcp_output fails in tcp_close, the code in do_close_internal gets simpler\r
+    (tcp_output is called again later from tcp timers).\r
+\r
+  2007-07-25 Simon Goldschmidt\r
+  * ip_frag.c: Fixed bug #20429: use the new pbuf_copy_partial instead of the old\r
+    copy_from_pbuf, which illegally modified the given pbuf.\r
+\r
+  2007-07-25 Simon Goldschmidt\r
+  * tcp_out.c: tcp_enqueue: pcb->snd_queuelen didn't work for chaine PBUF_RAMs:\r
+    changed snd_queuelen++ to snd_queuelen += pbuf_clen(p).\r
+\r
+  2007-07-24 Simon Goldschmidt\r
+  * api_msg.c, tcp.c: Fix bug #20480: Check the pcb passed to tcp_listen() for the\r
+    correct state (must be CLOSED).\r
+\r
+  2007-07-13 Thomas Taranowski (commited by Jared Grubb)\r
+  * memp.c: Fix bug #20478: memp_malloc returned NULL+MEMP_SIZE on failed\r
+    allocation. It now returns NULL.\r
+\r
+  2007-07-13 Frédéric Bernon\r
+  * api_msg.c: Fix bug #20318: api_msg "recv" callbacks don't call pbuf_free in\r
+    all error cases.\r
+\r
+  2007-07-13 Frédéric Bernon\r
+  * api_msg.c: Fix bug #20315: possible memory leak problem if tcp_listen failed,\r
+    because current code doesn't follow rawapi.txt documentation.\r
+\r
+  2007-07-13 Kieran Mansley\r
+  * src/core/tcp_in.c Apply patch#5741 from Oleg Tyshev to fix bug in\r
+    out of sequence processing of received packets\r
+\r
+  2007-07-03 Simon Goldschmidt\r
+  * nearly-all-files: Added assertions where PBUF_RAM pbufs are used and an\r
+    assumption is made that this pbuf is in one piece (i.e. not chained). These\r
+    assumptions clash with the possibility of converting to fully pool-based\r
+    pbuf implementations, where PBUF_RAM pbufs might be chained.\r
+\r
+  2007-07-03 Simon Goldschmidt\r
+  * api.h, api_lib.c, api_msg.c: Final fix for bug #20021 and some other problems\r
+    when closing tcp netconns: removed conn->sem, less context switches when\r
+    closing, both netconn_close and netconn_delete should safely close tcp\r
+    connections.\r
+\r
+  2007-07-02 Simon Goldschmidt\r
+  * ipv4/ip.h, ipv6/ip.h, opt.h, netif.h, etharp.h, ipv4/ip.c, netif.c, raw.c,\r
+    tcp_out.c, udp.c, etharp.c: Added option LWIP_NETIF_HWADDRHINT (default=off)\r
+    to cache ARP table indices with each pcb instead of single-entry cache for\r
+    the complete stack.\r
+\r
+  2007-07-02 Simon Goldschmidt\r
+  * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Added some ASSERTS and casts to prevent\r
+    warnings when assigning to smaller types.\r
+\r
+  2007-06-28 Simon Goldschmidt\r
+  * tcp_out.c: Added check to prevent tcp_pcb->snd_queuelen from overflowing.\r
+\r
+  2007-06-28 Simon Goldschmidt\r
+  * tcp.h: Fixed bug #20287: Fixed nagle algorithm (sending was done too early if\r
+    a segment contained chained pbufs)\r
+\r
+  2007-06-28 Frédéric Bernon\r
+  * autoip.c: replace most of rand() calls by a macro LWIP_AUTOIP_RAND which compute\r
+    a "pseudo-random" value based on netif's MAC and some autoip fields. It's always\r
+    possible to define this macro in your own lwipopts.h to always use C library's\r
+    rand(). Note that autoip_create_rand_addr doesn't use this macro.\r
+\r
+  2007-06-28 Frédéric Bernon\r
+  * netifapi.h, netifapi.c, tcpip.h, tcpip.c: Update code to handle the option\r
+    LWIP_TCPIP_CORE_LOCKING, and do some changes to be coherent with last modifications\r
+    in api_lib/api_msg (use pointers and not type with table, etc...) \r
+\r
+  2007-06-26 Simon Goldschmidt\r
+  * udp.h: Fixed bug #20259: struct udp_hdr was lacking the packin defines.\r
+\r
+  2007-06-25 Simon Goldschmidt\r
+  * udp.c: Fixed bug #20253: icmp_dest_unreach was called with a wrong p->payload\r
+    for udp packets with no matching pcb.\r
+\r
+  2007-06-25 Simon Goldschmidt\r
+  * udp.c: Fixed bug #20220: UDP PCB search in udp_input(): a non-local match\r
+    could get udp input packets if the remote side matched.\r
+\r
+  2007-06-13 Simon Goldschmidt\r
+  * netif.c: Fixed bug #20180 (TCP pcbs listening on IP_ADDR_ANY could get\r
+    changed in netif_set_ipaddr if previous netif->ip_addr.addr was 0.\r
+\r
+  2007-06-13 Simon Goldschmidt\r
+  * api_msg.c: pcb_new sets conn->err if protocol is not implemented\r
+    -> netconn_new_..() does not allocate a new connection for unsupported\r
+    protocols.\r
+\r
+  2007-06-13 Frédéric Bernon, Simon Goldschmidt\r
+  * api_lib.c: change return expression in netconn_addr and netconn_peer, because\r
+    conn->err was reset to ERR_OK without any reasons (and error was lost)...\r
+\r
+  2007-06-13 Frédéric Bernon, Matthias Weisser\r
+  * opt.h, mem.h, mem.c, memp.c, pbuf.c, ip_frag.c, vj.c: Fix bug #20162. Rename\r
+    MEM_ALIGN in LWIP_MEM_ALIGN and MEM_ALIGN_SIZE in LWIP_MEM_ALIGN_SIZE to avoid\r
+    some macro names collision with some OS macros.\r
+\r
+  2007-06-11 Simon Goldschmidt\r
+  * udp.c: UDP Lite: corrected the use of chksum_len (based on RFC3828: if it's 0,\r
+    create checksum over the complete packet. On RX, if it's < 8 (and not 0),\r
+    discard the packet. Also removed the duplicate 'udphdr->chksum = 0' for both\r
+    UDP & UDP Lite.\r
+\r
+  2007-06-11 Srinivas Gollakota & Oleg Tyshev\r
+  * tcp_out.c: Fix for bug #20075 : "A problem with keep-alive timer and TCP flags"\r
+    where TCP flags wasn't initialized in tcp_keepalive.\r
+\r
+  2007-06-03 Simon Goldschmidt\r
+  * udp.c: udp_input(): Input pbuf was not freed if pcb had no recv function\r
+    registered, p->payload was modified without modifying p->len if sending\r
+    icmp_dest_unreach() (had no negative effect but was definitively wrong).\r
+\r
+  2007-06-03 Simon Goldschmidt\r
+  * icmp.c: Corrected bug #19937: For responding to an icmp echo request, icmp\r
+    re-used the input pbuf even if that didn't have enough space to include the\r
+    link headers. Now the space is tested and a new pbuf is allocated for the\r
+    echo response packet if the echo request pbuf isn't big enough.\r
+\r
+  2007-06-01 Simon Goldschmidt\r
+  * sockets.c: Checked in patch #5914: Moved sockopt processing into tcpip_thread.\r
+\r
+  2007-05-23 Frédéric Bernon\r
+  * api_lib.c, sockets.c: Fixed bug #5958 for netconn_listen (acceptmbox only\r
+    allocated by do_listen if success) and netconn_accept errors handling. In\r
+    most of api_lib functions, we replace some errors checkings like "if (conn==NULL)"\r
+    by ASSERT, except for netconn_delete.\r
+\r
+  2007-05-23 Frédéric Bernon\r
+  * api_lib.c: Fixed bug #5957 "Safe-thread problem inside netconn_recv" to return\r
+    an error code if it's impossible to fetch a pbuf on a TCP connection (and not\r
+    directly close the recvmbox).\r
+\r
+  2007-05-22 Simon Goldschmidt\r
+  * tcp.c: Fixed bug #1895 (tcp_bind not correct) by introducing a list of\r
+    bound but unconnected (and non-listening) tcp_pcbs.\r
+\r
+  2007-05-22 Frédéric Bernon\r
+  * sys.h, sys.c, api_lib.c, tcpip.c: remove sys_mbox_fetch_timeout() (was only\r
+    used for LWIP_SO_RCVTIMEO option) and use sys_arch_mbox_fetch() instead of\r
+    sys_mbox_fetch() in api files. Now, users SHOULD NOT use internal lwIP features\r
+    like "sys_timeout" in their application threads.\r
+\r
+  2007-05-22 Frédéric Bernon\r
+  * api.h, api_lib.c, api_msg.h, api_msg.c: change the struct api_msg_msg to see\r
+    which parameters are used by which do_xxx function, and to avoid "misusing"\r
+    parameters (patch #5938).\r
+\r
+  2007-05-22 Simon Goldschmidt\r
+  * api_lib.c, api_msg.c, raw.c, api.h, api_msg.h, raw.h: Included patch #5938:\r
+    changed raw_pcb.protocol from u16_t to u8_t since for IPv4 and IPv6, proto\r
+    is only 8 bits wide. This affects the api, as there, the protocol was\r
+    u16_t, too.\r
+\r
+  2007-05-18 Simon Goldschmidt\r
+  * memp.c: addition to patch #5913: smaller pointer was returned but\r
+    memp_memory was the same size -> did not save memory.\r
+\r
+  2007-05-16 Simon Goldschmidt\r
+  * loopif.c, slipif.c: Fix bug #19729: free pbuf if netif->input() returns\r
+    != ERR_OK.\r
+\r
+  2007-05-16 Simon Goldschmidt\r
+  * api_msg.c, udp.c: If a udp_pcb has a local_ip set, check if it is the same\r
+    as the one of the netif used for sending to prevent sending from old\r
+    addresses after a netif address gets changed (partly fixes bug #3168).\r
+\r
+  2007-05-16 Frédéric Bernon\r
+  * tcpip.c, igmp.h, igmp.c: Fixed bug "#19800 : IGMP: igmp_tick() will not work\r
+    with NO_SYS=1". Note that igmp_init is always in tcpip_thread (and not in \r
+    tcpip_init) because we have to be sure that network interfaces are already\r
+    added (mac filter is updated only in igmp_init for the moment).\r
+\r
+  2007-05-16 Simon Goldschmidt\r
+  * mem.c, memp.c: Removed semaphores from memp, changed sys_sem_wait calls\r
+    into sys_arch_sem_wait calls to prevent timers from running while waiting\r
+    for the heap. This fixes bug #19167.\r
+\r
+  2007-05-13 Simon Goldschmidt\r
+  * tcp.h, sockets.h, sockets.c: Fixed bug from patch #5865 by moving the defines\r
+    for socket options (lwip_set/-getsockopt) used with level IPPROTO_TCP from\r
+    tcp.h to sockets.h.\r
+\r
+  2007-05-07 Simon Goldschmidt\r
+  * mem.c: Another attempt to fix bug #17922.\r
+\r
+  2007-05-04 Simon Goldschmidt\r
+  * pbuf.c, pbuf.h, etharp.c: Further update to ARP queueing: Changed pbuf_copy()\r
+    implementation so that it can be reused (don't allocate the target\r
+    pbuf inside pbuf_copy()).\r
+\r
+  2007-05-04 Simon Goldschmidt\r
+  * memp.c: checked in patch #5913: in memp_malloc() we can return memp as mem\r
+    to save a little RAM (next pointer of memp is not used while not in pool).\r
+\r
+  2007-05-03 "maq"\r
+  * sockets.c: Fix ioctl FIONREAD when some data remains from last recv.\r
+    (patch #3574).\r
+\r
+  2007-04-23 Simon Goldschmidt\r
+  * loopif.c, loopif.h, opt.h, src/netif/FILES: fix bug #2595: "loopif results\r
+    in NULL reference for incoming TCP packets". Loopif has to be configured\r
+    (using LWIP_LOOPIF_MULTITHREADING) to directly call netif->input()\r
+    (multithreading environments, e.g. netif->input() = tcpip_input()) or\r
+    putting packets on a list that is fed to the stack by calling loopif_poll()\r
+    (single-thread / NO_SYS / polling environment where e.g.\r
+    netif->input() = ip_input).\r
+\r
+  2007-04-17 Jonathan Larmour\r
+  * pbuf.c: Use s32_t in pbuf_realloc(), as an s16_t can't reliably hold\r
+    the difference between two u16_t's.\r
+  * sockets.h: FD_SETSIZE needs to match number of sockets, which is\r
+    MEMP_NUM_NETCONN in sockets.c right now.\r
+\r
+  2007-04-12 Jonathan Larmour\r
+  * icmp.c: Reset IP header TTL in ICMP ECHO responses (bug #19580).\r
+\r
+  2007-04-12 Kieran Mansley\r
+  * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission\r
+    timer is reset to fix bug#19434, with help from Oleg Tyshev.\r
+\r
+  2007-04-11 Simon Goldschmidt\r
+  * etharp.c, pbuf.c, pbuf.h: 3rd fix for bug #11400 (arp-queuing): More pbufs than\r
+    previously thought need to be copied (everything but PBUF_ROM!). Cleaned up\r
+    pbuf.c: removed functions no needed any more (by etharp).\r
+\r
+  2007-04-11 Kieran Mansley\r
+  * inet.c, ip_addr.h, sockets.h, sys.h, tcp.h: Apply patch #5745: Fix\r
+    "Constant is long" warnings with 16bit compilers.  Contributed by\r
+    avatar@mmlab.cse.yzu.edu.tw\r
+\r
+  2007-04-05 Frédéric Bernon, Jonathan Larmour\r
+  * api_msg.c: Fix bug #16830: "err_tcp() posts to connection mailbox when no pend on\r
+    the mailbox is active". Now, the post is only done during a connect, and do_send,\r
+    do_write and do_join_leave_group don't do anything if a previous error was signaled.\r
+\r
+  2007-04-03 Frédéric Bernon\r
+  * ip.c: Don't set the IP_DF ("Don't fragment") flag in the IP header in IP output\r
+    packets. See patch #5834.\r
+\r
+  2007-03-30 Frédéric Bernon\r
+  * api_msg.c: add a "pcb_new" helper function to avoid redundant code, and to add\r
+    missing  pcb allocations checking (in do_bind, and for each raw_new). Fix style.\r
+\r
+  2007-03-30 Frédéric Bernon\r
+  * most of files: prefix all debug.h define with "LWIP_" to avoid any conflict with\r
+    others environment defines (these were too "generic").\r
+\r
+  2007-03-28 Frédéric Bernon\r
+  * api.h, api_lib.c, sockets.c: netbuf_ref doesn't check its internal pbuf_alloc call\r
+    result and can cause a crash. lwip_send now check netbuf_ref result.\r
+\r
+  2007-03-28 Simon Goldschmidt\r
+  * sockets.c Remove "#include <errno.h>" from sockets.c to avoid multiple\r
+    definition of macros (in errno.h and lwip/arch.h) if LWIP_PROVIDE_ERRNO is\r
+    defined. This is the way it should have been already (looking at\r
+    doc/sys_arch.txt)\r
+\r
+  2007-03-28 Kieran Mansley\r
+  * opt.h Change default PBUF_POOL_BUFSIZE (again) to accomodate default MSS +\r
+    IP and TCP headers *and* physical link headers\r
+\r
+  2007-03-26 Frédéric Bernon (based on patch from Dmitry Potapov)\r
+  * api_lib.c: patch for netconn_write(), fixes a possible race condition which cause\r
+    to send some garbage. It is not a definitive solution, but the patch does solve\r
+    the problem for most cases.\r
+\r
+  2007-03-22 Frédéric Bernon\r
+  * api_msg.h, api_msg.c: Remove obsolete API_MSG_ACCEPT and do_accept (never used).\r
+\r
+  2007-03-22 Frédéric Bernon\r
+  * api_lib.c: somes resources couldn't be freed if there was errors during\r
+    netconn_new_with_proto_and_callback.\r
+\r
+  2007-03-22 Frédéric Bernon\r
+  * ethernetif.c: update netif->input calls to check return value. In older ports,\r
+    it's a good idea to upgrade them, even if before, there could be another problem\r
+    (access to an uninitialized mailbox).\r
+\r
+  2007-03-21 Simon Goldschmidt\r
+  * sockets.c: fixed bug #5067 (essentialy a signed/unsigned warning fixed\r
+    by casting to unsigned).\r
+\r
+  2007-03-21 Frédéric Bernon\r
+  * api_lib.c, api_msg.c, tcpip.c: integrate sys_mbox_fetch(conn->mbox, NULL) calls from\r
+    api_lib.c to tcpip.c's tcpip_apimsg(). Now, use a local variable and not a\r
+    dynamic one from memp to send tcpip_msg to tcpip_thread in a synchrone call.\r
+    Free tcpip_msg from tcpip_apimsg is not done in tcpip_thread. This give a\r
+    faster and more reliable communication between api_lib and tcpip.\r
+\r
+  2007-03-21 Frédéric Bernon\r
+  * opt.h: Add LWIP_NETIF_CALLBACK (to avoid compiler warning) and set it to 0.\r
+\r
+  2007-03-21 Frédéric Bernon\r
+  * api_msg.c, igmp.c, igmp.h: Fix C++ style comments\r
+\r
+  2007-03-21 Kieran Mansley\r
+  * opt.h Change default PBUF_POOL_BUFSIZE to accomodate default MSS +\r
+    IP and TCP headers\r
+\r
+  2007-03-21 Kieran Mansley\r
+  * Fix all uses of pbuf_header to check the return value.  In some\r
+    cases just assert if it fails as I'm not sure how to fix them, but\r
+    this is no worse than before when they would carry on regardless\r
+    of the failure.\r
+\r
+  2007-03-21 Kieran Mansley\r
+  * sockets.c, igmp.c, igmp.h, memp.h: Fix C++ style comments and\r
+    comment out missing header include in icmp.c\r
+\r
+  2007-03-20 Frédéric Bernon\r
+  * memp.h, stats.c: Fix stats_display function where memp_names table wasn't\r
+    synchronized with memp.h.\r
+\r
+  2007-03-20 Frédéric Bernon\r
+  * tcpip.c: Initialize tcpip's mbox, and verify if initialized in tcpip_input,\r
+    tcpip_ethinput, tcpip_callback, tcpip_apimsg, to fix a init problem with \r
+    network interfaces. Also fix a compiler warning.\r
+\r
+  2007-03-20 Kieran Mansley\r
+  * udp.c: Only try and use pbuf_header() to make space for headers if\r
+    not a ROM or REF pbuf.\r
+\r
+  2007-03-19 Frédéric Bernon\r
+  * api_msg.h, api_msg.c, tcpip.h, tcpip.c: Add return types to tcpip_apimsg()\r
+    and api_msg_post().\r
+\r
+  2007-03-19 Frédéric Bernon\r
+  * Remove unimplemented "memp_realloc" function from memp.h.\r
+\r
+  2007-03-11 Simon Goldschmidt\r
+  * pbuf.c: checked in patch #5796: pbuf_alloc: len field claculation caused\r
+    memory corruption.\r
+\r
+  2007-03-11 Simon Goldschmidt (based on patch from Dmitry Potapov)\r
+  * api_lib.c, sockets.c, api.h, api_msg.h, sockets.h: Fixed bug #19251\r
+    (missing `const' qualifier in socket functions), to get more compatible to\r
+    standard POSIX sockets.\r
+\r
+  2007-03-11 Frédéric Bernon (based on patch from Dmitry Potapov)\r
+  * sockets.c: Add asserts inside bind, connect and sendto to check input\r
+    parameters. Remove excessive set_errno() calls after get_socket(), because\r
+    errno is set inside of get_socket(). Move last sock_set_errno() inside\r
+    lwip_close.\r
+\r
+  2007-03-09 Simon Goldschmidt\r
+  * memp.c: Fixed bug #11400: New etharp queueing introduced bug: memp_memory\r
+    was allocated too small.\r
+\r
+  2007-03-06 Simon Goldschmidt\r
+  * tcpip.c: Initialize dhcp timers in tcpip_thread (if LWIP_DHCP) to protect\r
+    the stack from concurrent access.\r
+\r
+  2007-03-06 Frédéric Bernon, Dmitry Potapov\r
+  * tcpip.c, ip_frag.c, ethernetif.c: Fix some build problems, and a redundancy\r
+    call to "lwip_stats.link.recv++;" in low_level_input() & ethernetif_input().\r
+\r
+  2007-03-06 Simon Goldschmidt\r
+  * ip_frag.c, ip_frag.h: Reduce code size: don't include code in those files\r
+    if IP_FRAG == 0 and IP_REASSEMBLY == 0\r
+\r
+  2007-03-06 Frédéric Bernon, Simon Goldschmidt\r
+  * opt.h, ip_frag.h, tcpip.h, tcpip.c, ethernetif.c: add new configuration\r
+    option named ETHARP_TCPIP_ETHINPUT, which enable the new tcpip_ethinput.\r
+    Allow to do ARP processing for incoming packets inside tcpip_thread\r
+    (protecting ARP layer against concurrent access). You can also disable\r
+    old code using tcp_input with new define ETHARP_TCPIP_INPUT set to 0.\r
+    Older ports have to use tcpip_ethinput.\r
+\r
+  2007-03-06 Simon Goldschmidt (based on patch from Dmitry Potapov)\r
+  * err.h, err.c: fixed compiler warning "initialization dircards qualifiers\r
+    from pointer target type"\r
+\r
+  2007-03-05 Frédéric Bernon\r
+  * opt.h, sockets.h: add new configuration options (LWIP_POSIX_SOCKETS_IO_NAMES,\r
+    ETHARP_TRUST_IP_MAC, review SO_REUSE)\r
+\r
+  2007-03-04 Frédéric Bernon\r
+  * api_msg.c: Remove some compiler warnings : parameter "pcb" was never\r
+    referenced.\r
+\r
+  2007-03-04 Frédéric Bernon\r
+  * api_lib.c: Fix "[patch #5764] api_lib.c cleanup: after patch #5687" (from\r
+    Dmitry Potapov).\r
+    The api_msg struct stay on the stack (not moved to netconn struct).\r
+\r
+  2007-03-04 Simon Goldschmidt (based on patch from Dmitry Potapov)\r
+  * pbuf.c: Fix BUG#19168 - pbuf_free can cause deadlock (if\r
+    SYS_LIGHTWEIGHT_PROT=1 & freeing PBUF_RAM when mem_sem is not available)\r
+    Also fixed cast warning in pbuf_alloc()\r
+\r
+  2007-03-04 Simon Goldschmidt\r
+  * etharp.c, etharp.h, memp.c, memp.h, opt.h: Fix BUG#11400 - don't corrupt\r
+    existing pbuf chain when enqueuing multiple pbufs to a pending ARP request\r
+\r
+  2007-03-03 Frédéric Bernon\r
+  * udp.c: remove obsolete line "static struct udp_pcb *pcb_cache = NULL;"\r
+    It is static, and never used in udp.c except udp_init().\r
+\r
+  2007-03-02 Simon Goldschmidt\r
+  * tcpip.c: Moved call to ip_init(), udp_init() and tcp_init() from\r
+    tcpip_thread() to tcpip_init(). This way, raw API connections can be\r
+    initialized before tcpip_thread is running (e.g. before OS is started)\r
+\r
+  2007-03-02 Frédéric Bernon\r
+  * rawapi.txt: Fix documentation mismatch with etharp.h about etharp_tmr's call\r
+    interval.\r
+\r
+  2007-02-28 Kieran Mansley \r
+  * pbuf.c: Fix BUG#17645 - ensure pbuf payload pointer is not moved\r
+    outside the region of the pbuf by pbuf_header()\r
+\r
+  2007-02-28 Kieran Mansley \r
+  * sockets.c: Fix BUG#19161 - ensure milliseconds timeout is non-zero\r
+    when supplied timeout is also non-zero \r
+\r
+(STABLE-1.2.0)\r
+\r
+  2006-12-05 Leon Woestenberg\r
+  * CHANGELOG: Mention STABLE-1.2.0 release.\r
+\r
+  ++ New features:\r
+\r
+  2006-12-01 Christiaan Simons\r
+  * mem.h, opt.h: Added MEM_LIBC_MALLOC option.\r
+    Note this is a workaround. Currently I have no other options left.\r
+\r
+  2006-10-26 Christiaan Simons (accepted patch by Jonathan Larmour)\r
+  * ipv4/ip_frag.c: rename MAX_MTU to IP_FRAG_MAX_MTU and move define\r
+    to include/lwip/opt.h.\r
+  * ipv4/lwip/ip_frag.h: Remove unused IP_REASS_INTERVAL.\r
+    Move IP_REASS_MAXAGE and IP_REASS_BUFSIZE to include/lwip/opt.h.\r
+  * opt.h: Add above new options.\r
+\r
+  2006-08-18 Christiaan Simons\r
+  * tcp_{in,out}.c: added SNMP counters.\r
+  * ipv4/ip.c: added SNMP counters.\r
+  * ipv4/ip_frag.c: added SNMP counters.\r
+\r
+  2006-08-08 Christiaan Simons\r
+  * etharp.{c,h}: added etharp_find_addr() to read\r
+    (stable) ethernet/IP address pair from ARP table\r
+\r
+  2006-07-14 Christiaan Simons\r
+  * mib_structs.c: added\r
+  * include/lwip/snmp_structs.h: added\r
+  * netif.{c,h}, netif/ethernetif.c: added SNMP statistics to netif struct\r
+\r
+  2006-07-06 Christiaan Simons\r
+  * snmp/asn1_{enc,dec}.c added\r
+  * snmp/mib2.c added\r
+  * snmp/msg_{in,out}.c added\r
+  * include/lwip/snmp_asn1.h added\r
+  * include/lwip/snmp_msg.h added\r
+  * doc/snmp_agent.txt added\r
+\r
+  2006-03-29 Christiaan Simons\r
+  * inet.c, inet.h: Added platform byteswap support.\r
+    Added LWIP_PLATFORM_BYTESWAP define (defaults to 0) and\r
+    optional LWIP_PLATFORM_HTONS(), LWIP_PLATFORM_HTONL() macros.\r
+\r
+  ++ Bug fixes:\r
+\r
+  2006-11-30 Christiaan Simons\r
+  * dhcp.c: Fixed false triggers of request_timeout.\r
+\r
+  2006-11-28 Christiaan Simons\r
+  * netif.c: In netif_add() fixed missing clear of ip_addr, netmask, gw and flags.\r
+\r
+  2006-10-11 Christiaan Simons\r
+  * api_lib.c etharp.c, ip.c, memp.c, stats.c, sys.{c,h} tcp.h:\r
+    Partially accepted patch #5449 for ANSI C compatibility / build fixes.\r
+  * ipv4/lwip/ip.h ipv6/lwip/ip.h: Corrected UDP-Lite protocol\r
+    identifier from 170 to 136 (bug #17574).\r
+\r
+  2006-10-10 Christiaan Simons\r
+  * api_msg.c: Fixed Nagle algorithm as reported by Bob Grice.\r
+\r
+  2006-08-17 Christiaan Simons\r
+  * udp.c: Fixed bug #17200, added check for broadcast\r
+    destinations for PCBs bound to a unicast address.\r
+\r
+  2006-08-07 Christiaan Simons\r
+  * api_msg.c: Flushing TCP output in do_close() (bug #15926).\r
+\r
+  2006-06-27 Christiaan Simons\r
+  * api_msg.c: Applied patch for cold case (bug #11135).\r
+    In accept_function() ensure newconn->callback is always initialized.\r
+\r
+  2006-06-15 Christiaan Simons\r
+  * mem.h: added MEM_SIZE_F alias to fix an ancient cold case (bug #1748),\r
+    facilitate printing of mem_size_t and u16_t statistics.\r
+\r
+  2006-06-14 Christiaan Simons\r
+  * api_msg.c: Applied patch #5146 to handle allocation failures\r
+    in accept() by Kevin Lawson.\r
+\r
+  2006-05-26 Christiaan Simons\r
+  * api_lib.c: Removed conn->sem creation and destruction \r
+    from netconn_write() and added sys_sem_new to netconn_new_*.\r
+\r
+(STABLE-1_1_1)\r
+\r
+  2006-03-03  Christiaan Simons\r
+  * ipv4/ip_frag.c: Added bound-checking assertions on ip_reassbitmap\r
+    access and added pbuf_alloc() return value checks.\r
+\r
+  2006-01-01  Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * tcp_{in,out}.c, tcp_out.c: Removed 'even sndbuf' fix in TCP, which is\r
+    now handled by the checksum routine properly.\r
+\r
+  2006-02-27  Leon Woestenberg <leon.woestenberg@gmx.net>\r
+   * pbuf.c: Fix alignment; pbuf_init() would not work unless\r
+     pbuf_pool_memory[] was properly aligned. (Patch by Curt McDowell.)\r
+\r
+  2005-12-20  Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * tcp.c: Remove PCBs which stay in LAST_ACK state too long. Patch\r
+    submitted by Mitrani Hiroshi.\r
+\r
+  2005-12-15  Christiaan Simons\r
+  * inet.c: Disabled the added summing routine to preserve code space.\r
+\r
+  2005-12-14  Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * tcp_in.c: Duplicate FIN ACK race condition fix by Kelvin Lawson.\r
+    Added Curt McDowell's optimized checksumming routine for future\r
+    inclusion. Need to create test case for unaliged, aligned, odd,\r
+    even length combination of cases on various endianess machines.\r
+\r
+  2005-12-09  Christiaan Simons\r
+  * inet.c: Rewrote standard checksum routine in proper portable C.\r
+\r
+  2005-11-25  Christiaan Simons\r
+  * udp.c tcp.c: Removed SO_REUSE hack. Should reside in socket code only.\r
+  * *.c: introduced cc.h LWIP_DEBUG formatters matching the u16_t, s16_t,\r
+    u32_t, s32_t typedefs. This solves most debug word-length assumes.\r
+\r
+  2005-07-17 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * inet.c: Fixed unaligned 16-bit access in the standard checksum\r
+    routine by Peter Jolasson.\r
+  * slipif.c: Fixed implementation assumption of single-pbuf datagrams.\r
+\r
+  2005-02-04 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * tcp_out.c: Fixed uninitialized 'queue' referenced in memerr branch.\r
+  * tcp_{out|in}.c: Applied patch fixing unaligned access.\r
+\r
+  2005-01-04 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * pbuf.c: Fixed missing semicolon after LWIP_DEBUG statement.\r
+\r
+  2005-01-03 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * udp.c: UDP pcb->recv() was called even when it was NULL.\r
+\r
+(STABLE-1_1_0)\r
+\r
+  2004-12-28 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * etharp.*: Disabled multiple packets on the ARP queue.\r
+    This clashes with TCP queueing.\r
+\r
+  2004-11-28 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * etharp.*: Fixed race condition from ARP request to ARP timeout.\r
+    Halved the ARP period, doubled the period counts.\r
+    ETHARP_MAX_PENDING now should be at least 2. This prevents\r
+    the counter from reaching 0 right away (which would allow\r
+    too little time for ARP responses to be received).\r
+\r
+  2004-11-25 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * dhcp.c: Decline messages were not multicast but unicast.\r
+  * etharp.c: ETHARP_CREATE is renamed to ETHARP_TRY_HARD.\r
+    Do not try hard to insert arbitrary packet's source address,\r
+    etharp_ip_input() now calls etharp_update() without ETHARP_TRY_HARD. \r
+    etharp_query() now always DOES call ETHARP_TRY_HARD so that users\r
+    querying an address will see it appear in the cache (DHCP could\r
+    suffer from this when a server invalidly gave an in-use address.)\r
+  * ipv4/ip_addr.h: Renamed ip_addr_maskcmp() to _netcmp() as we are\r
+    comparing network addresses (identifiers), not the network masks\r
+    themselves.\r
+  * ipv4/ip_addr.c: ip_addr_isbroadcast() now checks that the given\r
+    IP address actually belongs to the network of the given interface.\r
+\r
+  2004-11-24 Kieran Mansley <kjm25@cam.ac.uk>\r
+  * tcp.c: Increment pcb->snd_buf when ACK is received in SYN_SENT state.\r
+\r
+(STABLE-1_1_0-RC1)\r
+\r
+  2004-10-16 Kieran Mansley <kjm25@cam.ac.uk>\r
+  * tcp.c: Add code to tcp_recved() to send an ACK (window update) immediately,\r
+    even if one is already pending, if the rcv_wnd is above a threshold\r
+    (currently TCP_WND/2). This avoids waiting for a timer to expire to send a\r
+    delayed ACK in order to open the window if the stack is only receiving data.\r
+\r
+  2004-09-12 Kieran Mansley <kjm25@cam.ac.uk>\r
+  * tcp*.*: Retransmit time-out handling improvement by Sam Jansen.\r
+\r
+  2004-08-20 Tony Mountifield <tony@softins.co.uk>\r
+  * etharp.c: Make sure the first pbuf queued on an ARP entry\r
+    is properly ref counted.\r
+\r
+  2004-07-27 Tony Mountifield <tony@softins.co.uk>\r
+  * debug.h: Added (int) cast in LWIP_DEBUGF() to avoid compiler\r
+    warnings about comparison.\r
+  * pbuf.c: Stopped compiler complaining of empty if statement\r
+    when LWIP_DEBUGF() empty.  Closed an unclosed comment.\r
+  * tcp.c: Stopped compiler complaining of empty if statement\r
+    when LWIP_DEBUGF() empty.\r
+  * ip.h Corrected IPH_TOS() macro: returns a byte, so doesn't need htons().\r
+  * inet.c: Added a couple of casts to quiet the compiler.\r
+    No need to test isascii(c) before isdigit(c) or isxdigit(c).\r
+\r
+  2004-07-22 Tony Mountifield <tony@softins.co.uk>\r
+  * inet.c: Made data types consistent in inet_ntoa().\r
+    Added casts for return values of checksum routines, to pacify compiler.\r
+  * ip_frag.c, tcp_out.c, sockets.c, pbuf.c\r
+    Small corrections to some debugging statements, to pacify compiler.\r
+\r
+  2004-07-21 Tony Mountifield <tony@softins.co.uk>\r
+  * etharp.c: Removed spurious semicolon and added missing end-of-comment.\r
+  * ethernetif.c Updated low_level_output() to match prototype for\r
+    netif->linkoutput and changed low_level_input() similarly for consistency.\r
+  * api_msg.c: Changed recv_raw() from int to u8_t, to match prototype\r
+    of raw_recv() in raw.h and so avoid compiler error.\r
+  * sockets.c: Added trivial (int) cast to keep compiler happier.\r
+  * ip.c, netif.c Changed debug statements to use the tidier ip4_addrN() macros.\r
+\r
+(STABLE-1_0_0)\r
+\r
+  ++ Changes:\r
+\r
+  2004-07-05 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * sockets.*: Restructured LWIP_PRIVATE_TIMEVAL. Make sure\r
+    your cc.h file defines this either 1 or 0. If non-defined,\r
+    defaults to 1.\r
+  * .c: Added <string.h> and <errno.h> includes where used.\r
+  * etharp.c: Made some array indices unsigned.\r
+\r
+  2004-06-27 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * netif.*: Added netif_set_up()/down().\r
+  * dhcp.c: Changes to restart program flow.\r
+\r
+  2004-05-07 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * etharp.c: In find_entry(), instead of a list traversal per candidate, do a\r
+    single-pass lookup for different candidates. Should exploit locality.\r
+\r
+  2004-04-29 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * tcp*.c: Cleaned up source comment documentation for Doxygen processing.\r
+  * opt.h: ETHARP_ALWAYS_INSERT option removed to comply with ARP RFC.\r
+  * etharp.c: update_arp_entry() only adds new ARP entries when adviced to by\r
+    the caller. This deprecates the ETHARP_ALWAYS_INSERT overrule option.\r
+\r
+  ++ Bug fixes:\r
+\r
+  2004-04-27 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * etharp.c: Applied patch of bug #8708 by Toni Mountifield with a solution\r
+    suggested by Timmy Brolin. Fix for 32-bit processors that cannot access\r
+    non-aligned 32-bit words, such as soms 32-bit TCP/IP header fields. Fix\r
+    is to prefix the 14-bit Ethernet headers with two padding bytes.\r
+\r
+  2004-04-23 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+  * ip_addr.c: Fix in the ip_addr_isbroadcast() check.\r
+  * etharp.c: Fixed the case where the packet that initiates the ARP request\r
+    is not queued, and gets lost. Fixed the case where the packets destination\r
+    address is already known; we now always queue the packet and perform an ARP\r
+    request.\r
+\r
+(STABLE-0_7_0)\r
+\r
+  ++ Bug fixes:\r
+\r
+  * Fixed TCP bug for SYN_SENT to ESTABLISHED state transition.\r
+  * Fixed TCP bug in dequeueing of FIN from out of order segment queue.\r
+  * Fixed two possible NULL references in rare cases.\r
+\r
+(STABLE-0_6_6)\r
+\r
+  ++ Bug fixes:\r
+\r
+  * Fixed DHCP which did not include the IP address in DECLINE messages.\r
+\r
+  ++ Changes:\r
+\r
+  * etharp.c has been hauled over a bit.\r
+\r
+(STABLE-0_6_5)\r
+\r
+  ++ Bug fixes:\r
+\r
+  * Fixed TCP bug induced by bad window resizing with unidirectional TCP traffic.\r
+  * Packets sent from ARP queue had invalid source hardware address.\r
+\r
+  ++ Changes:\r
+\r
+  * Pass-by ARP requests do now update the cache.\r
+\r
+  ++ New features:\r
+\r
+  * No longer dependent on ctype.h.\r
+  * New socket options.\r
+  * Raw IP pcb support.\r
+\r
+(STABLE-0_6_4)\r
+\r
+  ++ Bug fixes:\r
+\r
+  * Some debug formatters and casts fixed.\r
+  * Numereous fixes in PPP.\r
+\r
+  ++ Changes:\r
+\r
+  * DEBUGF now is LWIP_DEBUGF\r
+  * pbuf_dechain() has been re-enabled.\r
+  * Mentioned the changed use of CVS branches in README.\r
+\r
+(STABLE-0_6_3)\r
+\r
+  ++ Bug fixes:\r
+\r
+  * Fixed pool pbuf memory leak in pbuf_alloc().\r
+    Occured if not enough PBUF_POOL pbufs for a packet pbuf chain.\r
+    Reported by Savin Zlobec.\r
+\r
+  * PBUF_POOL chains had their tot_len field not set for non-first\r
+    pbufs. Fixed in pbuf_alloc().\r
+\r
+  ++ New features:\r
+\r
+  * Added PPP stack contributed by Marc Boucher\r
+\r
+  ++ Changes:\r
+\r
+  * Now drops short packets for ICMP/UDP/TCP protocols. More robust.\r
+\r
+  * ARP queueuing now queues the latest packet instead of the first.\r
+    This is the RFC recommended behaviour, but can be overridden in\r
+    lwipopts.h.\r
+\r
+(0.6.2)\r
+\r
+  ++ Bugfixes:\r
+\r
+  * TCP has been fixed to deal with the new use of the pbuf->ref\r
+    counter.\r
+\r
+  * DHCP dhcp_inform() crash bug fixed.\r
+\r
+  ++ Changes:\r
+\r
+  * Removed pbuf_pool_free_cache and pbuf_pool_alloc_cache. Also removed\r
+    pbuf_refresh(). This has sped up pbuf pool operations considerably.\r
+    Implemented by David Haas.\r
+\r
+(0.6.1)\r
+\r
+  ++ New features:\r
+\r
+  * The packet buffer implementation has been enhanced to support\r
+    zero-copy and copy-on-demand for packet buffers which have their\r
+    payloads in application-managed memory.\r
+    Implemented by David Haas.\r
+\r
+    Use PBUF_REF to make a pbuf refer to RAM. lwIP will use zero-copy\r
+    if an outgoing packet can be directly sent on the link, or perform\r
+    a copy-on-demand when necessary.\r
+\r
+    The application can safely assume the packet is sent, and the RAM\r
+    is available to the application directly after calling udp_send()\r
+    or similar function.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * ARP_QUEUEING should now correctly work for all cases, including\r
+    PBUF_REF.\r
+    Implemented by Leon Woestenberg.\r
+\r
+  ++ Changes:\r
+\r
+  * IP_ADDR_ANY is no longer a NULL pointer. Instead, it is a pointer\r
+    to a '0.0.0.0' IP address.\r
+\r
+  * The packet buffer implementation is changed. The pbuf->ref counter\r
+    meaning has changed, and several pbuf functions have been\r
+    adapted accordingly.\r
+\r
+  * netif drivers have to be changed to set the hardware address length field\r
+    that must be initialized correctly by the driver (hint: 6 for Ethernet MAC).\r
+    See the contrib/ports/c16x cs8900 driver as a driver example.\r
+\r
+  * netif's have a dhcp field that must be initialized to NULL by the driver.\r
+    See the contrib/ports/c16x cs8900 driver as a driver example.\r
+\r
+(0.5.x) This file has been unmaintained up to 0.6.1. All changes are\r
+  logged in CVS but have not been explained here.\r
+\r
+(0.5.3) Changes since version 0.5.2\r
+\r
+  ++ Bugfixes:\r
+\r
+  * memp_malloc(MEMP_API_MSG) could fail with multiple application\r
+    threads because it wasn't protected by semaphores.\r
+\r
+  ++ Other changes:\r
+\r
+  * struct ip_addr now packed.\r
+\r
+  * The name of the time variable in arp.c has been changed to ctime\r
+    to avoid conflicts with the time() function.\r
+\r
+(0.5.2) Changes since version 0.5.1\r
+\r
+  ++ New features:\r
+\r
+  * A new TCP function, tcp_tmr(), now handles both TCP timers.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * A bug in tcp_parseopt() could cause the stack to hang because of a\r
+    malformed TCP option.\r
+\r
+  * The address of new connections in the accept() function in the BSD\r
+    socket library was not handled correctly.\r
+\r
+  * pbuf_dechain() did not update the ->tot_len field of the tail.\r
+\r
+  * Aborted TCP connections were not handled correctly in all\r
+    situations.\r
+\r
+  ++ Other changes:\r
+\r
+  * All protocol header structs are now packed.\r
+\r
+  * The ->len field in the tcp_seg structure now counts the actual\r
+    amount of data, and does not add one for SYN and FIN segments.\r
+\r
+(0.5.1) Changes since version 0.5.0\r
+\r
+  ++ New features:\r
+\r
+  * Possible to run as a user process under Linux.\r
+\r
+  * Preliminary support for cross platform packed structs.\r
+\r
+  * ARP timer now implemented.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * TCP output queue length was badly initialized when opening\r
+    connections.\r
+\r
+  * TCP delayed ACKs were not sent correctly.\r
+\r
+  * Explicit initialization of BSS segment variables.\r
+\r
+  * read() in BSD socket library could drop data.\r
+\r
+  * Problems with memory alignment.\r
+\r
+  * Situations when all TCP buffers were used could lead to\r
+    starvation.\r
+\r
+  * TCP MSS option wasn't parsed correctly.\r
+\r
+  * Problems with UDP checksum calculation.\r
+\r
+  * IP multicast address tests had endianess problems.\r
+\r
+  * ARP requests had wrong destination hardware address.\r
+\r
+  ++ Other changes:\r
+\r
+  * struct eth_addr changed from u16_t[3] array to u8_t[6].\r
+\r
+  * A ->linkoutput() member was added to struct netif.\r
+\r
+  * TCP and UDP ->dest_* struct members where changed to ->remote_*.\r
+\r
+  * ntoh* macros are now null definitions for big endian CPUs.\r
+\r
+(0.5.0) Changes since version 0.4.2\r
+\r
+  ++ New features:\r
+\r
+  * Redesigned operating system emulation layer to make porting easier.\r
+\r
+  * Better control over TCP output buffers.\r
+\r
+  * Documenation added.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * Locking issues in buffer management.\r
+\r
+  * Bugfixes in the sequential API.\r
+\r
+  * IP forwarding could cause memory leakage. This has been fixed.\r
+\r
+  ++ Other changes:\r
+\r
+  * Directory structure somewhat changed; the core/ tree has been\r
+    collapsed.\r
+\r
+(0.4.2) Changes since version 0.4.1\r
+\r
+  ++ New features:\r
+\r
+  * Experimental ARP implementation added.\r
+\r
+  * Skeleton Ethernet driver added.\r
+\r
+  * Experimental BSD socket API library added.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * In very intense situations, memory leakage could occur. This has\r
+    been fixed.\r
+\r
+  ++ Other changes:\r
+\r
+  * Variables named "data" and "code" have been renamed in order to\r
+    avoid name conflicts in certain compilers.\r
+\r
+  * Variable++ have in appliciable cases been translated to ++variable\r
+    since some compilers generate better code in the latter case.\r
+\r
+(0.4.1) Changes since version 0.4\r
+\r
+  ++ New features:\r
+\r
+  * TCP: Connection attempts time out earlier than data\r
+    transmissions. Nagle algorithm implemented. Push flag set on the\r
+    last segment in a burst.\r
+\r
+  * UDP: experimental support for UDP-Lite extensions.\r
+\r
+  ++ Bugfixes:\r
+\r
+  * TCP: out of order segments were in some cases handled incorrectly,\r
+    and this has now been fixed. Delayed acknowledgements was broken\r
+    in 0.4, has now been fixed. Binding to an address that is in use\r
+    now results in an error. Reset connections sometimes hung an\r
+    application; this has been fixed.\r
+\r
+  * Checksum calculation sometimes failed for chained pbufs with odd\r
+    lengths. This has been fixed.\r
+\r
+  * API: a lot of bug fixes in the API. The UDP API has been improved\r
+    and tested. Error reporting and handling has been\r
+    improved. Logical flaws and race conditions for incoming TCP\r
+    connections has been found and removed.\r
+\r
+  * Memory manager: alignment issues. Reallocating memory sometimes\r
+    failed, this has been fixed.\r
+\r
+  * Generic library: bcopy was flawed and has been fixed.\r
+\r
+  ++ Other changes:\r
+\r
+  * API: all datatypes has been changed from generic ones such as\r
+    ints, to specified ones such as u16_t. Functions that return\r
+    errors now have the correct type (err_t).\r
+\r
+  * General: A lot of code cleaned up and debugging code removed. Many\r
+    portability issues have been fixed.\r
+\r
+  * The license was changed; the advertising clause was removed.\r
+\r
+  * C64 port added.\r
+\r
+  * Thanks: Huge thanks go to Dagan Galarneau, Horst Garnetzke, Petri\r
+    Kosunen, Mikael Caleres, and Frits Wilmink for reporting and\r
+    fixing bugs!\r
+\r
+(0.4) Changes since version 0.3.1\r
+\r
+  * Memory management has been radically changed; instead of\r
+    allocating memory from a shared heap, memory for objects that are\r
+    rapidly allocated and deallocated is now kept in pools. Allocation\r
+    and deallocation from those memory pools is very fast. The shared\r
+    heap is still present but is used less frequently.\r
+\r
+  * The memory, memory pool, and packet buffer subsystems now support\r
+    4-, 2-, or 1-byte alignment.\r
+\r
+  * "Out of memory" situations are handled in a more robust way.\r
+\r
+  * Stack usage has been reduced.\r
+\r
+  * Easier configuration of lwIP parameters such as memory usage,\r
+    TTLs, statistics gathering, etc. All configuration parameters are\r
+    now kept in a single header file "lwipopts.h".\r
+\r
+  * The directory structure has been changed slightly so that all\r
+    architecture specific files are kept under the src/arch\r
+    hierarchy.\r
+\r
+  * Error propagation has been improved, both in the protocol modules\r
+    and in the API.\r
+\r
+  * The code for the RTXC architecture has been implemented, tested\r
+    and put to use.\r
+\r
+  * Bugs have been found and corrected in the TCP, UDP, IP, API, and\r
+    the Internet checksum modules.\r
+\r
+  * Bugs related to porting between a 32-bit and a 16-bit architecture\r
+    have been found and corrected.\r
+\r
+  * The license has been changed slightly to conform more with the\r
+    original BSD license, including the advertisement clause.\r
+\r
+(0.3.1) Changes since version 0.3\r
+\r
+  * Fix of a fatal bug in the buffer management. Pbufs with allocated\r
+    RAM never returned the RAM when the pbuf was deallocated.\r
+\r
+  * TCP congestion control, window updates and retransmissions did not\r
+    work correctly. This has now been fixed.\r
+\r
+  * Bugfixes in the API.\r
+\r
+(0.3) Changes since version 0.2\r
+\r
+  * New and improved directory structure. All include files are now\r
+    kept in a dedicated include/ directory.\r
+\r
+  * The API now has proper error handling. A new function,\r
+    netconn_err(), now returns an error code for the connection in\r
+    case of errors.\r
+\r
+  * Improvements in the memory management subsystem. The system now\r
+    keeps a pointer to the lowest free memory block. A new function,\r
+    mem_malloc2() tries to allocate memory once, and if it fails tries\r
+    to free some memory and retry the allocation.\r
+\r
+  * Much testing has been done with limited memory\r
+    configurations. lwIP now does a better job when overloaded.\r
+\r
+  * Some bugfixes and improvements to the buffer (pbuf) subsystem.\r
+\r
+  * Many bugfixes in the TCP code:\r
+\r
+    - Fixed a bug in tcp_close().\r
+\r
+    - The TCP receive window was incorrectly closed when out of\r
+      sequence segments was received. This has been fixed.\r
+\r
+    - Connections are now timed-out of the FIN-WAIT-2 state.\r
+\r
+    - The initial congestion window could in some cases be too\r
+      large. This has been fixed.\r
+\r
+    - The retransmission queue could in some cases be screwed up. This\r
+      has been fixed.\r
+\r
+    - TCP RST flag now handled correctly.\r
+\r
+    - Out of sequence data was in some cases never delivered to the\r
+      application. This has been fixed.\r
+\r
+    - Retransmitted segments now contain the correct acknowledgment\r
+      number and advertised window.\r
+\r
+    - TCP retransmission timeout backoffs are not correctly computed\r
+      (ala BSD). After a number of retransmissions, TCP now gives up\r
+      the connection.\r
+\r
+  * TCP connections now are kept on three lists, one for active\r
+    connections, one for listening connections, and one for\r
+    connections that are in TIME-WAIT. This greatly speeds up the fast\r
+    timeout processing for sending delayed ACKs.\r
+\r
+  * TCP now provides proper feedback to the application when a\r
+    connection has been successfully set up.\r
+\r
+  * More comments have been added to the code. The code has also been\r
+    somewhat cleaned up.\r
+\r
+(0.2) Initial public release.\r
diff --git a/Demo/Common/ethernet/lwIP_130/COPYING b/Demo/Common/ethernet/lwIP_130/COPYING
new file mode 100644 (file)
index 0000000..0d77a67
--- /dev/null
@@ -0,0 +1,33 @@
+/*\r
+ * Copyright (c) 2001, 2002 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/FILES b/Demo/Common/ethernet/lwIP_130/FILES
new file mode 100644 (file)
index 0000000..30d6e32
--- /dev/null
@@ -0,0 +1,4 @@
+src/      - The source code for the lwIP TCP/IP stack.\r
+doc/      - The documentation for lwIP.\r
+\r
+See also the FILES file in each subdirectory.\r
diff --git a/Demo/Common/ethernet/lwIP_130/README b/Demo/Common/ethernet/lwIP_130/README
new file mode 100644 (file)
index 0000000..a6c9c73
--- /dev/null
@@ -0,0 +1,89 @@
+INTRODUCTION\r
+\r
+lwIP is a small independent implementation of the TCP/IP protocol\r
+suite that has been developed by Adam Dunkels at the Computer and\r
+Networks Architectures (CNA) lab at the Swedish Institute of Computer\r
+Science (SICS).\r
+\r
+The focus of the lwIP TCP/IP implementation is to reduce the RAM usage\r
+while still having a full scale TCP. This making lwIP suitable for use\r
+in embedded systems with tens of kilobytes of free RAM and room for\r
+around 40 kilobytes of code ROM.\r
+\r
+FEATURES\r
+\r
+  * IP (Internet Protocol) including packet forwarding over multiple network\r
+    interfaces\r
+  * ICMP (Internet Control Message Protocol) for network maintenance and debugging\r
+  * IGMP (Internet Group Management Protocol) for multicast traffic management\r
+  * UDP (User Datagram Protocol) including experimental UDP-lite extensions\r
+  * TCP (Transmission Control Protocol) with congestion control, RTT estimation\r
+    and fast recovery/fast retransmit\r
+  * Specialized raw/native API for enhanced performance\r
+  * Optional Berkeley-like socket API\r
+  * DNS (Domain names resolver)\r
+  * SNMP (Simple Network Management Protocol)\r
+  * DHCP (Dynamic Host Configuration Protocol)\r
+  * AUTOIP (for IPv4, conform with RFC 3927)\r
+  * PPP (Point-to-Point Protocol)\r
+  * ARP (Address Resolution Protocol) for Ethernet\r
+\r
+LICENSE\r
+\r
+lwIP is freely available under a BSD license.\r
+\r
+DEVELOPMENT\r
+\r
+lwIP has grown into an excellent TCP/IP stack for embedded devices,\r
+and developers using the stack often submit bug fixes, improvements,\r
+and additions to the stack to further increase its usefulness.\r
+\r
+Development of lwIP is hosted on Savannah, a central point for\r
+software development, maintenance and distribution. Everyone can\r
+help improve lwIP by use of Savannah's interface, CVS and the\r
+mailing list. A core team of developers will commit changes to the\r
+CVS source tree.\r
+\r
+The lwIP TCP/IP stack is maintained in the 'lwip' CVS module and\r
+contributions (such as platform ports) are in the 'contrib' module.\r
+\r
+See doc/savannah.txt for details on CVS server access for users and\r
+developers.\r
+\r
+Last night's CVS tar ball can be downloaded from:\r
+  http://savannah.gnu.org/cvs.backups/lwip.tar.gz [CHANGED - NEEDS FIXING]\r
+\r
+The current CVS trees are web-browsable:\r
+  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/lwip/\r
+  http://savannah.nongnu.org/cgi-bin/viewcvs/lwip/contrib/\r
+\r
+Submit patches and bugs via the lwIP project page:\r
+  http://savannah.nongnu.org/projects/lwip/\r
+\r
+\r
+DOCUMENTATION\r
+\r
+The original out-dated homepage of lwIP and Adam Dunkels' papers on\r
+lwIP are at the official lwIP home page:\r
+  http://www.sics.se/~adam/lwip/\r
+\r
+Self documentation of the source code is regularly extracted from the\r
+current CVS sources and is available from this web page:\r
+  http://www.nongnu.org/lwip/\r
+\r
+There is now a constantly growin wiki about lwIP at\r
+  http://lwip.scribblewiki.com/\r
+\r
+Also, there are mailing lists you can subscribe at\r
+  http://savannah.nongnu.org/mail/?group=lwip\r
+plus searchable archives:\r
+  http://lists.nongnu.org/archive/html/lwip-users/\r
+  http://lists.nongnu.org/archive/html/lwip-devel/\r
+\r
+Reading Adam's papers, the files in docs/, browsing the source code\r
+documentation and browsing the mailing list archives is a good way to\r
+become familiar with the design of lwIP.\r
+\r
+Adam Dunkels <adam@sics.se>\r
+Leon Woestenberg <leon.woestenberg@gmx.net>\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cc.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cc.h
new file mode 100644 (file)
index 0000000..37b18f5
--- /dev/null
@@ -0,0 +1,57 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __CC_H__\r
+#define __CC_H__\r
+\r
+#include <stdio.h>\r
+#include <stdlib.h>\r
+\r
+#include "cpu.h"\r
+\r
+typedef unsigned   char    u8_t;\r
+typedef signed     char    s8_t;\r
+typedef unsigned   short   u16_t;\r
+typedef signed     short   s16_t;\r
+typedef unsigned   long    u32_t;\r
+typedef signed     long    s32_t;\r
+typedef u32_t mem_ptr_t;\r
+typedef int sys_prot_t;\r
+\r
+#define PACK_STRUCT_BEGIN\r
+#define PACK_STRUCT_STRUCT\r
+#define PACK_STRUCT_END\r
+#define PACK_STRUCT_FIELD(x) x\r
+\r
+#define LWIP_PLATFORM_DIAG(x)\r
+#define LWIP_PLATFORM_ASSERT(x)\r
+\r
+#endif /* __CC_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cpu.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/cpu.h
new file mode 100644 (file)
index 0000000..2af31a8
--- /dev/null
@@ -0,0 +1,37 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __CPU_H__\r
+#define __CPU_H__\r
+\r
+#define BYTE_ORDER LITTLE_ENDIAN\r
+\r
+#endif /* __CPU_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/init.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/init.h
new file mode 100644 (file)
index 0000000..14b9515
--- /dev/null
@@ -0,0 +1,44 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __ARCH_INIT_H__\r
+#define __ARCH_INIT_H__\r
+\r
+#define TCPIP_INIT_DONE(arg)  tcpip_init_done(arg)\r
+\r
+void tcpip_init_done(void *);\r
+int wait_for_tcpip_init(void);\r
+\r
+#endif /* __ARCH_INIT_H__ */\r
+\r
+\r
+\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/lib.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/lib.h
new file mode 100644 (file)
index 0000000..9726dee
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LIB_H__\r
+#define __LIB_H__\r
+\r
+#include <string.h>\r
+\r
+\r
+#endif /* __LIB_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/perf.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/perf.h
new file mode 100644 (file)
index 0000000..68afdb5
--- /dev/null
@@ -0,0 +1,38 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __PERF_H__\r
+#define __PERF_H__\r
+\r
+#define PERF_START    /* null definition */\r
+#define PERF_STOP(x)  /* null definition */\r
+\r
+#endif /* __PERF_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/sys_arch.h b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/arch/sys_arch.h
new file mode 100644 (file)
index 0000000..7cf2963
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __SYS_RTXC_H__\r
+#define __SYS_RTXC_H__\r
+\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+#include "queue.h"\r
+#include "semphr.h"\r
+\r
+#define SYS_MBOX_NULL (xQueueHandle)0\r
+#define SYS_SEM_NULL  (xSemaphoreHandle)0\r
+\r
+typedef xSemaphoreHandle sys_sem_t;\r
+typedef xQueueHandle sys_mbox_t;\r
+typedef xTaskHandle sys_thread_t;\r
+\r
+/* Message queue constants. */\r
+#define archMESG_QUEUE_LENGTH  ( 6 )\r
+#define archPOST_BLOCK_TIME_MS ( ( unsigned portLONG ) 10000 )\r
+\r
+#endif /* __SYS_RTXC_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/sys_arch.c b/Demo/Common/ethernet/lwIP_130/contrib/port/FreeRTOS/STR91x/sys_arch.c
new file mode 100644 (file)
index 0000000..9baf735
--- /dev/null
@@ -0,0 +1,424 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* lwIP includes. */\r
+#include "lwip/debug.h"\r
+#include "lwip/def.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/stats.h"\r
+\r
+struct timeoutlist\r
+{\r
+       struct sys_timeouts timeouts;\r
+       xTaskHandle pid;\r
+};\r
+\r
+/* This is the number of threads that can be started with sys_thread_new() */\r
+#define SYS_THREAD_MAX 4\r
+\r
+static struct timeoutlist s_timeoutlist[SYS_THREAD_MAX];\r
+static u16_t s_nextthread = 0;\r
+\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+//  Creates an empty mailbox.\r
+sys_mbox_t sys_mbox_new(int size)\r
+{\r
+       xQueueHandle mbox;\r
+       \r
+       mbox = xQueueCreate( archMESG_QUEUE_LENGTH, sizeof( void * ) );\r
+\r
+#if SYS_STATS\r
+      ++lwip_stats.sys.mbox.used;\r
+      if (lwip_stats.sys.mbox.max < lwip_stats.sys.mbox.used) {\r
+         lwip_stats.sys.mbox.max = lwip_stats.sys.mbox.used;\r
+         }\r
+#endif /* SYS_STATS */\r
+\r
+       return mbox;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Deallocates a mailbox. If there are messages still present in the\r
+  mailbox when the mailbox is deallocated, it is an indication of a\r
+  programming error in lwIP and the developer should be notified.\r
+*/\r
+void sys_mbox_free(sys_mbox_t mbox)\r
+{\r
+       if( uxQueueMessagesWaiting( mbox ) )\r
+       {\r
+               /* Line for breakpoint.  Should never break here! */\r
+               portNOP();\r
+#if SYS_STATS\r
+           lwip_stats.sys.mbox.err++;\r
+#endif /* SYS_STATS */\r
+                       \r
+               // TODO notify the user of failure.\r
+       }\r
+\r
+       vQueueDelete( mbox );\r
+\r
+#if SYS_STATS\r
+     --lwip_stats.sys.mbox.used;\r
+#endif /* SYS_STATS */\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+//   Posts the "msg" to the mailbox.\r
+void sys_mbox_post(sys_mbox_t mbox, void *data)\r
+{\r
+       while ( xQueueSendToBack(mbox, &data, portMAX_DELAY ) != pdTRUE );\r
+}\r
+\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+//   Try to post the "msg" to the mailbox.\r
+err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)\r
+{\r
+err_t result;\r
+\r
+   if ( xQueueSend( mbox, &msg, 0 ) == pdPASS )\r
+   {\r
+      result = ERR_OK;\r
+   }\r
+   else {\r
+      // could not post, queue must be full\r
+      result = ERR_MEM;\r
+                       \r
+#if SYS_STATS\r
+      lwip_stats.sys.mbox.err++;\r
+#endif /* SYS_STATS */\r
+                       \r
+   }\r
+\r
+   return result;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Blocks the thread until a message arrives in the mailbox, but does\r
+  not block the thread longer than "timeout" milliseconds (similar to\r
+  the sys_arch_sem_wait() function). The "msg" argument is a result\r
+  parameter that is set by the function (i.e., by doing "*msg =\r
+  ptr"). The "msg" parameter maybe NULL to indicate that the message\r
+  should be dropped.\r
+\r
+  The return values are the same as for the sys_arch_sem_wait() function:\r
+  Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a\r
+  timeout.\r
+\r
+  Note that a function with a similar name, sys_mbox_fetch(), is\r
+  implemented by lwIP.\r
+*/\r
+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)\r
+{\r
+void *dummyptr;\r
+portTickType StartTime, EndTime, Elapsed;\r
+\r
+       StartTime = xTaskGetTickCount();\r
+\r
+       if ( msg == NULL )\r
+       {\r
+               msg = &dummyptr;\r
+       }\r
+               \r
+       if ( timeout != 0 )\r
+       {\r
+               if ( pdTRUE == xQueueReceive( mbox, &(*msg), timeout / portTICK_RATE_MS ) )\r
+               {\r
+                       EndTime = xTaskGetTickCount();\r
+                       Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;\r
+                       \r
+                       return ( Elapsed );\r
+               }\r
+               else // timed out blocking for message\r
+               {\r
+                       *msg = NULL;\r
+                       \r
+                       return SYS_ARCH_TIMEOUT;\r
+               }\r
+       }\r
+       else // block forever for a message.\r
+       {\r
+               while( pdTRUE != xQueueReceive( mbox, &(*msg), portMAX_DELAY ) ); // time is arbitrary\r
+               EndTime = xTaskGetTickCount();\r
+               Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;\r
+               \r
+               return ( Elapsed ); // return time blocked TODO test    \r
+       }\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Similar to sys_arch_mbox_fetch, but if message is not ready immediately, we'll\r
+  return with SYS_MBOX_EMPTY.  On success, 0 is returned.\r
+*/\r
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)\r
+{\r
+void *dummyptr;\r
+\r
+       if ( msg == NULL )\r
+       {\r
+               msg = &dummyptr;\r
+       }\r
+\r
+   if ( pdTRUE == xQueueReceive( mbox, &(*msg), 0 ) )\r
+   {\r
+      return ERR_OK;\r
+   }\r
+   else\r
+   {\r
+      return SYS_MBOX_EMPTY;\r
+   }\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+//  Creates and returns a new semaphore. The "count" argument specifies\r
+//  the initial state of the semaphore.\r
+sys_sem_t sys_sem_new(u8_t count)\r
+{\r
+       xSemaphoreHandle  xSemaphore;\r
+\r
+       vSemaphoreCreateBinary( xSemaphore );\r
+       \r
+       if( xSemaphore == NULL )\r
+       {\r
+               \r
+#if SYS_STATS\r
+      ++lwip_stats.sys.sem.err;\r
+#endif /* SYS_STATS */\r
+                       \r
+               return SYS_SEM_NULL;    // TODO need assert\r
+       }\r
+       \r
+       if(count == 0)  // Means it can't be taken\r
+       {\r
+               xSemaphoreTake(xSemaphore,1);\r
+       }\r
+\r
+#if SYS_STATS\r
+       ++lwip_stats.sys.sem.used;\r
+       if (lwip_stats.sys.sem.max < lwip_stats.sys.sem.used) {\r
+               lwip_stats.sys.sem.max = lwip_stats.sys.sem.used;\r
+       }\r
+#endif /* SYS_STATS */\r
+               \r
+       return xSemaphore;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Blocks the thread while waiting for the semaphore to be\r
+  signaled. If the "timeout" argument is non-zero, the thread should\r
+  only be blocked for the specified time (measured in\r
+  milliseconds).\r
+\r
+  If the timeout argument is non-zero, the return value is the number of\r
+  milliseconds spent waiting for the semaphore to be signaled. If the\r
+  semaphore wasn't signaled within the specified time, the return value is\r
+  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
+  (i.e., it was already signaled), the function may return zero.\r
+\r
+  Notice that lwIP implements a function with a similar name,\r
+  sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
+*/\r
+u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)\r
+{\r
+portTickType StartTime, EndTime, Elapsed;\r
+\r
+       StartTime = xTaskGetTickCount();\r
+\r
+       if(     timeout != 0)\r
+       {\r
+               if( xSemaphoreTake( sem, timeout / portTICK_RATE_MS ) == pdTRUE )\r
+               {\r
+                       EndTime = xTaskGetTickCount();\r
+                       Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;\r
+                       \r
+                       return (Elapsed); // return time blocked TODO test      \r
+               }\r
+               else\r
+               {\r
+                       return SYS_ARCH_TIMEOUT;\r
+               }\r
+       }\r
+       else // must block without a timeout\r
+       {\r
+               while( xSemaphoreTake( sem, portMAX_DELAY ) != pdTRUE );\r
+               EndTime = xTaskGetTickCount();\r
+               Elapsed = (EndTime - StartTime) * portTICK_RATE_MS;\r
+\r
+               return ( Elapsed ); // return time blocked      \r
+               \r
+       }\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Signals a semaphore\r
+void sys_sem_signal(sys_sem_t sem)\r
+{\r
+       xSemaphoreGive( sem );\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Deallocates a semaphore\r
+void sys_sem_free(sys_sem_t sem)\r
+{\r
+#if SYS_STATS\r
+      --lwip_stats.sys.sem.used;\r
+#endif /* SYS_STATS */\r
+                       \r
+       vQueueDelete( sem );\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+// Initialize sys arch\r
+void sys_init(void)\r
+{\r
+       int i;\r
+\r
+       // Initialize the the per-thread sys_timeouts structures\r
+       // make sure there are no valid pids in the list\r
+       for(i = 0; i < SYS_THREAD_MAX; i++)\r
+       {\r
+               s_timeoutlist[i].pid = 0;\r
+               s_timeoutlist[i].timeouts.next = NULL;\r
+       }\r
+\r
+       // keep track of how many threads have been created\r
+       s_nextthread = 0;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Returns a pointer to the per-thread sys_timeouts structure. In lwIP,\r
+  each thread has a list of timeouts which is represented as a linked\r
+  list of sys_timeout structures. The sys_timeouts structure holds a\r
+  pointer to a linked list of timeouts. This function is called by\r
+  the lwIP timeout scheduler and must not return a NULL value.\r
+\r
+  In a single threaded sys_arch implementation, this function will\r
+  simply return a pointer to a global sys_timeouts variable stored in\r
+  the sys_arch module.\r
+*/\r
+struct sys_timeouts *sys_arch_timeouts(void)\r
+{\r
+int i;\r
+xTaskHandle pid;\r
+struct timeoutlist *tl;\r
+\r
+       pid = xTaskGetCurrentTaskHandle( );\r
+\r
+       for(i = 0; i < s_nextthread; i++)\r
+       {\r
+               tl = &(s_timeoutlist[i]);\r
+               if(tl->pid == pid)\r
+               {\r
+                       return &(tl->timeouts);\r
+               }\r
+       }\r
+\r
+       // Error\r
+       return NULL;\r
+}\r
+\r
+/*-----------------------------------------------------------------------------------*/\r
+/*-----------------------------------------------------------------------------------*/\r
+// TODO\r
+/*-----------------------------------------------------------------------------------*/\r
+/*\r
+  Starts a new thread with priority "prio" that will begin its execution in the\r
+  function "thread()". The "arg" argument will be passed as an argument to the\r
+  thread() function. The id of the new thread is returned. Both the id and\r
+  the priority are system dependent.\r
+*/\r
+sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)\r
+{\r
+xTaskHandle CreatedTask;\r
+int result;\r
+\r
+   if ( s_nextthread < SYS_THREAD_MAX )\r
+   {\r
+      result = xTaskCreate( thread, ( signed portCHAR * ) name, stacksize, arg, prio, &CreatedTask );\r
+\r
+          // For each task created, store the task handle (pid) in the timers array.\r
+          // This scheme doesn't allow for threads to be deleted\r
+          s_timeoutlist[s_nextthread++].pid = CreatedTask;\r
+\r
+          if(result == pdPASS)\r
+          {\r
+                  return CreatedTask;\r
+          }\r
+          else\r
+          {\r
+                  return NULL;\r
+          }\r
+   }\r
+   else\r
+   {\r
+      return NULL;\r
+   }\r
+}\r
+\r
+/*\r
+  This optional function does a "fast" critical region protection and returns\r
+  the previous protection level. This function is only called during very short\r
+  critical regions. An embedded system which supports ISR-based drivers might\r
+  want to implement this function by disabling interrupts. Task-based systems\r
+  might want to implement this by using a mutex or disabling tasking. This\r
+  function should support recursive calls from the same task or interrupt. In\r
+  other words, sys_arch_protect() could be called while already protected. In\r
+  that case the return value indicates that it is already protected.\r
+\r
+  sys_arch_protect() is only required if your port is supporting an operating\r
+  system.\r
+*/\r
+sys_prot_t sys_arch_protect(void)\r
+{\r
+       vPortEnterCritical();\r
+       return 1;\r
+}\r
+\r
+/*\r
+  This optional function does a "fast" set of critical region protection to the\r
+  value specified by pval. See the documentation for sys_arch_protect() for\r
+  more information. This function is only required if your port is supporting\r
+  an operating system.\r
+*/\r
+void sys_arch_unprotect(sys_prot_t pval)\r
+{\r
+       ( void ) pval;\r
+       vPortExitCritical();\r
+}\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/doc/FILES b/Demo/Common/ethernet/lwIP_130/doc/FILES
new file mode 100644 (file)
index 0000000..7455d4b
--- /dev/null
@@ -0,0 +1,5 @@
+savannah.txt   - How to obtain the current development source code.\r
+contrib.txt    - How to contribute to lwIP as a developer.\r
+rawapi.txt     - The documentation for the core API of lwIP.\r
+snmp_agent.txt - The documentation for the lwIP SNMP agent.\r
+sys_arch.txt   - The documentation for a system abstraction layer of lwIP.\r
diff --git a/Demo/Common/ethernet/lwIP_130/doc/contrib.txt b/Demo/Common/ethernet/lwIP_130/doc/contrib.txt
new file mode 100644 (file)
index 0000000..3057beb
--- /dev/null
@@ -0,0 +1,63 @@
+1 Introduction\r
+\r
+This document describes some guidelines for people participating\r
+in lwIP development.\r
+\r
+2 How to contribute to lwIP\r
+\r
+Here is a short list of suggestions to anybody working with lwIP and \r
+trying to contribute bug reports, fixes, enhancements, platform ports etc.\r
+First of all as you may already know lwIP is a volunteer project so feedback\r
+to fixes or questions might often come late. Hopefully the bug and patch tracking \r
+features of Savannah help us not lose users' input.\r
+\r
+2.1 Source code style:\r
+\r
+1. do not use tabs.\r
+2. indentation is two spaces per level (i.e. per tab).\r
+3. end debug messages with a trailing newline (\n).\r
+4. one space between keyword and opening bracket.\r
+5. no space between function and opening bracket.\r
+6. one space and no newline before opening curly braces of a block.\r
+7. closing curly brace on a single line.\r
+8. spaces surrounding assignment and comparisons.\r
+9. don't initialize static and/or global variables to zero, the compiler takes care of that.\r
+10. use current source code style as further reference.\r
+\r
+2.2 Source code documentation style:\r
+\r
+1. JavaDoc compliant and Doxygen compatible.\r
+2. Function documentation above functions in .c files, not .h files.\r
+   (This forces you to synchronize documentation and implementation.)\r
+3. Use current documentation style as further reference.\r
\r
+2.3 Bug reports and patches:\r
+\r
+1. Make sure you are reporting bugs or send patches against the latest\r
+   sources. (From the latest release and/or the current CVS sources.)\r
+2. If you think you found a bug make sure it's not already filed in the\r
+   bugtracker at Savannah.\r
+3. If you have a fix put the patch on Savannah. If it is a patch that affects\r
+   both core and arch specific stuff please separate them so that the core can\r
+   be applied separately while leaving the other patch 'open'. The prefered way\r
+   is to NOT touch archs you can't test and let maintainers take care of them.\r
+   This is a good way to see if they are used at all - the same goes for unix\r
+   netifs except tapif.\r
+4. Do not file a bug and post a fix to it to the patch area. Either a bug report\r
+   or a patch will be enough.\r
+   If you correct an existing bug then attach the patch to the bug rather than creating a new entry in the patch area.\r
+5. Trivial patches (compiler warning, indentation and spelling fixes or anything obvious which takes a line or two)\r
+   can go to the lwip-users list. This is still the fastest way of interaction and the list is not so crowded\r
+   as to allow for loss of fixes. Putting bugs on Savannah and subsequently closing them is too much an overhead\r
+   for reporting a compiler warning fix.\r
+6. Patches should be specific to a single change or to related changes.Do not mix bugfixes with spelling and other\r
+   trivial fixes unless the bugfix is trivial too.Do not reorganize code and rename identifiers in the same patch you\r
+   change behaviour if not necessary.A patch is easier to read and understand if it's to the point and short than\r
+   if it's not to the point and long :) so the chances for it to be applied are greater. \r
+\r
+2.4 Platform porters:\r
+\r
+1. If you have ported lwIP to a platform (an OS, a uC/processor or a combination of these) and\r
+   you think it could benefit others[1] you might want discuss this on the mailing list. You\r
+   can also ask for CVS access to submit and maintain your port in the contrib CVS module.\r
+   
\ No newline at end of file
diff --git a/Demo/Common/ethernet/lwIP_130/doc/rawapi.txt b/Demo/Common/ethernet/lwIP_130/doc/rawapi.txt
new file mode 100644 (file)
index 0000000..d511280
--- /dev/null
@@ -0,0 +1,437 @@
+Raw TCP/IP interface for lwIP\r
+\r
+Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons\r
+\r
+lwIP provides two Application Program's Interfaces (APIs) for programs\r
+to use for communication with the TCP/IP code:\r
+* low-level "core" / "callback" or "raw" API.\r
+* higher-level "sequential" API.\r
+\r
+The sequential API provides a way for ordinary, sequential, programs\r
+to use the lwIP stack. It is quite similar to the BSD socket API. The\r
+model of execution is based on the blocking open-read-write-close\r
+paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP\r
+code and the application program must reside in different execution\r
+contexts (threads).\r
+\r
+** The remainder of this document discusses the "raw" API. **\r
+\r
+The raw TCP/IP interface allows the application program to integrate\r
+better with the TCP/IP code. Program execution is event based by\r
+having callback functions being called from within the TCP/IP\r
+code. The TCP/IP code and the application program both run in the same\r
+thread. The sequential API has a much higher overhead and is not very\r
+well suited for small systems since it forces a multithreaded paradigm\r
+on the application.\r
+\r
+The raw TCP/IP interface is not only faster in terms of code execution\r
+time but is also less memory intensive. The drawback is that program\r
+development is somewhat harder and application programs written for\r
+the raw TCP/IP interface are more difficult to understand. Still, this\r
+is the preferred way of writing applications that should be small in\r
+code size and memory usage.\r
+\r
+Both APIs can be used simultaneously by different application\r
+programs. In fact, the sequential API is implemented as an application\r
+program using the raw TCP/IP interface.\r
+\r
+--- Callbacks\r
+\r
+Program execution is driven by callbacks. Each callback is an ordinary\r
+C function that is called from within the TCP/IP code. Every callback\r
+function is passed the current TCP or UDP connection state as an\r
+argument. Also, in order to be able to keep program specific state,\r
+the callback functions are called with a program specified argument\r
+that is independent of the TCP/IP state.\r
+\r
+The function for setting the application connection state is:\r
+\r
+- void tcp_arg(struct tcp_pcb *pcb, void *arg)\r
+\r
+  Specifies the program specific state that should be passed to all\r
+  other callback functions. The "pcb" argument is the current TCP\r
+  connection control block, and the "arg" argument is the argument\r
+  that will be passed to the callbacks.\r
+\r
+  \r
+--- TCP connection setup\r
+\r
+The functions used for setting up connections is similar to that of\r
+the sequential API and of the BSD socket API. A new TCP connection\r
+identifier (i.e., a protocol control block - PCB) is created with the\r
+tcp_new() function. This PCB can then be either set to listen for new\r
+incoming connections or be explicitly connected to another host.\r
+\r
+- struct tcp_pcb *tcp_new(void)\r
+\r
+  Creates a new connection identifier (PCB). If memory is not\r
+  available for creating the new pcb, NULL is returned.\r
+\r
+- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port)\r
+\r
+  Binds the pcb to a local IP address and port number. The IP address\r
+  can be specified as IP_ADDR_ANY in order to bind the connection to\r
+  all local IP addresses.\r
+\r
+  If another connection is bound to the same port, the function will\r
+  return ERR_USE, otherwise ERR_OK is returned.\r
+\r
+- struct tcp_pcb *tcp_listen(struct tcp_pcb *pcb)\r
+\r
+  Commands a pcb to start listening for incoming connections. When an\r
+  incoming connection is accepted, the function specified with the\r
+  tcp_accept() function will be called. The pcb will have to be bound\r
+  to a local port with the tcp_bind() function.\r
+\r
+  The tcp_listen() function returns a new connection identifier, and\r
+  the one passed as an argument to the function will be\r
+  deallocated. The reason for this behavior is that less memory is\r
+  needed for a connection that is listening, so tcp_listen() will\r
+  reclaim the memory needed for the original connection and allocate a\r
+  new smaller memory block for the listening connection.\r
+\r
+  tcp_listen() may return NULL if no memory was available for the\r
+  listening connection. If so, the memory associated with the pcb\r
+  passed as an argument to tcp_listen() will not be deallocated.\r
+\r
+- struct tcp_pcb *tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)\r
+\r
+  Same as tcp_listen, but limits the number of outstanding connections\r
+  in the listen queue to the value specified by the backlog argument.\r
+  To use it, your need to set TCP_LISTEN_BACKLOG=1 in your lwipopts.h.\r
+\r
+- void tcp_accepted(struct tcp_pcb *pcb)\r
+\r
+  Inform lwIP that an incoming connection has been accepted. This would\r
+  usually be called from the accept callback. This allows lwIP to perform\r
+  housekeeping tasks, such as allowing further incoming connections to be\r
+  queued in the listen backlog.\r
+\r
+- void tcp_accept(struct tcp_pcb *pcb,\r
+                  err_t (* accept)(void *arg, struct tcp_pcb *newpcb,\r
+                                   err_t err))\r
+\r
+  Specified the callback function that should be called when a new\r
+  connection arrives on a listening connection.\r
+      \r
+- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+                    u16_t port, err_t (* connected)(void *arg,\r
+                                                    struct tcp_pcb *tpcb,\r
+                                                    err_t err));\r
+\r
+  Sets up the pcb to connect to the remote host and sends the\r
+  initial SYN segment which opens the connection. \r
+\r
+  The tcp_connect() function returns immediately; it does not wait for\r
+  the connection to be properly setup. Instead, it will call the\r
+  function specified as the fourth argument (the "connected" argument)\r
+  when the connection is established. If the connection could not be\r
+  properly established, either because the other host refused the\r
+  connection or because the other host didn't answer, the "connected"\r
+  function will be called with an the "err" argument set accordingly.\r
+\r
+  The tcp_connect() function can return ERR_MEM if no memory is\r
+  available for enqueueing the SYN segment. If the SYN indeed was\r
+  enqueued successfully, the tcp_connect() function returns ERR_OK.\r
+\r
+  \r
+--- Sending TCP data\r
+\r
+TCP data is sent by enqueueing the data with a call to\r
+tcp_write(). When the data is successfully transmitted to the remote\r
+host, the application will be notified with a call to a specified\r
+callback function.\r
+\r
+- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,\r
+                  u8_t copy)\r
+\r
+  Enqueues the data pointed to by the argument dataptr. The length of\r
+  the data is passed as the len parameter. The copy argument is either\r
+  0 or 1 and indicates whether the new memory should be allocated for\r
+  the data to be copied into. If the argument is 0, no new memory\r
+  should be allocated and the data should only be referenced by\r
+  pointer.\r
+\r
+  The tcp_write() function will fail and return ERR_MEM if the length\r
+  of the data exceeds the current send buffer size or if the length of\r
+  the queue of outgoing segment is larger than the upper limit defined\r
+  in lwipopts.h. The number of bytes available in the output queue can\r
+  be retrieved with the tcp_sndbuf() function.\r
+\r
+  The proper way to use this function is to call the function with at\r
+  most tcp_sndbuf() bytes of data. If the function returns ERR_MEM,\r
+  the application should wait until some of the currently enqueued\r
+  data has been successfully received by the other host and try again.\r
+\r
+- void tcp_sent(struct tcp_pcb *pcb,\r
+                err_t (* sent)(void *arg, struct tcp_pcb *tpcb,\r
+                u16_t len))\r
+\r
+  Specifies the callback function that should be called when data has\r
+  successfully been received (i.e., acknowledged) by the remote\r
+  host. The len argument passed to the callback function gives the\r
+  amount bytes that was acknowledged by the last acknowledgment.\r
+\r
+  \r
+--- Receiving TCP data\r
+\r
+TCP data reception is callback based - an application specified\r
+callback function is called when new data arrives. When the\r
+application has taken the data, it has to call the tcp_recved()\r
+function to indicate that TCP can advertise increase the receive\r
+window.\r
+\r
+- void tcp_recv(struct tcp_pcb *pcb,\r
+                err_t (* recv)(void *arg, struct tcp_pcb *tpcb,\r
+                               struct pbuf *p, err_t err))\r
+\r
+  Sets the callback function that will be called when new data\r
+  arrives. The callback function will be passed a NULL pbuf to\r
+  indicate that the remote host has closed the connection. If\r
+  there are no errors and the callback function is to return\r
+  ERR_OK, then it must free the pbuf. Otherwise, it must not\r
+  free the pbuf so that lwIP core code can store it.\r
+\r
+- void tcp_recved(struct tcp_pcb *pcb, u16_t len)\r
+\r
+  Must be called when the application has received the data. The len\r
+  argument indicates the length of the received data.\r
+    \r
+\r
+--- Application polling\r
+\r
+When a connection is idle (i.e., no data is either transmitted or\r
+received), lwIP will repeatedly poll the application by calling a\r
+specified callback function. This can be used either as a watchdog\r
+timer for killing connections that have stayed idle for too long, or\r
+as a method of waiting for memory to become available. For instance,\r
+if a call to tcp_write() has failed because memory wasn't available,\r
+the application may use the polling functionality to call tcp_write()\r
+again when the connection has been idle for a while.\r
+\r
+- void tcp_poll(struct tcp_pcb *pcb, u8_t interval,\r
+                err_t (* poll)(void *arg, struct tcp_pcb *tpcb))\r
+\r
+  Specifies the polling interval and the callback function that should\r
+  be called to poll the application. The interval is specified in\r
+  number of TCP coarse grained timer shots, which typically occurs\r
+  twice a second. An interval of 10 means that the application would\r
+  be polled every 5 seconds.\r
+\r
+\r
+--- Closing and aborting connections\r
+\r
+- err_t tcp_close(struct tcp_pcb *pcb)\r
+\r
+  Closes the connection. The function may return ERR_MEM if no memory\r
+  was available for closing the connection. If so, the application\r
+  should wait and try again either by using the acknowledgment\r
+  callback or the polling functionality. If the close succeeds, the\r
+  function returns ERR_OK.\r
+\r
+  The pcb is deallocated by the TCP code after a call to tcp_close(). \r
+\r
+- void tcp_abort(struct tcp_pcb *pcb)\r
+\r
+  Aborts the connection by sending a RST (reset) segment to the remote\r
+  host. The pcb is deallocated. This function never fails.\r
+\r
+If a connection is aborted because of an error, the application is\r
+alerted of this event by the err callback. Errors that might abort a\r
+connection are when there is a shortage of memory. The callback\r
+function to be called is set using the tcp_err() function.\r
+\r
+- void tcp_err(struct tcp_pcb *pcb, void (* err)(void *arg,\r
+       err_t err))\r
+\r
+  The error callback function does not get the pcb passed to it as a\r
+  parameter since the pcb may already have been deallocated.\r
+\r
+\r
+--- Lower layer TCP interface\r
+\r
+TCP provides a simple interface to the lower layers of the\r
+system. During system initialization, the function tcp_init() has\r
+to be called before any other TCP function is called. When the system\r
+is running, the two timer functions tcp_fasttmr() and tcp_slowtmr()\r
+must be called with regular intervals. The tcp_fasttmr() should be\r
+called every TCP_FAST_INTERVAL milliseconds (defined in tcp.h) and\r
+tcp_slowtmr() should be called every TCP_SLOW_INTERVAL milliseconds. \r
+\r
+\r
+--- UDP interface\r
+\r
+The UDP interface is similar to that of TCP, but due to the lower\r
+level of complexity of UDP, the interface is significantly simpler.\r
+\r
+- struct udp_pcb *udp_new(void)\r
+\r
+  Creates a new UDP pcb which can be used for UDP communication. The\r
+  pcb is not active until it has either been bound to a local address\r
+  or connected to a remote address.\r
+\r
+- void udp_remove(struct udp_pcb *pcb)\r
+\r
+  Removes and deallocates the pcb.  \r
+  \r
+- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port)\r
+\r
+  Binds the pcb to a local address. The IP-address argument "ipaddr"\r
+  can be IP_ADDR_ANY to indicate that it should listen to any local IP\r
+  address. The function currently always return ERR_OK.\r
+\r
+- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                    u16_t port)\r
+\r
+  Sets the remote end of the pcb. This function does not generate any\r
+  network traffic, but only set the remote address of the pcb.\r
+\r
+- err_t udp_disconnect(struct udp_pcb *pcb)\r
+\r
+  Remove the remote end of the pcb. This function does not generate\r
+  any network traffic, but only removes the remote address of the pcb.\r
+\r
+- err_t udp_send(struct udp_pcb *pcb, struct pbuf *p)\r
+\r
+  Sends the pbuf p. The pbuf is not deallocated.\r
+\r
+- void udp_recv(struct udp_pcb *pcb,\r
+                void (* recv)(void *arg, struct udp_pcb *upcb,\r
+                                         struct pbuf *p,\r
+                                         struct ip_addr *addr,\r
+                                         u16_t port),\r
+                              void *recv_arg)\r
+\r
+  Specifies a callback function that should be called when a UDP\r
+  datagram is received.\r
+  \r
+\r
+--- System initalization\r
+\r
+A truly complete and generic sequence for initializing the lwip stack\r
+cannot be given because it depends on the build configuration (lwipopts.h)\r
+and additional initializations for your runtime environment (e.g. timers).\r
+\r
+We can give you some idea on how to proceed when using the raw API.\r
+We assume a configuration using a single Ethernet netif and the\r
+UDP and TCP transport layers, IPv4 and the DHCP client.\r
+\r
+Call these functions in the order of appearance:\r
+\r
+- stats_init()\r
+\r
+  Clears the structure where runtime statistics are gathered.\r
+\r
+- sys_init()\r
+  \r
+  Not of much use since we set the NO_SYS 1 option in lwipopts.h,\r
+  to be called for easy configuration changes.\r
+\r
+- mem_init()\r
+\r
+  Initializes the dynamic memory heap defined by MEM_SIZE.\r
+\r
+- memp_init()\r
+\r
+  Initializes the memory pools defined by MEMP_NUM_x.\r
+\r
+- pbuf_init()\r
+\r
+  Initializes the pbuf memory pool defined by PBUF_POOL_SIZE.\r
+  \r
+- etharp_init()\r
+\r
+  Initializes the ARP table and queue.\r
+  Note: you must call etharp_tmr at a ARP_TMR_INTERVAL (5 seconds) regular interval\r
+  after this initialization.\r
+\r
+- ip_init()\r
+\r
+  Doesn't do much, it should be called to handle future changes.\r
+\r
+- udp_init()\r
+\r
+  Clears the UDP PCB list.\r
+\r
+- tcp_init()\r
+\r
+  Clears the TCP PCB list and clears some internal TCP timers.\r
+  Note: you must call tcp_fasttmr() and tcp_slowtmr() at the\r
+  predefined regular intervals after this initialization. \r
+  \r
+- netif_add(struct netif *netif, struct ip_addr *ipaddr,\r
+            struct ip_addr *netmask, struct ip_addr *gw,\r
+            void *state, err_t (* init)(struct netif *netif),\r
+            err_t (* input)(struct pbuf *p, struct netif *netif))\r
+\r
+  Adds your network interface to the netif_list. Allocate a struct\r
+  netif and pass a pointer to this structure as the first argument.\r
+  Give pointers to cleared ip_addr structures when using DHCP,\r
+  or fill them with sane numbers otherwise. The state pointer may be NULL.\r
+\r
+  The init function pointer must point to a initialization function for\r
+  your ethernet netif interface. The following code illustrates it's use.\r
+  \r
+  err_t netif_if_init(struct netif *netif)\r
+  {\r
+    u8_t i;\r
+    \r
+    for(i = 0; i < ETHARP_HWADDR_LEN; i++) netif->hwaddr[i] = some_eth_addr[i];\r
+    init_my_eth_device();\r
+    return ERR_OK;\r
+  }\r
+  \r
+  For ethernet drivers, the input function pointer must point to the lwip\r
+  function ethernet_input() declared in "netif/etharp.h". Other drivers\r
+  must use ip_input() declared in "lwip/ip.h".\r
+  \r
+- netif_set_default(struct netif *netif)\r
+\r
+  Registers the default network interface.\r
+\r
+- netif_set_up(struct netif *netif)\r
+\r
+  When the netif is fully configured this function must be called.\r
+\r
+- dhcp_start(struct netif *netif)\r
+\r
+  Creates a new DHCP client for this interface on the first call.\r
+  Note: you must call dhcp_fine_tmr() and dhcp_coarse_tmr() at\r
+  the predefined regular intervals after starting the client.\r
+  \r
+  You can peek in the netif->dhcp struct for the actual DHCP status.\r
+\r
+\r
+--- Optimalization hints\r
+\r
+The first thing you want to optimize is the lwip_standard_checksum()\r
+routine from src/core/inet.c. You can override this standard\r
+function with the #define LWIP_CHKSUM <your_checksum_routine>.\r
+\r
+There are C examples given in inet.c or you might want to\r
+craft an assembly function for this. RFC1071 is a good\r
+introduction to this subject.\r
+\r
+Other significant improvements can be made by supplying\r
+assembly or inline replacements for htons() and htonl()\r
+if you're using a little-endian architecture.\r
+#define LWIP_PLATFORM_BYTESWAP 1\r
+#define LWIP_PLATFORM_HTONS(x) <your_htons>\r
+#define LWIP_PLATFORM_HTONL(x) <your_htonl>\r
+\r
+Check your network interface driver if it reads at\r
+a higher speed than the maximum wire-speed. If the\r
+hardware isn't serviced frequently and fast enough\r
+buffer overflows are likely to occur.\r
+\r
+E.g. when using the cs8900 driver, call cs8900if_service(ethif)\r
+as frequently as possible. When using an RTOS let the cs8900 interrupt\r
+wake a high priority task that services your driver using a binary\r
+semaphore or event flag. Some drivers might allow additional tuning\r
+to match your application and network.\r
+\r
+For a production release it is recommended to set LWIP_STATS to 0.\r
+Note that speed performance isn't influenced much by simply setting\r
+high values to the memory options.\r
diff --git a/Demo/Common/ethernet/lwIP_130/doc/savannah.txt b/Demo/Common/ethernet/lwIP_130/doc/savannah.txt
new file mode 100644 (file)
index 0000000..b4c6acb
--- /dev/null
@@ -0,0 +1,135 @@
+Daily Use Guide for using Savannah for lwIP\r
+\r
+Table of Contents:\r
+\r
+1 - Obtaining lwIP from the CVS repository\r
+2 - Committers/developers CVS access using SSH (to be written)\r
+3 - Merging from DEVEL branch to main trunk (stable branch)\r
+4 - How to release lwIP\r
+\r
+\r
+\r
+1 Obtaining lwIP from the CVS repository\r
+----------------------------------------\r
+\r
+To perform an anonymous CVS checkout of the main trunk (this is where\r
+bug fixes and incremental enhancements occur), do this:\r
+\r
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout lwip\r
\r
+Or, obtain a stable branch (updated with bug fixes only) as follows:\r
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \\r
+  -r STABLE-0_7 -d lwip-0.7 lwip\r
+\r
+Or, obtain a specific (fixed) release as follows:\r
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \\r
+  -r STABLE-0_7_0 -d lwip-0.7.0 lwip\r
+\r
+3 Committers/developers CVS access using SSH\r
+--------------------------------------------\r
+\r
+The Savannah server uses SSH (Secure Shell) protocol 2 authentication and encryption.\r
+As such, CVS commits to the server occur through a SSH tunnel for project members.\r
+To create a SSH2 key pair in UNIX-like environments, do this:\r
+\r
+ssh-keygen -t dsa\r
+\r
+Under Windows, a recommended SSH client is "PuTTY", freely available with good\r
+documentation and a graphic user interface. Use its key generator.\r
+\r
+Now paste the id_dsa.pub contents into your Savannah account public key list. Wait\r
+a while so that Savannah can update its configuration (This can take minutes).\r
+\r
+Try to login using SSH:\r
+\r
+ssh -v your_login@cvs.sv.gnu.org\r
+\r
+If it tells you:\r
+\r
+Authenticating with public key "your_key_name"...\r
+Server refused to allocate pty\r
+\r
+then you could login; Savannah refuses to give you a shell - which is OK, as we\r
+are allowed to use SSH for CVS only. Now, you should be able to do this:\r
+\r
+export CVS_RSH=ssh\r
+cvs -z3 -d:ext:your_login@cvs.sv.gnu.org:/sources/lwip co lwip\r
\r
+after which you can edit your local files with bug fixes or new features and\r
+commit them. Make sure you know what you are doing when using CVS to make\r
+changes on the repository. If in doubt, ask on the lwip-members mailing list.\r
+\r
+(If SSH asks about authenticity of the host, you can check the key\r
+ fingerprint against http://savannah.nongnu.org/cvs/?group=lwip)\r
+\r
+\r
+3 Merging from DEVEL branch to main trunk (stable)\r
+--------------------------------------------------\r
+\r
+Merging is a delicate process in CVS and requires the\r
+following disciplined steps in order to prevent conflicts\r
+in the future. Conflicts can be hard to solve!\r
+\r
+Merging from branch A to branch B requires that the A branch\r
+has a tag indicating the previous merger. This tag is called\r
+'merged_from_A_to_B'. After merging, the tag is moved in the\r
+A branch to remember this merger for future merge actions.\r
+\r
+IMPORTANT: AFTER COMMITTING A SUCCESFUL MERGE IN THE\r
+REPOSITORY, THE TAG MUST BE SET ON THE SOURCE BRANCH OF THE\r
+MERGE ACTION (REPLACING EXISTING TAGS WITH THE SAME NAME).\r
+\r
+Merge all changes in DEVEL since our last merge to main:\r
+\r
+In the working copy of the main trunk:\r
+cvs update -P -jmerged_from_DEVEL_to_main -jDEVEL \r
+\r
+(This will apply the changes between 'merged_from_DEVEL_to_main'\r
+and 'DEVEL' to your work set of files)\r
+\r
+We can now commit the merge result.\r
+cvs commit -R -m "Merged from DEVEL to main." \r
+\r
+If this worked out OK, we now move the tag in the DEVEL branch\r
+to this merge point, so we can use this point for future merges:\r
+\r
+cvs rtag -F -r DEVEL merged_from_DEVEL_to_main lwip \r
+\r
+4 How to release lwIP\r
+---------------------\r
+\r
+First, checkout a clean copy of the branch to be released. Tag this set with\r
+tag name "STABLE-0_6_3". (I use release number 0.6.3 throughout this example).\r
+\r
+Login CVS using pserver authentication, then export a clean copy of the\r
+tagged tree. Export is similar to a checkout, except that the CVS metadata\r
+is not created locally. \r
+\r
+export CVS_RSH=ssh\r
+cvs -z3 -d:pserver:anonymous@cvs.sv.gnu.org:/sources/lwip checkout \\r
+  -r STABLE-0_6_3 -d lwip-0.6.3 lwip\r
+\r
+Archive this directory using tar, gzip'd, bzip2'd and zip'd.\r
+\r
+tar czvf lwip-0.6.3.tar.gz lwip-0.6.3\r
+tar cjvf lwip-0.6.3.tar.bz2 lwip-0.6.3\r
+zip -r lwip-0.6.3.zip lwip-0.6.3\r
+\r
+Now, sign the archives with a detached GPG binary signature as follows:\r
+\r
+gpg -b lwip-0.6.3.tar.gz\r
+gpg -b lwip-0.6.3.tar.bz2\r
+gpg -b lwip-0.6.3.zip\r
+\r
+Upload these files using anonymous FTP:\r
+ncftp ftp://savannah.gnu.org/incoming/savannah/lwip\r
+\r
+ncftp>mput *0.6.3.*\r
+\r
+Additionally, you may post a news item on Savannah, like this:\r
+\r
+A new 0.6.3 release is now available here:\r
+http://savannah.nongnu.org/files/?group=lwip&highlight=0.6.3\r
+\r
+You will have to submit this via the user News interface, then approve\r
+this via the Administrator News interface.
\ No newline at end of file
diff --git a/Demo/Common/ethernet/lwIP_130/doc/snmp_agent.txt b/Demo/Common/ethernet/lwIP_130/doc/snmp_agent.txt
new file mode 100644 (file)
index 0000000..54c278a
--- /dev/null
@@ -0,0 +1,181 @@
+SNMPv1 agent for lwIP\r
+\r
+Author: Christiaan Simons\r
+\r
+This is a brief introduction how to use and configure the SNMP agent.\r
+Note the agent uses the raw-API UDP interface so you may also want to\r
+read rawapi.txt to gain a better understanding of the SNMP message handling.\r
+\r
+0 Agent Capabilities\r
+====================\r
+\r
+SNMPv1 per RFC1157\r
+  This is an old(er) standard but is still widely supported.\r
+  For SNMPv2c and v3 have a greater complexity and need many\r
+  more lines of code. IMHO this breaks the idea of "lightweight IP".\r
+\r
+  Note the S in SNMP stands for "Simple". Note that "Simple" is\r
+  relative. SNMP is simple compared to the complex ISO network\r
+  management protocols CMIP (Common Management Information Protocol)\r
+  and CMOT (CMip Over Tcp).\r
+\r
+MIB II per RFC1213\r
+  The standard lwIP stack management information base.\r
+  This is a required MIB, so this is always enabled.\r
+  When builing lwIP without TCP, the mib-2.tcp group is omitted.\r
+  The groups EGP, CMOT and transmission are disabled by default.\r
+  \r
+  Most mib-2 objects are not writable except:\r
+  sysName, sysLocation, sysContact, snmpEnableAuthenTraps.\r
+  Writing to or changing the ARP and IP address and route\r
+  tables is not possible.\r
\r
+  Note lwIP has a very limited notion of IP routing. It currently\r
+  doen't have a route table and doesn't have a notion of the U,G,H flags.\r
+  Instead lwIP uses the interface list with only one default interface\r
+  acting as a single gateway interface (G) for the default route.\r
+\r
+  The agent returns a "virtual table" with the default route 0.0.0.0\r
+  for the default interface and network routes (no H) for each\r
+  network interface in the netif_list.\r
+  All routes are considered to be up (U).\r
+\r
+Loading additional MIBs\r
+  MIBs can only be added in compile-time, not in run-time.\r
+  There is no MIB compiler thus additional MIBs must be hand coded.\r
+\r
+Large SNMP message support\r
+  The packet decoding and encoding routines are designed\r
+  to use pbuf-chains. Larger payloads then the minimum\r
+  SNMP requirement of 484 octets are supported if the \r
+  PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your\r
+  local requirement.\r
+\r
+1 Building the Agent\r
+====================\r
+\r
+First of all you'll need to add the following define\r
+to your local lwipopts.h:\r
+\r
+#define LWIP_SNMP               1\r
+\r
+and add the source files in lwip/src/core/snmp\r
+and some snmp headers in lwip/src/include/lwip to your makefile.\r
+\r
+Note you'll might need to adapt you network driver to update\r
+the mib2 variables for your interface.\r
+\r
+2 Running the Agent\r
+===================\r
+\r
+The following function calls must be made in your program to\r
+actually get the SNMP agent running.\r
+\r
+Before starting the agent you should supply pointers\r
+to non-volatile memory for sysContact, sysLocation,\r
+and snmpEnableAuthenTraps. You can do this by calling\r
+\r
+snmp_set_syscontact()\r
+snmp_set_syslocation()\r
+snmp_set_snmpenableauthentraps()\r
+\r
+Additionally you may want to set\r
+\r
+snmp_set_sysdescr()\r
+snmp_set_sysobjid() (if you have a private MIB)\r
+snmp_set_sysname()\r
+\r
+Also before starting the agent you need to setup\r
+one or more trap destinations using these calls:\r
+\r
+snmp_trap_dst_enable();\r
+snmp_trap_dst_ip_set();\r
+\r
+In the lwIP initialisation sequence call snmp_init() just after\r
+the call to udp_init().\r
+\r
+Exactly every 10 msec the SNMP uptime timestamp must be updated with\r
+snmp_inc_sysuptime(). You should call this from a timer interrupt\r
+or a timer signal handler depending on your runtime environment.\r
+\r
+An alternative way to update the SNMP uptime timestamp is to do a call like\r
+snmp_add_sysuptime(100) each 1000ms (which is bigger "step", but call to\r
+a lower frequency). Another one is to not call snmp_inc_sysuptime() or\r
+snmp_add_sysuptime(), and to define the SNMP_GET_SYSUPTIME(sysuptime) macro.\r
+This one is undefined by default in mib2.c. SNMP_GET_SYSUPTIME is called inside\r
+snmp_get_sysuptime(u32_t *value), and enable to change "sysuptime" value only\r
+when it's queried (any function which need "sysuptime" have to call\r
+snmp_get_sysuptime).\r
+\r
+\r
+3 Private MIBs\r
+==============\r
+\r
+If want to extend the agent with your own private MIB you'll need to\r
+add the following define to your local lwipopts.h:\r
+\r
+#define SNMP_PRIVATE_MIB        1\r
+\r
+You must provide the private_mib.h and associated files yourself.\r
+Note we don't have a "MIB compiler" that generates C source from a MIB,\r
+so you're required to do some serious coding if you enable this!\r
+\r
+Note the lwIP enterprise ID (26381) is assigned to the lwIP project,\r
+ALL OBJECT IDENTIFIERS LIVING UNDER THIS ID ARE ASSIGNED BY THE lwIP\r
+MAINTAINERS!\r
+\r
+If you need to create your own private MIB you'll need\r
+to apply for your own enterprise ID with IANA: http://www.iana.org/numbers.html \r
+\r
+You can set it by passing a struct snmp_obj_id to the agent\r
+using snmp_set_sysobjid(&my_object_id), just before snmp_init().\r
+\r
+Note the object identifiers for thes MIB-2 and your private MIB\r
+tree must be kept in sorted ascending (lexicographical) order.\r
+This to ensure correct getnext operation.\r
+\r
+An example for a private MIB is part of the "minimal Unix" project:\r
+contrib/ports/unix/proj/minimal/lwip_prvmib.c\r
+\r
+The next chapter gives a more detailed description of the\r
+MIB-2 tree and the optional private MIB.\r
+\r
+4 The Gory Details\r
+==================\r
+\r
+4.0 Object identifiers and the MIB tree.\r
+\r
+We have three distinct parts for all object identifiers:\r
+\r
+The prefix\r
+  .iso.org.dod.internet\r
+\r
+the middle part \r
+  .mgmt.mib-2.ip.ipNetToMediaTable.ipNetToMediaEntry.ipNetToMediaPhysAddress\r
+\r
+and the index part\r
+  .1.192.168.0.1\r
+\r
+Objects located above the .internet hierarchy aren't supported.\r
+Currently only the .mgmt sub-tree is available and\r
+when the SNMP_PRIVATE_MIB is enabled the .private tree\r
+becomes available too.\r
+\r
+Object identifiers from incoming requests are checked\r
+for a matching prefix, middle part and index part\r
+or are expanded(*) for GetNext requests with short\r
+or inexisting names in the request.\r
+(* we call this "expansion" but this also\r
+resembles the "auto-completion" operation)\r
+\r
+The middle part is usually located in ROM (const)\r
+to preserve precious RAM on small microcontrollers.\r
+However RAM location is possible for an dynamically\r
+changing private tree.\r
+\r
+The index part is handled by functions which in\r
+turn use dynamically allocated index trees from RAM.\r
+These trees are updated by e.g. the etharp code\r
+when new entries are made or removed form the ARP cache.\r
+\r
+/** @todo more gory details */\r
diff --git a/Demo/Common/ethernet/lwIP_130/doc/sys_arch.txt b/Demo/Common/ethernet/lwIP_130/doc/sys_arch.txt
new file mode 100644 (file)
index 0000000..bc68096
--- /dev/null
@@ -0,0 +1,226 @@
+sys_arch interface for lwIP 0.6++\r
+\r
+Author: Adam Dunkels\r
+\r
+The operating system emulation layer provides a common interface\r
+between the lwIP code and the underlying operating system kernel. The\r
+general idea is that porting lwIP to new architectures requires only\r
+small changes to a few header files and a new sys_arch\r
+implementation. It is also possible to do a sys_arch implementation\r
+that does not rely on any underlying operating system.\r
+\r
+The sys_arch provides semaphores and mailboxes to lwIP. For the full\r
+lwIP functionality, multiple threads support can be implemented in the\r
+sys_arch, but this is not required for the basic lwIP\r
+functionality. Previous versions of lwIP required the sys_arch to\r
+implement timer scheduling as well but as of lwIP 0.5 this is\r
+implemented in a higher layer.\r
+\r
+In addition to the source file providing the functionality of sys_arch,\r
+the OS emulation layer must provide several header files defining\r
+macros used throughout lwip.  The files required and the macros they\r
+must define are listed below the sys_arch description.\r
+\r
+Semaphores can be either counting or binary - lwIP works with both\r
+kinds. Mailboxes are used for message passing and can be implemented\r
+either as a queue which allows multiple messages to be posted to a\r
+mailbox, or as a rendez-vous point where only one message can be\r
+posted at a time. lwIP works with both kinds, but the former type will\r
+be more efficient. A message in a mailbox is just a pointer, nothing\r
+more. \r
+\r
+Semaphores are represented by the type "sys_sem_t" which is typedef'd\r
+in the sys_arch.h file. Mailboxes are equivalently represented by the\r
+type "sys_mbox_t". lwIP does not place any restrictions on how\r
+sys_sem_t or sys_mbox_t are represented internally.\r
+\r
+The following functions must be implemented by the sys_arch:\r
+\r
+- void sys_init(void)\r
+\r
+  Is called to initialize the sys_arch layer.\r
+\r
+- sys_sem_t sys_sem_new(u8_t count)\r
+\r
+  Creates and returns a new semaphore. The "count" argument specifies\r
+  the initial state of the semaphore.\r
+\r
+- void sys_sem_free(sys_sem_t sem)\r
+\r
+  Deallocates a semaphore.\r
+\r
+- void sys_sem_signal(sys_sem_t sem)\r
+\r
+  Signals a semaphore.\r
+\r
+- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)\r
+\r
+  Blocks the thread while waiting for the semaphore to be\r
+  signaled. If the "timeout" argument is non-zero, the thread should\r
+  only be blocked for the specified time (measured in\r
+  milliseconds). If the "timeout" argument is zero, the thread should be\r
+  blocked until the semaphore is signalled.\r
+\r
+  If the timeout argument is non-zero, the return value is the number of\r
+  milliseconds spent waiting for the semaphore to be signaled. If the\r
+  semaphore wasn't signaled within the specified time, the return value is\r
+  SYS_ARCH_TIMEOUT. If the thread didn't have to wait for the semaphore\r
+  (i.e., it was already signaled), the function may return zero.\r
+\r
+  Notice that lwIP implements a function with a similar name,\r
+  sys_sem_wait(), that uses the sys_arch_sem_wait() function.\r
+\r
+- sys_mbox_t sys_mbox_new(int size)\r
+\r
+  Creates an empty mailbox for maximum "size" elements. Elements stored\r
+  in mailboxes are pointers. You have to define macros "_MBOX_SIZE"\r
+  in your lwipopts.h, or ignore this parameter in your implementation\r
+  and use a default size.\r
+\r
+- void sys_mbox_free(sys_mbox_t mbox)\r
+\r
+  Deallocates a mailbox. If there are messages still present in the\r
+  mailbox when the mailbox is deallocated, it is an indication of a\r
+  programming error in lwIP and the developer should be notified.\r
+\r
+- void sys_mbox_post(sys_mbox_t mbox, void *msg)\r
+\r
+  Posts the "msg" to the mailbox. This function have to block until\r
+  the "msg" is really posted.\r
+\r
+- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)\r
+\r
+  Try to post the "msg" to the mailbox. Returns ERR_MEM if this one\r
+  is full, else, ERR_OK if the "msg" is posted.\r
+\r
+- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)\r
+\r
+  Blocks the thread until a message arrives in the mailbox, but does\r
+  not block the thread longer than "timeout" milliseconds (similar to\r
+  the sys_arch_sem_wait() function). If "timeout" is 0, the thread should\r
+  be blocked until a message arrives. The "msg" argument is a result\r
+  parameter that is set by the function (i.e., by doing "*msg =\r
+  ptr"). The "msg" parameter maybe NULL to indicate that the message\r
+  should be dropped.\r
+\r
+  The return values are the same as for the sys_arch_sem_wait() function:\r
+  Number of milliseconds spent waiting or SYS_ARCH_TIMEOUT if there was a\r
+  timeout.\r
+\r
+  Note that a function with a similar name, sys_mbox_fetch(), is\r
+  implemented by lwIP. \r
+\r
+- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)\r
+\r
+  This is similar to sys_arch_mbox_fetch, however if a message is not\r
+  present in the mailbox, it immediately returns with the code\r
+  SYS_MBOX_EMPTY. On success 0 is returned.\r
+\r
+  To allow for efficient implementations, this can be defined as a\r
+  function-like macro in sys_arch.h instead of a normal function. For\r
+  example, a naive implementation could be:\r
+    #define sys_arch_mbox_tryfetch(mbox,msg) \\r
+      sys_arch_mbox_fetch(mbox,msg,1)\r
+  although this would introduce unnecessary delays.\r
+  \r
+- struct sys_timeouts *sys_arch_timeouts(void)\r
+\r
+  Returns a pointer to the per-thread sys_timeouts structure. In lwIP,\r
+  each thread has a list of timeouts which is repressented as a linked\r
+  list of sys_timeout structures. The sys_timeouts structure holds a\r
+  pointer to a linked list of timeouts. This function is called by\r
+  the lwIP timeout scheduler and must not return a NULL value. \r
+\r
+  In a single thread sys_arch implementation, this function will\r
+  simply return a pointer to a global sys_timeouts variable stored in\r
+  the sys_arch module.\r
+  \r
+If threads are supported by the underlying operating system and if\r
+such functionality is needed in lwIP, the following function will have\r
+to be implemented as well:\r
+\r
+- sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio)\r
+\r
+  Starts a new thread named "name" with priority "prio" that will begin its\r
+  execution in the function "thread()". The "arg" argument will be passed as an\r
+  argument to the thread() function. The stack size to used for this thread is\r
+  the "stacksize" parameter. The id of the new thread is returned. Both the id\r
+  and the priority are system dependent.\r
+\r
+- sys_prot_t sys_arch_protect(void)\r
+\r
+  This optional function does a "fast" critical region protection and returns\r
+  the previous protection level. This function is only called during very short\r
+  critical regions. An embedded system which supports ISR-based drivers might\r
+  want to implement this function by disabling interrupts. Task-based systems\r
+  might want to implement this by using a mutex or disabling tasking. This\r
+  function should support recursive calls from the same task or interrupt. In\r
+  other words, sys_arch_protect() could be called while already protected. In\r
+  that case the return value indicates that it is already protected.\r
+\r
+  sys_arch_protect() is only required if your port is supporting an operating\r
+  system.\r
+\r
+- void sys_arch_unprotect(sys_prot_t pval)\r
+\r
+  This optional function does a "fast" set of critical region protection to the\r
+  value specified by pval. See the documentation for sys_arch_protect() for\r
+  more information. This function is only required if your port is supporting\r
+  an operating system.\r
+\r
+Note:\r
+\r
+Be carefull with using mem_malloc() in sys_arch. When malloc() refers to\r
+mem_malloc() you can run into a circular function call problem. In mem.c\r
+mem_init() tries to allcate a semaphore using mem_malloc, which of course\r
+can't be performed when sys_arch uses mem_malloc.\r
+\r
+-------------------------------------------------------------------------------\r
+Additional files required for the "OS support" emulation layer:\r
+-------------------------------------------------------------------------------\r
+\r
+cc.h       - Architecture environment, some compiler specific, some\r
+             environment specific (probably should move env stuff \r
+             to sys_arch.h.)\r
+\r
+  Typedefs for the types used by lwip -\r
+    u8_t, s8_t, u16_t, s16_t, u32_t, s32_t, mem_ptr_t\r
+\r
+  Compiler hints for packing lwip's structures -\r
+    PACK_STRUCT_FIELD(x)\r
+    PACK_STRUCT_STRUCT\r
+    PACK_STRUCT_BEGIN\r
+    PACK_STRUCT_END\r
+\r
+  Platform specific diagnostic output -\r
+    LWIP_PLATFORM_DIAG(x)    - non-fatal, print a message.\r
+    LWIP_PLATFORM_ASSERT(x)  - fatal, print message and abandon execution.\r
+\r
+  "lightweight" synchronization mechanisms -\r
+    SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.\r
+    SYS_ARCH_PROTECT(x)      - enter protection mode.\r
+    SYS_ARCH_UNPROTECT(x)    - leave protection mode.\r
+\r
+  If the compiler does not provide memset() this file must include a\r
+  definition of it, or include a file which defines it.\r
+\r
+  This file must either include a system-local <errno.h> which defines\r
+  the standard *nix error codes, or it should #define LWIP_PROVIDE_ERRNO\r
+  to make lwip/arch.h define the codes which are used throughout.\r
+\r
+\r
+perf.h     - Architecture specific performance measurement.\r
+  Measurement calls made throughout lwip, these can be defined to nothing.\r
+    PERF_START               - start measuring something.\r
+    PERF_STOP(x)             - stop measuring something, and record the result.\r
+\r
+sys_arch.h - Tied to sys_arch.c\r
+\r
+  Arch dependent types for the following objects:\r
+    sys_sem_t, sys_mbox_t, sys_thread_t,\r
+  And, optionally:\r
+    sys_prot_t\r
+\r
+  Defines to set vars of sys_mbox_t and sys_sem_t to NULL.\r
+    SYS_MBOX_NULL NULL\r
+    SYS_SEM_NULL NULL\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/FILES b/Demo/Common/ethernet/lwIP_130/src/FILES
new file mode 100644 (file)
index 0000000..10115a7
--- /dev/null
@@ -0,0 +1,13 @@
+api/      - The code for the high-level wrapper API. Not needed if\r
+            you use the lowel-level call-back/raw API.\r
+\r
+core/     - The core of the TPC/IP stack; protocol implementations,\r
+            memory and buffer management, and the low-level raw API.\r
+\r
+include/  - lwIP include files.\r
+\r
+netif/    - Generic network interface device drivers are kept here,\r
+            as well as the ARP module.\r
+\r
+For more information on the various subdirectories, check the FILES\r
+file in each directory.\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/api_lib.c b/Demo/Common/ethernet/lwIP_130/src/api/api_lib.c
new file mode 100644 (file)
index 0000000..36d52f9
--- /dev/null
@@ -0,0 +1,570 @@
+/**\r
+ * @file\r
+ * Sequential API External module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* This is the part of the API that is linked with\r
+   the application */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/api.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/memp.h"\r
+\r
+#include "lwip/ip.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include <string.h>\r
+\r
+/**\r
+ * Create a new netconn (of a specific type) that has a callback function.\r
+ * The corresponding pcb is also created.\r
+ *\r
+ * @param t the type of 'connection' to create (@see enum netconn_type)\r
+ * @param proto the IP protocol for RAW IP pcbs\r
+ * @param callback a function to call on status changes (RX available, TX'ed)\r
+ * @return a newly allocated struct netconn or\r
+ *         NULL on memory error\r
+ */\r
+struct netconn*\r
+netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_callback callback)\r
+{\r
+  struct netconn *conn;\r
+  struct api_msg msg;\r
+\r
+  conn = netconn_alloc(t, callback);\r
+  if (conn != NULL ) {\r
+    msg.function = do_newconn;\r
+    msg.msg.msg.n.proto = proto;\r
+    msg.msg.conn = conn;\r
+    TCPIP_APIMSG(&msg);\r
+\r
+    if (conn->err != ERR_OK) {\r
+      LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL);\r
+      LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL);\r
+      LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL);\r
+      LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL);\r
+      sys_sem_free(conn->op_completed);\r
+      sys_mbox_free(conn->recvmbox);\r
+      memp_free(MEMP_NETCONN, conn);\r
+      return NULL;\r
+    }\r
+  }\r
+  return conn;\r
+}\r
+\r
+/**\r
+ * Close a netconn 'connection' and free its resources.\r
+ * UDP and RAW connection are completely closed, TCP pcbs might still be in a waitstate\r
+ * after this returns.\r
+ *\r
+ * @param conn the netconn to delete\r
+ * @return ERR_OK if the connection was deleted\r
+ */\r
+err_t\r
+netconn_delete(struct netconn *conn)\r
+{\r
+  struct api_msg msg;\r
+\r
+  /* No ASSERT here because possible to get a (conn == NULL) if we got an accept error */\r
+  if (conn == NULL) {\r
+    return ERR_OK;\r
+  }\r
+\r
+  msg.function = do_delconn;\r
+  msg.msg.conn = conn;\r
+  tcpip_apimsg(&msg);\r
+\r
+  conn->pcb.tcp = NULL;\r
+  netconn_free(conn);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Get the type of a netconn (as enum netconn_type).\r
+ *\r
+ * @param conn the netconn of which to get the type\r
+ * @return the netconn_type of conn\r
+ */\r
+enum netconn_type\r
+netconn_type(struct netconn *conn)\r
+{\r
+  LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);\r
+  return conn->type;\r
+}\r
+\r
+/**\r
+ * Get the local or remote IP address and port of a netconn.\r
+ * For RAW netconns, this returns the protocol instead of a port!\r
+ *\r
+ * @param conn the netconn to query\r
+ * @param addr a pointer to which to save the IP address\r
+ * @param port a pointer to which to save the port (or protocol for RAW)\r
+ * @param local 1 to get the local IP address, 0 to get the remote one\r
+ * @return ERR_CONN for invalid connections\r
+ *         ERR_OK if the information was retrieved\r
+ */\r
+err_t\r
+netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_getaddr;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.ad.ipaddr = addr;\r
+  msg.msg.msg.ad.port = port;\r
+  msg.msg.msg.ad.local = local;\r
+  TCPIP_APIMSG(&msg);\r
+\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Bind a netconn to a specific local IP address and port.\r
+ * Binding one netconn twice might not always be checked correctly!\r
+ *\r
+ * @param conn the netconn to bind\r
+ * @param addr the local IP address to bind the netconn to (use IP_ADDR_ANY\r
+ *             to bind to all addresses)\r
+ * @param port the local port to bind the netconn to (not used for RAW)\r
+ * @return ERR_OK if bound, any other err_t on failure\r
+ */\r
+err_t\r
+netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_bind;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.bc.ipaddr = addr;\r
+  msg.msg.msg.bc.port = port;\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Connect a netconn to a specific remote IP address and port.\r
+ *\r
+ * @param conn the netconn to connect\r
+ * @param addr the remote IP address to connect to\r
+ * @param port the remote port to connect to (no used for RAW)\r
+ * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise\r
+ */\r
+err_t\r
+netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_connect;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.bc.ipaddr = addr;\r
+  msg.msg.msg.bc.port = port;\r
+  /* This is the only function which need to not block tcpip_thread */\r
+  tcpip_apimsg(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Disconnect a netconn from its current peer (only valid for UDP netconns).\r
+ *\r
+ * @param conn the netconn to disconnect\r
+ * @return TODO: return value is not set here...\r
+ */\r
+err_t\r
+netconn_disconnect(struct netconn *conn)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_disconnect;\r
+  msg.msg.conn = conn;\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Set a TCP netconn into listen mode\r
+ *\r
+ * @param conn the tcp netconn to set to listen mode\r
+ * @param backlog the listen backlog, only used if TCP_LISTEN_BACKLOG==1\r
+ * @return ERR_OK if the netconn was set to listen (UDP and RAW netconns\r
+ *         don't return any error (yet?))\r
+ */\r
+err_t\r
+netconn_listen_with_backlog(struct netconn *conn, u8_t backlog)\r
+{\r
+  struct api_msg msg;\r
+\r
+  /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */\r
+  LWIP_UNUSED_ARG(backlog);\r
+\r
+  LWIP_ERROR("netconn_listen: invalid conn", (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_listen;\r
+  msg.msg.conn = conn;\r
+#if TCP_LISTEN_BACKLOG\r
+  msg.msg.msg.lb.backlog = backlog;\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Accept a new connection on a TCP listening netconn.\r
+ *\r
+ * @param conn the TCP listen netconn\r
+ * @return the newly accepted netconn or NULL on timeout\r
+ */\r
+struct netconn *\r
+netconn_accept(struct netconn *conn)\r
+{\r
+  struct netconn *newconn;\r
+\r
+  LWIP_ERROR("netconn_accept: invalid conn",       (conn != NULL),                      return NULL;);\r
+  LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);\r
+\r
+#if LWIP_SO_RCVTIMEO\r
+  if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {\r
+    newconn = NULL;\r
+  } else\r
+#else\r
+  sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);\r
+#endif /* LWIP_SO_RCVTIMEO*/\r
+  {\r
+    /* Register event with callback */\r
+    API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);\r
+\r
+#if TCP_LISTEN_BACKLOG\r
+    if (newconn != NULL) {\r
+      /* Let the stack know that we have accepted the connection. */\r
+      struct api_msg msg;\r
+      msg.function = do_recv;\r
+      msg.msg.conn = conn;\r
+      TCPIP_APIMSG(&msg);\r
+    }\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+  }\r
+\r
+  return newconn;\r
+}\r
+\r
+/**\r
+ * Receive data (in form of a netbuf containing a packet buffer) from a netconn\r
+ *\r
+ * @param conn the netconn from which to receive data\r
+ * @return a new netbuf containing received data or NULL on memory error or timeout\r
+ */\r
+struct netbuf *\r
+netconn_recv(struct netconn *conn)\r
+{\r
+  struct api_msg msg;\r
+  struct netbuf *buf = NULL;\r
+  struct pbuf *p;\r
+  u16_t len;\r
+\r
+  LWIP_ERROR("netconn_recv: invalid conn",  (conn != NULL), return NULL;);\r
+\r
+  if (conn->recvmbox == SYS_MBOX_NULL) {\r
+    /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */\r
+    /* TCP listen conns don't have a recvmbox! */\r
+    conn->err = ERR_CONN;\r
+    return NULL;\r
+  }\r
+\r
+  if (ERR_IS_FATAL(conn->err)) {\r
+    return NULL;\r
+  }\r
+\r
+  if (conn->type == NETCONN_TCP) {\r
+#if LWIP_TCP\r
+    if (conn->state == NETCONN_LISTEN) {\r
+      /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */\r
+      conn->err = ERR_CONN;\r
+      return NULL;\r
+    }\r
+\r
+    buf = memp_malloc(MEMP_NETBUF);\r
+\r
+    if (buf == NULL) {\r
+      conn->err = ERR_MEM;\r
+      return NULL;\r
+    }\r
+\r
+#if LWIP_SO_RCVTIMEO\r
+    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {\r
+      conn->err = ERR_TIMEOUT;\r
+      p = NULL;\r
+    }\r
+#else\r
+    sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);\r
+#endif /* LWIP_SO_RCVTIMEO*/\r
+\r
+    if (p != NULL) {\r
+      len = p->tot_len;\r
+      SYS_ARCH_DEC(conn->recv_avail, len);\r
+    } else {\r
+      len = 0;\r
+    }\r
+\r
+    /* Register event with callback */\r
+    API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);\r
+\r
+    /* If we are closed, we indicate that we no longer wish to use the socket */\r
+    if (p == NULL) {\r
+      memp_free(MEMP_NETBUF, buf);\r
+      /* Avoid to lose any previous error code */\r
+      if (conn->err == ERR_OK) {\r
+        conn->err = ERR_CLSD;\r
+      }\r
+      return NULL;\r
+    }\r
+\r
+    buf->p = p;\r
+    buf->ptr = p;\r
+    buf->port = 0;\r
+    buf->addr = NULL;\r
+\r
+    /* Let the stack know that we have taken the data. */\r
+    msg.function = do_recv;\r
+    msg.msg.conn = conn;\r
+    if (buf != NULL) {\r
+      msg.msg.msg.r.len = buf->p->tot_len;\r
+    } else {\r
+      msg.msg.msg.r.len = 1;\r
+    }\r
+    TCPIP_APIMSG(&msg);\r
+#endif /* LWIP_TCP */\r
+  } else {\r
+#if (LWIP_UDP || LWIP_RAW)\r
+#if LWIP_SO_RCVTIMEO\r
+    if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {\r
+      buf = NULL;\r
+    }\r
+#else\r
+    sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0);\r
+#endif /* LWIP_SO_RCVTIMEO*/\r
+    if (buf!=NULL) {\r
+      SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len);\r
+      /* Register event with callback */\r
+      API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len);\r
+    }\r
+#endif /* (LWIP_UDP || LWIP_RAW) */\r
+  }\r
+\r
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));\r
+\r
+  return buf;\r
+}\r
+\r
+/**\r
+ * Send data (in form of a netbuf) to a specific remote IP address and port.\r
+ * Only to be used for UDP and RAW netconns (not TCP).\r
+ *\r
+ * @param conn the netconn over which to send data\r
+ * @param buf a netbuf containing the data to send\r
+ * @param addr the remote IP address to which to send the data\r
+ * @param port the remote port to which to send the data\r
+ * @return ERR_OK if data was sent, any other err_t on error\r
+ */\r
+err_t\r
+netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port)\r
+{\r
+  if (buf != NULL) {\r
+    buf->addr = addr;\r
+    buf->port = port;\r
+    return netconn_send(conn, buf);\r
+  }\r
+  return ERR_VAL;\r
+}\r
+\r
+/**\r
+ * Send data over a UDP or RAW netconn (that is already connected).\r
+ *\r
+ * @param conn the UDP or RAW netconn over which to send data\r
+ * @param buf a netbuf containing the data to send\r
+ * @return ERR_OK if data was sent, any other err_t on error\r
+ */\r
+err_t\r
+netconn_send(struct netconn *conn, struct netbuf *buf)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_send: invalid conn",  (conn != NULL), return ERR_ARG;);\r
+\r
+  LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));\r
+  msg.function = do_send;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.b = buf;\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Send data over a TCP netconn.\r
+ *\r
+ * @param conn the TCP netconn over which to send data\r
+ * @param dataptr pointer to the application buffer that contains the data to send\r
+ * @param size size of the application data to send\r
+ * @param apiflags combination of following flags :\r
+ * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack\r
+ * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent\r
+ * @return ERR_OK if data was sent, any other err_t on error\r
+ */\r
+err_t\r
+netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_write: invalid conn",  (conn != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netconn_write: invalid conn->type",  (conn->type == NETCONN_TCP), return ERR_VAL;);\r
+\r
+  msg.function = do_write;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.w.dataptr = dataptr;\r
+  msg.msg.msg.w.apiflags = apiflags;\r
+  msg.msg.msg.w.len = size;\r
+  /* For locking the core: this _can_ be delayed on low memory/low send buffer,\r
+     but if it is, this is done inside api_msg.c:do_write(), so we can use the\r
+     non-blocking version here. */\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+\r
+/**\r
+ * Close a TCP netconn (doesn't delete it).\r
+ *\r
+ * @param conn the TCP netconn to close\r
+ * @return ERR_OK if the netconn was closed, any other err_t on error\r
+ */\r
+err_t\r
+netconn_close(struct netconn *conn)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_close: invalid conn",  (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_close;\r
+  msg.msg.conn = conn;\r
+  tcpip_apimsg(&msg);\r
+  return conn->err;\r
+}\r
+\r
+#if LWIP_IGMP\r
+/**\r
+ * Join multicast groups for UDP netconns.\r
+ *\r
+ * @param conn the UDP netconn for which to change multicast addresses\r
+ * @param multiaddr IP address of the multicast group to join or leave\r
+ * @param interface the IP address of the network interface on which to send\r
+ *                  the igmp message\r
+ * @param join_or_leave flag whether to send a join- or leave-message\r
+ * @return ERR_OK if the action was taken, any err_t on error\r
+ */\r
+err_t\r
+netconn_join_leave_group(struct netconn *conn,\r
+                         struct ip_addr *multiaddr,\r
+                         struct ip_addr *interface,\r
+                         enum netconn_igmp join_or_leave)\r
+{\r
+  struct api_msg msg;\r
+\r
+  LWIP_ERROR("netconn_join_leave_group: invalid conn",  (conn != NULL), return ERR_ARG;);\r
+\r
+  msg.function = do_join_leave_group;\r
+  msg.msg.conn = conn;\r
+  msg.msg.msg.jl.multiaddr = multiaddr;\r
+  msg.msg.msg.jl.interface = interface;\r
+  msg.msg.msg.jl.join_or_leave = join_or_leave;\r
+  TCPIP_APIMSG(&msg);\r
+  return conn->err;\r
+}\r
+#endif /* LWIP_IGMP */\r
+\r
+#if LWIP_DNS\r
+/**\r
+ * Execute a DNS query, only one IP address is returned\r
+ *\r
+ * @param name a string representation of the DNS host name to query\r
+ * @param addr a preallocated struct ip_addr where to store the resolved IP address\r
+ * @return ERR_OK: resolving succeeded\r
+ *         ERR_MEM: memory error, try again later\r
+ *         ERR_ARG: dns client not initialized or invalid hostname\r
+ *         ERR_VAL: dns server response was invalid\r
+ */\r
+err_t\r
+netconn_gethostbyname(const char *name, struct ip_addr *addr)\r
+{\r
+  struct dns_api_msg msg;\r
+  err_t err;\r
+  sys_sem_t sem;\r
+\r
+  LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;);\r
+\r
+  sem = sys_sem_new(0);\r
+  if (sem == SYS_SEM_NULL) {\r
+    return ERR_MEM;\r
+  }\r
+\r
+  msg.name = name;\r
+  msg.addr = addr;\r
+  msg.err = &err;\r
+  msg.sem = sem;\r
+\r
+  tcpip_callback(do_gethostbyname, &msg);\r
+  sys_sem_wait(sem);\r
+  sys_sem_free(sem);\r
+\r
+  return err;\r
+}\r
+#endif /* LWIP_DNS*/\r
+\r
+#endif /* LWIP_NETCONN */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/api_msg.c b/Demo/Common/ethernet/lwIP_130/src/api/api_msg.c
new file mode 100644 (file)
index 0000000..f08177c
--- /dev/null
@@ -0,0 +1,1202 @@
+/**\r
+ * @file\r
+ * Sequential API Internal module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/api_msg.h"\r
+\r
+#include "lwip/ip.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/raw.h"\r
+\r
+#include "lwip/memp.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/dns.h"\r
+\r
+/* forward declarations */\r
+#if LWIP_TCP\r
+static err_t do_writemore(struct netconn *conn);\r
+static void do_close_internal(struct netconn *conn);\r
+#endif\r
+\r
+#if LWIP_RAW\r
+/**\r
+ * Receive callback function for RAW netconns.\r
+ * Doesn't 'eat' the packet, only references it and sends it to\r
+ * conn->recvmbox\r
+ *\r
+ * @see raw.h (struct raw_pcb.recv) for parameters and return value\r
+ */\r
+static u8_t\r
+recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr)\r
+{\r
+  struct pbuf *q;\r
+  struct netbuf *buf;\r
+  struct netconn *conn;\r
+#if LWIP_SO_RCVBUF\r
+  int recv_avail;\r
+#endif /* LWIP_SO_RCVBUF */\r
+\r
+  LWIP_UNUSED_ARG(addr);\r
+  conn = arg;\r
+\r
+#if LWIP_SO_RCVBUF\r
+  SYS_ARCH_GET(conn->recv_avail, recv_avail);\r
+  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) &&\r
+      ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) {\r
+#else  /* LWIP_SO_RCVBUF */\r
+  if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) {\r
+#endif /* LWIP_SO_RCVBUF */\r
+    /* copy the whole packet into new pbufs */\r
+    q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+    if(q != NULL) {\r
+      if (pbuf_copy(q, p) != ERR_OK) {\r
+        pbuf_free(q);\r
+        q = NULL;\r
+      }\r
+    }\r
+\r
+    if(q != NULL) {\r
+      buf = memp_malloc(MEMP_NETBUF);\r
+      if (buf == NULL) {\r
+        pbuf_free(q);\r
+        return 0;\r
+      }\r
+\r
+      buf->p = q;\r
+      buf->ptr = q;\r
+      buf->addr = &(((struct ip_hdr*)(q->payload))->src);\r
+      buf->port = pcb->protocol;\r
+\r
+      SYS_ARCH_INC(conn->recv_avail, q->tot_len);\r
+      /* Register event with callback */\r
+      API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len);\r
+      if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {\r
+        netbuf_delete(buf);\r
+      }\r
+    }\r
+  }\r
+\r
+  return 0; /* do not eat the packet */\r
+}\r
+#endif /* LWIP_RAW*/\r
+\r
+#if LWIP_UDP\r
+/**\r
+ * Receive callback function for UDP netconns.\r
+ * Posts the packet to conn->recvmbox or deletes it on memory error.\r
+ *\r
+ * @see udp.h (struct udp_pcb.recv) for parameters\r
+ */\r
+static void\r
+recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p,\r
+   struct ip_addr *addr, u16_t port)\r
+{\r
+  struct netbuf *buf;\r
+  struct netconn *conn;\r
+#if LWIP_SO_RCVBUF\r
+  int recv_avail;\r
+#endif /* LWIP_SO_RCVBUF */\r
+\r
+  LWIP_UNUSED_ARG(pcb); /* only used for asserts... */\r
+  LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL);\r
+  LWIP_ASSERT("recv_udp must have an argument", arg != NULL);\r
+  conn = arg;\r
+  LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb);\r
+\r
+#if LWIP_SO_RCVBUF\r
+  SYS_ARCH_GET(conn->recv_avail, recv_avail);\r
+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) ||\r
+      ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) {\r
+#else  /* LWIP_SO_RCVBUF */\r
+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {\r
+#endif /* LWIP_SO_RCVBUF */\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  buf = memp_malloc(MEMP_NETBUF);\r
+  if (buf == NULL) {\r
+    pbuf_free(p);\r
+    return;\r
+  } else {\r
+    buf->p = p;\r
+    buf->ptr = p;\r
+    buf->addr = addr;\r
+    buf->port = port;\r
+  }\r
+\r
+  SYS_ARCH_INC(conn->recv_avail, p->tot_len);\r
+  /* Register event with callback */\r
+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len);\r
+  if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) {\r
+    netbuf_delete(buf);\r
+    return;\r
+  }\r
+}\r
+#endif /* LWIP_UDP */\r
+\r
+#if LWIP_TCP\r
+/**\r
+ * Receive callback function for TCP netconns.\r
+ * Posts the packet to conn->recvmbox, but doesn't delete it on errors.\r
+ *\r
+ * @see tcp.h (struct tcp_pcb.recv) for parameters and return value\r
+ */\r
+static err_t\r
+recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
+{\r
+  struct netconn *conn;\r
+  u16_t len;\r
+\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL);\r
+  LWIP_ASSERT("recv_tcp must have an argument", arg != NULL);\r
+  conn = arg;\r
+  LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb);\r
+\r
+  if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  conn->err = err;\r
+  if (p != NULL) {\r
+    len = p->tot_len;\r
+    SYS_ARCH_INC(conn->recv_avail, len);\r
+  } else {\r
+    len = 0;\r
+  }\r
+  /* Register event with callback */\r
+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, len);\r
+  if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) {\r
+    return ERR_MEM;\r
+  }\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Poll callback function for TCP netconns.\r
+ * Wakes up an application thread that waits for a connection to close\r
+ * or data to be sent. The application thread then takes the\r
+ * appropriate action to go on.\r
+ *\r
+ * Signals the conn->sem.\r
+ * netconn_close waits for conn->sem if closing failed.\r
+ *\r
+ * @see tcp.h (struct tcp_pcb.poll) for parameters and return value\r
+ */\r
+static err_t\r
+poll_tcp(void *arg, struct tcp_pcb *pcb)\r
+{\r
+  struct netconn *conn = arg;\r
+\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_ASSERT("conn != NULL", (conn != NULL));\r
+\r
+  if (conn->state == NETCONN_WRITE) {\r
+    do_writemore(conn);\r
+  } else if (conn->state == NETCONN_CLOSE) {\r
+    do_close_internal(conn);\r
+  }\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Sent callback function for TCP netconns.\r
+ * Signals the conn->sem and calls API_EVENT.\r
+ * netconn_write waits for conn->sem if send buffer is low.\r
+ *\r
+ * @see tcp.h (struct tcp_pcb.sent) for parameters and return value\r
+ */\r
+static err_t\r
+sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len)\r
+{\r
+  struct netconn *conn = arg;\r
+\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_ASSERT("conn != NULL", (conn != NULL));\r
+\r
+  if (conn->state == NETCONN_WRITE) {\r
+    LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL);\r
+    do_writemore(conn);\r
+  } else if (conn->state == NETCONN_CLOSE) {\r
+    do_close_internal(conn);\r
+  }\r
+\r
+  if (conn) {\r
+    if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) {\r
+      API_EVENT(conn, NETCONN_EVT_SENDPLUS, len);\r
+    }\r
+  }\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Error callback function for TCP netconns.\r
+ * Signals conn->sem, posts to all conn mboxes and calls API_EVENT.\r
+ * The application thread has then to decide what to do.\r
+ *\r
+ * @see tcp.h (struct tcp_pcb.err) for parameters\r
+ */\r
+static void\r
+err_tcp(void *arg, err_t err)\r
+{\r
+  struct netconn *conn;\r
+\r
+  conn = arg;\r
+  LWIP_ASSERT("conn != NULL", (conn != NULL));\r
+\r
+  conn->pcb.tcp = NULL;\r
+\r
+  conn->err = err;\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    /* Register event with callback */\r
+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
+    sys_mbox_post(conn->recvmbox, NULL);\r
+  }\r
+  if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) {\r
+    conn->state = NETCONN_NONE;\r
+    sys_sem_signal(conn->op_completed);\r
+  }\r
+  if (conn->acceptmbox != SYS_MBOX_NULL) {\r
+    /* Register event with callback */\r
+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
+    sys_mbox_post(conn->acceptmbox, NULL);\r
+  }\r
+  if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) {\r
+    /* calling do_writemore/do_close_internal is not necessary\r
+       since the pcb has already been deleted! */\r
+    conn->state = NETCONN_NONE;\r
+    /* wake up the waiting task */\r
+    sys_sem_signal(conn->op_completed);\r
+  }\r
+}\r
+\r
+/**\r
+ * Setup a tcp_pcb with the correct callback function pointers\r
+ * and their arguments.\r
+ *\r
+ * @param conn the TCP netconn to setup\r
+ */\r
+static void\r
+setup_tcp(struct netconn *conn)\r
+{\r
+  struct tcp_pcb *pcb;\r
+\r
+  pcb = conn->pcb.tcp;\r
+  tcp_arg(pcb, conn);\r
+  tcp_recv(pcb, recv_tcp);\r
+  tcp_sent(pcb, sent_tcp);\r
+  tcp_poll(pcb, poll_tcp, 4);\r
+  tcp_err(pcb, err_tcp);\r
+}\r
+\r
+/**\r
+ * Accept callback function for TCP netconns.\r
+ * Allocates a new netconn and posts that to conn->acceptmbox.\r
+ *\r
+ * @see tcp.h (struct tcp_pcb_listen.accept) for parameters and return value\r
+ */\r
+static err_t\r
+accept_function(void *arg, struct tcp_pcb *newpcb, err_t err)\r
+{\r
+  struct netconn *newconn;\r
+  struct netconn *conn;\r
+\r
+#if API_MSG_DEBUG\r
+#if TCP_DEBUG\r
+  tcp_debug_print_state(newpcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* API_MSG_DEBUG */\r
+  conn = (struct netconn *)arg;\r
+\r
+  LWIP_ERROR("accept_function: invalid conn->acceptmbox",\r
+             conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;);\r
+\r
+  /* We have to set the callback here even though\r
+   * the new socket is unknown. conn->socket is marked as -1. */\r
+  newconn = netconn_alloc(conn->type, conn->callback);\r
+  if (newconn == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+  newconn->pcb.tcp = newpcb;\r
+  setup_tcp(newconn);\r
+  newconn->err = err;\r
+  /* Register event with callback */\r
+  API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
+\r
+  if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) {\r
+    /* When returning != ERR_OK, the connection is aborted in tcp_process(),\r
+       so do nothing here! */\r
+    newconn->pcb.tcp = NULL;\r
+    netconn_free(newconn);\r
+    return ERR_MEM;\r
+  }\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+/**\r
+ * Create a new pcb of a specific type.\r
+ * Called from do_newconn().\r
+ *\r
+ * @param msg the api_msg_msg describing the connection type\r
+ * @return msg->conn->err, but the return value is currently ignored\r
+ */\r
+static err_t\r
+pcb_new(struct api_msg_msg *msg)\r
+{\r
+   msg->conn->err = ERR_OK;\r
+\r
+   LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL);\r
+\r
+   /* Allocate a PCB for this connection */\r
+   switch(NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+   case NETCONN_RAW:\r
+     msg->conn->pcb.raw = raw_new(msg->msg.n.proto);\r
+     if(msg->conn->pcb.raw == NULL) {\r
+       msg->conn->err = ERR_MEM;\r
+       break;\r
+     }\r
+     raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn);\r
+     break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+   case NETCONN_UDP:\r
+     msg->conn->pcb.udp = udp_new();\r
+     if(msg->conn->pcb.udp == NULL) {\r
+       msg->conn->err = ERR_MEM;\r
+       break;\r
+     }\r
+#if LWIP_UDPLITE\r
+     if (msg->conn->type==NETCONN_UDPLITE) {\r
+       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE);\r
+     }\r
+#endif /* LWIP_UDPLITE */\r
+     if (msg->conn->type==NETCONN_UDPNOCHKSUM) {\r
+       udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM);\r
+     }\r
+     udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn);\r
+     break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+   case NETCONN_TCP:\r
+     msg->conn->pcb.tcp = tcp_new();\r
+     if(msg->conn->pcb.tcp == NULL) {\r
+       msg->conn->err = ERR_MEM;\r
+       break;\r
+     }\r
+     setup_tcp(msg->conn);\r
+     break;\r
+#endif /* LWIP_TCP */\r
+   default:\r
+     /* Unsupported netconn type, e.g. protocol disabled */\r
+     msg->conn->err = ERR_VAL;\r
+     break;\r
+   }\r
+\r
+  return msg->conn->err;\r
+}\r
+\r
+/**\r
+ * Create a new pcb of a specific type inside a netconn.\r
+ * Called from netconn_new_with_proto_and_callback.\r
+ *\r
+ * @param msg the api_msg_msg describing the connection type\r
+ */\r
+void\r
+do_newconn(struct api_msg_msg *msg)\r
+{\r
+   if(msg->conn->pcb.tcp == NULL) {\r
+     pcb_new(msg);\r
+   }\r
+   /* Else? This "new" connection already has a PCB allocated. */\r
+   /* Is this an error condition? Should it be deleted? */\r
+   /* We currently just are happy and return. */\r
+\r
+   TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Create a new netconn (of a specific type) that has a callback function.\r
+ * The corresponding pcb is NOT created!\r
+ *\r
+ * @param t the type of 'connection' to create (@see enum netconn_type)\r
+ * @param proto the IP protocol for RAW IP pcbs\r
+ * @param callback a function to call on status changes (RX available, TX'ed)\r
+ * @return a newly allocated struct netconn or\r
+ *         NULL on memory error\r
+ */\r
+struct netconn*\r
+netconn_alloc(enum netconn_type t, netconn_callback callback)\r
+{\r
+  struct netconn *conn;\r
+  int size;\r
+\r
+  conn = memp_malloc(MEMP_NETCONN);\r
+  if (conn == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  conn->err = ERR_OK;\r
+  conn->type = t;\r
+  conn->pcb.tcp = NULL;\r
+\r
+#if (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_UDP_RECVMBOX_SIZE) && \\r
+    (DEFAULT_RAW_RECVMBOX_SIZE == DEFAULT_TCP_RECVMBOX_SIZE)\r
+  size = DEFAULT_RAW_RECVMBOX_SIZE;\r
+#else\r
+  switch(NETCONNTYPE_GROUP(t)) {\r
+#if LWIP_RAW\r
+  case NETCONN_RAW:\r
+    size = DEFAULT_RAW_RECVMBOX_SIZE;\r
+    break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+  case NETCONN_UDP:\r
+    size = DEFAULT_UDP_RECVMBOX_SIZE;\r
+    break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+  case NETCONN_TCP:\r
+    size = DEFAULT_TCP_RECVMBOX_SIZE;\r
+    break;\r
+#endif /* LWIP_TCP */\r
+  default:\r
+    LWIP_ASSERT("netconn_alloc: undefined netconn_type", 0);\r
+    break;\r
+  }\r
+#endif\r
+\r
+  if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) {\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+  if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) {\r
+    sys_sem_free(conn->op_completed);\r
+    memp_free(MEMP_NETCONN, conn);\r
+    return NULL;\r
+  }\r
+\r
+  conn->acceptmbox   = SYS_MBOX_NULL;\r
+  conn->state        = NETCONN_NONE;\r
+  /* initialize socket to -1 since 0 is a valid socket */\r
+  conn->socket       = -1;\r
+  conn->callback     = callback;\r
+  conn->recv_avail   = 0;\r
+#if LWIP_SO_RCVTIMEO\r
+  conn->recv_timeout = 0;\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+  conn->recv_bufsize = INT_MAX;\r
+#endif /* LWIP_SO_RCVBUF */\r
+  return conn;\r
+}\r
+\r
+/**\r
+ * Delete a netconn and all its resources.\r
+ * The pcb is NOT freed (since we might not be in the right thread context do this).\r
+ *\r
+ * @param conn the netconn to free\r
+ */\r
+void\r
+netconn_free(struct netconn *conn)\r
+{\r
+  void *mem;\r
+  LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL);\r
+\r
+  /* Drain the recvmbox. */\r
+  if (conn->recvmbox != SYS_MBOX_NULL) {\r
+    while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) {\r
+      if (conn->type == NETCONN_TCP) {\r
+        if(mem != NULL) {\r
+          pbuf_free((struct pbuf *)mem);\r
+        }\r
+      } else {\r
+        netbuf_delete((struct netbuf *)mem);\r
+      }\r
+    }\r
+    sys_mbox_free(conn->recvmbox);\r
+    conn->recvmbox = SYS_MBOX_NULL;\r
+  }\r
+\r
+  /* Drain the acceptmbox. */\r
+  if (conn->acceptmbox != SYS_MBOX_NULL) {\r
+    while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) {\r
+      netconn_delete((struct netconn *)mem);\r
+    }\r
+    sys_mbox_free(conn->acceptmbox);\r
+    conn->acceptmbox = SYS_MBOX_NULL;\r
+  }\r
+\r
+  sys_sem_free(conn->op_completed);\r
+  conn->op_completed = SYS_SEM_NULL;\r
+\r
+  memp_free(MEMP_NETCONN, conn);\r
+}\r
+\r
+#if LWIP_TCP\r
+/**\r
+ * Internal helper function to close a TCP netconn: since this sometimes\r
+ * doesn't work at the first attempt, this function is called from multiple\r
+ * places.\r
+ *\r
+ * @param conn the TCP netconn to close\r
+ */\r
+static void\r
+do_close_internal(struct netconn *conn)\r
+{\r
+  err_t err;\r
+\r
+  LWIP_ASSERT("invalid conn", (conn != NULL));\r
+  LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP));\r
+  LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE));\r
+  LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL));\r
+\r
+  /* Set back some callback pointers */\r
+  if (conn->pcb.tcp->state == LISTEN) {\r
+    tcp_arg(conn->pcb.tcp, NULL);\r
+    tcp_accept(conn->pcb.tcp, NULL);\r
+  } else {\r
+    tcp_recv(conn->pcb.tcp, NULL);\r
+  }\r
+  /* Try to close the connection */\r
+  err = tcp_close(conn->pcb.tcp);\r
+  if (err == ERR_OK) {\r
+    /* Closing succeeded */\r
+    conn->state = NETCONN_NONE;\r
+    /* Set back some callback pointers as conn is going away */\r
+    tcp_err(conn->pcb.tcp, NULL);\r
+    tcp_poll(conn->pcb.tcp, NULL, 4);\r
+    tcp_sent(conn->pcb.tcp, NULL);\r
+    tcp_recv(conn->pcb.tcp, NULL);\r
+    tcp_arg(conn->pcb.tcp, NULL);\r
+    conn->pcb.tcp = NULL;\r
+    conn->err = ERR_OK;\r
+    /* Trigger select() in socket layer. This send should something else so the\r
+       errorfd is set, not the read and write fd! */\r
+    API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0);\r
+    API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0);\r
+    /* wake up the application task */\r
+    sys_sem_signal(conn->op_completed);\r
+  }\r
+  /* If closing didn't succeed, we get called again either\r
+     from poll_tcp or from sent_tcp */\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+/**\r
+ * Delete the pcb inside a netconn.\r
+ * Called from netconn_delete.\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_delconn(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp != NULL) {\r
+    switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      raw_remove(msg->conn->pcb.raw);\r
+      break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+    case NETCONN_UDP:\r
+      msg->conn->pcb.udp->recv_arg = NULL;\r
+      udp_remove(msg->conn->pcb.udp);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+    case NETCONN_TCP:\r
+      msg->conn->state = NETCONN_CLOSE;\r
+      do_close_internal(msg->conn);\r
+      /* API_EVENT is called inside do_close_internal, before releasing\r
+         the application thread, so we can return at this point! */\r
+      return;\r
+#endif /* LWIP_TCP */\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+  /* tcp netconns don't come here! */\r
+\r
+  /* Trigger select() in socket layer. This send should something else so the\r
+     errorfd is set, not the read and write fd! */\r
+  API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0);\r
+  API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0);\r
+\r
+  if (msg->conn->op_completed != SYS_SEM_NULL) {\r
+    sys_sem_signal(msg->conn->op_completed);\r
+  }\r
+}\r
+\r
+/**\r
+ * Bind a pcb contained in a netconn\r
+ * Called from netconn_bind.\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection and containing\r
+ *            the IP address and port to bind to\r
+ */\r
+void\r
+do_bind(struct api_msg_msg *msg)\r
+{\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if (msg->conn->pcb.tcp != NULL) {\r
+      switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+      case NETCONN_RAW:\r
+        msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\r
+        break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+      case NETCONN_UDP:\r
+        msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+        break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+      case NETCONN_TCP:\r
+        msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+        break;\r
+#endif /* LWIP_TCP */\r
+      default:\r
+        break;\r
+      }\r
+    } else {\r
+      /* msg->conn->pcb is NULL */\r
+      msg->conn->err = ERR_VAL;\r
+    }\r
+  }\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+#if LWIP_TCP\r
+/**\r
+ * TCP callback function if a connection (opened by tcp_connect/do_connect) has\r
+ * been established (or reset by the remote host).\r
+ *\r
+ * @see tcp.h (struct tcp_pcb.connected) for parameters and return values\r
+ */\r
+static err_t\r
+do_connected(void *arg, struct tcp_pcb *pcb, err_t err)\r
+{\r
+  struct netconn *conn;\r
+\r
+  LWIP_UNUSED_ARG(pcb);\r
+\r
+  conn = arg;\r
+\r
+  if (conn == NULL) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+  conn->err = err;\r
+  if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) {\r
+    setup_tcp(conn);\r
+  }\r
+  conn->state = NETCONN_NONE;\r
+  sys_sem_signal(conn->op_completed);\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+/**\r
+ * Connect a pcb contained inside a netconn\r
+ * Called from netconn_connect.\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection and containing\r
+ *            the IP address and port to connect to\r
+ */\r
+void\r
+do_connect(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.tcp == NULL) {\r
+    sys_sem_signal(msg->conn->op_completed);\r
+    return;\r
+  }\r
+\r
+  switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+  case NETCONN_RAW:\r
+    msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr);\r
+    sys_sem_signal(msg->conn->op_completed);\r
+    break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+  case NETCONN_UDP:\r
+    msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port);\r
+    sys_sem_signal(msg->conn->op_completed);\r
+    break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+  case NETCONN_TCP:\r
+    msg->conn->state = NETCONN_CONNECT;\r
+    setup_tcp(msg->conn);\r
+    msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port,\r
+                                 do_connected);\r
+    /* sys_sem_signal() is called from do_connected (or err_tcp()),\r
+     * when the connection is established! */\r
+    break;\r
+#endif /* LWIP_TCP */\r
+  default:\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+ * Connect a pcb contained inside a netconn\r
+ * Only used for UDP netconns.\r
+ * Called from netconn_disconnect.\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection to disconnect\r
+ */\r
+void\r
+do_disconnect(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_UDP\r
+  if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\r
+    udp_disconnect(msg->conn->pcb.udp);\r
+  }\r
+#endif /* LWIP_UDP */\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Set a TCP pcb contained in a netconn into listen mode\r
+ * Called from netconn_listen.\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_listen(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_TCP\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if (msg->conn->pcb.tcp != NULL) {\r
+      if (msg->conn->type == NETCONN_TCP) {\r
+        if (msg->conn->pcb.tcp->state == CLOSED) {\r
+#if TCP_LISTEN_BACKLOG\r
+          struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog);\r
+#else  /* TCP_LISTEN_BACKLOG */\r
+          struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp);\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+          if (lpcb == NULL) {\r
+            msg->conn->err = ERR_MEM;\r
+          } else {\r
+            /* delete the recvmbox and allocate the acceptmbox */\r
+            if (msg->conn->recvmbox != SYS_MBOX_NULL) {\r
+              /** @todo: should we drain the recvmbox here? */\r
+              sys_mbox_free(msg->conn->recvmbox);\r
+              msg->conn->recvmbox = SYS_MBOX_NULL;\r
+            }\r
+            if (msg->conn->acceptmbox == SYS_MBOX_NULL) {\r
+              if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) {\r
+                msg->conn->err = ERR_MEM;\r
+              }\r
+            }\r
+            if (msg->conn->err == ERR_OK) {\r
+              msg->conn->state = NETCONN_LISTEN;\r
+              msg->conn->pcb.tcp = lpcb;\r
+              tcp_arg(msg->conn->pcb.tcp, msg->conn);\r
+              tcp_accept(msg->conn->pcb.tcp, accept_function);\r
+            }\r
+          }\r
+        } else {\r
+          msg->conn->err = ERR_CONN;\r
+        }\r
+      }\r
+    }\r
+  }\r
+#endif /* LWIP_TCP */\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Send some data on a RAW or UDP pcb contained in a netconn\r
+ * Called from netconn_send\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_send(struct api_msg_msg *msg)\r
+{\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if (msg->conn->pcb.tcp != NULL) {\r
+      switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+      case NETCONN_RAW:\r
+        if (msg->msg.b->addr == NULL) {\r
+          msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p);\r
+        } else {\r
+          msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr);\r
+        }\r
+        break;\r
+#endif\r
+#if LWIP_UDP\r
+      case NETCONN_UDP:\r
+        if (msg->msg.b->addr == NULL) {\r
+          msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p);\r
+        } else {\r
+          msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port);\r
+        }\r
+        break;\r
+#endif /* LWIP_UDP */\r
+      default:\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Recv some data from a RAW or UDP pcb contained in a netconn\r
+ * Called from netconn_recv\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_recv(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_TCP\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if (msg->conn->pcb.tcp != NULL) {\r
+      if (msg->conn->type == NETCONN_TCP) {\r
+#if TCP_LISTEN_BACKLOG\r
+        if (msg->conn->pcb.tcp->state == LISTEN) {\r
+          tcp_accepted(msg->conn->pcb.tcp);\r
+        } else\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+        {\r
+          tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len);\r
+        }\r
+      }\r
+    }\r
+  }\r
+#endif /* LWIP_TCP */\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+#if LWIP_TCP\r
+/**\r
+ * See if more data needs to be written from a previous call to netconn_write.\r
+ * Called initially from do_write. If the first call can't send all data\r
+ * (because of low memory or empty send-buffer), this function is called again\r
+ * from sent_tcp() or poll_tcp() to send more data. If all data is sent, the\r
+ * blocking application thread (waiting in netconn_write) is released.\r
+ *\r
+ * @param conn netconn (that is currently in state NETCONN_WRITE) to process\r
+ * @return ERR_OK\r
+ *         ERR_MEM if LWIP_TCPIP_CORE_LOCKING=1 and sending hasn't yet finished\r
+ */\r
+static err_t\r
+do_writemore(struct netconn *conn)\r
+{\r
+  err_t err;\r
+  void *dataptr;\r
+  u16_t len, available;\r
+  u8_t write_finished = 0;\r
+\r
+  LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE));\r
+\r
+  dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset;\r
+  if ((conn->write_msg->msg.w.len - conn->write_offset > 0xffff)) { /* max_u16_t */\r
+    len = 0xffff;\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+    conn->write_delayed = 1;\r
+#endif\r
+  } else {\r
+    len = conn->write_msg->msg.w.len - conn->write_offset;\r
+  }\r
+  available = tcp_sndbuf(conn->pcb.tcp);\r
+  if (available < len) {\r
+    /* don't try to write more than sendbuf */\r
+    len = available;\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+    conn->write_delayed = 1;\r
+#endif\r
+  }\r
+\r
+  err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags);\r
+  LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len));\r
+  if (err == ERR_OK) {\r
+    conn->write_offset += len;\r
+    if (conn->write_offset == conn->write_msg->msg.w.len) {\r
+      /* everything was written */\r
+      write_finished = 1;\r
+      conn->write_msg = NULL;\r
+      conn->write_offset = 0;\r
+    }\r
+    err = tcp_output_nagle(conn->pcb.tcp);\r
+    conn->err = err;\r
+    if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) {\r
+      API_EVENT(conn, NETCONN_EVT_SENDMINUS, len);\r
+    }\r
+  } else if (err == ERR_MEM) {\r
+    /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called\r
+       we do NOT return to the application thread, since ERR_MEM is\r
+       only a temporary error! */\r
+\r
+    /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */\r
+    err = tcp_output(conn->pcb.tcp);\r
+\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+    conn->write_delayed = 1;\r
+#endif\r
+  } else {\r
+    /* On errors != ERR_MEM, we don't try writing any more but return\r
+       the error to the application thread. */\r
+    conn->err = err;\r
+    write_finished = 1;\r
+  }\r
+\r
+  if (write_finished) {\r
+    /* everything was written: set back connection state\r
+       and back to application task */\r
+    conn->state = NETCONN_NONE;\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+    if (conn->write_delayed != 0)\r
+#endif\r
+    {\r
+      sys_sem_signal(conn->op_completed);\r
+    }\r
+  }\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+  else\r
+    return ERR_MEM;\r
+#endif\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_TCP */\r
+\r
+/**\r
+ * Send some data on a TCP pcb contained in a netconn\r
+ * Called from netconn_write\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_write(struct api_msg_msg *msg)\r
+{\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {\r
+#if LWIP_TCP\r
+      msg->conn->state = NETCONN_WRITE;\r
+      /* set all the variables used by do_writemore */\r
+      msg->conn->write_msg = msg;\r
+      msg->conn->write_offset = 0;\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+      msg->conn->write_delayed = 0;\r
+      if (do_writemore(msg->conn) != ERR_OK) {\r
+        LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE);\r
+        UNLOCK_TCPIP_CORE();\r
+        sys_arch_sem_wait(msg->conn->op_completed, 0);\r
+        LOCK_TCPIP_CORE();\r
+        LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE);\r
+      }\r
+#else\r
+      do_writemore(msg->conn);\r
+#endif\r
+      /* for both cases: if do_writemore was called, don't ACK the APIMSG! */\r
+      return;\r
+#endif /* LWIP_TCP */\r
+#if (LWIP_UDP || LWIP_RAW)\r
+    } else {\r
+      msg->conn->err = ERR_VAL;\r
+#endif /* (LWIP_UDP || LWIP_RAW) */\r
+    }\r
+  }\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Return a connection's local or remote address\r
+ * Called from netconn_getaddr\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_getaddr(struct api_msg_msg *msg)\r
+{\r
+  if (msg->conn->pcb.ip != NULL) {\r
+    *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip);\r
+\r
+    switch (NETCONNTYPE_GROUP(msg->conn->type)) {\r
+#if LWIP_RAW\r
+    case NETCONN_RAW:\r
+      if (msg->msg.ad.local) {\r
+        *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol;\r
+      } else {\r
+        /* return an error as connecting is only a helper for upper layers */\r
+        msg->conn->err = ERR_CONN;\r
+      }\r
+      break;\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+    case NETCONN_UDP:\r
+      if (msg->msg.ad.local) {\r
+        *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port;\r
+      } else {\r
+        if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) {\r
+          msg->conn->err = ERR_CONN;\r
+        } else {\r
+          *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port;\r
+        }\r
+      }\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+    case NETCONN_TCP:\r
+      *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port);\r
+      break;\r
+#endif /* LWIP_TCP */\r
+    }\r
+  } else {\r
+    msg->conn->err = ERR_CONN;\r
+  }\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Close a TCP pcb contained in a netconn\r
+ * Called from netconn_close\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_close(struct api_msg_msg *msg)\r
+{\r
+#if LWIP_TCP\r
+  if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) {\r
+      msg->conn->state = NETCONN_CLOSE;\r
+      do_close_internal(msg->conn);\r
+      /* for tcp netconns, do_close_internal ACKs the message */\r
+  } else\r
+#endif /* LWIP_TCP */\r
+  {\r
+    msg->conn->err = ERR_VAL;\r
+    TCPIP_APIMSG_ACK(msg);\r
+  }\r
+}\r
+\r
+#if LWIP_IGMP\r
+/**\r
+ * Join multicast groups for UDP netconns.\r
+ * Called from netconn_join_leave_group\r
+ *\r
+ * @param msg the api_msg_msg pointing to the connection\r
+ */\r
+void\r
+do_join_leave_group(struct api_msg_msg *msg)\r
+{\r
+  if (!ERR_IS_FATAL(msg->conn->err)) {\r
+    if (msg->conn->pcb.tcp != NULL) {\r
+      if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) {\r
+#if LWIP_UDP\r
+        if (msg->msg.jl.join_or_leave == NETCONN_JOIN) {\r
+          msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);\r
+        } else {\r
+          msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr);\r
+        }\r
+#endif /* LWIP_UDP */\r
+#if (LWIP_TCP || LWIP_RAW)\r
+      } else {\r
+        msg->conn->err = ERR_VAL;\r
+#endif /* (LWIP_TCP || LWIP_RAW) */\r
+      }\r
+    }\r
+  }\r
+  TCPIP_APIMSG_ACK(msg);\r
+}\r
+#endif /* LWIP_IGMP */\r
+\r
+#if LWIP_DNS\r
+/**\r
+ * Callback function that is called when DNS name is resolved\r
+ * (or on timeout). A waiting application thread is waked up by\r
+ * signaling the semaphore.\r
+ */\r
+static void\r
+do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg)\r
+{\r
+  struct dns_api_msg *msg = (struct dns_api_msg*)arg;\r
+\r
+  LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0);\r
+\r
+  if (ipaddr == NULL) {\r
+    /* timeout or memory error */\r
+    *msg->err = ERR_VAL;\r
+  } else {\r
+    /* address was resolved */\r
+    *msg->err = ERR_OK;\r
+    *msg->addr = *ipaddr;\r
+  }\r
+  /* wake up the application task waiting in netconn_gethostbyname */\r
+  sys_sem_signal(msg->sem);\r
+}\r
+\r
+/**\r
+ * Execute a DNS query\r
+ * Called from netconn_gethostbyname\r
+ *\r
+ * @param arg the dns_api_msg pointing to the query\r
+ */\r
+void\r
+do_gethostbyname(void *arg)\r
+{\r
+  struct dns_api_msg *msg = (struct dns_api_msg*)arg;\r
+\r
+  *msg->err = dns_gethostbyname(msg->name, msg->addr, do_dns_found, msg);\r
+  if (*msg->err != ERR_INPROGRESS) {\r
+    /* on error or immediate success, wake up the application\r
+     * task waiting in netconn_gethostbyname */\r
+    sys_sem_signal(msg->sem);\r
+  }\r
+}\r
+#endif /* LWIP_DNS */\r
+\r
+#endif /* LWIP_NETCONN */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/err.c b/Demo/Common/ethernet/lwIP_130/src/api/err.c
new file mode 100644 (file)
index 0000000..19ad3e7
--- /dev/null
@@ -0,0 +1,74 @@
+/**\r
+ * @file\r
+ * Error Management module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/err.h"\r
+\r
+#ifdef LWIP_DEBUG\r
+\r
+static const char *err_strerr[] = {\r
+           "Ok.",                    /* ERR_OK          0  */\r
+           "Out of memory error.",   /* ERR_MEM        -1  */\r
+           "Buffer error.",          /* ERR_BUF        -2  */\r
+           "Routing problem.",       /* ERR_RTE        -3  */\r
+           "Connection aborted.",    /* ERR_ABRT       -4  */\r
+           "Connection reset.",      /* ERR_RST        -5  */\r
+           "Connection closed.",     /* ERR_CLSD       -6  */\r
+           "Not connected.",         /* ERR_CONN       -7  */\r
+           "Illegal value.",         /* ERR_VAL        -8  */\r
+           "Illegal argument.",      /* ERR_ARG        -9  */\r
+           "Address in use.",        /* ERR_USE        -10 */\r
+           "Low-level netif error.", /* ERR_IF         -11 */\r
+           "Already connected.",     /* ERR_ISCONN     -12 */\r
+           "Timeout.",               /* ERR_TIMEOUT    -13 */\r
+           "Operation in progress."  /* ERR_INPROGRESS -14 */\r
+};\r
+\r
+/**\r
+ * Convert an lwip internal error to a string representation.\r
+ *\r
+ * @param err an lwip internal err_t\r
+ * @return a string representation for err\r
+ */\r
+const char *\r
+lwip_strerr(err_t err)\r
+{\r
+  return err_strerr[-err];\r
+\r
+}\r
+\r
+#endif /* LWIP_DEBUG */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/netbuf.c b/Demo/Common/ethernet/lwIP_130/src/api/netbuf.c
new file mode 100644 (file)
index 0000000..12f4881
--- /dev/null
@@ -0,0 +1,235 @@
+/**\r
+ * @file\r
+ * Network buffer management\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/netbuf.h"\r
+#include "lwip/memp.h"\r
+\r
+#include <string.h>\r
+\r
+/**\r
+ * Create (allocate) and initialize a new netbuf.\r
+ * The netbuf doesn't yet contain a packet buffer!\r
+ *\r
+ * @return a pointer to a new netbuf\r
+ *         NULL on lack of memory\r
+ */\r
+struct\r
+netbuf *netbuf_new(void)\r
+{\r
+  struct netbuf *buf;\r
+\r
+  buf = memp_malloc(MEMP_NETBUF);\r
+  if (buf != NULL) {\r
+    buf->p = NULL;\r
+    buf->ptr = NULL;\r
+    buf->addr = NULL;\r
+    return buf;\r
+  } else {\r
+    return NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * Deallocate a netbuf allocated by netbuf_new().\r
+ *\r
+ * @param buf pointer to a netbuf allocated by netbuf_new()\r
+ */\r
+void\r
+netbuf_delete(struct netbuf *buf)\r
+{\r
+  if (buf != NULL) {\r
+    if (buf->p != NULL) {\r
+      pbuf_free(buf->p);\r
+      buf->p = buf->ptr = NULL;\r
+    }\r
+    memp_free(MEMP_NETBUF, buf);\r
+  }\r
+}\r
+\r
+/**\r
+ * Allocate memory for a packet buffer for a given netbuf.\r
+ *\r
+ * @param buf the netbuf for which to allocate a packet buffer\r
+ * @param size the size of the packet buffer to allocate\r
+ * @return pointer to the allocated memory\r
+ *         NULL if no memory could be allocated\r
+ */\r
+void *\r
+netbuf_alloc(struct netbuf *buf, u16_t size)\r
+{\r
+  LWIP_ERROR("netbuf_alloc: invalid buf", (buf != NULL), return NULL;);\r
+\r
+  /* Deallocate any previously allocated memory. */\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, size, PBUF_RAM);\r
+  if (buf->p == NULL) {\r
+     return NULL;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold size",\r
+             (buf->p->len >= size));\r
+  buf->ptr = buf->p;\r
+  return buf->p->payload;\r
+}\r
+\r
+/**\r
+ * Free the packet buffer included in a netbuf\r
+ *\r
+ * @param buf pointer to the netbuf which contains the packet buffer to free\r
+ */\r
+void\r
+netbuf_free(struct netbuf *buf)\r
+{\r
+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = buf->ptr = NULL;\r
+}\r
+\r
+/**\r
+ * Let a netbuf reference existing (non-volatile) data.\r
+ *\r
+ * @param buf netbuf which should reference the data\r
+ * @param dataptr pointer to the data to reference\r
+ * @param size size of the data\r
+ * @return ERR_OK if data is referenced\r
+ *         ERR_MEM if data couldn't be referenced due to lack of memory\r
+ */\r
+err_t\r
+netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)\r
+{\r
+  LWIP_ERROR("netbuf_ref: invalid buf", (buf != NULL), return ERR_ARG;);\r
+  if (buf->p != NULL) {\r
+    pbuf_free(buf->p);\r
+  }\r
+  buf->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\r
+  if (buf->p == NULL) {\r
+    buf->ptr = NULL;\r
+    return ERR_MEM;\r
+  }\r
+  buf->p->payload = (void*)dataptr;\r
+  buf->p->len = buf->p->tot_len = size;\r
+  buf->ptr = buf->p;\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Chain one netbuf to another (@see pbuf_chain)\r
+ *\r
+ * @param head the first netbuf\r
+ * @param tail netbuf to chain after head\r
+ */\r
+void\r
+netbuf_chain(struct netbuf *head, struct netbuf *tail)\r
+{\r
+  LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);\r
+  LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);\r
+  pbuf_chain(head->p, tail->p);\r
+  head->ptr = head->p;\r
+  memp_free(MEMP_NETBUF, tail);\r
+}\r
+\r
+/**\r
+ * Get the data pointer and length of the data inside a netbuf.\r
+ *\r
+ * @param buf netbuf to get the data from\r
+ * @param dataptr pointer to a void pointer where to store the data pointer\r
+ * @param len pointer to an u16_t where the length of the data is stored\r
+ * @return ERR_OK if the information was retreived,\r
+ *         ERR_BUF on error.\r
+ */\r
+err_t\r
+netbuf_data(struct netbuf *buf, void **dataptr, u16_t *len)\r
+{\r
+  LWIP_ERROR("netbuf_data: invalid buf", (buf != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netbuf_data: invalid dataptr", (dataptr != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("netbuf_data: invalid len", (len != NULL), return ERR_ARG;);\r
+\r
+  if (buf->ptr == NULL) {\r
+    return ERR_BUF;\r
+  }\r
+  *dataptr = buf->ptr->payload;\r
+  *len = buf->ptr->len;\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Move the current data pointer of a packet buffer contained in a netbuf\r
+ * to the next part.\r
+ * The packet buffer itself is not modified.\r
+ *\r
+ * @param buf the netbuf to modify\r
+ * @return -1 if there is no next part\r
+ *         1  if moved to the next part but now there is no next part\r
+ *         0  if moved to the next part and there are still more parts\r
+ */\r
+s8_t\r
+netbuf_next(struct netbuf *buf)\r
+{\r
+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return -1;);\r
+  if (buf->ptr->next == NULL) {\r
+    return -1;\r
+  }\r
+  buf->ptr = buf->ptr->next;\r
+  if (buf->ptr->next == NULL) {\r
+    return 1;\r
+  }\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Move the current data pointer of a packet buffer contained in a netbuf\r
+ * to the beginning of the packet.\r
+ * The packet buffer itself is not modified.\r
+ *\r
+ * @param buf the netbuf to modify\r
+ */\r
+void\r
+netbuf_first(struct netbuf *buf)\r
+{\r
+  LWIP_ERROR("netbuf_free: invalid buf", (buf != NULL), return;);\r
+  buf->ptr = buf->p;\r
+}\r
+\r
+#endif /* LWIP_NETCONN */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/netdb.c b/Demo/Common/ethernet/lwIP_130/src/api/netdb.c
new file mode 100644 (file)
index 0000000..d45f83f
--- /dev/null
@@ -0,0 +1,352 @@
+/**\r
+ * @file\r
+ * API functions for name resolving\r
+ *\r
+ */\r
+\r
+/*\r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Simon Goldschmidt\r
+ *\r
+ */\r
+\r
+#include "lwip/netdb.h"\r
+\r
+#if LWIP_DNS && LWIP_SOCKET\r
+\r
+#include "lwip/err.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/api.h"\r
+\r
+/** helper struct for gethostbyname_r to access the char* buffer */\r
+struct gethostbyname_r_helper {\r
+  struct ip_addr *addrs;\r
+  struct ip_addr addr;\r
+  char *aliases;\r
+};\r
+\r
+/** h_errno is exported in netdb.h for access by applications. */\r
+#if LWIP_DNS_API_DECLARE_H_ERRNO\r
+int h_errno;\r
+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO */\r
+\r
+/** define "hostent" variables storage: 0 if we use a static (but unprotected)\r
+ * set of variables for lwip_gethostbyname, 1 if we use a local storage */\r
+#ifndef LWIP_DNS_API_HOSTENT_STORAGE\r
+#define LWIP_DNS_API_HOSTENT_STORAGE 0\r
+#endif\r
+\r
+/** define "hostent" variables storage */\r
+#if LWIP_DNS_API_HOSTENT_STORAGE\r
+#define HOSTENT_STORAGE\r
+#else\r
+#define HOSTENT_STORAGE static\r
+#endif /* LWIP_DNS_API_STATIC_HOSTENT */\r
+\r
+/**\r
+ * Returns an entry containing addresses of address family AF_INET\r
+ * for the host with name name.\r
+ * Due to dns_gethostbyname limitations, only one address is returned.\r
+ *\r
+ * @param name the hostname to resolve\r
+ * @return an entry containing addresses of address family AF_INET\r
+ *         for the host with name name\r
+ */\r
+struct hostent*\r
+lwip_gethostbyname(const char *name)\r
+{\r
+  err_t err;\r
+  struct ip_addr addr;\r
+\r
+  /* buffer variables for lwip_gethostbyname() */\r
+  HOSTENT_STORAGE struct hostent s_hostent;\r
+  HOSTENT_STORAGE char *s_aliases;\r
+  HOSTENT_STORAGE struct ip_addr s_hostent_addr;\r
+  HOSTENT_STORAGE struct ip_addr *s_phostent_addr;\r
+\r
+  /* query host IP address */\r
+  err = netconn_gethostbyname(name, &addr);\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));\r
+    h_errno = HOST_NOT_FOUND;\r
+    return NULL;\r
+  }\r
+\r
+  /* fill hostent */\r
+  s_hostent_addr = addr;\r
+  s_phostent_addr = &s_hostent_addr;\r
+  s_hostent.h_name = (char*)name;\r
+  s_hostent.h_aliases = &s_aliases;\r
+  s_hostent.h_addrtype = AF_INET;\r
+  s_hostent.h_length = sizeof(struct ip_addr);\r
+  s_hostent.h_addr_list = (char**)&s_phostent_addr;\r
+\r
+#if DNS_DEBUG\r
+  /* dump hostent */\r
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name           == %s\n",      s_hostent.h_name));\r
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases        == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));\r
+  if (s_hostent.h_aliases != NULL) {\r
+    u8_t idx;\r
+    for ( idx=0; s_hostent.h_aliases[idx]; idx++) {\r
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == 0x%08lX\n", idx, s_hostent.h_aliases[idx]));\r
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]->   == %s\n",      idx, s_hostent.h_aliases[idx]));\r
+    }\r
+  }\r
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype       == %lu\n",    (u32_t)(s_hostent.h_addrtype)));\r
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length         == %lu\n",    (u32_t)(s_hostent.h_length)));\r
+  LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list      == 0x%08lX\n", s_hostent.h_addr_list));\r
+  if (s_hostent.h_addr_list != NULL) {\r
+    u8_t idx;\r
+    for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {\r
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]   == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));\r
+      LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n",      idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));\r
+    }\r
+  }\r
+#endif /* DNS_DEBUG */\r
+\r
+#if LWIP_DNS_API_HOSTENT_STORAGE\r
+  /* this function should return the "per-thread" hostent after copy from s_hostent */\r
+  return sys_thread_hostent(&s_hostent);\r
+#else\r
+  return &s_hostent;\r
+#endif /* LWIP_DNS_API_HOSTENT_STORAGE */\r
+}\r
+\r
+/**\r
+ * Thread-safe variant of lwip_gethostbyname: instead of using a static\r
+ * buffer, this function takes buffer and errno pointers as arguments\r
+ * and uses these for the result.\r
+ *\r
+ * @param name the hostname to resolve\r
+ * @param ret pre-allocated struct where to store the result\r
+ * @param buf pre-allocated buffer where to store additional data\r
+ * @param buflen the size of buf\r
+ * @param result pointer to a hostent pointer that is set to ret on success\r
+ *               and set to zero on error\r
+ * @param h_errnop pointer to an int where to store errors (instead of modifying\r
+ *                 the global h_errno)\r
+ * @return 0 on success, non-zero on error, additional error information\r
+ *         is stored in *h_errnop instead of h_errno to be thread-safe\r
+ */\r
+int\r
+lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,\r
+                size_t buflen, struct hostent **result, int *h_errnop)\r
+{\r
+  err_t err;\r
+  struct gethostbyname_r_helper *h;\r
+  char *hostname;\r
+  size_t namelen;\r
+  int lh_errno;\r
+\r
+  if (h_errnop == NULL) {\r
+    /* ensure h_errnop is never NULL */\r
+    h_errnop = &lh_errno;\r
+  }\r
+\r
+  if (result == NULL) {\r
+    /* not all arguments given */\r
+    *h_errnop = EINVAL;\r
+    return -1;\r
+  }\r
+  /* first thing to do: set *result to nothing */\r
+  *result = NULL;\r
+  if ((name == NULL) || (ret == NULL) || (buf == 0)) {\r
+    /* not all arguments given */\r
+    *h_errnop = EINVAL;\r
+    return -1;\r
+  }\r
+\r
+  namelen = strlen(name);\r
+  if (buflen < (sizeof(struct gethostbyname_r_helper) + namelen + 1 + (MEM_ALIGNMENT - 1))) {\r
+    /* buf can't hold the data needed + a copy of name */\r
+    *h_errnop = ERANGE;\r
+    return -1;\r
+  }\r
+\r
+  h = (struct gethostbyname_r_helper*)LWIP_MEM_ALIGN(buf);\r
+  hostname = ((char*)h) + sizeof(struct gethostbyname_r_helper);\r
+\r
+  /* query host IP address */\r
+  err = netconn_gethostbyname(name, &(h->addr));\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("lwip_gethostbyname(%s) failed, err=%d\n", name, err));\r
+    *h_errnop = ENSRNOTFOUND;\r
+    return -1;\r
+  }\r
+\r
+  /* copy the hostname into buf */\r
+  MEMCPY(hostname, name, namelen);\r
+  hostname[namelen] = 0;\r
+\r
+  /* fill hostent */\r
+  h->addrs = &(h->addr);\r
+  h->aliases = NULL;\r
+  ret->h_name = (char*)hostname;\r
+  ret->h_aliases = &(h->aliases);\r
+  ret->h_addrtype = AF_INET;\r
+  ret->h_length = sizeof(struct ip_addr);\r
+  ret->h_addr_list = (char**)&(h->addrs);\r
+\r
+  /* set result != NULL */\r
+  *result = ret;\r
+\r
+  /* return success */\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Frees one or more addrinfo structures returned by getaddrinfo(), along with\r
+ * any additional storage associated with those structures. If the ai_next field\r
+ * of the structure is not null, the entire list of structures is freed.\r
+ *\r
+ * @param ai struct addrinfo to free\r
+ */\r
+void\r
+lwip_freeaddrinfo(struct addrinfo *ai)\r
+{\r
+  struct addrinfo *next;\r
+\r
+  while (ai != NULL) {\r
+    if (ai->ai_addr != NULL) {\r
+      mem_free(ai->ai_addr);\r
+    }\r
+    if (ai->ai_canonname != NULL) {\r
+      mem_free(ai->ai_canonname);\r
+    }\r
+    next = ai->ai_next;\r
+    mem_free(ai);\r
+    ai = next;\r
+  }\r
+}\r
+\r
+/**\r
+ * Translates the name of a service location (for example, a host name) and/or\r
+ * a service name and returns a set of socket addresses and associated\r
+ * information to be used in creating a socket with which to address the\r
+ * specified service.\r
+ * Memory for the result is allocated internally and must be freed by calling\r
+ * lwip_freeaddrinfo()!\r
+ *\r
+ * Due to a limitation in dns_gethostbyname, only the first address of a\r
+ * host is returned.\r
+ * Also, service names are not supported (only port numbers)!\r
+ *\r
+ * @param nodename descriptive name or address string of the host\r
+ *                 (may be NULL -> local address)\r
+ * @param servname port number as string of NULL \r
+ * @param hints structure containing input values that set socktype and protocol\r
+ * @param res pointer to a pointer where to store the result (set to NULL on failure)\r
+ * @return 0 on success, non-zero on failure\r
+ */\r
+int\r
+lwip_getaddrinfo(const char *nodename, const char *servname,\r
+       const struct addrinfo *hints, struct addrinfo **res)\r
+{\r
+  err_t err;\r
+  struct ip_addr addr;\r
+  struct addrinfo *ai;\r
+  struct sockaddr_in *sa = NULL;\r
+  int port_nr = 0;\r
+\r
+  if (res == NULL) {\r
+    return EAI_FAIL;\r
+  }\r
+  *res = NULL;\r
+  if ((nodename == NULL) && (servname == NULL)) {\r
+    return EAI_NONAME;\r
+  }\r
+\r
+  if (servname != NULL) {\r
+    /* service name specified: convert to port number\r
+     * @todo?: currently, only ASCII integers (port numbers) are supported! */\r
+    port_nr = atoi(servname);\r
+    if ((port_nr <= 0) || (port_nr > 0xffff)) {\r
+      return EAI_SERVICE;\r
+    }\r
+  }\r
+\r
+  if (nodename != NULL) {\r
+    /* service location specified, try to resolve */\r
+    err = netconn_gethostbyname(nodename, &addr);\r
+    if (err != ERR_OK) {\r
+      return EAI_FAIL;\r
+    }\r
+  } else {\r
+    /* service location specified, use loopback address */\r
+    addr.addr = INADDR_LOOPBACK;\r
+  }\r
+\r
+  ai = mem_malloc(sizeof(struct addrinfo));\r
+  if (ai == NULL) {\r
+    goto memerr;\r
+  }\r
+  memset(ai, 0, sizeof(struct addrinfo));\r
+  sa = mem_malloc(sizeof(struct sockaddr_in));\r
+  if (sa == NULL) {\r
+    goto memerr;\r
+  }\r
+  memset(sa, 0, sizeof(struct sockaddr_in));\r
+  /* set up sockaddr */\r
+  sa->sin_addr.s_addr = addr.addr;\r
+  sa->sin_family = AF_INET;\r
+  sa->sin_len = sizeof(struct sockaddr_in);\r
+  sa->sin_port = htons(port_nr);\r
+\r
+  /* set up addrinfo */\r
+  ai->ai_family = AF_INET;\r
+  if (hints != NULL) {\r
+    /* copy socktype & protocol from hints if specified */\r
+    ai->ai_socktype = hints->ai_socktype;\r
+    ai->ai_protocol = hints->ai_protocol;\r
+  }\r
+  if (nodename != NULL) {\r
+    /* copy nodename to canonname if specified */\r
+    size_t namelen = strlen(nodename);\r
+    ai->ai_canonname = mem_malloc(namelen + 1);\r
+    if (ai->ai_canonname == NULL) {\r
+      goto memerr;\r
+    }\r
+    MEMCPY(ai->ai_canonname, nodename, namelen);\r
+    ai->ai_canonname[namelen] = 0;\r
+  }\r
+  ai->ai_addrlen = sizeof(struct sockaddr_in);\r
+  ai->ai_addr = (struct sockaddr*)sa;\r
+\r
+  *res = ai;\r
+\r
+  return 0;\r
+memerr:\r
+  if (ai != NULL) {\r
+    mem_free(ai);\r
+  }\r
+  if (sa != NULL) {\r
+    mem_free(sa);\r
+  }\r
+  return EAI_MEMORY;\r
+}\r
+\r
+#endif /* LWIP_DNS && LWIP_SOCKET */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/netifapi.c b/Demo/Common/ethernet/lwIP_130/src/api/netifapi.c
new file mode 100644 (file)
index 0000000..49b6ef0
--- /dev/null
@@ -0,0 +1,126 @@
+/**\r
+ * @file\r
+ * Network Interface Sequential API module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/netifapi.h"\r
+#include "lwip/tcpip.h"\r
+\r
+/**\r
+ * Call netif_add() inside the tcpip_thread context.\r
+ */\r
+void\r
+do_netifapi_netif_add( struct netifapi_msg_msg *msg)\r
+{\r
+  if (!netif_add( msg->netif,\r
+                  msg->msg.add.ipaddr,\r
+                  msg->msg.add.netmask,\r
+                  msg->msg.add.gw,\r
+                  msg->msg.add.state,\r
+                  msg->msg.add.init,\r
+                  msg->msg.add.input)) {\r
+    msg->err = ERR_IF;\r
+  } else {\r
+    msg->err = ERR_OK;\r
+  }\r
+  TCPIP_NETIFAPI_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the\r
+ * tcpip_thread context.\r
+ */\r
+void\r
+do_netifapi_netif_common( struct netifapi_msg_msg *msg)\r
+{\r
+  if (msg->msg.common.errtfunc!=NULL) {\r
+    msg->err =\r
+    msg->msg.common.errtfunc(msg->netif);\r
+  } else {\r
+    msg->err = ERR_OK;\r
+    msg->msg.common.voidfunc(msg->netif);\r
+  }\r
+  TCPIP_NETIFAPI_ACK(msg);\r
+}\r
+\r
+/**\r
+ * Call netif_add() in a thread-safe way by running that function inside the\r
+ * tcpip_thread context.\r
+ *\r
+ * @note for params @see netif_add()\r
+ */\r
+err_t\r
+netifapi_netif_add(struct netif *netif,\r
+                   struct ip_addr *ipaddr,\r
+                   struct ip_addr *netmask,\r
+                   struct ip_addr *gw,\r
+                   void *state,\r
+                   err_t (* init)(struct netif *netif),\r
+                   err_t (* input)(struct pbuf *p, struct netif *netif))\r
+{\r
+  struct netifapi_msg msg;\r
+  msg.function = do_netifapi_netif_add;\r
+  msg.msg.netif = netif;\r
+  msg.msg.msg.add.ipaddr  = ipaddr;\r
+  msg.msg.msg.add.netmask = netmask;\r
+  msg.msg.msg.add.gw      = gw;\r
+  msg.msg.msg.add.state   = state;\r
+  msg.msg.msg.add.init    = init;\r
+  msg.msg.msg.add.input   = input;\r
+  TCPIP_NETIFAPI(&msg);\r
+  return msg.msg.err;\r
+}\r
+\r
+/**\r
+ * call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe\r
+ * way by running that function inside the tcpip_thread context.\r
+ *\r
+ * @note use only for functions where there is only "netif" parameter.\r
+ */\r
+err_t\r
+netifapi_netif_common( struct netif *netif,\r
+                       void  (* voidfunc)(struct netif *netif),\r
+                       err_t (* errtfunc)(struct netif *netif) )\r
+{\r
+  struct netifapi_msg msg;\r
+  msg.function = do_netifapi_netif_common;\r
+  msg.msg.netif = netif;\r
+  msg.msg.msg.common.voidfunc = voidfunc;\r
+  msg.msg.msg.common.errtfunc = errtfunc;\r
+  TCPIP_NETIFAPI(&msg);\r
+  return msg.msg.err;\r
+}\r
+\r
+#endif /* LWIP_NETIF_API */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/sockets.c b/Demo/Common/ethernet/lwIP_130/src/api/sockets.c
new file mode 100644 (file)
index 0000000..18663c9
--- /dev/null
@@ -0,0 +1,1924 @@
+/**\r
+ * @file\r
+ * Sockets BSD-Like API module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ * Improved by Marc Boucher <marc@mbsi.ca> and David Haas <dhaas@alum.rpi.edu>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/sockets.h"\r
+#include "lwip/api.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcpip.h"\r
+\r
+#include <string.h>\r
+\r
+#define NUM_SOCKETS MEMP_NUM_NETCONN\r
+\r
+/** Contains all internal pointers and states used for a socket */\r
+struct lwip_socket {\r
+  /** sockets currently are built on netconns, each socket has one netconn */\r
+  struct netconn *conn;\r
+  /** data that was left from the previous read */\r
+  struct netbuf *lastdata;\r
+  /** offset in the data that was left from the previous read */\r
+  u16_t lastoffset;\r
+  /** number of times data was received, set by event_callback(),\r
+      tested by the receive and select functions */\r
+  u16_t rcvevent;\r
+  /** number of times data was received, set by event_callback(),\r
+      tested by select */\r
+  u16_t sendevent;\r
+  /** socket flags (currently, only used for O_NONBLOCK) */\r
+  u16_t flags;\r
+  /** last error that occurred on this socket */\r
+  int err;\r
+};\r
+\r
+/** Description for a task waiting in select */\r
+struct lwip_select_cb {\r
+  /** Pointer to the next waiting task */\r
+  struct lwip_select_cb *next;\r
+  /** readset passed to select */\r
+  fd_set *readset;\r
+  /** writeset passed to select */\r
+  fd_set *writeset;\r
+  /** unimplemented: exceptset passed to select */\r
+  fd_set *exceptset;\r
+  /** don't signal the same semaphore twice: set to 1 when signalled */\r
+  int sem_signalled;\r
+  /** semaphore to wake up a task waiting for select */\r
+  sys_sem_t sem;\r
+};\r
+\r
+/** This struct is used to pass data to the set/getsockopt_internal\r
+ * functions running in tcpip_thread context (only a void* is allowed) */\r
+struct lwip_setgetsockopt_data {\r
+  /** socket struct for which to change options */\r
+  struct lwip_socket *sock;\r
+  /** socket index for which to change options */\r
+  int s;\r
+  /** level of the option to process */\r
+  int level;\r
+  /** name of the option to process */\r
+  int optname;\r
+  /** set: value to set the option to\r
+    * get: value of the option is stored here */\r
+  void *optval;\r
+  /** size of *optval */\r
+  socklen_t *optlen;\r
+  /** if an error occures, it is temporarily stored here */\r
+  err_t err;\r
+};\r
+\r
+/** The global array of available sockets */\r
+static struct lwip_socket sockets[NUM_SOCKETS];\r
+/** The global list of tasks waiting for select */\r
+static struct lwip_select_cb *select_cb_list;\r
+\r
+/** Semaphore protecting the sockets array */\r
+static sys_sem_t socksem;\r
+/** Semaphore protecting select_cb_list */\r
+static sys_sem_t selectsem;\r
+\r
+/** Table to quickly map an lwIP error (err_t) to a socket error\r
+  * by using -err as an index */\r
+static const int err_to_errno_table[] = {\r
+  0,             /* ERR_OK          0      No error, everything OK. */\r
+  ENOMEM,        /* ERR_MEM        -1      Out of memory error.     */\r
+  ENOBUFS,       /* ERR_BUF        -2      Buffer error.            */\r
+  EHOSTUNREACH,  /* ERR_RTE        -3      Routing problem.         */\r
+  ECONNABORTED,  /* ERR_ABRT       -4      Connection aborted.      */\r
+  ECONNRESET,    /* ERR_RST        -5      Connection reset.        */\r
+  ESHUTDOWN,     /* ERR_CLSD       -6      Connection closed.       */\r
+  ENOTCONN,      /* ERR_CONN       -7      Not connected.           */\r
+  EINVAL,        /* ERR_VAL        -8      Illegal value.           */\r
+  EIO,           /* ERR_ARG        -9      Illegal argument.        */\r
+  EADDRINUSE,    /* ERR_USE        -10     Address in use.          */\r
+  -1,            /* ERR_IF         -11     Low-level netif error    */\r
+  -1,            /* ERR_ISCONN     -12     Already connected.       */\r
+  ETIMEDOUT,     /* ERR_TIMEOUT    -13     Timeout                  */\r
+  EINPROGRESS    /* ERR_INPROGRESS -14     Operation in progress    */\r
+};\r
+\r
+#define ERR_TO_ERRNO_TABLE_SIZE \\r
+  (sizeof(err_to_errno_table)/sizeof(err_to_errno_table[0]))\r
+\r
+#define err_to_errno(err) \\r
+  ((unsigned)(-(err)) < ERR_TO_ERRNO_TABLE_SIZE ? \\r
+    err_to_errno_table[-(err)] : EIO)\r
+\r
+#ifdef ERRNO\r
+#define set_errno(err) errno = (err)\r
+#else\r
+#define set_errno(err)\r
+#endif\r
+\r
+#define sock_set_errno(sk, e) do { \\r
+  sk->err = (e); \\r
+  set_errno(sk->err); \\r
+} while (0)\r
+\r
+/* Forward delcaration of some functions */\r
+static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len);\r
+static void lwip_getsockopt_internal(void *arg);\r
+static void lwip_setsockopt_internal(void *arg);\r
+\r
+/**\r
+ * Initialize this module. This function has to be called before any other\r
+ * functions in this module!\r
+ */\r
+void\r
+lwip_socket_init(void)\r
+{\r
+  socksem   = sys_sem_new(1);\r
+  selectsem = sys_sem_new(1);\r
+}\r
+\r
+/**\r
+ * Map a externally used socket index to the internal socket representation.\r
+ *\r
+ * @param s externally used socket index\r
+ * @return struct lwip_socket for the socket or NULL if not found\r
+ */\r
+static struct lwip_socket *\r
+get_socket(int s)\r
+{\r
+  struct lwip_socket *sock;\r
+\r
+  if ((s < 0) || (s >= NUM_SOCKETS)) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s));\r
+    set_errno(EBADF);\r
+    return NULL;\r
+  }\r
+\r
+  sock = &sockets[s];\r
+\r
+  if (!sock->conn) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): not active\n", s));\r
+    set_errno(EBADF);\r
+    return NULL;\r
+  }\r
+\r
+  return sock;\r
+}\r
+\r
+/**\r
+ * Allocate a new socket for a given netconn.\r
+ *\r
+ * @param newconn the netconn for which to allocate a socket\r
+ * @return the index of the new socket; -1 on error\r
+ */\r
+static int\r
+alloc_socket(struct netconn *newconn)\r
+{\r
+  int i;\r
+\r
+  /* Protect socket array */\r
+  sys_sem_wait(socksem);\r
+\r
+  /* allocate a new socket identifier */\r
+  for (i = 0; i < NUM_SOCKETS; ++i) {\r
+    if (!sockets[i].conn) {\r
+      sockets[i].conn       = newconn;\r
+      sockets[i].lastdata   = NULL;\r
+      sockets[i].lastoffset = 0;\r
+      sockets[i].rcvevent   = 0;\r
+      sockets[i].sendevent  = 1; /* TCP send buf is empty */\r
+      sockets[i].flags      = 0;\r
+      sockets[i].err        = 0;\r
+      sys_sem_signal(socksem);\r
+      return i;\r
+    }\r
+  }\r
+  sys_sem_signal(socksem);\r
+  return -1;\r
+}\r
+\r
+/* Below this, the well-known socket functions are implemented.\r
+ * Use google.com or opengroup.org to get a good description :-)\r
+ *\r
+ * Exceptions are documented!\r
+ */\r
+\r
+int\r
+lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen)\r
+{\r
+  struct lwip_socket *sock, *nsock;\r
+  struct netconn *newconn;\r
+  struct ip_addr naddr;\r
+  u16_t port;\r
+  int newsock;\r
+  struct sockaddr_in sin;\r
+  err_t err;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s));\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  newconn = netconn_accept(sock->conn);\r
+  if (!newconn) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err));\r
+    sock_set_errno(sock, err_to_errno(sock->conn->err));\r
+    return -1;\r
+  }\r
+\r
+  /* get the IP address and port of the remote host */\r
+  err = netconn_peer(newconn, &naddr, &port);\r
+  if (err != ERR_OK) {\r
+    netconn_delete(newconn);\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  memset(&sin, 0, sizeof(sin));\r
+  sin.sin_len = sizeof(sin);\r
+  sin.sin_family = AF_INET;\r
+  sin.sin_port = htons(port);\r
+  sin.sin_addr.s_addr = naddr.addr;\r
+\r
+  if (*addrlen > sizeof(sin))\r
+    *addrlen = sizeof(sin);\r
+\r
+  SMEMCPY(addr, &sin, *addrlen);\r
+\r
+  newsock = alloc_socket(newconn);\r
+  if (newsock == -1) {\r
+    netconn_delete(newconn);\r
+    sock_set_errno(sock, ENFILE);\r
+    return -1;\r
+  }\r
+  LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS));\r
+  newconn->callback = event_callback;\r
+  nsock = &sockets[newsock];\r
+  LWIP_ASSERT("invalid socket pointer", nsock != NULL);\r
+\r
+  sys_sem_wait(socksem);\r
+  /* See event_callback: If data comes in right away after an accept, even\r
+   * though the server task might not have created a new socket yet.\r
+   * In that case, newconn->socket is counted down (newconn->socket--),\r
+   * so nsock->rcvevent is >= 1 here!\r
+   */\r
+  nsock->rcvevent += -1 - newconn->socket;\r
+  newconn->socket = newsock;\r
+  sys_sem_signal(socksem);\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", port));\r
+\r
+  sock_set_errno(sock, 0);\r
+  return newsock;\r
+}\r
+\r
+int\r
+lwip_bind(int s, struct sockaddr *name, socklen_t namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct ip_addr local_addr;\r
+  u16_t local_port;\r
+  err_t err;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&\r
+             ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),\r
+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\r
+\r
+  local_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;\r
+  local_port = ((struct sockaddr_in *)name)->sin_port;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &local_addr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(local_port)));\r
+\r
+  err = netconn_bind(sock->conn, &local_addr, ntohs(local_port));\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d) succeeded\n", s));\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_close(int s)\r
+{\r
+  struct lwip_socket *sock;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s));\r
+\r
+  sock = get_socket(s);\r
+  if (!sock) {\r
+    return -1;\r
+  }\r
+\r
+  netconn_delete(sock->conn);\r
+\r
+  sys_sem_wait(socksem);\r
+  if (sock->lastdata) {\r
+    netbuf_delete(sock->lastdata);\r
+  }\r
+  sock->lastdata   = NULL;\r
+  sock->lastoffset = 0;\r
+  sock->conn       = NULL;\r
+  sock_set_errno(sock, 0);\r
+  sys_sem_signal(socksem);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_connect(int s, const struct sockaddr *name, socklen_t namelen)\r
+{\r
+  struct lwip_socket *sock;\r
+  err_t err;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) &&\r
+             ((((struct sockaddr_in *)name)->sin_family) == AF_INET)),\r
+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\r
+\r
+  if (((struct sockaddr_in *)name)->sin_family == AF_UNSPEC) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s));\r
+    err = netconn_disconnect(sock->conn);\r
+  } else {\r
+    struct ip_addr remote_addr;\r
+    u16_t remote_port;\r
+\r
+    remote_addr.addr = ((struct sockaddr_in *)name)->sin_addr.s_addr;\r
+    remote_port = ((struct sockaddr_in *)name)->sin_port;\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u)\n", ntohs(remote_port)));\r
+\r
+    err = netconn_connect(sock->conn, &remote_addr, ntohs(remote_port));\r
+  }\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d) succeeded\n", s));\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Set a socket into listen mode.\r
+ * The socket may not have been used for another connection previously.\r
+ *\r
+ * @param s the socket to set to listening mode\r
+ * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1)\r
+ * @return 0 on success, non-zero on failure\r
+ */\r
+int\r
+lwip_listen(int s, int backlog)\r
+{\r
+  struct lwip_socket *sock;\r
+  err_t err;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog));\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  /* limit the "backlog" parameter to fit in an u8_t */\r
+  if (backlog < 0) {\r
+    backlog = 0;\r
+  }\r
+  if (backlog > 0xff) {\r
+    backlog = 0xff;\r
+  }\r
+\r
+  err = netconn_listen_with_backlog(sock->conn, backlog);\r
+\r
+  if (err != ERR_OK) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err));\r
+    sock_set_errno(sock, err_to_errno(err));\r
+    return -1;\r
+  }\r
+\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_recvfrom(int s, void *mem, int len, unsigned int flags,\r
+        struct sockaddr *from, socklen_t *fromlen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct netbuf      *buf;\r
+  u16_t               buflen, copylen, off = 0;\r
+  struct ip_addr     *addr;\r
+  u16_t               port;\r
+  u8_t                done = 0;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %d, 0x%x, ..)\n", s, mem, len, flags));\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  do {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata));\r
+    /* Check if there is data left from the last recv operation. */\r
+    if (sock->lastdata) {\r
+      buf = sock->lastdata;\r
+    } else {\r
+      /* If this is non-blocking call, then check first */\r
+      if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && !sock->rcvevent) {\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): returning EWOULDBLOCK\n", s));\r
+        sock_set_errno(sock, EWOULDBLOCK);\r
+        return -1;\r
+      }\r
+\r
+      /* No data was left from the previous operation, so we try to get\r
+      some from the network. */\r
+      sock->lastdata = buf = netconn_recv(sock->conn);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf));\r
+\r
+      if (!buf) {\r
+        /* We should really do some error checking here. */\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s));\r
+        sock_set_errno(sock, (((sock->conn->pcb.ip!=NULL) && (sock->conn->err==ERR_OK))?ETIMEDOUT:err_to_errno(sock->conn->err)));\r
+        return 0;\r
+      }\r
+    }\r
+\r
+    buflen = netbuf_len(buf);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%d len=%d off=%d sock->lastoffset=%d\n", buflen, len, off, sock->lastoffset));\r
+\r
+    buflen -= sock->lastoffset;\r
+\r
+    if (len > buflen) {\r
+      copylen = buflen;\r
+    } else {\r
+      copylen = len;\r
+    }\r
+\r
+    /* copy the contents of the received buffer into\r
+    the supplied memory pointer mem */\r
+    netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset);\r
+\r
+    off += copylen;\r
+\r
+    if (netconn_type(sock->conn) == NETCONN_TCP) {\r
+      len -= copylen;\r
+      if ( (len <= 0) || (buf->p->flags & PBUF_FLAG_PUSH) || !sock->rcvevent) {\r
+        done = 1;\r
+      }\r
+    } else {\r
+      done = 1;\r
+    }\r
+\r
+    /* If we don't peek the incoming message... */\r
+    if ((flags & MSG_PEEK)==0) {\r
+      /* If this is a TCP socket, check if there is data left in the\r
+         buffer. If so, it should be saved in the sock structure for next\r
+         time around. */\r
+      if ((sock->conn->type == NETCONN_TCP) && (buflen - copylen > 0)) {\r
+        sock->lastdata = buf;\r
+        sock->lastoffset += copylen;\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf));\r
+      } else {\r
+        sock->lastdata = NULL;\r
+        sock->lastoffset = 0;\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf));\r
+        netbuf_delete(buf);\r
+      }\r
+    } else {\r
+      done = 1;\r
+    }\r
+  } while (!done);\r
+\r
+  /* Check to see from where the data was.*/\r
+  if (from && fromlen) {\r
+    struct sockaddr_in sin;\r
+\r
+    if (netconn_type(sock->conn) == NETCONN_TCP) {\r
+      addr = (struct ip_addr*)&(sin.sin_addr.s_addr);\r
+      netconn_getaddr(sock->conn, addr, &port, 0);\r
+    } else {\r
+      addr = netbuf_fromaddr(buf);\r
+      port = netbuf_fromport(buf);\r
+    }\r
+\r
+    memset(&sin, 0, sizeof(sin));\r
+    sin.sin_len = sizeof(sin);\r
+    sin.sin_family = AF_INET;\r
+    sin.sin_port = htons(port);\r
+    sin.sin_addr.s_addr = addr->addr;\r
+\r
+    if (*fromlen > sizeof(sin))\r
+      *fromlen = sizeof(sin);\r
+\r
+    SMEMCPY(from, &sin, *fromlen);\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));\r
+  } else {\r
+#if SOCKETS_DEBUG\r
+    struct sockaddr_in sin;\r
+\r
+    if (netconn_type(sock->conn) == NETCONN_TCP) {\r
+      addr = (struct ip_addr*)&(sin.sin_addr.s_addr);\r
+      netconn_getaddr(sock->conn, addr, &port, 0);\r
+    } else {\r
+      addr = netbuf_fromaddr(buf);\r
+      port = netbuf_fromport(buf);\r
+    }\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s));\r
+    ip_addr_debug_print(SOCKETS_DEBUG, addr);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u len=%u\n", port, off));\r
+#endif /*  SOCKETS_DEBUG */\r
+  }\r
+\r
+  sock_set_errno(sock, 0);\r
+  return off;\r
+}\r
+\r
+int\r
+lwip_read(int s, void *mem, int len)\r
+{\r
+  return lwip_recvfrom(s, mem, len, 0, NULL, NULL);\r
+}\r
+\r
+int\r
+lwip_recv(int s, void *mem, int len, unsigned int flags)\r
+{\r
+  return lwip_recvfrom(s, mem, len, flags, NULL, NULL);\r
+}\r
+\r
+int\r
+lwip_send(int s, const void *data, int size, unsigned int flags)\r
+{\r
+  struct lwip_socket *sock;\r
+  err_t err;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%d, flags=0x%x)\n",\r
+                              s, data, size, flags));\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  if (sock->conn->type!=NETCONN_TCP) {\r
+#if (LWIP_UDP || LWIP_RAW)\r
+    return lwip_sendto(s, data, size, flags, NULL, 0);\r
+#else\r
+    sock_set_errno(sock, err_to_errno(ERR_ARG));\r
+    return -1;\r
+#endif /* (LWIP_UDP || LWIP_RAW) */\r
+  }\r
+\r
+  err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0));\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%d\n", s, err, size));\r
+  sock_set_errno(sock, err_to_errno(err));\r
+  return (err==ERR_OK?size:-1);\r
+}\r
+\r
+int\r
+lwip_sendto(int s, const void *data, int size, unsigned int flags,\r
+       struct sockaddr *to, socklen_t tolen)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct ip_addr remote_addr;\r
+  int err;\r
+#if !LWIP_TCPIP_CORE_LOCKING\r
+  struct netbuf buf;\r
+  u16_t remote_port;\r
+#endif\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  if (sock->conn->type==NETCONN_TCP) {\r
+#if LWIP_TCP\r
+    return lwip_send(s, data, size, flags);\r
+#else\r
+    sock_set_errno(sock, err_to_errno(ERR_ARG));\r
+    return -1;\r
+#endif /* LWIP_TCP */\r
+  }\r
+\r
+  LWIP_ASSERT("lwip_sendto: size must fit in u16_t",\r
+              ((size >= 0) && (size <= 0xffff)));\r
+  LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) ||\r
+             ((tolen == sizeof(struct sockaddr_in)) &&\r
+             ((((struct sockaddr_in *)to)->sin_family) == AF_INET))),\r
+             sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;);\r
+\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+  /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */\r
+  { struct pbuf* p;\r
+\r
+    p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF);\r
+    if (p == NULL) {\r
+      err = ERR_MEM;\r
+    } else {\r
+      p->payload = (void*)data;\r
+      p->len = p->tot_len = size;\r
+\r
+      remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;\r
+\r
+      LOCK_TCPIP_CORE();\r
+      if (sock->conn->type==NETCONN_RAW) {\r
+        err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr);\r
+      } else {\r
+        err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((struct sockaddr_in *)to)->sin_port));\r
+      }\r
+      UNLOCK_TCPIP_CORE();\r
+\r
+      pbuf_free(p);\r
+    }\r
+  }\r
+#else\r
+  /* initialize a buffer */\r
+  buf.p = buf.ptr = NULL;\r
+  if (to) {\r
+    remote_addr.addr = ((struct sockaddr_in *)to)->sin_addr.s_addr;\r
+    remote_port      = ntohs(((struct sockaddr_in *)to)->sin_port);\r
+    buf.addr         = &remote_addr;\r
+    buf.port         = remote_port;\r
+  } else {\r
+    remote_addr.addr = 0;\r
+    remote_port      = 0;\r
+    buf.addr         = NULL;\r
+    buf.port         = 0;\r
+  }\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, size=%d, flags=0x%x to=",\r
+              s, data, size, flags));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%u\n", remote_port));\r
+\r
+  /* make the buffer point to the data that should be sent */\r
+  if ((err = netbuf_ref(&buf, data, size)) == ERR_OK) {\r
+    /* send the data */\r
+    err = netconn_send(sock->conn, &buf);\r
+  }\r
+\r
+  /* deallocated the buffer */\r
+  if (buf.p != NULL) {\r
+    pbuf_free(buf.p);\r
+  }\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+  sock_set_errno(sock, err_to_errno(err));\r
+  return (err==ERR_OK?size:-1);\r
+}\r
+\r
+int\r
+lwip_socket(int domain, int type, int protocol)\r
+{\r
+  struct netconn *conn;\r
+  int i;\r
+\r
+  LWIP_UNUSED_ARG(domain);\r
+\r
+  /* create a netconn */\r
+  switch (type) {\r
+  case SOCK_RAW:\r
+    conn = netconn_new_with_proto_and_callback(NETCONN_RAW, (u8_t)protocol, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_RAW, %d) = ",\r
+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  case SOCK_DGRAM:\r
+    conn = netconn_new_with_callback( (protocol == IPPROTO_UDPLITE) ?\r
+                 NETCONN_UDPLITE : NETCONN_UDP, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_DGRAM, %d) = ",\r
+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  case SOCK_STREAM:\r
+    conn = netconn_new_with_callback(NETCONN_TCP, event_callback);\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ",\r
+                                 domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol));\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n",\r
+                                 domain, type, protocol));\r
+    set_errno(EINVAL);\r
+    return -1;\r
+  }\r
+\r
+  if (!conn) {\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("-1 / ENOBUFS (could not create netconn)\n"));\r
+    set_errno(ENOBUFS);\r
+    return -1;\r
+  }\r
+\r
+  i = alloc_socket(conn);\r
+\r
+  if (i == -1) {\r
+    netconn_delete(conn);\r
+    set_errno(ENFILE);\r
+    return -1;\r
+  }\r
+  conn->socket = i;\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("%d\n", i));\r
+  set_errno(0);\r
+  return i;\r
+}\r
+\r
+int\r
+lwip_write(int s, const void *data, int size)\r
+{\r
+  return lwip_send(s, data, size, 0);\r
+}\r
+\r
+/**\r
+ * Go through the readset and writeset lists and see which socket of the sockets\r
+ * set in the sets has events. On return, readset, writeset and exceptset have\r
+ * the sockets enabled that had events.\r
+ *\r
+ * exceptset is not used for now!!!\r
+ *\r
+ * @param maxfdp1 the highest socket index in the sets\r
+ * @param readset in: set of sockets to check for read events;\r
+ *                out: set of sockets that had read events\r
+ * @param writeset in: set of sockets to check for write events;\r
+ *                 out: set of sockets that had write events\r
+ * @param exceptset not yet implemented\r
+ * @return number of sockets that had events (read+write)\r
+ */\r
+static int\r
+lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset)\r
+{\r
+  int i, nready = 0;\r
+  fd_set lreadset, lwriteset, lexceptset;\r
+  struct lwip_socket *p_sock;\r
+\r
+  FD_ZERO(&lreadset);\r
+  FD_ZERO(&lwriteset);\r
+  FD_ZERO(&lexceptset);\r
+\r
+  /* Go through each socket in each list to count number of sockets which\r
+  currently match */\r
+  for(i = 0; i < maxfdp1; i++) {\r
+    if (FD_ISSET(i, readset)) {\r
+      /* See if netconn of this socket is ready for read */\r
+      p_sock = get_socket(i);\r
+      if (p_sock && (p_sock->lastdata || p_sock->rcvevent)) {\r
+        FD_SET(i, &lreadset);\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i));\r
+        nready++;\r
+      }\r
+    }\r
+    if (FD_ISSET(i, writeset)) {\r
+      /* See if netconn of this socket is ready for write */\r
+      p_sock = get_socket(i);\r
+      if (p_sock && p_sock->sendevent) {\r
+        FD_SET(i, &lwriteset);\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i));\r
+        nready++;\r
+      }\r
+    }\r
+  }\r
+  *readset = lreadset;\r
+  *writeset = lwriteset;\r
+  FD_ZERO(exceptset);\r
+\r
+  return nready;\r
+}\r
+\r
+\r
+/**\r
+ * Processing exceptset is not yet implemented.\r
+ */\r
+int\r
+lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\r
+               struct timeval *timeout)\r
+{\r
+  int i;\r
+  int nready;\r
+  fd_set lreadset, lwriteset, lexceptset;\r
+  u32_t msectimeout;\r
+  struct lwip_select_cb select_cb;\r
+  struct lwip_select_cb *p_selcb;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n",\r
+                  maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset,\r
+                  timeout ? timeout->tv_sec : -1L, timeout ? timeout->tv_usec : -1L));\r
+\r
+  select_cb.next = 0;\r
+  select_cb.readset = readset;\r
+  select_cb.writeset = writeset;\r
+  select_cb.exceptset = exceptset;\r
+  select_cb.sem_signalled = 0;\r
+\r
+  /* Protect ourselves searching through the list */\r
+  sys_sem_wait(selectsem);\r
+\r
+  if (readset)\r
+    lreadset = *readset;\r
+  else\r
+    FD_ZERO(&lreadset);\r
+  if (writeset)\r
+    lwriteset = *writeset;\r
+  else\r
+    FD_ZERO(&lwriteset);\r
+  if (exceptset)\r
+    lexceptset = *exceptset;\r
+  else\r
+    FD_ZERO(&lexceptset);\r
+\r
+  /* Go through each socket in each list to count number of sockets which\r
+     currently match */\r
+  nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);\r
+\r
+  /* If we don't have any current events, then suspend if we are supposed to */\r
+  if (!nready) {\r
+    if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) {\r
+      sys_sem_signal(selectsem);\r
+      if (readset)\r
+        FD_ZERO(readset);\r
+      if (writeset)\r
+        FD_ZERO(writeset);\r
+      if (exceptset)\r
+        FD_ZERO(exceptset);\r
+\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n"));\r
+      set_errno(0);\r
+\r
+      return 0;\r
+    }\r
+\r
+    /* add our semaphore to list */\r
+    /* We don't actually need any dynamic memory. Our entry on the\r
+     * list is only valid while we are in this function, so it's ok\r
+     * to use local variables */\r
+\r
+    select_cb.sem = sys_sem_new(0);\r
+    /* Note that we are still protected */\r
+    /* Put this select_cb on top of list */\r
+    select_cb.next = select_cb_list;\r
+    select_cb_list = &select_cb;\r
+\r
+    /* Now we can safely unprotect */\r
+    sys_sem_signal(selectsem);\r
+\r
+    /* Now just wait to be woken */\r
+    if (timeout == 0)\r
+      /* Wait forever */\r
+      msectimeout = 0;\r
+    else {\r
+      msectimeout =  ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000));\r
+      if(msectimeout == 0)\r
+        msectimeout = 1;\r
+    }\r
+\r
+    i = sys_sem_wait_timeout(select_cb.sem, msectimeout);\r
+\r
+    /* Take us off the list */\r
+    sys_sem_wait(selectsem);\r
+    if (select_cb_list == &select_cb)\r
+      select_cb_list = select_cb.next;\r
+    else\r
+      for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) {\r
+        if (p_selcb->next == &select_cb) {\r
+          p_selcb->next = select_cb.next;\r
+          break;\r
+        }\r
+      }\r
+\r
+    sys_sem_signal(selectsem);\r
+\r
+    sys_sem_free(select_cb.sem);\r
+    if (i == 0)  {\r
+      /* Timeout */\r
+      if (readset)\r
+        FD_ZERO(readset);\r
+      if (writeset)\r
+        FD_ZERO(writeset);\r
+      if (exceptset)\r
+        FD_ZERO(exceptset);\r
+\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n"));\r
+      set_errno(0);\r
+\r
+      return 0;\r
+    }\r
+\r
+    if (readset)\r
+      lreadset = *readset;\r
+    else\r
+      FD_ZERO(&lreadset);\r
+    if (writeset)\r
+      lwriteset = *writeset;\r
+    else\r
+      FD_ZERO(&lwriteset);\r
+    if (exceptset)\r
+      lexceptset = *exceptset;\r
+    else\r
+      FD_ZERO(&lexceptset);\r
+\r
+    /* See what's set */\r
+    nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset);\r
+  } else\r
+    sys_sem_signal(selectsem);\r
+\r
+  if (readset)\r
+    *readset = lreadset;\r
+  if (writeset)\r
+    *writeset = lwriteset;\r
+  if (exceptset)\r
+    *exceptset = lexceptset;\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready));\r
+  set_errno(0);\r
+\r
+  return nready;\r
+}\r
+\r
+/**\r
+ * Callback registered in the netconn layer for each socket-netconn.\r
+ * Processes recvevent (data available) and wakes up tasks waiting for select.\r
+ */\r
+static void\r
+event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len)\r
+{\r
+  int s;\r
+  struct lwip_socket *sock;\r
+  struct lwip_select_cb *scb;\r
+\r
+  LWIP_UNUSED_ARG(len);\r
+\r
+  /* Get socket */\r
+  if (conn) {\r
+    s = conn->socket;\r
+    if (s < 0) {\r
+      /* Data comes in right away after an accept, even though\r
+       * the server task might not have created a new socket yet.\r
+       * Just count down (or up) if that's the case and we\r
+       * will use the data later. Note that only receive events\r
+       * can happen before the new socket is set up. */\r
+      sys_sem_wait(socksem);\r
+      if (conn->socket < 0) {\r
+        if (evt == NETCONN_EVT_RCVPLUS) {\r
+          conn->socket--;\r
+        }\r
+        sys_sem_signal(socksem);\r
+        return;\r
+      }\r
+      sys_sem_signal(socksem);\r
+    }\r
+\r
+    sock = get_socket(s);\r
+    if (!sock) {\r
+      return;\r
+    }\r
+  } else {\r
+    return;\r
+  }\r
+\r
+  sys_sem_wait(selectsem);\r
+  /* Set event as required */\r
+  switch (evt) {\r
+    case NETCONN_EVT_RCVPLUS:\r
+      sock->rcvevent++;\r
+      break;\r
+    case NETCONN_EVT_RCVMINUS:\r
+      sock->rcvevent--;\r
+      break;\r
+    case NETCONN_EVT_SENDPLUS:\r
+      sock->sendevent = 1;\r
+      break;\r
+    case NETCONN_EVT_SENDMINUS:\r
+      sock->sendevent = 0;\r
+      break;\r
+    default:\r
+      LWIP_ASSERT("unknown event", 0);\r
+      break;\r
+  }\r
+  sys_sem_signal(selectsem);\r
+\r
+  /* Now decide if anyone is waiting for this socket */\r
+  /* NOTE: This code is written this way to protect the select link list\r
+     but to avoid a deadlock situation by releasing socksem before\r
+     signalling for the select. This means we need to go through the list\r
+     multiple times ONLY IF a select was actually waiting. We go through\r
+     the list the number of waiting select calls + 1. This list is\r
+     expected to be small. */\r
+  while (1) {\r
+    sys_sem_wait(selectsem);\r
+    for (scb = select_cb_list; scb; scb = scb->next) {\r
+      if (scb->sem_signalled == 0) {\r
+        /* Test this select call for our socket */\r
+        if (scb->readset && FD_ISSET(s, scb->readset))\r
+          if (sock->rcvevent)\r
+            break;\r
+        if (scb->writeset && FD_ISSET(s, scb->writeset))\r
+          if (sock->sendevent)\r
+            break;\r
+      }\r
+    }\r
+    if (scb) {\r
+      scb->sem_signalled = 1;\r
+      sys_sem_signal(selectsem);\r
+      sys_sem_signal(scb->sem);\r
+    } else {\r
+      sys_sem_signal(selectsem);\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Unimplemented: Close one end of a full-duplex connection.\r
+ * Currently, the full connection is closed.\r
+ */\r
+int\r
+lwip_shutdown(int s, int how)\r
+{\r
+  LWIP_UNUSED_ARG(how);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how));\r
+  return lwip_close(s); /* XXX temporary hack until proper implementation */\r
+}\r
+\r
+static int\r
+lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local)\r
+{\r
+  struct lwip_socket *sock;\r
+  struct sockaddr_in sin;\r
+  struct ip_addr naddr;\r
+\r
+  sock = get_socket(s);\r
+  if (!sock)\r
+    return -1;\r
+\r
+  memset(&sin, 0, sizeof(sin));\r
+  sin.sin_len = sizeof(sin);\r
+  sin.sin_family = AF_INET;\r
+\r
+  /* get the IP address and port */\r
+  netconn_getaddr(sock->conn, &naddr, &sin.sin_port, local);\r
+\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getaddrname(%d, addr=", s));\r
+  ip_addr_debug_print(SOCKETS_DEBUG, &naddr);\r
+  LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%d)\n", sin.sin_port));\r
+\r
+  sin.sin_port = htons(sin.sin_port);\r
+  sin.sin_addr.s_addr = naddr.addr;\r
+\r
+  if (*namelen > sizeof(sin))\r
+    *namelen = sizeof(sin);\r
+\r
+  SMEMCPY(name, &sin, *namelen);\r
+  sock_set_errno(sock, 0);\r
+  return 0;\r
+}\r
+\r
+int\r
+lwip_getpeername(int s, struct sockaddr *name, socklen_t *namelen)\r
+{\r
+  return lwip_getaddrname(s, name, namelen, 0);\r
+}\r
+\r
+int\r
+lwip_getsockname(int s, struct sockaddr *name, socklen_t *namelen)\r
+{\r
+  return lwip_getaddrname(s, name, namelen, 1);\r
+}\r
+\r
+int\r
+lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen)\r
+{\r
+  err_t err = ERR_OK;\r
+  struct lwip_socket *sock = get_socket(s);\r
+  struct lwip_setgetsockopt_data data;\r
+\r
+  if (!sock)\r
+    return -1;\r
+\r
+  if ((NULL == optval) || (NULL == optlen)) {\r
+    sock_set_errno(sock, EFAULT);\r
+    return -1;\r
+  }\r
+\r
+  /* Do length and type checks for the various options first, to keep it readable. */\r
+  switch (level) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch (optname) {\r
+\r
+    case SO_ACCEPTCONN:\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_ERROR:\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_CONTIMEO: */\r
+    /* UNIMPL case SO_SNDTIMEO: */\r
+#if LWIP_SO_RCVTIMEO\r
+    case SO_RCVTIMEO:\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+    case SO_RCVBUF:\r
+#endif /* LWIP_SO_RCVBUF */\r
+    /* UNIMPL case SO_OOBINLINE: */\r
+    /* UNIMPL case SO_SNDBUF: */\r
+    /* UNIMPL case SO_RCVLOWAT: */\r
+    /* UNIMPL case SO_SNDLOWAT: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    case SO_TYPE:\r
+    /* UNIMPL case SO_USELOOPBACK: */\r
+      if (*optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+\r
+    case SO_NO_CHECK:\r
+      if (*optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+#if LWIP_UDP\r
+      if ((sock->conn->type != NETCONN_UDP) ||\r
+          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {\r
+        /* this flag is only available for UDP, not for UDP lite */\r
+        err = EAFNOSUPPORT;\r
+      }\r
+#endif /* LWIP_UDP */\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",\r
+                                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch (optname) {\r
+    /* UNIMPL case IP_HDRINCL: */\r
+    /* UNIMPL case IP_RCVDSTADDR: */\r
+    /* UNIMPL case IP_RCVIF: */\r
+    case IP_TTL:\r
+    case IP_TOS:\r
+      if (*optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+#if LWIP_IGMP\r
+    case IP_MULTICAST_TTL:\r
+      if (*optlen < sizeof(u8_t)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+    case IP_MULTICAST_IF:\r
+      if (*optlen < sizeof(struct in_addr)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+#endif /* LWIP_IGMP */\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",\r
+                                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+#if LWIP_TCP\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    if (*optlen < sizeof(int)) {\r
+      err = EINVAL;\r
+      break;\r
+    }\r
+\r
+    /* If this is no TCP socket, ignore any options. */\r
+    if (sock->conn->type != NETCONN_TCP)\r
+      return 0;\r
+\r
+    switch (optname) {\r
+    case TCP_NODELAY:\r
+    case TCP_KEEPALIVE:\r
+#if LWIP_TCP_KEEPALIVE\r
+    case TCP_KEEPIDLE:\r
+    case TCP_KEEPINTVL:\r
+    case TCP_KEEPCNT:\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",\r
+                                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_TCP */\r
+#if LWIP_UDP && LWIP_UDPLITE\r
+/* Level: IPPROTO_UDPLITE */\r
+  case IPPROTO_UDPLITE:\r
+    if (*optlen < sizeof(int)) {\r
+      err = EINVAL;\r
+      break;\r
+    }\r
+\r
+    /* If this is no UDP lite socket, ignore any options. */\r
+    if (sock->conn->type != NETCONN_UDPLITE)\r
+      return 0;\r
+\r
+    switch (optname) {\r
+    case UDPLITE_SEND_CSCOV:\r
+    case UDPLITE_RECV_CSCOV:\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",\r
+                                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_UDP && LWIP_UDPLITE*/\r
+/* UNDEFINED LEVEL */\r
+  default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",\r
+                                  s, level, optname));\r
+      err = ENOPROTOOPT;\r
+  }  /* switch */\r
+\r
+\r
+  if (err != ERR_OK) {\r
+    sock_set_errno(sock, err);\r
+    return -1;\r
+  }\r
+\r
+  /* Now do the actual option processing */\r
+  data.sock = sock;\r
+  data.level = level;\r
+  data.optname = optname;\r
+  data.optval = optval;\r
+  data.optlen = optlen;\r
+  data.err = err;\r
+  tcpip_callback(lwip_getsockopt_internal, &data);\r
+  sys_arch_sem_wait(sock->conn->op_completed, 0);\r
+  /* maybe lwip_getsockopt_internal has changed err */\r
+  err = data.err;\r
+\r
+  sock_set_errno(sock, err);\r
+  return err ? -1 : 0;\r
+}\r
+\r
+static void\r
+lwip_getsockopt_internal(void *arg)\r
+{\r
+  struct lwip_socket *sock;\r
+#ifdef LWIP_DEBUG\r
+  int s;\r
+#endif /* LWIP_DEBUG */\r
+  int level, optname;\r
+  void *optval;\r
+  struct lwip_setgetsockopt_data *data;\r
+\r
+  LWIP_ASSERT("arg != NULL", arg != NULL);\r
+\r
+  data = (struct lwip_setgetsockopt_data*)arg;\r
+  sock = data->sock;\r
+#ifdef LWIP_DEBUG\r
+  s = data->s;\r
+#endif /* LWIP_DEBUG */\r
+  level = data->level;\r
+  optname = data->optname;\r
+  optval = data->optval;\r
+\r
+  switch (level) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch (optname) {\r
+\r
+    /* The option flags */\r
+    case SO_ACCEPTCONN:\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_OOBINCLUDE: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /*case SO_USELOOPBACK: UNIMPL */\r
+      *(int*)optval = sock->conn->pcb.ip->so_options & optname;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, optname=0x%x, ..) = %s\n",\r
+                                  s, optname, (*(int*)optval?"on":"off")));\r
+      break;\r
+\r
+    case SO_TYPE:\r
+      switch (NETCONNTYPE_GROUP(sock->conn->type)) {\r
+      case NETCONN_RAW:\r
+        *(int*)optval = SOCK_RAW;\r
+        break;\r
+      case NETCONN_TCP:\r
+        *(int*)optval = SOCK_STREAM;\r
+        break;\r
+      case NETCONN_UDP:\r
+        *(int*)optval = SOCK_DGRAM;\r
+        break;\r
+      default: /* unrecognized socket type */\r
+        *(int*)optval = sock->conn->type;\r
+        LWIP_DEBUGF(SOCKETS_DEBUG,\r
+                    ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE): unrecognized socket type %d\n",\r
+                    s, *(int *)optval));\r
+      }  /* switch (sock->conn->type) */\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_TYPE) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+\r
+    case SO_ERROR:\r
+      if (sock->err == 0) {\r
+        sock_set_errno(sock, err_to_errno(sock->conn->err));\r
+      }\r
+      *(int *)optval = sock->err;\r
+      sock->err = 0;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, SOL_SOCKET, SO_ERROR) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+\r
+#if LWIP_SO_RCVTIMEO\r
+    case SO_RCVTIMEO:\r
+      *(int *)optval = sock->conn->recv_timeout;\r
+      break;\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+    case SO_RCVBUF:\r
+      *(int *)optval = sock->conn->recv_bufsize;\r
+      break;\r
+#endif /* LWIP_SO_RCVBUF */\r
+#if LWIP_UDP\r
+    case SO_NO_CHECK:\r
+      *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0;\r
+      break;\r
+#endif /* LWIP_UDP*/\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch (optname) {\r
+    case IP_TTL:\r
+      *(int*)optval = sock->conn->pcb.ip->ttl;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TTL) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+    case IP_TOS:\r
+      *(int*)optval = sock->conn->pcb.ip->tos;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_TOS) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+#if LWIP_IGMP\r
+    case IP_MULTICAST_TTL:\r
+      *(u8_t*)optval = sock->conn->pcb.ip->ttl;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_TTL) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+    case IP_MULTICAST_IF:\r
+      ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%x\n",\r
+                  s, *(u32_t *)optval));\r
+      break;\r
+#endif /* LWIP_IGMP */\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+#if LWIP_TCP\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    switch (optname) {\r
+    case TCP_NODELAY:\r
+      *(int*)optval = (sock->conn->pcb.tcp->flags & TF_NODELAY);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_TCP, TCP_NODELAY) = %s\n",\r
+                  s, (*(int*)optval)?"on":"off") );\r
+      break;\r
+    case TCP_KEEPALIVE:\r
+      *(int*)optval = (int)sock->conn->pcb.tcp->keep_idle;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPALIVE) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+\r
+#if LWIP_TCP_KEEPALIVE\r
+    case TCP_KEEPIDLE:\r
+      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_idle/1000);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPIDLE) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+    case TCP_KEEPINTVL:\r
+      *(int*)optval = (int)(sock->conn->pcb.tcp->keep_intvl/1000);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPINTVL) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+    case TCP_KEEPCNT:\r
+      *(int*)optval = (int)sock->conn->pcb.tcp->keep_cnt;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, TCP_KEEPCNT) = %d\n",\r
+                  s, *(int *)optval));\r
+      break;\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_TCP */\r
+#if LWIP_UDP && LWIP_UDPLITE\r
+  /* Level: IPPROTO_UDPLITE */\r
+  case IPPROTO_UDPLITE:\r
+    switch (optname) {\r
+    case UDPLITE_SEND_CSCOV:\r
+      *(int*)optval = sock->conn->pcb.udp->chksum_len_tx;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) = %d\n",\r
+                  s, (*(int*)optval)) );\r
+      break;\r
+    case UDPLITE_RECV_CSCOV:\r
+      *(int*)optval = sock->conn->pcb.udp->chksum_len_rx;\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n",\r
+                  s, (*(int*)optval)) );\r
+      break;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_UDP */\r
+  } /* switch (level) */\r
+  sys_sem_signal(sock->conn->op_completed);\r
+}\r
+\r
+int\r
+lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen)\r
+{\r
+  struct lwip_socket *sock = get_socket(s);\r
+  int err = ERR_OK;\r
+  struct lwip_setgetsockopt_data data;\r
+\r
+  if (!sock)\r
+    return -1;\r
+\r
+  if (NULL == optval) {\r
+    sock_set_errno(sock, EFAULT);\r
+    return -1;\r
+  }\r
+\r
+  /* Do length and type checks for the various options first, to keep it readable. */\r
+  switch (level) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch (optname) {\r
+\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case case SO_CONTIMEO: */\r
+    /* UNIMPL case case SO_SNDTIMEO: */\r
+#if LWIP_SO_RCVTIMEO\r
+    case SO_RCVTIMEO:\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+    case SO_RCVBUF:\r
+#endif /* LWIP_SO_RCVBUF */\r
+    /* UNIMPL case SO_OOBINLINE: */\r
+    /* UNIMPL case SO_SNDBUF: */\r
+    /* UNIMPL case SO_RCVLOWAT: */\r
+    /* UNIMPL case SO_SNDLOWAT: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /* UNIMPL case SO_USELOOPBACK: */\r
+      if (optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+    case SO_NO_CHECK:\r
+      if (optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+#if LWIP_UDP\r
+      if ((sock->conn->type != NETCONN_UDP) ||\r
+          ((udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_UDPLITE) != 0)) {\r
+        /* this flag is only available for UDP, not for UDP lite */\r
+        err = EAFNOSUPPORT;\r
+      }\r
+#endif /* LWIP_UDP */\r
+      break;\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, UNIMPL: optname=0x%x, ..)\n",\r
+                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch (optname) {\r
+    /* UNIMPL case IP_HDRINCL: */\r
+    /* UNIMPL case IP_RCVDSTADDR: */\r
+    /* UNIMPL case IP_RCVIF: */\r
+    case IP_TTL:\r
+    case IP_TOS:\r
+      if (optlen < sizeof(int)) {\r
+        err = EINVAL;\r
+      }\r
+      break;\r
+#if LWIP_IGMP\r
+    case IP_MULTICAST_TTL:\r
+      if (optlen < sizeof(u8_t)) {\r
+        err = EINVAL;\r
+      }\r
+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\r
+        err = EAFNOSUPPORT;\r
+      }\r
+      break;\r
+    case IP_MULTICAST_IF:\r
+      if (optlen < sizeof(struct in_addr)) {\r
+        err = EINVAL;\r
+      }\r
+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\r
+        err = EAFNOSUPPORT;\r
+      }\r
+      break;\r
+    case IP_ADD_MEMBERSHIP:\r
+    case IP_DROP_MEMBERSHIP:\r
+      if (optlen < sizeof(struct ip_mreq)) {\r
+        err = EINVAL;\r
+      }\r
+      if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) {\r
+        err = EAFNOSUPPORT;\r
+      }\r
+      break;\r
+#endif /* LWIP_IGMP */\r
+      default:\r
+        LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, UNIMPL: optname=0x%x, ..)\n",\r
+                    s, optname));\r
+        err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+#if LWIP_TCP\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    if (optlen < sizeof(int)) {\r
+      err = EINVAL;\r
+      break;\r
+    }\r
+\r
+    /* If this is no TCP socket, ignore any options. */\r
+    if (sock->conn->type != NETCONN_TCP)\r
+      return 0;\r
+\r
+    switch (optname) {\r
+    case TCP_NODELAY:\r
+    case TCP_KEEPALIVE:\r
+#if LWIP_TCP_KEEPALIVE\r
+    case TCP_KEEPIDLE:\r
+    case TCP_KEEPINTVL:\r
+    case TCP_KEEPCNT:\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, UNIMPL: optname=0x%x, ..)\n",\r
+                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_TCP */\r
+#if LWIP_UDP && LWIP_UDPLITE\r
+/* Level: IPPROTO_UDPLITE */\r
+  case IPPROTO_UDPLITE:\r
+    if (optlen < sizeof(int)) {\r
+      err = EINVAL;\r
+      break;\r
+    }\r
+\r
+    /* If this is no UDP lite socket, ignore any options. */\r
+    if (sock->conn->type != NETCONN_UDPLITE)\r
+      return 0;\r
+\r
+    switch (optname) {\r
+    case UDPLITE_SEND_CSCOV:\r
+    case UDPLITE_RECV_CSCOV:\r
+      break;\r
+\r
+    default:\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UNIMPL: optname=0x%x, ..)\n",\r
+                  s, optname));\r
+      err = ENOPROTOOPT;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_UDP && LWIP_UDPLITE */\r
+/* UNDEFINED LEVEL */\r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, level=0x%x, UNIMPL: optname=0x%x, ..)\n",\r
+                s, level, optname));\r
+    err = ENOPROTOOPT;\r
+  }  /* switch (level) */\r
+\r
+\r
+  if (err != ERR_OK) {\r
+    sock_set_errno(sock, err);\r
+    return -1;\r
+  }\r
+\r
+\r
+  /* Now do the actual option processing */\r
+  data.sock = sock;\r
+  data.level = level;\r
+  data.optname = optname;\r
+  data.optval = (void*)optval;\r
+  data.optlen = &optlen;\r
+  data.err = err;\r
+  tcpip_callback(lwip_setsockopt_internal, &data);\r
+  sys_arch_sem_wait(sock->conn->op_completed, 0);\r
+  /* maybe lwip_setsockopt_internal has changed err */\r
+  err = data.err;\r
+\r
+  sock_set_errno(sock, err);\r
+  return err ? -1 : 0;\r
+}\r
+\r
+static void\r
+lwip_setsockopt_internal(void *arg)\r
+{\r
+  struct lwip_socket *sock;\r
+#ifdef LWIP_DEBUG\r
+  int s;\r
+#endif /* LWIP_DEBUG */\r
+  int level, optname;\r
+  const void *optval;\r
+  struct lwip_setgetsockopt_data *data;\r
+\r
+  LWIP_ASSERT("arg != NULL", arg != NULL);\r
+\r
+  data = (struct lwip_setgetsockopt_data*)arg;\r
+  sock = data->sock;\r
+#ifdef LWIP_DEBUG\r
+  s = data->s;\r
+#endif /* LWIP_DEBUG */\r
+  level = data->level;\r
+  optname = data->optname;\r
+  optval = data->optval;\r
+\r
+  switch (level) {\r
+\r
+/* Level: SOL_SOCKET */\r
+  case SOL_SOCKET:\r
+    switch (optname) {\r
+\r
+    /* The option flags */\r
+    case SO_BROADCAST:\r
+    /* UNIMPL case SO_DEBUG: */\r
+    /* UNIMPL case SO_DONTROUTE: */\r
+    case SO_KEEPALIVE:\r
+    /* UNIMPL case SO_OOBINCLUDE: */\r
+#if SO_REUSE\r
+    case SO_REUSEADDR:\r
+    case SO_REUSEPORT:\r
+#endif /* SO_REUSE */\r
+    /* UNIMPL case SO_USELOOPBACK: */\r
+      if (*(int*)optval) {\r
+        sock->conn->pcb.ip->so_options |= optname;\r
+      } else {\r
+        sock->conn->pcb.ip->so_options &= ~optname;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, SOL_SOCKET, optname=0x%x, ..) -> %s\n",\r
+                  s, optname, (*(int*)optval?"on":"off")));\r
+      break;\r
+#if LWIP_SO_RCVTIMEO\r
+    case SO_RCVTIMEO:\r
+      sock->conn->recv_timeout = ( *(int*)optval );\r
+      break;\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+    case SO_RCVBUF:\r
+      sock->conn->recv_bufsize = ( *(int*)optval );\r
+      break;\r
+#endif /* LWIP_SO_RCVBUF */\r
+#if LWIP_UDP\r
+    case SO_NO_CHECK:\r
+      if (*(int*)optval) {\r
+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_NOCHKSUM);\r
+      } else {\r
+        udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_NOCHKSUM);\r
+      }\r
+      break;\r
+#endif /* LWIP_UDP */\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+/* Level: IPPROTO_IP */\r
+  case IPPROTO_IP:\r
+    switch (optname) {\r
+    case IP_TTL:\r
+      sock->conn->pcb.ip->ttl = (u8_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TTL, ..) -> %u\n",\r
+                  s, sock->conn->pcb.ip->ttl));\r
+      break;\r
+    case IP_TOS:\r
+      sock->conn->pcb.ip->tos = (u8_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_IP, IP_TOS, ..)-> %u\n",\r
+                  s, sock->conn->pcb.ip->tos));\r
+      break;\r
+#if LWIP_IGMP\r
+    case IP_MULTICAST_TTL:\r
+      sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval);\r
+      break;\r
+    case IP_MULTICAST_IF:\r
+      sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr;\r
+      break;\r
+    case IP_ADD_MEMBERSHIP:\r
+    case IP_DROP_MEMBERSHIP:\r
+      {\r
+        /* If this is a TCP or a RAW socket, ignore these options. */\r
+        struct ip_mreq *imr = (struct ip_mreq *)optval;\r
+        if(optname == IP_ADD_MEMBERSHIP){\r
+          data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));\r
+        } else {\r
+          data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr));\r
+        }\r
+        if(data->err != ERR_OK) {\r
+          data->err = EADDRNOTAVAIL;\r
+        }\r
+      }\r
+      break;\r
+#endif /* LWIP_IGMP */\r
+    }  /* switch (optname) */\r
+    break;\r
+\r
+#if LWIP_TCP\r
+/* Level: IPPROTO_TCP */\r
+  case IPPROTO_TCP:\r
+    switch (optname) {\r
+    case TCP_NODELAY:\r
+      if (*(int*)optval) {\r
+        sock->conn->pcb.tcp->flags |= TF_NODELAY;\r
+      } else {\r
+        sock->conn->pcb.tcp->flags &= ~TF_NODELAY;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_NODELAY) -> %s\n",\r
+                  s, (*(int *)optval)?"on":"off") );\r
+      break;\r
+    case TCP_KEEPALIVE:\r
+      sock->conn->pcb.tcp->keep_idle = (u32_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPALIVE) -> %lu\n",\r
+                  s, sock->conn->pcb.tcp->keep_idle));\r
+      break;\r
+\r
+#if LWIP_TCP_KEEPALIVE\r
+    case TCP_KEEPIDLE:\r
+      sock->conn->pcb.tcp->keep_idle = 1000*(u32_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPIDLE) -> %lu\n",\r
+                  s, sock->conn->pcb.tcp->keep_idle));\r
+      break;\r
+    case TCP_KEEPINTVL:\r
+      sock->conn->pcb.tcp->keep_intvl = 1000*(u32_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPINTVL) -> %lu\n",\r
+                  s, sock->conn->pcb.tcp->keep_intvl));\r
+      break;\r
+    case TCP_KEEPCNT:\r
+      sock->conn->pcb.tcp->keep_cnt = (u32_t)(*(int*)optval);\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_TCP, TCP_KEEPCNT) -> %lu\n",\r
+                  s, sock->conn->pcb.tcp->keep_cnt));\r
+      break;\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_TCP*/\r
+#if LWIP_UDP && LWIP_UDPLITE\r
+  /* Level: IPPROTO_UDPLITE */\r
+  case IPPROTO_UDPLITE:\r
+    switch (optname) {\r
+    case UDPLITE_SEND_CSCOV:\r
+      if ((*(int*)optval != 0) && (*(int*)optval < 8)) {\r
+        /* don't allow illegal values! */\r
+        sock->conn->pcb.udp->chksum_len_tx = 8;\r
+      } else {\r
+        sock->conn->pcb.udp->chksum_len_tx = *(int*)optval;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n",\r
+                  s, (*(int*)optval)) );\r
+      break;\r
+    case UDPLITE_RECV_CSCOV:\r
+      if ((*(int*)optval != 0) && (*(int*)optval < 8)) {\r
+        /* don't allow illegal values! */\r
+        sock->conn->pcb.udp->chksum_len_rx = 8;\r
+      } else {\r
+        sock->conn->pcb.udp->chksum_len_rx = *(int*)optval;\r
+      }\r
+      LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n",\r
+                  s, (*(int*)optval)) );\r
+      break;\r
+    }  /* switch (optname) */\r
+    break;\r
+#endif /* LWIP_UDP */\r
+  }  /* switch (level) */\r
+  sys_sem_signal(sock->conn->op_completed);\r
+}\r
+\r
+int\r
+lwip_ioctl(int s, long cmd, void *argp)\r
+{\r
+  struct lwip_socket *sock = get_socket(s);\r
+  u16_t buflen = 0;\r
+\r
+  if (!sock)\r
+    return -1;\r
+\r
+  switch (cmd) {\r
+  case FIONREAD:\r
+    if (!argp) {\r
+      sock_set_errno(sock, EINVAL);\r
+      return -1;\r
+    }\r
+\r
+    SYS_ARCH_GET(sock->conn->recv_avail, *((u16_t*)argp));\r
+\r
+    /* Check if there is data left from the last recv operation. /maq 041215 */\r
+    if (sock->lastdata) {\r
+      buflen = netbuf_len(sock->lastdata);\r
+      buflen -= sock->lastoffset;\r
+\r
+      *((u16_t*)argp) += buflen;\r
+    }\r
+\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %u\n", s, argp, *((u16_t*)argp)));\r
+    sock_set_errno(sock, 0);\r
+    return 0;\r
+\r
+  case FIONBIO:\r
+    if (argp && *(u32_t*)argp)\r
+      sock->flags |= O_NONBLOCK;\r
+    else\r
+      sock->flags &= ~O_NONBLOCK;\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK)));\r
+    sock_set_errno(sock, 0);\r
+    return 0;\r
+\r
+  default:\r
+    LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, UNIMPL: 0x%lx, %p)\n", s, cmd, argp));\r
+    sock_set_errno(sock, ENOSYS); /* not yet implemented */\r
+    return -1;\r
+  } /* switch (cmd) */\r
+}\r
+\r
+#endif /* LWIP_SOCKET */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/api/tcpip.c b/Demo/Common/ethernet/lwIP_130/src/api/tcpip.c
new file mode 100644 (file)
index 0000000..b22894e
--- /dev/null
@@ -0,0 +1,521 @@
+/**\r
+ * @file\r
+ * Sequential API Main thread module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/autoip.h"\r
+#include "lwip/dhcp.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/dns.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/init.h"\r
+#include "netif/etharp.h"\r
+#include "netif/ppp_oe.h"\r
+\r
+/* global variables */\r
+static void (* tcpip_init_done)(void *arg);\r
+static void *tcpip_init_done_arg;\r
+static sys_mbox_t mbox = SYS_MBOX_NULL;\r
+\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+/** The global semaphore to lock the stack. */\r
+sys_sem_t lock_tcpip_core;\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+\r
+#if LWIP_TCP\r
+/* global variable that shows if the tcp timer is currently scheduled or not */\r
+static int tcpip_tcp_timer_active;\r
+\r
+/**\r
+ * Timer callback function that calls tcp_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+tcpip_tcp_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+\r
+  /* call TCP timer handler */\r
+  tcp_tmr();\r
+  /* timer still needed? */\r
+  if (tcp_active_pcbs || tcp_tw_pcbs) {\r
+    /* restart timer */\r
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\r
+  } else {\r
+    /* disable timer */\r
+    tcpip_tcp_timer_active = 0;\r
+  }\r
+}\r
+\r
+#if !NO_SYS\r
+/**\r
+ * Called from TCP_REG when registering a new PCB:\r
+ * the reason is to have the TCP timer only running when\r
+ * there are active (or time-wait) PCBs.\r
+ */\r
+void\r
+tcp_timer_needed(void)\r
+{\r
+  /* timer is off but needed again? */\r
+  if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {\r
+    /* enable and start timer */\r
+    tcpip_tcp_timer_active = 1;\r
+    sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);\r
+  }\r
+}\r
+#endif /* !NO_SYS */\r
+#endif /* LWIP_TCP */\r
+\r
+#if IP_REASSEMBLY\r
+/**\r
+ * Timer callback function that calls ip_reass_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+ip_reass_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n"));\r
+  ip_reass_tmr();\r
+  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);\r
+}\r
+#endif /* IP_REASSEMBLY */\r
+\r
+#if LWIP_ARP\r
+/**\r
+ * Timer callback function that calls etharp_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+arp_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n"));\r
+  etharp_tmr();\r
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
+}\r
+#endif /* LWIP_ARP */\r
+\r
+#if LWIP_DHCP\r
+/**\r
+ * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+dhcp_timer_coarse(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));\r
+  dhcp_coarse_tmr();\r
+  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);\r
+}\r
+\r
+/**\r
+ * Timer callback function that calls dhcp_fine_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+dhcp_timer_fine(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));\r
+  dhcp_fine_tmr();\r
+  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);\r
+}\r
+#endif /* LWIP_DHCP */\r
+\r
+#if LWIP_AUTOIP\r
+/**\r
+ * Timer callback function that calls autoip_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+autoip_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n"));\r
+  autoip_tmr();\r
+  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);\r
+}\r
+#endif /* LWIP_AUTOIP */\r
+\r
+#if LWIP_IGMP\r
+/**\r
+ * Timer callback function that calls igmp_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+igmp_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n"));\r
+  igmp_tmr();\r
+  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);\r
+}\r
+#endif /* LWIP_IGMP */\r
+\r
+#if LWIP_DNS\r
+/**\r
+ * Timer callback function that calls dns_tmr() and reschedules itself.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+dns_timer(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n"));\r
+  dns_tmr();\r
+  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);\r
+}\r
+#endif /* LWIP_DNS */\r
+\r
+/**\r
+ * The main lwIP thread. This thread has exclusive access to lwIP core functions\r
+ * (unless access to them is not locked). Other threads communicate with this\r
+ * thread using message boxes.\r
+ *\r
+ * It also starts all the timers to make sure they are running in the right\r
+ * thread context.\r
+ *\r
+ * @param arg unused argument\r
+ */\r
+static void\r
+tcpip_thread(void *arg)\r
+{\r
+  struct tcpip_msg *msg;\r
+  LWIP_UNUSED_ARG(arg);\r
+\r
+#if IP_REASSEMBLY\r
+  sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);\r
+#endif /* IP_REASSEMBLY */\r
+#if LWIP_ARP\r
+  sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);\r
+#endif /* LWIP_ARP */\r
+#if LWIP_DHCP\r
+  sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);\r
+  sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);\r
+#endif /* LWIP_DHCP */\r
+#if LWIP_AUTOIP\r
+  sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);\r
+#endif /* LWIP_AUTOIP */\r
+#if LWIP_IGMP\r
+  sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);\r
+#endif /* LWIP_IGMP */\r
+#if LWIP_DNS\r
+  sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);\r
+#endif /* LWIP_DNS */\r
+\r
+  if (tcpip_init_done != NULL) {\r
+    tcpip_init_done(tcpip_init_done_arg);\r
+  }\r
+\r
+  LOCK_TCPIP_CORE();\r
+  while (1) {                          /* MAIN Loop */\r
+    sys_mbox_fetch(mbox, (void *)&msg);\r
+    switch (msg->type) {\r
+#if LWIP_NETCONN\r
+    case TCPIP_MSG_API:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: API message %p\n", (void *)msg));\r
+      msg->msg.apimsg->function(&(msg->msg.apimsg->msg));\r
+      break;\r
+#endif /* LWIP_NETCONN */\r
+\r
+    case TCPIP_MSG_INPKT:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg));\r
+#if LWIP_ARP\r
+      if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) {\r
+        ethernet_input(msg->msg.inp.p, msg->msg.inp.netif);\r
+      } else\r
+#endif /* LWIP_ARP */\r
+      { ip_input(msg->msg.inp.p, msg->msg.inp.netif);\r
+      }\r
+      memp_free(MEMP_TCPIP_MSG_INPKT, msg);\r
+      break;\r
+\r
+#if LWIP_NETIF_API\r
+    case TCPIP_MSG_NETIFAPI:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: Netif API message %p\n", (void *)msg));\r
+      msg->msg.netifapimsg->function(&(msg->msg.netifapimsg->msg));\r
+      break;\r
+#endif /* LWIP_NETIF_API */\r
+\r
+    case TCPIP_MSG_CALLBACK:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg));\r
+      msg->msg.cb.f(msg->msg.cb.ctx);\r
+      memp_free(MEMP_TCPIP_MSG_API, msg);\r
+      break;\r
+\r
+    case TCPIP_MSG_TIMEOUT:\r
+      LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));\r
+\r
+      if(msg->msg.tmo.msecs != 0xffffffff)\r
+        sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);\r
+      else\r
+        sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);\r
+      memp_free(MEMP_TCPIP_MSG_API, msg);\r
+      break;\r
+\r
+    default:\r
+      break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Pass a received packet to tcpip_thread for input processing\r
+ *\r
+ * @param p the received packet, p->payload pointing to the Ethernet header or\r
+ *          to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag)\r
+ * @param inp the network interface on which the packet was received\r
+ */\r
+err_t\r
+tcpip_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct tcpip_msg *msg;\r
+\r
+  if (mbox != SYS_MBOX_NULL) {\r
+    msg = memp_malloc(MEMP_TCPIP_MSG_INPKT);\r
+    if (msg == NULL) {\r
+      return ERR_MEM;\r
+    }\r
+\r
+    msg->type = TCPIP_MSG_INPKT;\r
+    msg->msg.inp.p = p;\r
+    msg->msg.inp.netif = inp;\r
+    if (sys_mbox_trypost(mbox, msg) != ERR_OK) {\r
+      memp_free(MEMP_TCPIP_MSG_INPKT, msg);\r
+      return ERR_MEM;\r
+    }\r
+    return ERR_OK;\r
+  }\r
+  return ERR_VAL;\r
+}\r
+\r
+/**\r
+ * Call a specific function in the thread context of\r
+ * tcpip_thread for easy access synchronization.\r
+ * A function called in that way may access lwIP core code\r
+ * without fearing concurrent access.\r
+ *\r
+ * @param f the function to call\r
+ * @param ctx parameter passed to f\r
+ * @param block 1 to block until the request is posted, 0 to non-blocking mode\r
+ * @return ERR_OK if the function was called, another err_t if not\r
+ */\r
+err_t\r
+tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block)\r
+{\r
+  struct tcpip_msg *msg;\r
+\r
+  if (mbox != SYS_MBOX_NULL) {\r
+    msg = memp_malloc(MEMP_TCPIP_MSG_API);\r
+    if (msg == NULL) {\r
+      return ERR_MEM;\r
+    }\r
+\r
+    msg->type = TCPIP_MSG_CALLBACK;\r
+    msg->msg.cb.f = f;\r
+    msg->msg.cb.ctx = ctx;\r
+    if (block) {\r
+      sys_mbox_post(mbox, msg);\r
+    } else {\r
+      if (sys_mbox_trypost(mbox, msg) != ERR_OK) {\r
+        memp_free(MEMP_TCPIP_MSG_API, msg);\r
+        return ERR_MEM;\r
+      }\r
+    }\r
+    return ERR_OK;\r
+  }\r
+  return ERR_VAL;\r
+}\r
+\r
+err_t\r
+tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)\r
+{\r
+  struct tcpip_msg *msg;\r
+\r
+  if (mbox != SYS_MBOX_NULL) {\r
+    msg = memp_malloc(MEMP_TCPIP_MSG_API);\r
+    if (msg == NULL) {\r
+      return ERR_MEM;\r
+    }\r
+\r
+    msg->type = TCPIP_MSG_TIMEOUT;\r
+    msg->msg.tmo.msecs = msecs;\r
+    msg->msg.tmo.h = h;\r
+    msg->msg.tmo.arg = arg;\r
+    sys_mbox_post(mbox, msg);\r
+    return ERR_OK;\r
+  }\r
+  return ERR_VAL;\r
+}\r
+\r
+#if LWIP_NETCONN\r
+/**\r
+ * Call the lower part of a netconn_* function\r
+ * This function is then running in the thread context\r
+ * of tcpip_thread and has exclusive access to lwIP core code.\r
+ *\r
+ * @param apimsg a struct containing the function to call and its parameters\r
+ * @return ERR_OK if the function was called, another err_t if not\r
+ */\r
+err_t\r
+tcpip_apimsg(struct api_msg *apimsg)\r
+{\r
+  struct tcpip_msg msg;\r
+\r
+  if (mbox != SYS_MBOX_NULL) {\r
+    msg.type = TCPIP_MSG_API;\r
+    msg.msg.apimsg = apimsg;\r
+    sys_mbox_post(mbox, &msg);\r
+    sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0);\r
+    return ERR_OK;\r
+  }\r
+  return ERR_VAL;\r
+}\r
+\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+/**\r
+ * Call the lower part of a netconn_* function\r
+ * This function has exclusive access to lwIP core code by locking it\r
+ * before the function is called.\r
+ *\r
+ * @param apimsg a struct containing the function to call and its parameters\r
+ * @return ERR_OK (only for compatibility fo tcpip_apimsg())\r
+ */\r
+err_t\r
+tcpip_apimsg_lock(struct api_msg *apimsg)\r
+{\r
+  LOCK_TCPIP_CORE();\r
+  apimsg->function(&(apimsg->msg));\r
+  UNLOCK_TCPIP_CORE();\r
+  return ERR_OK;\r
+\r
+}\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+#endif /* LWIP_NETCONN */\r
+\r
+#if LWIP_NETIF_API\r
+#if !LWIP_TCPIP_CORE_LOCKING\r
+/**\r
+ * Much like tcpip_apimsg, but calls the lower part of a netifapi_*\r
+ * function.\r
+ *\r
+ * @param netifapimsg a struct containing the function to call and its parameters\r
+ * @return error code given back by the function that was called\r
+ */\r
+err_t\r
+tcpip_netifapi(struct netifapi_msg* netifapimsg)\r
+{\r
+  struct tcpip_msg msg;\r
+\r
+  if (mbox != SYS_MBOX_NULL) {\r
+    netifapimsg->msg.sem = sys_sem_new(0);\r
+    if (netifapimsg->msg.sem == SYS_SEM_NULL) {\r
+      netifapimsg->msg.err = ERR_MEM;\r
+      return netifapimsg->msg.err;\r
+    }\r
+\r
+    msg.type = TCPIP_MSG_NETIFAPI;\r
+    msg.msg.netifapimsg = netifapimsg;\r
+    sys_mbox_post(mbox, &msg);\r
+    sys_sem_wait(netifapimsg->msg.sem);\r
+    sys_sem_free(netifapimsg->msg.sem);\r
+    return netifapimsg->msg.err;\r
+  }\r
+  return ERR_VAL;\r
+}\r
+#else /* !LWIP_TCPIP_CORE_LOCKING */\r
+/**\r
+ * Call the lower part of a netifapi_* function\r
+ * This function has exclusive access to lwIP core code by locking it\r
+ * before the function is called.\r
+ *\r
+ * @param netifapimsg a struct containing the function to call and its parameters\r
+ * @return ERR_OK (only for compatibility fo tcpip_netifapi())\r
+ */\r
+err_t\r
+tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)\r
+{\r
+  LOCK_TCPIP_CORE();\r
+  netifapimsg->function(&(netifapimsg->msg));\r
+  UNLOCK_TCPIP_CORE();\r
+  return netifapimsg->msg.err;\r
+}\r
+#endif /* !LWIP_TCPIP_CORE_LOCKING */\r
+#endif /* LWIP_NETIF_API */\r
+\r
+/**\r
+ * Initialize this module:\r
+ * - initialize all sub modules\r
+ * - start the tcpip_thread\r
+ *\r
+ * @param initfunc a function to call when tcpip_thread is running and finished initializing\r
+ * @param arg argument to pass to initfunc\r
+ */\r
+void\r
+tcpip_init(void (* initfunc)(void *), void *arg)\r
+{\r
+  lwip_init();\r
+\r
+  tcpip_init_done = initfunc;\r
+  tcpip_init_done_arg = arg;\r
+  mbox = sys_mbox_new(TCPIP_MBOX_SIZE);\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+  lock_tcpip_core = sys_sem_new(1);\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+\r
+  sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO);\r
+}\r
+\r
+#endif /* !NO_SYS */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/dhcp.c b/Demo/Common/ethernet/lwIP_130/src/core/dhcp.c
new file mode 100644 (file)
index 0000000..f0c41c6
--- /dev/null
@@ -0,0 +1,1548 @@
+/**\r
+ * @file\r
+ * Dynamic Host Configuration Protocol client\r
+ *\r
+ */\r
+\r
+/*\r
+ *\r
+ * Copyright (c) 2001-2004 Leon Woestenberg <leon.woestenberg@gmx.net>\r
+ * Copyright (c) 2001-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is a contribution to the lwIP TCP/IP stack.\r
+ * The Swedish Institute of Computer Science and Adam Dunkels\r
+ * are specifically granted permission to redistribute this\r
+ * source code.\r
+ *\r
+ * Author: Leon Woestenberg <leon.woestenberg@gmx.net>\r
+ *\r
+ * This is a DHCP client for the lwIP TCP/IP stack. It aims to conform\r
+ * with RFC 2131 and RFC 2132.\r
+ *\r
+ * TODO:\r
+ * - Proper parsing of DHCP messages exploiting file/sname field overloading.\r
+ * - Add JavaDoc style documentation (API, internals).\r
+ * - Support for interfaces other than Ethernet (SLIP, PPP, ...)\r
+ *\r
+ * Please coordinate changes and requests with Leon Woestenberg\r
+ * <leon.woestenberg@gmx.net>\r
+ *\r
+ * Integration with your code:\r
+ *\r
+ * In lwip/dhcp.h\r
+ * #define DHCP_COARSE_TIMER_SECS (recommended 60 which is a minute)\r
+ * #define DHCP_FINE_TIMER_MSECS (recommended 500 which equals TCP coarse timer)\r
+ *\r
+ * Then have your application call dhcp_coarse_tmr() and\r
+ * dhcp_fine_tmr() on the defined intervals.\r
+ *\r
+ * dhcp_start(struct netif *netif);\r
+ * starts a DHCP client instance which configures the interface by\r
+ * obtaining an IP address lease and maintaining it.\r
+ *\r
+ * Use dhcp_release(netif) to end the lease and use dhcp_stop(netif)\r
+ * to remove the DHCP client.\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/dhcp.h"\r
+#include "lwip/autoip.h"\r
+#include "lwip/dns.h"\r
+#include "netif/etharp.h"\r
+\r
+#include <string.h>\r
+\r
+/** global transaction identifier, must be\r
+ *  unique for each DHCP request. We simply increment, starting\r
+ *  with this value (easy to match with a packet analyzer) */\r
+static u32_t xid = 0xABCD0000;\r
+\r
+/* DHCP client state machine functions */\r
+static void dhcp_handle_ack(struct netif *netif);\r
+static void dhcp_handle_nak(struct netif *netif);\r
+static void dhcp_handle_offer(struct netif *netif);\r
+\r
+static err_t dhcp_discover(struct netif *netif);\r
+static err_t dhcp_select(struct netif *netif);\r
+static void dhcp_check(struct netif *netif);\r
+static void dhcp_bind(struct netif *netif);\r
+#if DHCP_DOES_ARP_CHECK\r
+static err_t dhcp_decline(struct netif *netif);\r
+#endif /* DHCP_DOES_ARP_CHECK */\r
+static err_t dhcp_rebind(struct netif *netif);\r
+static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state);\r
+\r
+/* receive, unfold, parse and free incoming messages */\r
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
+static err_t dhcp_unfold_reply(struct dhcp *dhcp);\r
+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type);\r
+static u8_t dhcp_get_option_byte(u8_t *ptr);\r
+#if 0\r
+static u16_t dhcp_get_option_short(u8_t *ptr);\r
+#endif\r
+static u32_t dhcp_get_option_long(u8_t *ptr);\r
+static void dhcp_free_reply(struct dhcp *dhcp);\r
+\r
+/* set the DHCP timers */\r
+static void dhcp_timeout(struct netif *netif);\r
+static void dhcp_t1_timeout(struct netif *netif);\r
+static void dhcp_t2_timeout(struct netif *netif);\r
+\r
+/* build outgoing messages */\r
+/* create a DHCP request, fill in common headers */\r
+static err_t dhcp_create_request(struct netif *netif);\r
+/* free a DHCP request */\r
+static void dhcp_delete_request(struct netif *netif);\r
+/* add a DHCP option (type, then length in bytes) */\r
+static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len);\r
+/* add option values */\r
+static void dhcp_option_byte(struct dhcp *dhcp, u8_t value);\r
+static void dhcp_option_short(struct dhcp *dhcp, u16_t value);\r
+static void dhcp_option_long(struct dhcp *dhcp, u32_t value);\r
+/* always add the DHCP options trailer to end and pad */\r
+static void dhcp_option_trailer(struct dhcp *dhcp);\r
+\r
+/**\r
+ * Back-off the DHCP client (because of a received NAK response).\r
+ *\r
+ * Back-off the DHCP client because of a received NAK. Receiving a\r
+ * NAK means the client asked for something non-sensible, for\r
+ * example when it tries to renew a lease obtained on another network.\r
+ *\r
+ * We clear any existing set IP address and restart DHCP negotiation\r
+ * afresh (as per RFC2131 3.2.3).\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_handle_nak(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_nak(netif=%p) %c%c%"U16_F"\n",\r
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
+  /* Set the interface down since the address must no longer be used, as per RFC2131 */\r
+  netif_set_down(netif);\r
+  /* remove IP address from interface */\r
+  netif_set_ipaddr(netif, IP_ADDR_ANY);\r
+  netif_set_gw(netif, IP_ADDR_ANY);\r
+  netif_set_netmask(netif, IP_ADDR_ANY);\r
+  /* Change to a defined state */\r
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
+  /* We can immediately restart discovery */\r
+  dhcp_discover(netif);\r
+}\r
+\r
+/**\r
+ * Checks if the offered IP address is already in use.\r
+ *\r
+ * It does so by sending an ARP request for the offered address and\r
+ * entering CHECKING state. If no ARP reply is received within a small\r
+ * interval, the address is assumed to be free for use by us.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_check(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_check(netif=%p) %c%c\n", (void *)netif, (s16_t)netif->name[0],\r
+    (s16_t)netif->name[1]));\r
+  /* create an ARP query for the offered IP address, expecting that no host\r
+     responds, as the IP address should not be in use. */\r
+  result = etharp_query(netif, &dhcp->offered_ip_addr, NULL);\r
+  if (result != ERR_OK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_check: could not perform ARP query\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = 500;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_check(): set request timeout %"U16_F" msecs\n", msecs));\r
+  dhcp_set_state(dhcp, DHCP_CHECKING);\r
+}\r
+\r
+/**\r
+ * Remember the configuration offered by a DHCP server.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_handle_offer(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  /* obtain the server address */\r
+  u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n",\r
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num));\r
+  if (option_ptr != NULL) {\r
+    dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr));\r
+    /* remember offered address */\r
+    ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_select(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * Select a DHCP server offer out of all offers.\r
+ *\r
+ * Simply select the first offer received.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ * @return lwIP specific error (see error.h)\r
+ */\r
+static err_t\r
+dhcp_select(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+#if LWIP_NETIF_HOSTNAME\r
+  const char *p;\r
+#endif /* LWIP_NETIF_HOSTNAME */\r
+\r
+  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));\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    /* MUST request the offered IP address */\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
+\r
+#if LWIP_NETIF_HOSTNAME\r
+    p = (const char*)netif->hostname;\r
+    if (p!=NULL) {\r
+      dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p));\r
+      while (*p) {\r
+        dhcp_option_byte(dhcp, *p++);\r
+      }\r
+    }\r
+#endif /* LWIP_NETIF_HOSTNAME */\r
+\r
+    dhcp_option_trailer(dhcp);\r
+    /* shrink the pbuf to the actual content length */\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* TODO: we really should bind to a specific local interface here\r
+       but we cannot specify an unconfigured netif as it is addressless */\r
+    /* send broadcast to any DHCP server */\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\r
+    /* reconnect to any (or to server here?!) */\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n"));\r
+    dhcp_set_state(dhcp, DHCP_REQUESTING);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_select: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 4 ? dhcp->tries * 1000 : 4 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_select(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * The DHCP timer that checks for lease renewal/rebind timeouts.\r
+ *\r
+ */\r
+void\r
+dhcp_coarse_tmr()\r
+{\r
+  struct netif *netif = netif_list;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_coarse_tmr()\n"));\r
+  /* iterate through all network interfaces */\r
+  while (netif != NULL) {\r
+    /* only act on DHCP configured interfaces */\r
+    if (netif->dhcp != NULL) {\r
+      /* timer is active (non zero), and triggers (zeroes) now? */\r
+      if (netif->dhcp->t2_timeout-- == 1) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t2 timeout\n"));\r
+        /* this clients' rebind timeout triggered */\r
+        dhcp_t2_timeout(netif);\r
+      /* timer is active (non zero), and triggers (zeroes) now */\r
+      } else if (netif->dhcp->t1_timeout-- == 1) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_coarse_tmr(): t1 timeout\n"));\r
+        /* this clients' renewal timeout triggered */\r
+        dhcp_t1_timeout(netif);\r
+      }\r
+    }\r
+    /* proceed to next netif */\r
+    netif = netif->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * DHCP transaction timeout handling\r
+ *\r
+ * A DHCP server is expected to respond within a short period of time.\r
+ * This timer checks whether an outstanding DHCP request is timed out.\r
+ *\r
+ */\r
+void\r
+dhcp_fine_tmr()\r
+{\r
+  struct netif *netif = netif_list;\r
+  /* loop through netif's */\r
+  while (netif != NULL) {\r
+    /* only act on DHCP configured interfaces */\r
+    if (netif->dhcp != NULL) {\r
+      /* timer is active (non zero), and is about to trigger now */\r
+      if (netif->dhcp->request_timeout > 1) {\r
+        netif->dhcp->request_timeout--;\r
+      }\r
+      else if (netif->dhcp->request_timeout == 1) {\r
+        netif->dhcp->request_timeout--;\r
+        /* { netif->dhcp->request_timeout == 0 } */\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n"));\r
+        /* this clients' request timeout triggered */\r
+        dhcp_timeout(netif);\r
+      }\r
+    }\r
+    /* proceed to next network interface */\r
+    netif = netif->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * A DHCP negotiation transaction, or ARP request, has timed out.\r
+ *\r
+ * The timer that was started with the DHCP or ARP request has\r
+ * timed out, indicating no response was received in time.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_timeout()\n"));\r
+  /* back-off period has passed, or server selection timed out */\r
+  if ((dhcp->state == DHCP_BACKING_OFF) || (dhcp->state == DHCP_SELECTING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_timeout(): restarting discovery\n"));\r
+    dhcp_discover(netif);\r
+  /* receiving the requested lease timed out */\r
+  } else if (dhcp->state == DHCP_REQUESTING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, DHCP request timed out\n"));\r
+    if (dhcp->tries <= 5) {\r
+      dhcp_select(netif);\r
+    } else {\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REQUESTING, releasing, restarting\n"));\r
+      dhcp_release(netif);\r
+      dhcp_discover(netif);\r
+    }\r
+  /* received no ARP reply for the offered address (which is good) */\r
+  } else if (dhcp->state == DHCP_CHECKING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): CHECKING, ARP request timed out\n"));\r
+    if (dhcp->tries <= 1) {\r
+      dhcp_check(netif);\r
+    /* no ARP replies on the offered address,\r
+       looks like the IP address is indeed free */\r
+    } else {\r
+      /* bind the interface to the offered address */\r
+      dhcp_bind(netif);\r
+    }\r
+  }\r
+  /* did not get response to renew request? */\r
+  else if (dhcp->state == DHCP_RENEWING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RENEWING, DHCP request timed out\n"));\r
+    /* just retry renewal */\r
+    /* note that the rebind timer will eventually time-out if renew does not work */\r
+    dhcp_renew(netif);\r
+  /* did not get response to rebind request? */\r
+  } else if (dhcp->state == DHCP_REBINDING) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): REBINDING, DHCP request timed out\n"));\r
+    if (dhcp->tries <= 8) {\r
+      dhcp_rebind(netif);\r
+    } else {\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_timeout(): RELEASING, DISCOVERING\n"));\r
+      dhcp_release(netif);\r
+      dhcp_discover(netif);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * The renewal period has timed out.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_t1_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n"));\r
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
+    /* just retry to renew - note that the rebind timer (t2) will\r
+     * eventually time-out if renew tries fail. */\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n"));\r
+    dhcp_renew(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * The rebind period has timed out.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_t2_timeout(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n"));\r
+  if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) {\r
+    /* just retry to rebind */\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n"));\r
+    dhcp_rebind(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * Handle a DHCP ACK packet\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_handle_ack(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  u8_t *option_ptr;\r
+  /* clear options we might not get from the ACK */\r
+  dhcp->offered_sn_mask.addr = 0;\r
+  dhcp->offered_gw_addr.addr = 0;\r
+  dhcp->offered_bc_addr.addr = 0;\r
+\r
+  /* lease time given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME);\r
+  if (option_ptr != NULL) {\r
+    /* remember offered lease time */\r
+    dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2);\r
+  }\r
+  /* renewal period given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1);\r
+  if (option_ptr != NULL) {\r
+    /* remember given renewal period */\r
+    dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2);\r
+  } else {\r
+    /* calculate safe periods for renewal */\r
+    dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2;\r
+  }\r
+\r
+  /* renewal period given? */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2);\r
+  if (option_ptr != NULL) {\r
+    /* remember given rebind period */\r
+    dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2);\r
+  } else {\r
+    /* calculate safe periods for rebinding */\r
+    dhcp->offered_t2_rebind = dhcp->offered_t0_lease;\r
+  }\r
+\r
+  /* (y)our internet address */\r
+  ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr);\r
+\r
+/**\r
+ * Patch #1308\r
+ * TODO: we must check if the file field is not overloaded by DHCP options!\r
+ */\r
+#if 0\r
+  /* boot server address */\r
+  ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr);\r
+  /* boot file name */\r
+  if (dhcp->msg_in->file[0]) {\r
+    dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1);\r
+    strcpy(dhcp->boot_file_name, dhcp->msg_in->file);\r
+  }\r
+#endif\r
+\r
+  /* subnet mask */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+  /* subnet mask given? */\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+\r
+  /* gateway router */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER);\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+\r
+  /* broadcast address */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST);\r
+  if (option_ptr != NULL) {\r
+    dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2]));\r
+  }\r
+\r
+  /* DNS servers */\r
+  option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER);\r
+  if (option_ptr != NULL) {\r
+    u8_t n;\r
+    dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr);\r
+    /* limit to at most DHCP_MAX_DNS DNS servers */\r
+    if (dhcp->dns_count > DHCP_MAX_DNS)\r
+      dhcp->dns_count = DHCP_MAX_DNS;\r
+    for (n = 0; n < dhcp->dns_count; n++) {\r
+      dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4]));\r
+#if LWIP_DNS\r
+      dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr)));\r
+#endif /* LWIP_DNS */\r
+    }\r
+#if LWIP_DNS\r
+    dns_setserver( n, (struct ip_addr *)(&ip_addr_any));\r
+#endif /* LWIP_DNS */\r
+  }\r
+}\r
+\r
+/**\r
+ * Start DHCP negotiation for a network interface.\r
+ *\r
+ * If no DHCP client instance was attached to this interface,\r
+ * a new client is created first. If a DHCP client instance\r
+ * was already present, it restarts negotiation.\r
+ *\r
+ * @param netif The lwIP network interface\r
+ * @return lwIP error code\r
+ * - ERR_OK - No error\r
+ * - ERR_MEM - Out of memory\r
+ */\r
+err_t\r
+dhcp_start(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp;\r
+  err_t result = ERR_OK;\r
+\r
+  LWIP_ERROR("netif != NULL", (netif != NULL), return ERR_ARG;);\r
+  dhcp = netif->dhcp;\r
+  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));\r
+  netif->flags &= ~NETIF_FLAG_DHCP;\r
+\r
+  /* no DHCP client attached yet? */\r
+  if (dhcp == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n"));\r
+    dhcp = mem_malloc(sizeof(struct dhcp));\r
+    if (dhcp == NULL) {\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* store this dhcp client in the netif */\r
+    netif->dhcp = dhcp;\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): allocated dhcp"));\r
+  /* already has DHCP client attached */\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("dhcp_start(): restarting DHCP configuration\n"));\r
+  }\r
+\r
+  /* clear data structure */\r
+  memset(dhcp, 0, sizeof(struct dhcp));\r
+  /* allocate UDP PCB */\r
+  dhcp->pcb = udp_new();\r
+  if (dhcp->pcb == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG  | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n"));\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = dhcp = NULL;\r
+    return ERR_MEM;\r
+  }\r
+  /* set up local and remote port for the pcb */\r
+  udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+  udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+  /* set up the recv callback and argument */\r
+  udp_recv(dhcp->pcb, dhcp_recv, netif);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting DHCP configuration\n"));\r
+  /* (re)start the DHCP negotiation */\r
+  result = dhcp_discover(netif);\r
+  if (result != ERR_OK) {\r
+    /* free resources allocated above */\r
+    dhcp_stop(netif);\r
+    return ERR_MEM;\r
+  }\r
+  netif->flags |= NETIF_FLAG_DHCP;\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Inform a DHCP server of our manual configuration.\r
+ *\r
+ * This informs DHCP servers of our fixed IP address configuration\r
+ * by sending an INFORM message. It does not involve DHCP address\r
+ * configuration, it is just here to be nice to the network.\r
+ *\r
+ * @param netif The lwIP network interface\r
+ */\r
+void\r
+dhcp_inform(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp, *old_dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+  dhcp = mem_malloc(sizeof(struct dhcp));\r
+  if (dhcp == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not allocate dhcp\n"));\r
+    return;\r
+  }\r
+  netif->dhcp = dhcp;\r
+  memset(dhcp, 0, sizeof(struct dhcp));\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n"));\r
+  dhcp->pcb = udp_new();\r
+  if (dhcp->pcb == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform(): could not obtain pcb"));\r
+    mem_free((void *)dhcp);\r
+    return;\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n"));\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_INFORM);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    /* TODO: use netif->mtu ?! */\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT);\r
+    udp_connect(dhcp->pcb, IP_ADDR_BROADCAST, DHCP_SERVER_PORT);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n"));\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    dhcp_delete_request(netif);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_inform: could not allocate DHCP request\n"));\r
+  }\r
+\r
+  if (dhcp != NULL) {\r
+    if (dhcp->pcb != NULL) {\r
+      udp_remove(dhcp->pcb);\r
+    }\r
+    dhcp->pcb = NULL;\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = old_dhcp;\r
+  }\r
+}\r
+\r
+#if DHCP_DOES_ARP_CHECK\r
+/**\r
+ * Match an ARP reply with the offered IP address.\r
+ *\r
+ * @param netif the network interface on which the reply was received\r
+ * @param addr The IP address we received a reply from\r
+ */\r
+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr)\r
+{\r
+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_arp_reply()\n"));\r
+  /* is a DHCP client doing an ARP check? */\r
+  if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr));\r
+    /* did a host respond with the address we\r
+       were offered by the DHCP server? */\r
+    if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) {\r
+      /* we will not accept the offered address */\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1, ("dhcp_arp_reply(): arp reply matched with offered address, declining\n"));\r
+      dhcp_decline(netif);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Decline an offered lease.\r
+ *\r
+ * Tell the DHCP server we do not accept the offered address.\r
+ * One reason to decline the lease is when we find out the address\r
+ * is already in use by another host (through ARP).\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static err_t\r
+dhcp_decline(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_decline()\n"));\r
+  dhcp_set_state(dhcp, DHCP_BACKING_OFF);\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_DECLINE);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option_trailer(dhcp);\r
+    /* resize pbuf to reflect true size of options */\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* @todo: should we really connect here? we are performing sendto() */\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    /* per section 4.4.4, broadcast DECLINE messages */\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_decline: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = 10*1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+#endif\r
+\r
+\r
+/**\r
+ * Start the DHCP process, discover a DHCP server.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static err_t\r
+dhcp_discover(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result = ERR_OK;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_discover()\n"));\r
+  ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY);\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n"));\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_DISCOVER);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_ROUTER);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_BROADCAST);\r
+    dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: realloc()ing\n"));\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n"));\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n"));\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n"));\r
+    dhcp_set_state(dhcp, DHCP_SELECTING);\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_discover: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+#if LWIP_DHCP_AUTOIP_COOP\r
+  /* that means we waited 57 seconds */\r
+  if(dhcp->tries >= 9 && dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_OFF) {\r
+    dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_ON;\r
+    autoip_start(netif);\r
+  }\r
+#endif /* LWIP_DHCP_AUTOIP_COOP */\r
+  msecs = dhcp->tries < 4 ? (dhcp->tries + 1) * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+\r
+/**\r
+ * Bind the interface to the offered IP address.\r
+ *\r
+ * @param netif network interface to bind to the offered address\r
+ */\r
+static void\r
+dhcp_bind(struct netif *netif)\r
+{\r
+  u32_t timeout;\r
+  struct dhcp *dhcp;\r
+  struct ip_addr sn_mask, gw_addr;\r
+  LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;);\r
+  dhcp = netif->dhcp;\r
+  LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;);\r
+  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));\r
+\r
+  /* temporary DHCP lease? */\r
+  if (dhcp->offered_t1_renew != 0xffffffffUL) {\r
+    /* set renewal period timer */\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t1 renewal timer %"U32_F" secs\n", dhcp->offered_t1_renew));\r
+    timeout = (dhcp->offered_t1_renew + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
+    if(timeout > 0xffff) {\r
+      timeout = 0xffff;\r
+    }\r
+    dhcp->t1_timeout = (u16_t)timeout;\r
+    if (dhcp->t1_timeout == 0) {\r
+      dhcp->t1_timeout = 1;\r
+    }\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t1_renew*1000));\r
+  }\r
+  /* set renewal period timer */\r
+  if (dhcp->offered_t2_rebind != 0xffffffffUL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_bind(): t2 rebind timer %"U32_F" secs\n", dhcp->offered_t2_rebind));\r
+    timeout = (dhcp->offered_t2_rebind + DHCP_COARSE_TIMER_SECS / 2) / DHCP_COARSE_TIMER_SECS;\r
+    if(timeout > 0xffff) {\r
+      timeout = 0xffff;\r
+    }\r
+    dhcp->t2_timeout = (u16_t)timeout;\r
+    if (dhcp->t2_timeout == 0) {\r
+      dhcp->t2_timeout = 1;\r
+    }\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000));\r
+  }\r
+  /* copy offered network mask */\r
+  ip_addr_set(&sn_mask, &dhcp->offered_sn_mask);\r
+\r
+  /* subnet mask not given? */\r
+  /* TODO: this is not a valid check. what if the network mask is 0? */\r
+  if (sn_mask.addr == 0) {\r
+    /* choose a safe subnet mask given the network class */\r
+    u8_t first_octet = ip4_addr1(&sn_mask);\r
+    if (first_octet <= 127) {\r
+      sn_mask.addr = htonl(0xff000000);\r
+    } else if (first_octet >= 192) {\r
+      sn_mask.addr = htonl(0xffffff00);\r
+    } else {\r
+      sn_mask.addr = htonl(0xffff0000);\r
+    }\r
+  }\r
+\r
+  ip_addr_set(&gw_addr, &dhcp->offered_gw_addr);\r
+  /* gateway address not given? */\r
+  if (gw_addr.addr == 0) {\r
+    /* copy network address */\r
+    gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr);\r
+    /* use first host address on network as gateway */\r
+    gw_addr.addr |= htonl(0x00000001);\r
+  }\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr));\r
+  netif_set_ipaddr(netif, &dhcp->offered_ip_addr);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr));\r
+  netif_set_netmask(netif, &sn_mask);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr));\r
+  netif_set_gw(netif, &gw_addr);\r
+  /* bring the interface up */\r
+  netif_set_up(netif);\r
+  /* netif is now bound to DHCP leased address */\r
+  dhcp_set_state(dhcp, DHCP_BOUND);\r
+}\r
+\r
+/**\r
+ * Renew an existing DHCP lease at the involved DHCP server.\r
+ *\r
+ * @param netif network interface which must renew its lease\r
+ */\r
+err_t\r
+dhcp_renew(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_renew()\n"));\r
+  dhcp_set_state(dhcp, DHCP_RENEWING);\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    /* TODO: use netif->mtu in some way */\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+#endif\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+#endif\r
+    /* append DHCP message trailer */\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);\r
+    dhcp_delete_request(netif);\r
+\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_renew: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  /* back-off on retries, but to a maximum of 20 seconds */\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 2000 : 20 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Rebind with a DHCP server for an existing DHCP lease.\r
+ *\r
+ * @param netif network interface which must rebind with a DHCP server\r
+ */\r
+static err_t\r
+dhcp_rebind(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n"));\r
+  dhcp_set_state(dhcp, DHCP_REBINDING);\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_REQUEST);\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN);\r
+    dhcp_option_short(dhcp, 576);\r
+\r
+#if 0\r
+    dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr));\r
+\r
+    dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4);\r
+    dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr));\r
+#endif\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    /* broadcast to server */\r
+    udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT);\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_rebind: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind(): set request timeout %"U16_F" msecs\n", msecs));\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Release a DHCP lease.\r
+ *\r
+ * @param netif network interface which must release its lease\r
+ */\r
+err_t\r
+dhcp_release(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  err_t result;\r
+  u16_t msecs;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_release()\n"));\r
+\r
+  /* idle DHCP client */\r
+  dhcp_set_state(dhcp, DHCP_OFF);\r
+  /* clean old DHCP offer */\r
+  dhcp->server_ip_addr.addr = 0;\r
+  dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0;\r
+  dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0;\r
+  dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0;\r
+  dhcp->dns_count = 0;\r
+\r
+  /* create and initialize the DHCP message header */\r
+  result = dhcp_create_request(netif);\r
+  if (result == ERR_OK) {\r
+    dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN);\r
+    dhcp_option_byte(dhcp, DHCP_RELEASE);\r
+\r
+    dhcp_option_trailer(dhcp);\r
+\r
+    pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len);\r
+\r
+    udp_connect(dhcp->pcb, &dhcp->server_ip_addr, DHCP_SERVER_PORT);\r
+    udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif);\r
+    dhcp_delete_request(netif);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n"));\r
+  } else {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_release: could not allocate DHCP request\n"));\r
+  }\r
+  dhcp->tries++;\r
+  msecs = dhcp->tries < 10 ? dhcp->tries * 1000 : 10 * 1000;\r
+  dhcp->request_timeout = (msecs + DHCP_FINE_TIMER_MSECS - 1) / DHCP_FINE_TIMER_MSECS;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release(): set request timeout %"U16_F" msecs\n", msecs));\r
+  /* bring the interface down */\r
+  netif_set_down(netif);\r
+  /* remove IP address from interface */\r
+  netif_set_ipaddr(netif, IP_ADDR_ANY);\r
+  netif_set_gw(netif, IP_ADDR_ANY);\r
+  netif_set_netmask(netif, IP_ADDR_ANY);\r
+\r
+  /* TODO: netif_down(netif); */\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Remove the DHCP client from the interface.\r
+ *\r
+ * @param netif The network interface to stop DHCP on\r
+ */\r
+void\r
+dhcp_stop(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;);\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 3, ("dhcp_stop()\n"));\r
+  /* netif is DHCP configured? */\r
+  if (dhcp != NULL) {\r
+    if (dhcp->pcb != NULL) {\r
+      udp_remove(dhcp->pcb);\r
+      dhcp->pcb = NULL;\r
+    }\r
+    if (dhcp->p != NULL) {\r
+      pbuf_free(dhcp->p);\r
+      dhcp->p = NULL;\r
+    }\r
+    /* free unfolded reply */\r
+    dhcp_free_reply(dhcp);\r
+    mem_free((void *)dhcp);\r
+    netif->dhcp = NULL;\r
+  }\r
+}\r
+\r
+/*\r
+ * Set the DHCP state of a DHCP client.\r
+ *\r
+ * If the state changed, reset the number of tries.\r
+ *\r
+ * TODO: we might also want to reset the timeout here?\r
+ */\r
+static void\r
+dhcp_set_state(struct dhcp *dhcp, u8_t new_state)\r
+{\r
+  if (new_state != dhcp->state) {\r
+    dhcp->state = new_state;\r
+    dhcp->tries = 0;\r
+  }\r
+}\r
+\r
+/*\r
+ * Concatenate an option type and length field to the outgoing\r
+ * DHCP message.\r
+ *\r
+ */\r
+static void\r
+dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len)\r
+{\r
+  LWIP_ASSERT("dhcp_option: dhcp->options_out_len + 2 + option_len <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U + option_len <= DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_type;\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = option_len;\r
+}\r
+/*\r
+ * Concatenate a single byte to the outgoing DHCP message.\r
+ *\r
+ */\r
+static void\r
+dhcp_option_byte(struct dhcp *dhcp, u8_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_byte: dhcp->options_out_len < DHCP_OPTIONS_LEN", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = value;\r
+}\r
+\r
+static void\r
+dhcp_option_short(struct dhcp *dhcp, u16_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_short: dhcp->options_out_len + 2 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 2U <= DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff00U) >> 8);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t) (value & 0x00ffU);\r
+}\r
+\r
+static void\r
+dhcp_option_long(struct dhcp *dhcp, u32_t value)\r
+{\r
+  LWIP_ASSERT("dhcp_option_long: dhcp->options_out_len + 4 <= DHCP_OPTIONS_LEN", dhcp->options_out_len + 4U <= DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0xff000000UL) >> 24);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x00ff0000UL) >> 16);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x0000ff00UL) >> 8);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = (u8_t)((value & 0x000000ffUL));\r
+}\r
+\r
+/**\r
+ * Extract the DHCP message and the DHCP options.\r
+ *\r
+ * Extract the DHCP message and the DHCP options, each into a contiguous\r
+ * piece of memory. As a DHCP message is variable sized by its options,\r
+ * and also allows overriding some fields for options, the easy approach\r
+ * is to first unfold the options into a conitguous piece of memory, and\r
+ * use that further on.\r
+ *\r
+ */\r
+static err_t\r
+dhcp_unfold_reply(struct dhcp *dhcp)\r
+{\r
+  u16_t ret;\r
+  LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;);\r
+  LWIP_ERROR("dhcp->p != NULL", (dhcp->p != NULL), return ERR_VAL;);\r
+  /* free any left-overs from previous unfolds */\r
+  dhcp_free_reply(dhcp);\r
+  /* options present? */\r
+  if (dhcp->p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) {\r
+    dhcp->options_in_len = dhcp->p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+    dhcp->options_in = mem_malloc(dhcp->options_in_len);\r
+    if (dhcp->options_in == NULL) {\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->options\n"));\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+  dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+  if (dhcp->msg_in == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n"));\r
+    mem_free((void *)dhcp->options_in);\r
+    dhcp->options_in = NULL;\r
+    return ERR_MEM;\r
+  }\r
+\r
+  /** copy the DHCP message without options */\r
+  ret = pbuf_copy_partial(dhcp->p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0);\r
+  LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n",\r
+     sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN));\r
+\r
+  if (dhcp->options_in != NULL) {\r
+    /** copy the DHCP options */\r
+    ret = pbuf_copy_partial(dhcp->p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN);\r
+    LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len);\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n",\r
+      dhcp->options_in_len));\r
+  }\r
+  LWIP_UNUSED_ARG(ret);\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Free the incoming DHCP message including contiguous copy of\r
+ * its DHCP options.\r
+ *\r
+ */\r
+static void dhcp_free_reply(struct dhcp *dhcp)\r
+{\r
+  if (dhcp->msg_in != NULL) {\r
+    mem_free((void *)dhcp->msg_in);\r
+    dhcp->msg_in = NULL;\r
+  }\r
+  if (dhcp->options_in) {\r
+    mem_free((void *)dhcp->options_in);\r
+    dhcp->options_in = NULL;\r
+    dhcp->options_in_len = 0;\r
+  }\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n"));\r
+}\r
+\r
+\r
+/**\r
+ * If an incoming DHCP message is in response to us, then trigger the state machine\r
+ */\r
+static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct netif *netif = (struct netif *)arg;\r
+  struct dhcp *dhcp = netif->dhcp;\r
+  struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload;\r
+  u8_t *options_ptr;\r
+  u8_t msg_type;\r
+  u8_t i;\r
+  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,\r
+    (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff),\r
+    (u16_t)(ntohl(addr->addr) >>  8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port));\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len));\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len));\r
+  /* prevent warnings about unused arguments */\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_UNUSED_ARG(addr);\r
+  LWIP_UNUSED_ARG(port);\r
+  dhcp->p = p;\r
+  /* TODO: check packet length before reading them */\r
+  if (reply_msg->op != DHCP_BOOTREPLY) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("not a DHCP reply message, but type %"U16_F"\n", (u16_t)reply_msg->op));\r
+    goto free_pbuf_and_return;\r
+  }\r
+  /* iterate through hardware address and match against DHCP message */\r
+  for (i = 0; i < netif->hwaddr_len; i++) {\r
+    if (netif->hwaddr[i] != reply_msg->chaddr[i]) {\r
+      LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("netif->hwaddr[%"U16_F"]==%02"X16_F" != reply_msg->chaddr[%"U16_F"]==%02"X16_F"\n",\r
+        (u16_t)i, (u16_t)netif->hwaddr[i], (u16_t)i, (u16_t)reply_msg->chaddr[i]));\r
+      goto free_pbuf_and_return;\r
+    }\r
+  }\r
+  /* match transaction ID against what we expected */\r
+  if (ntohl(reply_msg->xid) != dhcp->xid) {\r
+    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));\r
+    goto free_pbuf_and_return;\r
+  }\r
+  /* option fields could be unfold? */\r
+  if (dhcp_unfold_reply(dhcp) != ERR_OK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("problem unfolding DHCP message - too short on memory?\n"));\r
+    goto free_pbuf_and_return;\r
+  }\r
+\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n"));\r
+  /* obtain pointer to DHCP message type */\r
+  options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE);\r
+  if (options_ptr == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OPTION_MESSAGE_TYPE option not found\n"));\r
+    goto free_pbuf_and_return;\r
+  }\r
+\r
+  /* read DHCP message type */\r
+  msg_type = dhcp_get_option_byte(options_ptr + 2);\r
+  /* message type is DHCP ACK? */\r
+  if (msg_type == DHCP_ACK) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_ACK received\n"));\r
+    /* in requesting state? */\r
+    if (dhcp->state == DHCP_REQUESTING) {\r
+      dhcp_handle_ack(netif);\r
+      dhcp->request_timeout = 0;\r
+#if DHCP_DOES_ARP_CHECK\r
+      /* check if the acknowledged lease address is already in use */\r
+      dhcp_check(netif);\r
+#else\r
+      /* bind interface to the acknowledged lease address */\r
+      dhcp_bind(netif);\r
+#endif\r
+    }\r
+    /* already bound to the given lease address? */\r
+    else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) {\r
+      dhcp->request_timeout = 0;\r
+      dhcp_bind(netif);\r
+    }\r
+  }\r
+  /* received a DHCP_NAK in appropriate state? */\r
+  else if ((msg_type == DHCP_NAK) &&\r
+    ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) ||\r
+     (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING  ))) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_NAK received\n"));\r
+    dhcp->request_timeout = 0;\r
+    dhcp_handle_nak(netif);\r
+  }\r
+  /* received a DHCP_OFFER in DHCP_SELECTING state? */\r
+  else if ((msg_type == DHCP_OFFER) && (dhcp->state == DHCP_SELECTING)) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("DHCP_OFFER received in DHCP_SELECTING state\n"));\r
+    dhcp->request_timeout = 0;\r
+    /* remember offered lease */\r
+    dhcp_handle_offer(netif);\r
+  }\r
+free_pbuf_and_return:\r
+  pbuf_free(p);\r
+  dhcp->p = NULL;\r
+}\r
+\r
+/**\r
+ * Create a DHCP request, fill in common headers\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static err_t\r
+dhcp_create_request(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp;\r
+  u16_t i;\r
+  LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;);\r
+  dhcp = netif->dhcp;\r
+  LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;);\r
+  LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL);\r
+  LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL);\r
+  dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM);\r
+  if (dhcp->p_out == NULL) {\r
+    LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("dhcp_create_request(): could not allocate pbuf\n"));\r
+    return ERR_MEM;\r
+  }\r
+  LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg",\r
+           (dhcp->p_out->len >= sizeof(struct dhcp_msg)));\r
+\r
+  /* give unique transaction identifier to this request */\r
+  dhcp->xid = xid++;\r
+  LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("transaction id xid++(%"X32_F") dhcp->xid(%"U32_F")\n",xid,dhcp->xid));\r
+\r
+  dhcp->msg_out = (struct dhcp_msg *)dhcp->p_out->payload;\r
+\r
+  dhcp->msg_out->op = DHCP_BOOTREQUEST;\r
+  /* TODO: make link layer independent */\r
+  dhcp->msg_out->htype = DHCP_HTYPE_ETH;\r
+  /* TODO: make link layer independent */\r
+  dhcp->msg_out->hlen = DHCP_HLEN_ETH;\r
+  dhcp->msg_out->hops = 0;\r
+  dhcp->msg_out->xid = htonl(dhcp->xid);\r
+  dhcp->msg_out->secs = 0;\r
+  dhcp->msg_out->flags = 0;\r
+  dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr;\r
+  dhcp->msg_out->yiaddr.addr = 0;\r
+  dhcp->msg_out->siaddr.addr = 0;\r
+  dhcp->msg_out->giaddr.addr = 0;\r
+  for (i = 0; i < DHCP_CHADDR_LEN; i++) {\r
+    /* copy netif hardware address, pad with zeroes */\r
+    dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/;\r
+  }\r
+  for (i = 0; i < DHCP_SNAME_LEN; i++) {\r
+    dhcp->msg_out->sname[i] = 0;\r
+  }\r
+  for (i = 0; i < DHCP_FILE_LEN; i++) {\r
+    dhcp->msg_out->file[i] = 0;\r
+  }\r
+  dhcp->msg_out->cookie = htonl(0x63825363UL);\r
+  dhcp->options_out_len = 0;\r
+  /* fill options field with an incrementing array (for debugging purposes) */\r
+  for (i = 0; i < DHCP_OPTIONS_LEN; i++) {\r
+    dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Free previously allocated memory used to send a DHCP request.\r
+ *\r
+ * @param netif the netif under DHCP control\r
+ */\r
+static void\r
+dhcp_delete_request(struct netif *netif)\r
+{\r
+  struct dhcp *dhcp;\r
+  LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;);\r
+  dhcp = netif->dhcp;\r
+  LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;);\r
+  LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL);\r
+  LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL);\r
+  if (dhcp->p_out != NULL) {\r
+    pbuf_free(dhcp->p_out);\r
+  }\r
+  dhcp->p_out = NULL;\r
+  dhcp->msg_out = NULL;\r
+}\r
+\r
+/**\r
+ * Add a DHCP message trailer\r
+ *\r
+ * Adds the END option to the DHCP message, and if\r
+ * necessary, up to three padding bytes.\r
+ *\r
+ * @param dhcp DHCP state structure\r
+ */\r
+static void\r
+dhcp_option_trailer(struct dhcp *dhcp)\r
+{\r
+  LWIP_ERROR("dhcp_option_trailer: dhcp != NULL", (dhcp != NULL), return;);\r
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->msg_out != NULL\n", dhcp->msg_out != NULL);\r
+  LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+  dhcp->msg_out->options[dhcp->options_out_len++] = DHCP_OPTION_END;\r
+  /* packet is too small, or not 4 byte aligned? */\r
+  while ((dhcp->options_out_len < DHCP_MIN_OPTIONS_LEN) || (dhcp->options_out_len & 3)) {\r
+    /* 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)); */\r
+    LWIP_ASSERT("dhcp_option_trailer: dhcp->options_out_len < DHCP_OPTIONS_LEN\n", dhcp->options_out_len < DHCP_OPTIONS_LEN);\r
+    /* add a fill/padding byte */\r
+    dhcp->msg_out->options[dhcp->options_out_len++] = 0;\r
+  }\r
+}\r
+\r
+/**\r
+ * Find the offset of a DHCP option inside the DHCP message.\r
+ *\r
+ * @param dhcp DHCP client\r
+ * @param option_type\r
+ *\r
+ * @return a byte offset into the UDP message where the option was found, or\r
+ * zero if the given option was not found.\r
+ */\r
+static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type)\r
+{\r
+  u8_t overload = DHCP_OVERLOAD_NONE;\r
+\r
+  /* options available? */\r
+  if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) {\r
+    /* start with options field */\r
+    u8_t *options = (u8_t *)dhcp->options_in;\r
+    u16_t offset = 0;\r
+    /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */\r
+    while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) {\r
+      /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */\r
+      /* are the sname and/or file field overloaded with options? */\r
+      if (options[offset] == DHCP_OPTION_OVERLOAD) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 2, ("overloaded message detected\n"));\r
+        /* skip option type and length */\r
+        offset += 2;\r
+        overload = options[offset++];\r
+      }\r
+      /* requested option found */\r
+      else if (options[offset] == option_type) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset));\r
+        return &options[offset];\r
+      /* skip option */\r
+      } else {\r
+         LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset]));\r
+        /* skip option type */\r
+        offset++;\r
+        /* skip option length, and then length bytes */\r
+        offset += 1 + options[offset];\r
+      }\r
+    }\r
+    /* is this an overloaded message? */\r
+    if (overload != DHCP_OVERLOAD_NONE) {\r
+      u16_t field_len;\r
+      if (overload == DHCP_OVERLOAD_FILE) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded file field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->file;\r
+        field_len = DHCP_FILE_LEN;\r
+      } else if (overload == DHCP_OVERLOAD_SNAME) {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->sname;\r
+        field_len = DHCP_SNAME_LEN;\r
+      /* TODO: check if else if () is necessary */\r
+      } else {\r
+        LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | 1, ("overloaded sname and file field\n"));\r
+        options = (u8_t *)&dhcp->msg_in->sname;\r
+        field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN;\r
+      }\r
+      offset = 0;\r
+\r
+      /* at least 1 byte to read and no end marker */\r
+      while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) {\r
+        if (options[offset] == option_type) {\r
+           LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset));\r
+          return &options[offset];\r
+        /* skip option */\r
+        } else {\r
+          LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset]));\r
+          /* skip option type */\r
+          offset++;\r
+          offset += 1 + options[offset];\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Return the byte of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u8_t\r
+dhcp_get_option_byte(u8_t *ptr)\r
+{\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr)));\r
+  return *ptr;\r
+}\r
+\r
+#if 0 /* currently unused */\r
+/**\r
+ * Return the 16-bit value of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u16_t\r
+dhcp_get_option_short(u8_t *ptr)\r
+{\r
+  u16_t value;\r
+  value = *ptr++ << 8;\r
+  value |= *ptr;\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value));\r
+  return value;\r
+}\r
+#endif\r
+\r
+/**\r
+ * Return the 32-bit value of DHCP option data.\r
+ *\r
+ * @param client DHCP client.\r
+ * @param ptr pointer obtained by dhcp_get_option_ptr().\r
+ *\r
+ * @return byte value at the given address.\r
+ */\r
+static u32_t dhcp_get_option_long(u8_t *ptr)\r
+{\r
+  u32_t value;\r
+  value = (u32_t)(*ptr++) << 24;\r
+  value |= (u32_t)(*ptr++) << 16;\r
+  value |= (u32_t)(*ptr++) << 8;\r
+  value |= (u32_t)(*ptr++);\r
+  LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value));\r
+  return value;\r
+}\r
+\r
+#endif /* LWIP_DHCP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/dns.c b/Demo/Common/ethernet/lwIP_130/src/core/dns.c
new file mode 100644 (file)
index 0000000..8c2cf08
--- /dev/null
@@ -0,0 +1,814 @@
+/**\r
+ * @file\r
+ * DNS - host name to IP address resolver.\r
+ *\r
+ */\r
+\r
+/**\r
+\r
+ * This file implements a DNS host name to IP address resolver.\r
+\r
+ * Port to lwIP from uIP\r
+ * by Jim Pettinato April 2007\r
+\r
+ * uIP version Copyright (c) 2002-2003, Adam Dunkels.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote\r
+ *    products derived from this software without specific prior\r
+ *    written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ *\r
+ *\r
+ * DNS.C\r
+ *\r
+ * The lwIP DNS resolver functions are used to lookup a host name and\r
+ * map it to a numerical IP address. It maintains a list of resolved\r
+ * hostnames that can be queried with the dns_lookup() function.\r
+ * New hostnames can be resolved using the dns_query() function.\r
+ *\r
+ * The lwIP version of the resolver also adds a non-blocking version of\r
+ * gethostbyname() that will work with a raw API application. This function\r
+ * checks for an IP address string first and converts it if it is valid.\r
+ * gethostbyname() then does a dns_lookup() to see if the name is \r
+ * already in the table. If so, the IP is returned. If not, a query is \r
+ * issued and the function returns with a ERR_INPROGRESS status. The app\r
+ * using the dns client must then go into a waiting state.\r
+ *\r
+ * Once a hostname has been resolved (or found to be non-existent),\r
+ * the resolver code calls a specified callback function (which \r
+ * must be implemented by the module that uses the resolver).\r
+ */\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * RFC 1035 - Domain names - implementation and specification\r
+ * RFC 2181 - Clarifications to the DNS Specification\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/** @todo: define good default values (rfc compliance) */\r
+/** @todo: improve answer parsing, more checkings... */\r
+/** @todo: check RFC1035 - 7.3. Processing responses */\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * Includes\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/udp.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/dns.h"\r
+\r
+#include <string.h>\r
+\r
+/** DNS server IP address */\r
+#ifndef DNS_SERVER_ADDRESS\r
+#define DNS_SERVER_ADDRESS        inet_addr("208.67.222.222") /* resolver1.opendns.com */\r
+#endif\r
+\r
+/** DNS server port address */\r
+#ifndef DNS_SERVER_PORT\r
+#define DNS_SERVER_PORT           53\r
+#endif\r
+\r
+/** DNS maximum number of retries when asking for a name, before "timeout". */\r
+#ifndef DNS_MAX_RETRIES\r
+#define DNS_MAX_RETRIES           4\r
+#endif\r
+\r
+/** DNS resource record max. TTL (one week as default) */\r
+#ifndef DNS_MAX_TTL\r
+#define DNS_MAX_TTL               604800\r
+#endif\r
+\r
+/* DNS protocol flags */\r
+#define DNS_FLAG1_RESPONSE        0x80\r
+#define DNS_FLAG1_OPCODE_STATUS   0x10\r
+#define DNS_FLAG1_OPCODE_INVERSE  0x08\r
+#define DNS_FLAG1_OPCODE_STANDARD 0x00\r
+#define DNS_FLAG1_AUTHORATIVE     0x04\r
+#define DNS_FLAG1_TRUNC           0x02\r
+#define DNS_FLAG1_RD              0x01\r
+#define DNS_FLAG2_RA              0x80\r
+#define DNS_FLAG2_ERR_MASK        0x0f\r
+#define DNS_FLAG2_ERR_NONE        0x00\r
+#define DNS_FLAG2_ERR_NAME        0x03\r
+\r
+/* DNS protocol states */\r
+#define DNS_STATE_UNUSED          0\r
+#define DNS_STATE_NEW             1\r
+#define DNS_STATE_ASKING          2\r
+#define DNS_STATE_DONE            3\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** DNS message header */\r
+struct dns_hdr {\r
+  u16_t id;\r
+  u8_t flags1;\r
+  u8_t flags2;\r
+  u16_t numquestions;\r
+  u16_t numanswers;\r
+  u16_t numauthrr;\r
+  u16_t numextrarr;\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** DNS query message structure */\r
+struct dns_query {\r
+  /* DNS query record starts with either a domain name or a pointer\r
+     to a name already present somewhere in the packet. */\r
+  u16_t type;\r
+  u16_t class;\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** DNS answer message structure */\r
+struct dns_answer {\r
+  /* DNS answer record starts with either a domain name or a pointer\r
+     to a name already present somewhere in the packet. */\r
+  u16_t type;\r
+  u16_t class;\r
+  u32_t ttl;\r
+  u16_t len;\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/** DNS table entry */\r
+struct dns_table_entry {\r
+  u8_t  state;\r
+  u8_t  numdns;\r
+  u8_t  tmr;\r
+  u8_t  retries;\r
+  u8_t  seqno;\r
+  u8_t  err;\r
+  u32_t ttl;\r
+  char name[DNS_MAX_NAME_LENGTH];\r
+  struct ip_addr ipaddr;\r
+  /* pointer to callback on DNS query done */\r
+  dns_found_callback found;\r
+  void *arg;\r
+};\r
+\r
+\r
+/* forward declarations */\r
+static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
+static void dns_check_entries(void);\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * Globales\r
+ *----------------------------------------------------------------------------*/\r
+\r
+/* DNS variables */\r
+static struct udp_pcb        *dns_pcb;\r
+static u8_t                   dns_seqno;\r
+static struct dns_table_entry dns_table[DNS_TABLE_SIZE];\r
+static struct ip_addr         dns_servers[DNS_MAX_SERVERS];\r
+\r
+#if (DNS_USES_STATIC_BUF == 1)\r
+static u8_t                   dns_payload[DNS_MSG_SIZE];\r
+#endif /* (DNS_USES_STATIC_BUF == 1) */\r
+\r
+/**\r
+ * Initialize the resolver: set up the UDP pcb and configure the default server\r
+ * (DNS_SERVER_ADDRESS).\r
+ */\r
+void\r
+dns_init()\r
+{\r
+  struct ip_addr dnsserver;\r
+  \r
+  /* initialize default DNS server address */\r
+  dnsserver.addr = DNS_SERVER_ADDRESS;\r
+\r
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n"));\r
+\r
+  /* if dns client not yet initialized... */\r
+  if (dns_pcb == NULL) {\r
+    dns_pcb = udp_new();\r
+\r
+    if (dns_pcb != NULL) {\r
+      /* initialize DNS table not needed (initialized to zero since it is a\r
+       * global variable) */\r
+      LWIP_ASSERT("For implicit initialization to work, DNS_STATE_UNUSED needs to be 0",\r
+        DNS_STATE_UNUSED == 0);\r
+\r
+      /* initialize DNS client */\r
+      udp_bind(dns_pcb, IP_ADDR_ANY, 0);\r
+      udp_recv(dns_pcb, dns_recv, NULL);\r
+\r
+      /* initialize default DNS primary server */\r
+      dns_setserver(0, &dnsserver);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Initialize one of the DNS servers.\r
+ *\r
+ * @param numdns the index of the DNS server to set must be < DNS_MAX_SERVERS\r
+ * @param dnsserver IP address of the DNS server to set\r
+ */\r
+void\r
+dns_setserver(u8_t numdns, struct ip_addr *dnsserver)\r
+{\r
+  if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&\r
+      (dnsserver != NULL) && (dnsserver->addr !=0 )) {\r
+    dns_servers[numdns] = (*dnsserver);\r
+  }\r
+}\r
+\r
+/**\r
+ * Obtain one of the currently configured DNS server.\r
+ *\r
+ * @param numdns the index of the DNS server\r
+ * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS\r
+ *         server has not been configured.\r
+ */\r
+struct ip_addr\r
+dns_getserver(u8_t numdns)\r
+{\r
+  if (numdns < DNS_MAX_SERVERS) {\r
+    return dns_servers[numdns];\r
+  } else {\r
+    return *IP_ADDR_ANY;\r
+  }\r
+}\r
+\r
+/**\r
+ * The DNS resolver client timer - handle retries and timeouts and should\r
+ * be called every DNS_TMR_INTERVAL milliseconds (every second by default).\r
+ */\r
+void\r
+dns_tmr(void)\r
+{\r
+  if (dns_pcb != NULL) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_tmr: dns_check_entries\n"));\r
+    dns_check_entries();\r
+  }\r
+}\r
+\r
+/**\r
+ * Look up a hostname in the array of known hostnames.\r
+ *\r
+ * @note This function only looks in the internal array of known\r
+ * hostnames, it does not send out a query for the hostname if none\r
+ * was found. The function dns_enqueue() can be used to send a query\r
+ * for a hostname.\r
+ *\r
+ * @param name the hostname to look up\r
+ * @return the hostname's IP address, as u32_t (instead of struct ip_addr to\r
+ *         better check for failure: != 0) or 0 if the hostname was not found\r
+ *         in the cached dns_table.\r
+ */\r
+static u32_t\r
+dns_lookup(const char *name)\r
+{\r
+  u8_t i;\r
+\r
+  /* Walk through name list, return entry if found. If not, return NULL. */\r
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\r
+    if ((dns_table[i].state == DNS_STATE_DONE) &&\r
+        (strcmp(name, dns_table[i].name) == 0)) {\r
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name));\r
+      ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr));\r
+      LWIP_DEBUGF(DNS_DEBUG, ("\n"));\r
+      return dns_table[i].ipaddr.addr;\r
+    }\r
+  }\r
+\r
+  return 0;\r
+}\r
+\r
+#if DNS_DOES_NAME_CHECK\r
+/**\r
+ * Compare the "dotted" name "query" with the encoded name "response"\r
+ * to make sure an answer from the DNS server matches the current dns_table\r
+ * entry (otherwise, answers might arrive late for hostname not on the list\r
+ * any more).\r
+ *\r
+ * @param query hostname (not encoded) from the dns_table\r
+ * @param response encoded hostname in the DNS response\r
+ * @return 0: names equal; 1: names differ\r
+ */\r
+static u8_t\r
+dns_compare_name(unsigned char *query, unsigned char *response)\r
+{\r
+  unsigned char n;\r
+\r
+  do {\r
+    n = *response++;\r
+    /** @see RFC 1035 - 4.1.4. Message compression */\r
+    if ((n & 0xc0) == 0xc0) {\r
+      /* Compressed name */\r
+      break;\r
+    } else {\r
+      /* Not compressed name */\r
+      while (n > 0) {\r
+        if ((*query) != (*response)) {\r
+          return 1;\r
+        }\r
+        ++response;\r
+        ++query;\r
+        --n;\r
+      };\r
+      ++query;\r
+    }\r
+  } while (*response != 0);\r
+\r
+  return 0;\r
+}\r
+#endif /* DNS_DOES_NAME_CHECK */\r
+\r
+/**\r
+ * Walk through a compact encoded DNS name and return the end of the name.\r
+ *\r
+ * @param query encoded DNS name in the DNS server response\r
+ * @return end of the name\r
+ */\r
+static unsigned char *\r
+dns_parse_name(unsigned char *query)\r
+{\r
+  unsigned char n;\r
+\r
+  do {\r
+    n = *query++;\r
+    /** @see RFC 1035 - 4.1.4. Message compression */\r
+    if ((n & 0xc0) == 0xc0) {\r
+      /* Compressed name */\r
+      break;\r
+    } else {\r
+      /* Not compressed name */\r
+      while (n > 0) {\r
+        ++query;\r
+        --n;\r
+      };\r
+    }\r
+  } while (*query != 0);\r
+\r
+  return query + 1;\r
+}\r
+\r
+/**\r
+ * Send a DNS query packet.\r
+ *\r
+ * @param numdns index of the DNS server in the dns_servers table\r
+ * @param name hostname to query\r
+ * @param id index of the hostname in dns_table, used as transaction ID in the\r
+ *        DNS query packet\r
+ * @return ERR_OK if packet is sent; an err_t indicating the problem otherwise\r
+ */\r
+static err_t\r
+dns_send(u8_t numdns, const char* name, u8_t id)\r
+{\r
+  err_t err;\r
+  struct dns_hdr *hdr;\r
+  struct dns_query qry;\r
+  struct pbuf *p;\r
+  char *query, *nptr;\r
+  const char *pHostname;\r
+  u8_t n;\r
+\r
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n",\r
+              (u16_t)(numdns), name));\r
+  LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS);\r
+  LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0);\r
+\r
+  /* if here, we have either a new query or a retry on a previous query to process */\r
+  p = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dns_hdr) + DNS_MAX_NAME_LENGTH +\r
+                 sizeof(struct dns_query), PBUF_RAM);\r
+  if (p != NULL) {\r
+    LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);\r
+    /* fill dns header */\r
+    hdr = (struct dns_hdr*)p->payload;\r
+    memset(hdr, 0, sizeof(struct dns_hdr));\r
+    hdr->id = htons(id);\r
+    hdr->flags1 = DNS_FLAG1_RD;\r
+    hdr->numquestions = htons(1);\r
+    query = (char*)hdr + sizeof(struct dns_hdr);\r
+    pHostname = name;\r
+    --pHostname;\r
+\r
+    /* convert hostname into suitable query format. */\r
+    do {\r
+      ++pHostname;\r
+      nptr = query;\r
+      ++query;\r
+      for(n = 0; *pHostname != '.' && *pHostname != 0; ++pHostname) {\r
+        *query = *pHostname;\r
+        ++query;\r
+        ++n;\r
+      }\r
+      *nptr = n;\r
+    } while(*pHostname != 0);\r
+    *query++='\0';\r
+\r
+    /* fill dns query */\r
+    qry.type  = htons(DNS_RRTYPE_A);\r
+    qry.class = htons(DNS_RRCLASS_IN);\r
+    MEMCPY( query, &qry, sizeof(struct dns_query));\r
+\r
+    /* resize pbuf to the exact dns query */\r
+    pbuf_realloc(p, (query + sizeof(struct dns_query)) - ((char*)(p->payload)));\r
+\r
+    /* connect to the server for faster receiving */\r
+    udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT);\r
+    /* send dns packet */\r
+    err = udp_sendto(dns_pcb, p, &dns_servers[numdns], DNS_SERVER_PORT);\r
+\r
+    /* free pbuf */\r
+    pbuf_free(p);\r
+  } else {\r
+    err = ERR_MEM;\r
+  }\r
+\r
+  return err;\r
+}\r
+\r
+/**\r
+ * dns_check_entry() - see if pEntry has not yet been queried and, if so, sends out a query.\r
+ * Check an entry in the dns_table:\r
+ * - send out query for new entries\r
+ * - retry old pending entries on timeout (also with different servers)\r
+ * - remove completed entries from the table if their TTL has expired\r
+ *\r
+ * @param i index of the dns_table entry to check\r
+ */\r
+static void\r
+dns_check_entry(u8_t i)\r
+{\r
+  struct dns_table_entry *pEntry = &dns_table[i];\r
+\r
+  LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE);\r
+\r
+  switch(pEntry->state) {\r
+\r
+    case DNS_STATE_NEW: {\r
+      /* initialize new entry */\r
+      pEntry->state   = DNS_STATE_ASKING;\r
+      pEntry->numdns  = 0;\r
+      pEntry->tmr     = 1;\r
+      pEntry->retries = 0;\r
+      \r
+      /* send DNS packet for this entry */\r
+      dns_send(pEntry->numdns, pEntry->name, i);\r
+      break;\r
+    }\r
+\r
+    case DNS_STATE_ASKING: {\r
+      if (--pEntry->tmr == 0) {\r
+        if (++pEntry->retries == DNS_MAX_RETRIES) {\r
+          if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) {\r
+            /* change of server */\r
+            pEntry->numdns++;\r
+            pEntry->tmr     = 1;\r
+            pEntry->retries = 0;\r
+            break;\r
+          } else {\r
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": timeout\n", pEntry->name));\r
+            /* call specified callback function if provided */\r
+            if (pEntry->found)\r
+              (*pEntry->found)(pEntry->name, NULL, pEntry->arg);\r
+            /* flush this entry */\r
+            pEntry->state   = DNS_STATE_UNUSED;\r
+            pEntry->found   = NULL;\r
+            break;\r
+          }\r
+        }\r
+\r
+        /* wait longer for the next retry */\r
+        pEntry->tmr = pEntry->retries;\r
+\r
+        /* send DNS packet for this entry */\r
+        dns_send(pEntry->numdns, pEntry->name, i);\r
+      }\r
+      break;\r
+    }\r
+\r
+    case DNS_STATE_DONE: {\r
+      /* if the time to live is nul */\r
+      if (--pEntry->ttl == 0) {\r
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_check_entry: \"%s\": flush\n", pEntry->name));\r
+        /* flush this entry */\r
+        pEntry->state = DNS_STATE_UNUSED;\r
+        pEntry->found = NULL;\r
+      }\r
+      break;\r
+    }\r
+    case DNS_STATE_UNUSED:\r
+      /* nothing to do */\r
+      break;\r
+    default:\r
+      LWIP_ASSERT("unknown dns_table entry state:", 0);\r
+      break;\r
+  }\r
+}\r
+\r
+/**\r
+ * Call dns_check_entry for each entry in dns_table - check all entries.\r
+ */\r
+static void\r
+dns_check_entries(void)\r
+{\r
+  u8_t i;\r
+\r
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\r
+    dns_check_entry(i);\r
+  }\r
+}\r
+\r
+/**\r
+ * Receive input function for DNS response packets arriving for the dns UDP pcb.\r
+ *\r
+ * @params see udp.h\r
+ */\r
+static void\r
+dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
+{\r
+  u8_t i;\r
+  char *pHostname;\r
+  struct dns_hdr *hdr;\r
+  struct dns_answer ans;\r
+  struct dns_table_entry *pEntry;\r
+  u8_t nquestions, nanswers;\r
+#if (DNS_USES_STATIC_BUF == 0)\r
+  u8_t dns_payload[DNS_MSG_SIZE];\r
+#endif /* (DNS_USES_STATIC_BUF == 0) */\r
+#if (DNS_USES_STATIC_BUF == 2)\r
+  u8_t* dns_payload;\r
+#endif /* (DNS_USES_STATIC_BUF == 2) */\r
+\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_UNUSED_ARG(addr);\r
+  LWIP_UNUSED_ARG(port);\r
+\r
+  /* is the dns message too big ? */\r
+  if (p->tot_len > DNS_MSG_SIZE) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n"));\r
+    /* free pbuf and return */\r
+    goto memerr1;\r
+  }\r
+\r
+  /* is the dns message big enough ? */\r
+  if (p->tot_len < (sizeof(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n"));\r
+    /* free pbuf and return */\r
+    goto memerr1;\r
+  }\r
+\r
+#if (DNS_USES_STATIC_BUF == 2)\r
+  dns_payload = mem_malloc(p->tot_len);\r
+  if (dns_payload == NULL) {\r
+    LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));\r
+    /* free pbuf and return */\r
+    goto memerr1;\r
+  }\r
+#endif /* (DNS_USES_STATIC_BUF == 2) */\r
+\r
+  /* copy dns payload inside static buffer for processing */ \r
+  if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {\r
+    /* The ID in the DNS header should be our entry into the name table. */\r
+    hdr = (struct dns_hdr*)dns_payload;\r
+    i = htons(hdr->id);\r
+    if (i < DNS_TABLE_SIZE) {\r
+      pEntry = &dns_table[i];\r
+      if(pEntry->state == DNS_STATE_ASKING) {\r
+        /* This entry is now completed. */\r
+        pEntry->state = DNS_STATE_DONE;\r
+        pEntry->err   = hdr->flags2 & DNS_FLAG2_ERR_MASK;\r
+\r
+        /* We only care about the question(s) and the answers. The authrr\r
+           and the extrarr are simply discarded. */\r
+        nquestions = htons(hdr->numquestions);\r
+        nanswers   = htons(hdr->numanswers);\r
+\r
+        /* Check for error. If so, call callback to inform. */\r
+        if (((hdr->flags1 & DNS_FLAG1_RESPONSE) == 0) || (pEntry->err != 0) || (nquestions != 1)) {\r
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in flags\n", pEntry->name));\r
+          /* call callback to indicate error, clean up memory and return */\r
+          goto responseerr;\r
+        }\r
+\r
+#if DNS_DOES_NAME_CHECK\r
+        /* Check if the name in the "question" part match with the name in the entry. */\r
+        if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {\r
+          LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));\r
+          /* call callback to indicate error, clean up memory and return */\r
+          goto responseerr;\r
+        }\r
+#endif /* DNS_DOES_NAME_CHECK */\r
+\r
+        /* Skip the name in the "question" part */\r
+        pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);\r
+\r
+        while(nanswers > 0) {\r
+          /* skip answer resource record's host name */\r
+          pHostname = (char *) dns_parse_name((unsigned char *)pHostname);\r
+\r
+          /* Check for IP address type and Internet class. Others are discarded. */\r
+          MEMCPY(&ans, pHostname, sizeof(struct dns_answer));\r
+          if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) {\r
+            /* read the answer resource record's TTL, and maximize it if needed */\r
+            pEntry->ttl = ntohl(ans.ttl);\r
+            if (pEntry->ttl > DNS_MAX_TTL) {\r
+              pEntry->ttl = DNS_MAX_TTL;\r
+            }\r
+            /* read the IP address after answer resource record's header */\r
+            MEMCPY( &(pEntry->ipaddr), (pHostname+sizeof(struct dns_answer)), sizeof(struct ip_addr));\r
+            LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name));\r
+            ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr)));\r
+            LWIP_DEBUGF(DNS_DEBUG, ("\n"));\r
+            /* call specified callback function if provided */\r
+            if (pEntry->found) {\r
+              (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg);\r
+            }\r
+            /* deallocate memory and return */\r
+            goto memerr2;\r
+          } else {\r
+            pHostname = pHostname + sizeof(struct dns_answer) + htons(ans.len);\r
+          }\r
+          --nanswers;\r
+        }\r
+        LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": error in response\n", pEntry->name));\r
+        /* call callback to indicate error, clean up memory and return */\r
+        goto responseerr;\r
+      }\r
+    }\r
+  }\r
+\r
+  /* deallocate memory and return */\r
+  goto memerr2;\r
+\r
+responseerr:\r
+  /* ERROR: call specified callback function with NULL as name to indicate an error */\r
+  if (pEntry->found) {\r
+    (*pEntry->found)(pEntry->name, NULL, pEntry->arg);\r
+  }\r
+  /* flush this entry */\r
+  pEntry->state = DNS_STATE_UNUSED;\r
+  pEntry->found = NULL;\r
+\r
+memerr2:\r
+#if (DNS_USES_STATIC_BUF == 2)\r
+  /* free dns buffer */\r
+  mem_free(dns_payload);\r
+#endif /* (DNS_USES_STATIC_BUF == 2) */\r
+\r
+memerr1:\r
+  /* free pbuf */\r
+  pbuf_free(p);\r
+  return;\r
+}\r
+\r
+/**\r
+ * Queues a new hostname to resolve and sends out a DNS query for that hostname\r
+ *\r
+ * @param name the hostname that is to be queried\r
+ * @param found a callback founction to be called on success, failure or timeout\r
+ * @param callback_arg argument to pass to the callback function\r
+ * @return @return a err_t return code.\r
+ */\r
+static err_t\r
+dns_enqueue(const char *name, dns_found_callback found, void *callback_arg)\r
+{\r
+  u8_t i;\r
+  u8_t lseq, lseqi;\r
+  struct dns_table_entry *pEntry = NULL;\r
+\r
+  /* search an unused entry, or the oldest one */\r
+  lseq = lseqi = 0;\r
+  for (i = 0; i < DNS_TABLE_SIZE; ++i) {\r
+    pEntry = &dns_table[i];\r
+    /* is it an unused entry ? */\r
+    if (pEntry->state == DNS_STATE_UNUSED)\r
+      break;\r
+\r
+    /* check if this is the oldest completed entry */\r
+    if (pEntry->state == DNS_STATE_DONE) {\r
+      if ((dns_seqno - pEntry->seqno) > lseq) {\r
+        lseq = dns_seqno - pEntry->seqno;\r
+        lseqi = i;\r
+      }\r
+    }\r
+  }\r
+\r
+  /* if we don't have found an unused entry, use the oldest completed one */\r
+  if (i == DNS_TABLE_SIZE) {\r
+    if ((lseqi >= DNS_TABLE_SIZE) || (dns_table[lseqi].state != DNS_STATE_DONE)) {\r
+      /* no entry can't be used now, table is full */\r
+      LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": DNS entries table is full\n", name));\r
+      return ERR_MEM;\r
+    } else {\r
+      /* use the oldest completed one */\r
+      i = lseqi;\r
+      pEntry = &dns_table[i];\r
+    }\r
+  }\r
+\r
+  /* use this entry */\r
+  LWIP_DEBUGF(DNS_DEBUG, ("dns_enqueue: \"%s\": use DNS entry %"U16_F"\n", name, (u16_t)(i)));\r
+\r
+  /* fill the entry */\r
+  pEntry->state = DNS_STATE_NEW;\r
+  pEntry->seqno = dns_seqno++;\r
+  pEntry->found = found;\r
+  pEntry->arg   = callback_arg;\r
+  strcpy(pEntry->name, name);\r
+\r
+  /* force to send query without waiting timer */\r
+  dns_check_entry(i);\r
+\r
+  /* dns query is enqueued */\r
+  return ERR_INPROGRESS;\r
+}\r
+\r
+/**\r
+ * Resolve a hostname (string) into an IP address.\r
+ * NON-BLOCKING callback version for use with raw API!!!\r
+ *\r
+ * Returns immediately with one of err_t return codes:\r
+ * - ERR_OK if hostname is a valid IP address string or the host\r
+ *   name is already in the local names table.\r
+ * - ERR_INPROGRESS enqueue a request to be sent to the DNS server\r
+ *   for resolution if no errors are present.\r
+ *\r
+ * @param hostname the hostname that is to be queried\r
+ * @param addr pointer to a struct ip_addr where to store the address if it is already\r
+ *             cached in the dns_table (only valid if ERR_OK is returned!)\r
+ * @param found a callback function to be called on success, failure or timeout (only if\r
+ *              ERR_INPROGRESS is returned!)\r
+ * @param callback_arg argument to pass to the callback function\r
+ * @return a err_t return code.\r
+ */\r
+err_t\r
+dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found,\r
+                  void *callback_arg)\r
+{\r
+  /* not initialized or no valid server yet, or invalid addr pointer\r
+   * or invalid hostname or invalid hostname length */\r
+  if ((dns_pcb == NULL) || (addr == NULL) ||\r
+      (!hostname) || (!hostname[0]) ||\r
+      (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) {\r
+    return ERR_VAL;\r
+  }\r
+\r
+#if LWIP_HAVE_LOOPIF\r
+  if (strcmp(hostname,"localhost")==0) {\r
+    addr->addr = INADDR_LOOPBACK;\r
+    return ERR_OK;\r
+  }\r
+#endif /* LWIP_HAVE_LOOPIF */\r
+\r
+  /* host name already in octet notation? set ip addr and return ERR_OK\r
+   * already have this address cached? */\r
+  if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) ||\r
+      ((addr->addr = dns_lookup(hostname)) != 0)) {\r
+    return ERR_OK;\r
+  }\r
+\r
+  /* queue query with specified callback */\r
+  return dns_enqueue(hostname, found, callback_arg);\r
+}\r
+\r
+#endif /* LWIP_DNS */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/init.c b/Demo/Common/ethernet/lwIP_130/src/core/init.c
new file mode 100644 (file)
index 0000000..1faacb8
--- /dev/null
@@ -0,0 +1,253 @@
+/**\r
+ * @file\r
+ * Modules initialization\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/init.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/sockets.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/autoip.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/dns.h"\r
+#include "netif/etharp.h"\r
+\r
+/* Compile-time sanity checks for configuration errors.\r
+ * These can be done independently of LWIP_DEBUG, without penalty.\r
+ */\r
+#ifndef BYTE_ORDER\r
+  #error "BYTE_ORDER is not defined, you have to define it in your cc.h"\r
+#endif\r
+#if (!LWIP_ARP && ARP_QUEUEING)\r
+  #error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_UDP && LWIP_UDPLITE)\r
+  #error "If you want to use UDP Lite, you have to define LWIP_UDP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_UDP && LWIP_SNMP)\r
+  #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_UDP && LWIP_DHCP)\r
+  #error "If you want to use DHCP, you have to define LWIP_UDP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_UDP && LWIP_IGMP)\r
+  #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_UDP && LWIP_DNS)\r
+  #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))\r
+  #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"\r
+#endif\r
+#if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0))\r
+  #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_RAW && (MEMP_NUM_RAW_PCB<=0))\r
+  #error "If you want to use RAW, you have to define MEMP_NUM_RAW_PCB>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_UDP && (MEMP_NUM_UDP_PCB<=0))\r
+  #error "If you want to use UDP, you have to define MEMP_NUM_UDP_PCB>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_TCP && (MEMP_NUM_TCP_PCB<=0))\r
+  #error "If you want to use TCP, you have to define MEMP_NUM_TCP_PCB>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_TCP && (TCP_WND > 0xffff))\r
+  #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"\r
+#endif\r
+#if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff))\r
+  #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"\r
+#endif\r
+#if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12)))\r
+  #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"\r
+#endif\r
+#if (LWIP_TCP && TCP_LISTEN_BACKLOG && (TCP_DEFAULT_LISTEN_BACKLOG < 0) || (TCP_DEFAULT_LISTEN_BACKLOG > 0xff))\r
+  #error "If you want to use TCP backlog, TCP_DEFAULT_LISTEN_BACKLOG must fit into an u8_t"\r
+#endif\r
+#if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1))\r
+  #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h"\r
+#endif\r
+#if (PPP_SUPPORT && (NO_SYS==1))\r
+  #error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_NETIF_API && (NO_SYS==1))\r
+  #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h"\r
+#endif\r
+#if ((LWIP_SOCKET || LWIP_NETCONN) && (NO_SYS==1))\r
+  #error "If you want to use Sequential API, you have to define NO_SYS=0 in your lwipopts.h"\r
+#endif\r
+#if ((LWIP_NETCONN || LWIP_SOCKET) && (MEMP_NUM_TCPIP_MSG_API<=0))\r
+  #error "If you want to use Sequential API, you have to define MEMP_NUM_TCPIP_MSG_API>=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_NETCONN && LWIP_SOCKET)\r
+  #error "If you want to use Socket API, you have to define LWIP_NETCONN=1 in your lwipopts.h"\r
+#endif\r
+#if (((!LWIP_DHCP) || (!LWIP_AUTOIP)) && LWIP_DHCP_AUTOIP_COOP)\r
+  #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"\r
+#endif\r
+#if (((!LWIP_DHCP) || (!LWIP_ARP)) && DHCP_DOES_ARP_CHECK)\r
+  #error "If you want to use DHCP ARP checking, you have to define LWIP_DHCP=1 and LWIP_ARP=1 in your lwipopts.h"\r
+#endif\r
+#if (!LWIP_ARP && LWIP_AUTOIP)\r
+  #error "If you want to use AUTOIP, you have to define LWIP_ARP=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_SNMP && (SNMP_CONCURRENT_REQUESTS<=0))\r
+  #error "If you want to use SNMP, you have to define SNMP_CONCURRENT_REQUESTS>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_SNMP && (SNMP_TRAP_DESTINATIONS<=0))\r
+  #error "If you want to use SNMP, you have to define SNMP_TRAP_DESTINATIONS>=1 in your lwipopts.h"\r
+#endif\r
+#if (LWIP_TCP && ((LWIP_EVENT_API && LWIP_CALLBACK_API) || (!LWIP_EVENT_API && !LWIP_CALLBACK_API)))\r
+  #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h"\r
+#endif\r
+/* There must be sufficient timeouts, taking into account requirements of the subsystems. */\r
+#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)))\r
+  #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts"\r
+#endif\r
+#if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS))\r
+  #error "MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS doesn't make sense since each struct ip_reassdata must hold 2 pbufs at least!"\r
+#endif\r
+#if (MEM_LIBC_MALLOC && MEM_USE_POOLS)\r
+  #error "MEM_LIBC_MALLOC and MEM_USE_POOLS may not both be simultaneously enabled in your lwipopts.h"\r
+#endif\r
+#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)\r
+  #error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"\r
+#endif\r
+\r
+\r
+/* Compile-time checks for deprecated options.\r
+ */\r
+#ifdef MEMP_NUM_TCPIP_MSG\r
+  #error "MEMP_NUM_TCPIP_MSG option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#ifdef MEMP_NUM_API_MSG\r
+  #error "MEMP_NUM_API_MSG option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#ifdef TCP_REXMIT_DEBUG\r
+  #error "TCP_REXMIT_DEBUG option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#ifdef RAW_STATS\r
+  #error "RAW_STATS option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#ifdef ETHARP_QUEUE_FIRST\r
+  #error "ETHARP_QUEUE_FIRST option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#ifdef ETHARP_ALWAYS_INSERT\r
+  #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h."\r
+#endif\r
+#if SO_REUSE\r
+/* I removed the lot since this was an ugly hack. It broke the raw-API.\r
+   It also came with many ugly goto's, Christiaan Simons. */\r
+  #error "SO_REUSE currently unavailable, this was a hack"\r
+#endif\r
+\r
+#ifdef LWIP_DEBUG\r
+static void\r
+lwip_sanity_check(void)\r
+{\r
+  /* Warnings */\r
+#if LWIP_NETCONN\r
+  if (MEMP_NUM_NETCONN > (MEMP_NUM_TCP_PCB+MEMP_NUM_TCP_PCB_LISTEN+MEMP_NUM_UDP_PCB+MEMP_NUM_RAW_PCB))\r
+    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"));\r
+#endif /* LWIP_NETCONN */\r
+#if LWIP_TCP\r
+  if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)\r
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));\r
+  if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS)))\r
+    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"));\r
+  if (TCP_SNDLOWAT > TCP_SND_BUF)\r
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n"));\r
+  if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE))\r
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n"));\r
+  if (TCP_WND < TCP_MSS)\r
+    LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n"));\r
+#endif /* LWIP_TCP */\r
+}\r
+#else  /* LWIP_DEBUG */\r
+#define lwip_sanity_check()\r
+#endif /* LWIP_DEBUG */\r
+\r
+/**\r
+ * Perform Sanity check of user-configurable values, and initialize all modules.\r
+ */\r
+void\r
+lwip_init(void)\r
+{\r
+  /* Sanity check user-configurable values */\r
+  lwip_sanity_check();\r
+\r
+  /* Modules initialization */\r
+  stats_init();\r
+  sys_init();\r
+  mem_init();\r
+  memp_init();\r
+  pbuf_init();\r
+  netif_init();\r
+#if LWIP_SOCKET\r
+  lwip_socket_init();\r
+#endif /* LWIP_SOCKET */\r
+  ip_init();\r
+#if LWIP_ARP\r
+  etharp_init();\r
+#endif /* LWIP_ARP */\r
+#if LWIP_RAW\r
+  raw_init();\r
+#endif /* LWIP_RAW */\r
+#if LWIP_UDP\r
+  udp_init();\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+  tcp_init();\r
+#endif /* LWIP_TCP */\r
+#if LWIP_AUTOIP\r
+  autoip_init();\r
+#endif /* LWIP_AUTOIP */\r
+#if LWIP_IGMP\r
+  igmp_init();\r
+#endif /* LWIP_IGMP */\r
+#if LWIP_DNS\r
+  dns_init();\r
+#endif /* LWIP_DNS */\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/autoip.c
new file mode 100644 (file)
index 0000000..e7fd48e
--- /dev/null
@@ -0,0 +1,432 @@
+/**\r
+ * @file\r
+ * AutoIP Automatic LinkLocal IP Configuration\r
+ *\r
+ */\r
+\r
+/*\r
+ *\r
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Dominik Spies <kontakt@dspies.de>\r
+ *\r
+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform\r
+ * with RFC 3927.\r
+ *\r
+ *\r
+ * Please coordinate changes and requests with Dominik Spies\r
+ * <kontakt@dspies.de>\r
+ */\r
+\r
+/*******************************************************************************\r
+ * USAGE:\r
+ * \r
+ * define LWIP_AUTOIP 1  in your lwipopts.h\r
+ * \r
+ * If you don't use tcpip.c (so, don't call, you don't call tcpip_init):\r
+ * - First, call autoip_init().\r
+ * - call autoip_tmr() all AUTOIP_TMR_INTERVAL msces,\r
+ *   that should be defined in autoip.h.\r
+ *   I recommend a value of 100. The value must divide 1000 with a remainder almost 0.\r
+ *   Possible values are 1000, 500, 333, 250, 200, 166, 142, 125, 111, 100 ....\r
+ *\r
+ * Without DHCP:\r
+ * - Call autoip_start() after netif_add().\r
+ * \r
+ * With DHCP:\r
+ * - define LWIP_DHCP_AUTOIP_COOP 1 in your lwipopts.h.\r
+ * - Configure your DHCP Client.\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/mem.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/autoip.h"\r
+#include "netif/etharp.h"\r
+\r
+#include <stdlib.h>\r
+#include <string.h>\r
+\r
+/* Pseudo random macro based on netif informations.\r
+ * You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */\r
+#ifndef LWIP_AUTOIP_RAND\r
+#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \\r
+                                   ((u32_t)((netif->hwaddr[3]) & 0xff) << 16) | \\r
+                                   ((u32_t)((netif->hwaddr[2]) & 0xff) << 8) | \\r
+                                   ((u32_t)((netif->hwaddr[4]) & 0xff))) + \\r
+                                   (netif->autoip?netif->autoip->tried_llipaddr:0))\r
+#endif /* LWIP_AUTOIP_RAND */\r
+\r
+/* static functions */\r
+static void autoip_handle_arp_conflict(struct netif *netif);\r
+\r
+/* creates random LL IP-Address for a network interface */\r
+static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);\r
+\r
+/* sends an ARP announce */\r
+static err_t autoip_arp_announce(struct netif *netif);\r
+\r
+/* configure interface for use with current LL IP-Address */\r
+static err_t autoip_bind(struct netif *netif);\r
+\r
+/**\r
+ * Initialize this module\r
+ */\r
+void\r
+autoip_init(void)\r
+{\r
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));\r
+}\r
+\r
+/**\r
+ * Handle a IP address conflict after an ARP conflict detection\r
+ */\r
+static void\r
+autoip_handle_arp_conflict(struct netif *netif)\r
+{\r
+  /* Somehow detect if we are defending or retreating */\r
+  unsigned char defend = 1; /* tbd */\r
+\r
+  if(defend) {\r
+    if(netif->autoip->lastconflict > 0) {\r
+      /* retreat, there was a conflicting ARP in the last\r
+       * DEFEND_INTERVAL seconds\r
+       */\r
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+        ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n"));\r
+\r
+      /* TODO: close all TCP sessions */\r
+      autoip_start(netif);\r
+    } else {\r
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+        ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));\r
+      autoip_arp_announce(netif);\r
+      netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;\r
+    }\r
+  } else {\r
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+      ("autoip_handle_arp_conflict(): we do not defend, retreating\n"));\r
+    /* TODO: close all TCP sessions */\r
+    autoip_start(netif);\r
+  }\r
+}\r
+\r
+/**\r
+ * Create an IP-Address out of range 169.254.1.0 to 169.254.254.255\r
+ *\r
+ * @param netif network interface on which create the IP-Address\r
+ * @param RandomIPAddr ip address to initialize\r
+ */\r
+static void\r
+autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr)\r
+{\r
+  /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255\r
+   * compliant to RFC 3927 Section 2.1\r
+   * We have 254 * 256 possibilities\r
+   */\r
+  \r
+  RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |\r
+    ((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);\r
+\r
+  if (RandomIPAddr->addr>0xA9FEFEFF) {\r
+    RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));\r
+  }\r
+  if (RandomIPAddr->addr<0xA9FE0100) {\r
+    RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));\r
+  }\r
+  RandomIPAddr->addr = htonl(RandomIPAddr->addr);\r
+  \r
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+    ("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",\r
+    (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr)));\r
+}\r
+\r
+/**\r
+ * Sends an ARP announce from a network interface\r
+ *\r
+ * @param netif network interface used to send the announce\r
+ */\r
+static err_t\r
+autoip_arp_announce(struct netif *netif)\r
+{\r
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,\r
+    (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, &ethzero,\r
+    &netif->autoip->llipaddr, ARP_REQUEST);\r
+}\r
+\r
+/**\r
+ * Configure interface for use with current LL IP-Address\r
+ *\r
+ * @param netif network interface to configure with current LL IP-Address\r
+ */\r
+static err_t\r
+autoip_bind(struct netif *netif)\r
+{\r
+  struct autoip *autoip = netif->autoip;\r
+  struct ip_addr sn_mask, gw_addr;\r
+\r
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,\r
+    ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",\r
+    (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));\r
+\r
+  IP4_ADDR(&sn_mask, 255, 255, 0, 0);\r
+  IP4_ADDR(&gw_addr, 0, 0, 0, 0);\r
+\r
+  netif_set_ipaddr(netif, &autoip->llipaddr);\r
+  netif_set_netmask(netif, &sn_mask);\r
+  netif_set_gw(netif, &gw_addr);  \r
+\r
+  /* bring the interface up */\r
+  netif_set_up(netif);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Start AutoIP client\r
+ *\r
+ * @param netif network interface on which start the AutoIP client\r
+ */\r
+err_t\r
+autoip_start(struct netif *netif)\r
+{\r
+  struct autoip *autoip = netif->autoip;\r
+  err_t result = ERR_OK;\r
+\r
+  if(netif_is_up(netif)) {\r
+    netif_set_down(netif);\r
+  }\r
+\r
+  /* Set IP-Address, Netmask and Gateway to 0 to make sure that\r
+   * ARP Packets are formed correctly\r
+   */\r
+  netif->ip_addr.addr = 0;\r
+  netif->netmask.addr = 0;\r
+  netif->gw.addr      = 0;\r
+\r
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\r
+    ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0],\r
+    netif->name[1], (u16_t)netif->num));\r
+  if(autoip == NULL) {\r
+    /* no AutoIP client attached yet? */\r
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\r
+      ("autoip_start(): starting new AUTOIP client\n"));\r
+    autoip = mem_malloc(sizeof(struct autoip));\r
+    if(autoip == NULL) {\r
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\r
+        ("autoip_start(): could not allocate autoip\n"));\r
+      return ERR_MEM;\r
+    }\r
+    memset( autoip, 0, sizeof(struct autoip));\r
+    /* store this AutoIP client in the netif */\r
+    netif->autoip = autoip;\r
+    LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip"));\r
+  } else {\r
+    autoip->state = AUTOIP_STATE_OFF;\r
+    autoip->ttw = 0;\r
+    autoip->sent_num = 0;\r
+    memset(&autoip->llipaddr, 0, sizeof(struct ip_addr));\r
+    autoip->lastconflict = 0;\r
+  }\r
+\r
+  autoip_create_rand_addr(netif, &(autoip->llipaddr));\r
+  autoip->tried_llipaddr++;\r
+  autoip->state = AUTOIP_STATE_PROBING;\r
+  autoip->sent_num = 0;\r
+\r
+  /* time to wait to first probe, this is randomly\r
+   * choosen out of 0 to PROBE_WAIT seconds.\r
+   * compliant to RFC 3927 Section 2.2.1\r
+   */\r
+  autoip->ttw = (u16_t)(LWIP_AUTOIP_RAND(netif) % (PROBE_WAIT * AUTOIP_TICKS_PER_SECOND));\r
+\r
+  /*\r
+   * if we tried more then MAX_CONFLICTS we must limit our rate for\r
+   * accquiring and probing address\r
+   * compliant to RFC 3927 Section 2.2.1\r
+   */\r
+\r
+  if(autoip->tried_llipaddr > MAX_CONFLICTS) {\r
+    autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;\r
+  }\r
+\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Stop AutoIP client\r
+ *\r
+ * @param netif network interface on which stop the AutoIP client\r
+ */\r
+err_t\r
+autoip_stop(struct netif *netif)\r
+{\r
+  netif->autoip->state = AUTOIP_STATE_OFF;\r
+  netif_set_down(netif);\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds\r
+ */\r
+void\r
+autoip_tmr()\r
+{\r
+  struct netif *netif = netif_list;\r
+  /* loop through netif's */\r
+  while (netif != NULL) {\r
+    /* only act on AutoIP configured interfaces */\r
+    if (netif->autoip != NULL) {\r
+      if(netif->autoip->lastconflict > 0) {\r
+        netif->autoip->lastconflict--;\r
+      }\r
+\r
+      LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,\r
+        ("autoip_tmr() AutoIP-State: %"U16_F", ttw=%"U16_F"\n",\r
+        (u16_t)(netif->autoip->state), netif->autoip->ttw));\r
+\r
+      switch(netif->autoip->state) {\r
+        case AUTOIP_STATE_PROBING:\r
+          if(netif->autoip->ttw > 0) {\r
+            netif->autoip->ttw--;\r
+          } else {\r
+            if(netif->autoip->sent_num == PROBE_NUM) {\r
+              netif->autoip->state = AUTOIP_STATE_ANNOUNCING;\r
+              netif->autoip->sent_num = 0;\r
+              netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;\r
+            } else {\r
+              etharp_request(netif, &(netif->autoip->llipaddr));\r
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,\r
+                ("autoip_tmr() PROBING Sent Probe\n"));\r
+              netif->autoip->sent_num++;\r
+              /* calculate time to wait to next probe */\r
+              netif->autoip->ttw = (u16_t)((LWIP_AUTOIP_RAND(netif) %\r
+                ((PROBE_MAX - PROBE_MIN) * AUTOIP_TICKS_PER_SECOND) ) +\r
+                PROBE_MIN * AUTOIP_TICKS_PER_SECOND);\r
+            }\r
+          }\r
+          break;\r
+\r
+        case AUTOIP_STATE_ANNOUNCING:\r
+          if(netif->autoip->ttw > 0) {\r
+            netif->autoip->ttw--;\r
+          } else {\r
+            if(netif->autoip->sent_num == 0) {\r
+             /* We are here the first time, so we waited ANNOUNCE_WAIT seconds\r
+              * Now we can bind to an IP address and use it\r
+              */\r
+              autoip_bind(netif);\r
+            }\r
+\r
+            if(netif->autoip->sent_num == ANNOUNCE_NUM) {\r
+              netif->autoip->state = AUTOIP_STATE_BOUND;\r
+              netif->autoip->sent_num = 0;\r
+              netif->autoip->ttw = 0;\r
+            } else {\r
+              autoip_arp_announce(netif);\r
+              LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,\r
+                ("autoip_tmr() ANNOUNCING Sent Announce\n"));\r
+              netif->autoip->sent_num++;\r
+              netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;\r
+            }\r
+          }\r
+          break;\r
+      }\r
+    }\r
+    /* proceed to next network interface */\r
+    netif = netif->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * Handles every incoming ARP Packet, called by etharp_arp_input.\r
+ *\r
+ * @param netif network interface to use for autoip processing\r
+ * @param hdr Incoming ARP packet\r
+ */\r
+void\r
+autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)\r
+{\r
+  LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));\r
+  if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {\r
+   /* when ip.src == llipaddr && hw.src != netif->hwaddr\r
+    *\r
+    * when probing  ip.dst == llipaddr && hw.src != netif->hwaddr\r
+    * we have a conflict and must solve it\r
+    */\r
+    struct ip_addr sipaddr, dipaddr;\r
+    struct eth_addr netifaddr;\r
+    netifaddr.addr[0] = netif->hwaddr[0];\r
+    netifaddr.addr[1] = netif->hwaddr[1];\r
+    netifaddr.addr[2] = netif->hwaddr[2];\r
+    netifaddr.addr[3] = netif->hwaddr[3];\r
+    netifaddr.addr[4] = netif->hwaddr[4];\r
+    netifaddr.addr[5] = netif->hwaddr[5];\r
+\r
+    /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\r
+     * structure packing (not using structure copy which breaks strict-aliasing rules).\r
+     */\r
+    MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));\r
+    MEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));\r
+      \r
+    if ((netif->autoip->state == AUTOIP_STATE_PROBING) ||\r
+        ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) &&\r
+         (netif->autoip->sent_num == 0))) {\r
+     /* RFC 3927 Section 2.2.1:\r
+      * from beginning to after ANNOUNCE_WAIT\r
+      * seconds we have a conflict if\r
+      * ip.src == llipaddr OR\r
+      * ip.dst == llipaddr && hw.src != own hwaddr\r
+      */\r
+      if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||\r
+          (ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&\r
+           !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {\r
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+          ("autoip_arp_reply(): Probe Conflict detected\n"));\r
+        autoip_start(netif);\r
+      }\r
+    } else {\r
+     /* RFC 3927 Section 2.5:\r
+      * in any state we have a conflict if\r
+      * ip.src == llipaddr && hw.src != own hwaddr\r
+      */\r
+      if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&\r
+          !eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {\r
+        LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,\r
+          ("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));\r
+        autoip_handle_arp_conflict(netif);\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+#endif /* LWIP_AUTOIP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/icmp.c
new file mode 100644 (file)
index 0000000..aca1e5e
--- /dev/null
@@ -0,0 +1,317 @@
+/**\r
+ * @file\r
+ * ICMP - Internet Control Message Protocol\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* Some ICMP messages should be passed to the transport protocols. This\r
+   is not implemented. */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/icmp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/def.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+\r
+#include <string.h>\r
+\r
+/* The amount of data from the original packet to return in a dest-unreachable */\r
+#define ICMP_DEST_UNREACH_DATASIZE 8\r
+\r
+/**\r
+ * Processes ICMP input packets, called from ip_input().\r
+ *\r
+ * Currently only processes icmp echo requests and sends\r
+ * out the echo response.\r
+ *\r
+ * @param p the icmp echo request packet, p->payload pointing to the ip header\r
+ * @param inp the netif on which this packet was received\r
+ */\r
+void\r
+icmp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  u8_t type;\r
+#ifdef LWIP_DEBUG\r
+  u8_t code;\r
+#endif /* LWIP_DEBUG */\r
+  struct icmp_echo_hdr *iecho;\r
+  struct ip_hdr *iphdr;\r
+  struct ip_addr tmpaddr;\r
+  s16_t hlen;\r
+\r
+  ICMP_STATS_INC(icmp.recv);\r
+  snmp_inc_icmpinmsgs();\r
+\r
+\r
+  iphdr = p->payload;\r
+  hlen = IPH_HL(iphdr) * 4;\r
+  if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));\r
+    goto lenerr;\r
+  }\r
+\r
+  type = *((u8_t *)p->payload);\r
+#ifdef LWIP_DEBUG\r
+  code = *(((u8_t *)p->payload)+1);\r
+#endif /* LWIP_DEBUG */\r
+  switch (type) {\r
+  case ICMP_ECHO:\r
+    /* broadcast or multicast destination address? */\r
+    if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));\r
+      ICMP_STATS_INC(icmp.err);\r
+      pbuf_free(p);\r
+      return;\r
+    }\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));\r
+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));\r
+      goto lenerr;\r
+    }\r
+    if (inet_chksum_pbuf(p) != 0) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo\n"));\r
+      pbuf_free(p);\r
+      ICMP_STATS_INC(icmp.chkerr);\r
+      snmp_inc_icmpinerrors();\r
+      return;\r
+    }\r
+    if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {\r
+      /* p is not big enough to contain link headers\r
+       * allocate a new one and copy p into it\r
+       */\r
+      struct pbuf *r;\r
+      /* switch p->payload to ip header */\r
+      if (pbuf_header(p, hlen)) {\r
+        LWIP_ASSERT("icmp_input: moving p->payload to ip header failed\n", 0);\r
+        goto memerr;\r
+      }\r
+      /* allocate new packet buffer with space for link headers */\r
+      r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM);\r
+      if (r == NULL) {\r
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: allocating new pbuf failed\n"));\r
+        goto memerr;\r
+      }\r
+      LWIP_ASSERT("check that first pbuf can hold struct the ICMP header",\r
+                  (r->len >= hlen + sizeof(struct icmp_echo_hdr)));\r
+      /* copy the whole packet including ip header */\r
+      if (pbuf_copy(r, p) != ERR_OK) {\r
+        LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0);\r
+        goto memerr;\r
+      }\r
+      iphdr = r->payload;\r
+      /* switch r->payload back to icmp header */\r
+      if (pbuf_header(r, -hlen)) {\r
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);\r
+        goto memerr;\r
+      }\r
+      /* free the original p */\r
+      pbuf_free(p);\r
+      /* we now have an identical copy of p that has room for link headers */\r
+      p = r;\r
+    } else {\r
+      /* restore p->payload to point to icmp header */\r
+      if (pbuf_header(p, -(s16_t)(PBUF_IP_HLEN + PBUF_LINK_HLEN))) {\r
+        LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0);\r
+        goto memerr;\r
+      }\r
+    }\r
+    /* At this point, all checks are OK. */\r
+    /* We generate an answer by switching the dest and src ip addresses,\r
+     * setting the icmp type to ECHO_RESPONSE and updating the checksum. */\r
+    iecho = p->payload;\r
+    tmpaddr.addr = iphdr->src.addr;\r
+    iphdr->src.addr = iphdr->dest.addr;\r
+    iphdr->dest.addr = tmpaddr.addr;\r
+    ICMPH_TYPE_SET(iecho, ICMP_ER);\r
+    /* adjust the checksum */\r
+    if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) {\r
+      iecho->chksum += htons(ICMP_ECHO << 8) + 1;\r
+    } else {\r
+      iecho->chksum += htons(ICMP_ECHO << 8);\r
+    }\r
+\r
+    /* Set the correct TTL and recalculate the header checksum. */\r
+    IPH_TTL_SET(iphdr, ICMP_TTL);\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+#if CHECKSUM_GEN_IP\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+#endif /* CHECKSUM_GEN_IP */\r
+\r
+    ICMP_STATS_INC(icmp.xmit);\r
+    /* increase number of messages attempted to send */\r
+    snmp_inc_icmpoutmsgs();\r
+    /* increase number of echo replies attempted to send */\r
+    snmp_inc_icmpoutechoreps();\r
+\r
+    if(pbuf_header(p, hlen)) {\r
+      LWIP_ASSERT("Can't move over header in packet", 0);\r
+    } else {\r
+      err_t ret;\r
+      ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL,\r
+                   ICMP_TTL, 0, IP_PROTO_ICMP, inp);\r
+      if (ret != ERR_OK) {\r
+        LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret));\r
+      }\r
+    }\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" code %"S16_F" not supported.\n",\r
+                (s16_t)type, (s16_t)code));\r
+    ICMP_STATS_INC(icmp.proterr);\r
+    ICMP_STATS_INC(icmp.drop);\r
+  }\r
+  pbuf_free(p);\r
+  return;\r
+lenerr:\r
+  pbuf_free(p);\r
+  ICMP_STATS_INC(icmp.lenerr);\r
+  snmp_inc_icmpinerrors();\r
+  return;\r
+memerr:\r
+  pbuf_free(p);\r
+  ICMP_STATS_INC(icmp.err);\r
+  snmp_inc_icmpinerrors();\r
+  return;\r
+}\r
+\r
+/**\r
+ * Send an icmp 'destination unreachable' packet, called from ip_input() if\r
+ * the transport layer protocol is unknown and from udp_input() if the local\r
+ * port is not bound.\r
+ *\r
+ * @param p the input packet for which the 'unreachable' should be sent,\r
+ *          p->payload pointing to the IP header\r
+ * @param t type of the 'unreachable' packet\r
+ */\r
+void\r
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_dur_hdr *idur;\r
+\r
+  /* ICMP header + IP header + 8 bytes of data */\r
+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,\r
+                 PBUF_RAM);\r
+  if (q == NULL) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold icmp message",\r
+             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));\r
+\r
+  iphdr = p->payload;\r
+\r
+  idur = q->payload;\r
+  ICMPH_TYPE_SET(idur, ICMP_DUR);\r
+  ICMPH_CODE_SET(idur, t);\r
+\r
+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,\r
+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);\r
+\r
+  /* calculate checksum */\r
+  idur->chksum = 0;\r
+  idur->chksum = inet_chksum(idur, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+  /* increase number of messages attempted to send */\r
+  snmp_inc_icmpoutmsgs();\r
+  /* increase number of destination unreachable messages attempted to send */\r
+  snmp_inc_icmpoutdestunreachs();\r
+\r
+  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+#if IP_FORWARD || IP_REASSEMBLY\r
+/**\r
+ * Send a 'time exceeded' packet, called from ip_forward() if TTL is 0.\r
+ *\r
+ * @param p the input packet for which the 'time exceeded' should be sent,\r
+ *          p->payload pointing to the IP header\r
+ * @param t type of the 'time exceeded' packet\r
+ */\r
+void\r
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_te_hdr *tehdr;\r
+\r
+  /* ICMP header + IP header + 8 bytes of data */\r
+  q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,\r
+                 PBUF_RAM);\r
+  if (q == NULL) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold icmp message",\r
+             (q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));\r
+\r
+  iphdr = p->payload;\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from "));\r
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src));\r
+  LWIP_DEBUGF(ICMP_DEBUG, (" to "));\r
+  ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest));\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("\n"));\r
+\r
+  tehdr = q->payload;\r
+  ICMPH_TYPE_SET(tehdr, ICMP_TE);\r
+  ICMPH_CODE_SET(tehdr, t);\r
+\r
+  /* copy fields from original packet */\r
+  SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,\r
+          IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);\r
+\r
+  /* calculate checksum */\r
+  tehdr->chksum = 0;\r
+  tehdr->chksum = inet_chksum(tehdr, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+  /* increase number of messages attempted to send */\r
+  snmp_inc_icmpoutmsgs();\r
+  /* increase number of destination unreachable messages attempted to send */\r
+  snmp_inc_icmpouttimeexcds();\r
+  ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+#endif /* IP_FORWARD */\r
+\r
+#endif /* LWIP_ICMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/igmp.c
new file mode 100644 (file)
index 0000000..13144b6
--- /dev/null
@@ -0,0 +1,808 @@
+/**\r
+ * @file\r
+ * IGMP - Internet Group Management Protocol\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2002 CITEL Technologies Ltd.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without \r
+ * modification, are permitted provided that the following conditions \r
+ * are met: \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ *    notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright \r
+ *    notice, this list of conditions and the following disclaimer in the \r
+ *    documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors \r
+ *    may be used to endorse or promote products derived from this software \r
+ *    without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE \r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE. \r
+ *\r
+ * This file is a contribution to the lwIP TCP/IP stack.\r
+ * The Swedish Institute of Computer Science and Adam Dunkels\r
+ * are specifically granted permission to redistribute this\r
+ * source code.\r
+*/\r
+\r
+/*-------------------------------------------------------------\r
+Note 1)\r
+Although the rfc requires V1 AND V2 capability\r
+we will only support v2 since now V1 is very old (August 1989)\r
+V1 can be added if required\r
+\r
+a debug print and statistic have been implemented to\r
+show this up.\r
+-------------------------------------------------------------\r
+-------------------------------------------------------------\r
+Note 2)\r
+A query for a specific group address (as opposed to ALLHOSTS)\r
+has now been implemented as I am unsure if it is required\r
+\r
+a debug print and statistic have been implemented to\r
+show this up.\r
+-------------------------------------------------------------\r
+-------------------------------------------------------------\r
+Note 3)\r
+The router alert rfc 2113 is implemented in outgoing packets\r
+but not checked rigorously incoming\r
+-------------------------------------------------------------\r
+Steve Reynolds\r
+------------------------------------------------------------*/\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * RFC 988  - Host extensions for IP multicasting                         - V0\r
+ * RFC 1054 - Host extensions for IP multicasting                         -\r
+ * RFC 1112 - Host extensions for IP multicasting                         - V1\r
+ * RFC 2236 - Internet Group Management Protocol, Version 2               - V2  <- this code is based on this RFC (it's the "de facto" standard)\r
+ * RFC 3376 - Internet Group Management Protocol, Version 3               - V3\r
+ * RFC 4604 - Using Internet Group Management Protocol Version 3...       - V3+\r
+ * RFC 2113 - IP Router Alert Option                                      - \r
+ *----------------------------------------------------------------------------*/\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * Includes\r
+ *----------------------------------------------------------------------------*/\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/igmp.h"\r
+#include "lwip/debug.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/stats.h"\r
+\r
+#include "string.h"\r
+\r
+/*-----------------------------------------------------------------------------\r
+ * Globales\r
+ *----------------------------------------------------------------------------*/\r
+\r
+static struct igmp_group* igmp_group_list;\r
+static struct ip_addr     allsystems;\r
+static struct ip_addr     allrouters;\r
+\r
+/**\r
+ * Initialize the IGMP module\r
+ */\r
+void\r
+igmp_init(void)\r
+{\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_init: initializing\n"));\r
+\r
+  IP4_ADDR(&allsystems, 224, 0, 0, 1);\r
+  IP4_ADDR(&allrouters, 224, 0, 0, 2);\r
+}\r
+\r
+#ifdef LWIP_DEBUG\r
+/**\r
+ * Dump global IGMP groups list\r
+ */\r
+void\r
+igmp_dump_group_list()\r
+{ \r
+  struct igmp_group *group = igmp_group_list;\r
+\r
+  while (group != NULL) {\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state)));\r
+    ip_addr_debug_print(IGMP_DEBUG, &group->group_address);\r
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));\r
+    group = group->next;\r
+  }\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("\n"));\r
+}\r
+#else\r
+#define igmp_dump_group_list()\r
+#endif /* LWIP_DEBUG */\r
+\r
+/**\r
+ * Start IGMP processing on interface\r
+ *\r
+ * @param netif network interface on which start IGMP processing\r
+ */\r
+err_t\r
+igmp_start(struct netif *netif)\r
+{\r
+  struct igmp_group* group;\r
+\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif));\r
+\r
+  group = igmp_lookup_group(netif, &allsystems);\r
+\r
+  if (group != NULL) {\r
+    group->group_state = IGMP_GROUP_IDLE_MEMBER;\r
+    group->use++;\r
+\r
+    /* Allow the igmp messages at the MAC level */\r
+    if (netif->igmp_mac_filter != NULL) {\r
+      LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));\r
+      ip_addr_debug_print(IGMP_DEBUG, &allsystems);\r
+      LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));\r
+      netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);\r
+    }\r
+\r
+    return ERR_OK;\r
+  }\r
+\r
+  return ERR_MEM;\r
+}\r
+\r
+/**\r
+ * Stop IGMP processing on interface\r
+ *\r
+ * @param netif network interface on which stop IGMP processing\r
+ */\r
+err_t\r
+igmp_stop(struct netif *netif)\r
+{\r
+  struct igmp_group *group = igmp_group_list;\r
+  struct igmp_group *prev  = NULL;\r
+  struct igmp_group *next;\r
+\r
+  /* look for groups joined on this interface further down the list */\r
+  while (group != NULL) {\r
+    next = group->next;\r
+    /* is it a group joined on this interface? */\r
+    if (group->interface == netif) {\r
+      /* is it the first group of the list? */\r
+      if (group == igmp_group_list) {\r
+        igmp_group_list = next;\r
+      }\r
+      /* is there a "previous" group defined? */\r
+      if (prev != NULL) {\r
+        prev->next = next;\r
+      }\r
+      /* disable the group at the MAC level */\r
+      if (netif->igmp_mac_filter != NULL) {\r
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));\r
+        ip_addr_debug_print(IGMP_DEBUG, &group->group_address);\r
+        LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));\r
+        netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);\r
+      }\r
+      /* free group */\r
+      memp_free(MEMP_IGMP_GROUP, group);\r
+    } else {\r
+      /* change the "previous" */\r
+      prev = group;\r
+    }\r
+    /* move to "next" */\r
+    group = next;\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Report IGMP memberships for this interface\r
+ *\r
+ * @param netif network interface on which report IGMP memberships\r
+ */\r
+void\r
+igmp_report_groups( struct netif *netif)\r
+{\r
+  struct igmp_group *group = igmp_group_list;\r
+\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %x\n", (int) netif));\r
+\r
+  while (group != NULL) {\r
+    if (group->interface == netif) {\r
+      igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR);\r
+    }\r
+    group = group->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * Search for a group in the global igmp_group_list\r
+ *\r
+ * @param ifp the network interface for which to look\r
+ * @param addr the group ip address to search for\r
+ * @return a struct igmp_group* if the group has been found,\r
+ *         NULL if the group wasn't found.\r
+ */\r
+struct igmp_group *\r
+igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr)\r
+{\r
+  struct igmp_group *group = igmp_group_list;\r
+\r
+  while (group != NULL) {\r
+    if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) {\r
+      return group;\r
+    }\r
+    group = group->next;\r
+  }\r
+\r
+  /* to be clearer, we return NULL here instead of\r
+   * 'group' (which is also NULL at this point).\r
+   */\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Search for a specific igmp group and create a new one if not found-\r
+ *\r
+ * @param ifp the network interface for which to look\r
+ * @param addr the group ip address to search\r
+ * @return a struct igmp_group*,\r
+ *         NULL on memory error.\r
+ */\r
+struct igmp_group *\r
+igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)\r
+{\r
+  struct igmp_group *group = igmp_group_list;\r
+  \r
+  /* Search if the group already exists */\r
+  group = igmp_lookfor_group(ifp, addr);\r
+  if (group != NULL) {\r
+    /* Group already exists. */\r
+    return group;\r
+  }\r
+\r
+  /* Group doesn't exist yet, create a new one */\r
+  group = memp_malloc(MEMP_IGMP_GROUP);\r
+  if (group != NULL) {\r
+    group->interface          = ifp;\r
+    ip_addr_set(&(group->group_address), addr);\r
+    group->timer              = 0; /* Not running */\r
+    group->group_state        = IGMP_GROUP_NON_MEMBER;\r
+    group->last_reporter_flag = 0;\r
+    group->use                = 0;\r
+    group->next               = igmp_group_list;\r
+    \r
+    igmp_group_list = group;\r
+  }\r
+\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));\r
+  ip_addr_debug_print(IGMP_DEBUG, addr);\r
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp));\r
+\r
+  return group;\r
+}\r
+\r
+/**\r
+ * Remove a group in the global igmp_group_list\r
+ *\r
+ * @param group the group to remove from the global igmp_group_list\r
+ * @return ERR_OK if group was removed from the list, an err_t otherwise\r
+ */\r
+err_t\r
+igmp_remove_group(struct igmp_group *group)\r
+{\r
+  err_t err = ERR_OK;\r
+\r
+  /* Is it the first group? */\r
+  if (igmp_group_list == group) {\r
+    igmp_group_list = group->next;\r
+  } else {\r
+    /* look for group further down the list */\r
+    struct igmp_group *tmpGroup;\r
+    for (tmpGroup = igmp_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {\r
+      if (tmpGroup->next == group) {\r
+        tmpGroup->next = group->next;\r
+        break;\r
+      }\r
+    }\r
+    /* Group not found in the global igmp_group_list */\r
+    if (tmpGroup == NULL)\r
+      err = ERR_ARG;\r
+  }\r
+  /* free group */\r
+  memp_free(MEMP_IGMP_GROUP, group);\r
+\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Called from ip_input() if a new IGMP packet is received.\r
+ *\r
+ * @param p received igmp packet, p->payload pointing to the ip header\r
+ * @param inp network interface on which the packet was received\r
+ * @param dest destination ip address of the igmp packet\r
+ */\r
+void\r
+igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)\r
+{\r
+  struct ip_hdr *    iphdr;\r
+  struct igmp_msg*   igmp;\r
+  struct igmp_group* group;\r
+  struct igmp_group* groupref;\r
+\r
+  /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */    \r
+  iphdr = p->payload;\r
+  if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {\r
+    pbuf_free(p);\r
+    IGMP_STATS_INC(igmp.lenerr);\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));\r
+    return;\r
+  }\r
+\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));\r
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));\r
+  LWIP_DEBUGF(IGMP_DEBUG, (" to address "));\r
+  ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));\r
+  LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp));\r
+\r
+  /* Now calculate and check the checksum */\r
+  igmp = (struct igmp_msg *)p->payload;\r
+  if (inet_chksum(igmp, p->len)) {\r
+    pbuf_free(p);\r
+    IGMP_STATS_INC(igmp.chkerr);\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: checksum error\n"));\r
+    return;\r
+  }\r
+\r
+  /* Packet is ok so find an existing group */\r
+  group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */\r
+  \r
+  /* If group can be found or create... */\r
+  if (!group) {\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n"));\r
+    return;\r
+  }\r
+\r
+  /* NOW ACT ON THE INCOMING MESSAGE TYPE... */\r
+  switch (igmp->igmp_msgtype) {\r
+   case IGMP_MEMB_QUERY: {\r
+     /* IGMP_MEMB_QUERY to the "all systems" address ? */\r
+     if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) {\r
+       /* THIS IS THE GENERAL QUERY */\r
+       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)));\r
+\r
+       if (igmp->igmp_maxresp == 0) {\r
+         IGMP_STATS_INC(igmp.v1_rxed);\r
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n"));\r
+         igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR;\r
+       }\r
+\r
+       IGMP_STATS_INC(igmp.group_query_rxed);\r
+       groupref = igmp_group_list;\r
+       while (groupref) {\r
+         /* Do not send messages on the all systems group address! */\r
+         if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) {\r
+           igmp_delaying_member( groupref, igmp->igmp_maxresp);\r
+         }\r
+         groupref = groupref->next;\r
+       }\r
+     } else {\r
+       /* IGMP_MEMB_QUERY to a specific group ? */\r
+       if (group->group_address.addr != 0) {\r
+         LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group "));\r
+         ip_addr_debug_print(IGMP_DEBUG, &group->group_address);\r
+         if (ip_addr_cmp (dest, &allsystems)) {\r
+           LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));\r
+           /* we first need to re-lookfor the group since we used dest last time */\r
+           group = igmp_lookfor_group(inp, &igmp->igmp_group_address);\r
+         } else {\r
+           LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp)));\r
+         }\r
+\r
+         if (group != NULL) {\r
+           IGMP_STATS_INC(igmp.unicast_query);\r
+           igmp_delaying_member( group, igmp->igmp_maxresp);\r
+         }\r
+       }\r
+     }\r
+     break;\r
+   }\r
+   case IGMP_V2_MEMB_REPORT: {\r
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n"));\r
+\r
+     IGMP_STATS_INC(igmp.report_rxed);\r
+     if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {\r
+       /* This is on a specific group we have already looked up */\r
+       group->timer = 0; /* stopped */\r
+       group->group_state = IGMP_GROUP_IDLE_MEMBER;\r
+       group->last_reporter_flag = 0;\r
+     }\r
+     break;\r
+   }\r
+   default: {\r
+     LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));\r
+     break;\r
+   }\r
+  }\r
+\r
+  pbuf_free(p);\r
+  return;\r
+}\r
+\r
+/**\r
+ * Join a group on one network interface.\r
+ *\r
+ * @param ifaddr ip address of the network interface which should join a new group\r
+ * @param groupaddr the ip address of the group which to join\r
+ * @return ERR_OK if group was joined on the netif(s), an err_t otherwise\r
+ */\r
+err_t\r
+igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)\r
+{\r
+  err_t              err = ERR_VAL; /* no matching interface */\r
+  struct igmp_group *group;\r
+  struct netif      *netif;\r
+\r
+  /* make sure it is multicast address */\r
+  LWIP_ERROR("igmp_joingroup: attempt to join non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);\r
+  LWIP_ERROR("igmp_joingroup: attempt to join allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);\r
+\r
+  /* loop through netif's */\r
+  netif = netif_list;\r
+  while (netif != NULL) {\r
+    /* Should we join this interface ? */\r
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {\r
+      /* find group or create a new one if not found */\r
+      group = igmp_lookup_group(netif, groupaddr);\r
+\r
+      if (group != NULL) {\r
+        /* This should create a new group, check the state to make sure */\r
+        if (group->group_state != IGMP_GROUP_NON_MEMBER) {\r
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to group not in state IGMP_GROUP_NON_MEMBER\n"));\r
+        } else {\r
+          /* OK - it was new group */\r
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: join to new group: "));\r
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);\r
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));\r
+\r
+          /* If first use of the group, allow the group at the MAC level */\r
+          if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {\r
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));\r
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);\r
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));\r
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);\r
+          }\r
+\r
+          IGMP_STATS_INC(igmp.join_sent);\r
+          igmp_send(group, IGMP_V2_MEMB_REPORT);\r
+\r
+          igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);\r
+\r
+          /* Need to work out where this timer comes from */\r
+          group->group_state = IGMP_GROUP_DELAYING_MEMBER;\r
+        }\r
+        /* Increment group use */\r
+        group->use++;\r
+        /* Join on this interface */\r
+        err = ERR_OK;\r
+      } else {\r
+        /* Return an error even if some network interfaces are joined */\r
+        /** @todo undo any other netif already joined */\r
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: Not enought memory to join to group\n"));\r
+        return ERR_MEM;\r
+      }\r
+    }\r
+    /* proceed to next network interface */\r
+    netif = netif->next;\r
+  }\r
+\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Leave a group on one network interface.\r
+ *\r
+ * @param ifaddr ip address of the network interface which should leave a group\r
+ * @param groupaddr the ip address of the group which to leave\r
+ * @return ERR_OK if group was left on the netif(s), an err_t otherwise\r
+ */\r
+err_t\r
+igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)\r
+{\r
+  err_t              err = ERR_VAL; /* no matching interface */\r
+  struct igmp_group *group;\r
+  struct netif      *netif;\r
+\r
+  /* make sure it is multicast address */\r
+  LWIP_ERROR("igmp_leavegroup: attempt to leave non-multicast address", ip_addr_ismulticast(groupaddr), return ERR_VAL;);\r
+  LWIP_ERROR("igmp_leavegroup: attempt to leave allsystems address", (!ip_addr_cmp(groupaddr, &allsystems)), return ERR_VAL;);\r
+\r
+  /* loop through netif's */\r
+  netif = netif_list;\r
+  while (netif != NULL) {\r
+    /* Should we leave this interface ? */\r
+    if ((netif->flags & NETIF_FLAG_IGMP) && ((ip_addr_isany(ifaddr) || ip_addr_cmp(&(netif->ip_addr), ifaddr)))) {\r
+      /* find group */\r
+      group = igmp_lookfor_group(netif, groupaddr);\r
+\r
+      if (group != NULL) {\r
+        /* Only send a leave if the flag is set according to the state diagram */\r
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: Leaving group: "));\r
+        ip_addr_debug_print(IGMP_DEBUG, groupaddr);\r
+        LWIP_DEBUGF(IGMP_DEBUG, ("\n"));\r
+\r
+        /* If there is no other use of the group */\r
+        if (group->use <= 1) {\r
+          /* If we are the last reporter for this group */\r
+          if (group->last_reporter_flag) {\r
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n"));\r
+            IGMP_STATS_INC(igmp.leave_sent);\r
+            igmp_send(group, IGMP_LEAVE_GROUP);\r
+          }\r
+          \r
+          /* Disable the group at the MAC level */\r
+          if (netif->igmp_mac_filter != NULL) {\r
+            LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));\r
+            ip_addr_debug_print(IGMP_DEBUG, groupaddr);\r
+            LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));\r
+            netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);\r
+          }\r
+          \r
+          LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: remove group: "));\r
+          ip_addr_debug_print(IGMP_DEBUG, groupaddr);\r
+          LWIP_DEBUGF(IGMP_DEBUG, ("\n"));          \r
+          \r
+          /* Free the group */\r
+          igmp_remove_group(group);\r
+        } else {\r
+          /* Decrement group use */\r
+          group->use--;\r
+        }\r
+        /* Leave on this interface */\r
+        err = ERR_OK;\r
+      } else {\r
+        /* It's not a fatal error on "leavegroup" */\r
+        LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: not member of group\n"));\r
+      }\r
+    }\r
+    /* proceed to next network interface */\r
+    netif = netif->next;\r
+  }\r
+\r
+  return err;\r
+}\r
+\r
+/**\r
+ * The igmp timer function (both for NO_SYS=1 and =0)\r
+ * Should be called every IGMP_TMR_INTERVAL milliseconds (100 ms is default).\r
+ */\r
+void\r
+igmp_tmr(void)\r
+{\r
+  struct igmp_group *group = igmp_group_list;\r
+\r
+  while (group != NULL) {\r
+    if (group->timer != 0) {\r
+      group->timer -= 1;\r
+      if (group->timer == 0) {\r
+        igmp_timeout(group);\r
+      }\r
+    }\r
+    group = group->next;\r
+  }\r
+}\r
+\r
+/**\r
+ * Called if a timeout for one group is reached.\r
+ * Sends a report for this group.\r
+ *\r
+ * @param group an igmp_group for which a timeout is reached\r
+ */\r
+void\r
+igmp_timeout(struct igmp_group *group)\r
+{\r
+  /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */\r
+  if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) {\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address "));\r
+    ip_addr_debug_print(IGMP_DEBUG, &(group->group_address));\r
+    LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) group->interface));\r
+\r
+    igmp_send(group, IGMP_V2_MEMB_REPORT);\r
+  }\r
+}\r
+\r
+/**\r
+ * Start a timer for an igmp group\r
+ *\r
+ * @param group the igmp_group for which to start a timer\r
+ * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with\r
+ *        every call to igmp_tmr())\r
+ */\r
+void\r
+igmp_start_timer(struct igmp_group *group, u8_t max_time)\r
+{\r
+  /**\r
+   * @todo Important !! this should be random 0 -> max_time. Find out how to do this\r
+   */\r
+  group->timer = max_time;\r
+}\r
+\r
+/**\r
+ * Stop a timer for an igmp_group\r
+ *\r
+ * @param group the igmp_group for which to stop the timer\r
+ */\r
+void\r
+igmp_stop_timer(struct igmp_group *group)\r
+{\r
+  group->timer = 0;\r
+}\r
+\r
+/**\r
+ * Delaying membership report for a group if necessary\r
+ *\r
+ * @param group the igmp_group for which "delaying" membership report\r
+ * @param maxresp query delay\r
+ */\r
+void\r
+igmp_delaying_member( struct igmp_group *group, u8_t maxresp)\r
+{\r
+  if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) {\r
+    igmp_start_timer(group, (maxresp)/2);\r
+    group->group_state = IGMP_GROUP_DELAYING_MEMBER;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ * Sends an IP packet on a network interface. This function constructs the IP header\r
+ * and calculates the IP header checksum. If the source IP address is NULL,\r
+ * the IP address of the outgoing network interface is filled in as source address.\r
+ *\r
+ * @param p the packet to send (p->payload points to the data, e.g. next\r
+            protocol header; if dest == IP_HDRINCL, p already includes an IP\r
+            header and p->payload points to that IP header)\r
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\r
+ *         IP  address of the netif used to send is used as source address)\r
+ * @param dest the destination IP address to send the packet to\r
+ * @param ttl the TTL value to be set in the IP header\r
+ * @param proto the PROTOCOL to be set in the IP header\r
+ * @param netif the netif on which to send this packet\r
+ * @return ERR_OK if the packet was sent OK\r
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers\r
+ *         returns errors returned by netif->output\r
+ */\r
+err_t\r
+igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+                  u8_t ttl, u8_t proto, struct netif *netif)\r
+{\r
+  static u16_t    ip_id = 0;\r
+  struct ip_hdr * iphdr = NULL;\r
+  u16_t *         ra    = NULL;\r
+\r
+  /* First write in the "router alert" */\r
+  if (pbuf_header(p, ROUTER_ALERTLEN)) {\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));\r
+    return ERR_BUF;\r
+  }\r
+\r
+  /* This is the "router alert" option */\r
+  ra    = p->payload;\r
+  ra[0] = htons (ROUTER_ALERT);\r
+  ra[1] = 0x0000; /* Router shall examine packet */\r
+\r
+  /* now the normal ip header */\r
+  if (pbuf_header(p, IP_HLEN)) {\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));\r
+    return ERR_BUF;\r
+  }\r
+\r
+  iphdr = p->payload;\r
+\r
+  /* Should the IP header be generated or is it already included in p? */\r
+  if (dest != IP_HDRINCL) {\r
+    /** @todo should be shared with ip.c - ip_output_if */\r
+    IPH_TTL_SET(iphdr, ttl);\r
+    IPH_PROTO_SET(iphdr, proto);\r
+\r
+    ip_addr_set(&(iphdr->dest), dest);\r
+\r
+    IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);\r
+    IPH_LEN_SET(iphdr, htons(p->tot_len));\r
+    IPH_OFFSET_SET(iphdr, 0);\r
+    IPH_ID_SET(iphdr, htons(ip_id));\r
+    ++ip_id;\r
+\r
+    if (ip_addr_isany(src)) {\r
+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));\r
+    } else {\r
+      ip_addr_set(&(iphdr->src), src);\r
+    }\r
+\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+#if CHECKSUM_GEN_IP\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));\r
+#endif\r
+  } else {\r
+    dest = &(iphdr->dest);\r
+  }\r
+\r
+#if IP_DEBUG\r
+  ip_debug_print(p);\r
+#endif\r
+\r
+  LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));\r
+\r
+  return netif->output(netif, p, dest);\r
+}\r
+\r
+/**\r
+ * Send an igmp packet to a specific group.\r
+ *\r
+ * @param group the group to which to send the packet\r
+ * @param type the type of igmp packet to send\r
+ */\r
+void\r
+igmp_send(struct igmp_group *group, u8_t type)\r
+{\r
+  struct pbuf*     p    = NULL;\r
+  struct igmp_msg* igmp = NULL;\r
+  struct ip_addr   src  = {0};\r
+  struct ip_addr*  dest = NULL;\r
+\r
+  /* IP header + "router alert" option + IGMP header */\r
+  p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM);\r
+  \r
+  if (p) {\r
+    igmp = p->payload;\r
+    LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg",\r
+               (p->len >= sizeof(struct igmp_msg)));\r
+    ip_addr_set(&src, &((group->interface)->ip_addr));\r
+     \r
+    if (type == IGMP_V2_MEMB_REPORT) {\r
+      dest = &(group->group_address);\r
+      IGMP_STATS_INC(igmp.report_sent);\r
+      ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));\r
+      group->last_reporter_flag = 1; /* Remember we were the last to report */\r
+    } else {\r
+      if (type == IGMP_LEAVE_GROUP) {\r
+        dest = &allrouters;\r
+        ip_addr_set(&(igmp->igmp_group_address), &(group->group_address));\r
+      }\r
+    }\r
+\r
+    if ((type == IGMP_V2_MEMB_REPORT) || (type == IGMP_LEAVE_GROUP)) {\r
+      igmp->igmp_msgtype  = type;\r
+      igmp->igmp_maxresp  = 0;\r
+      igmp->igmp_checksum = 0;\r
+      igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN);\r
+\r
+      igmp_ip_output_if( p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface);\r
+    }\r
+\r
+    pbuf_free (p);\r
+  } else {\r
+    LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));\r
+  }\r
+}\r
+\r
+#endif /* LWIP_IGMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet.c
new file mode 100644 (file)
index 0000000..cded5ef
--- /dev/null
@@ -0,0 +1,278 @@
+/**\r
+ * @file\r
+ * Functions common to all TCP/IPv4 modules, such as the byte order functions.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/inet.h"\r
+\r
+/* Here for now until needed in other places in lwIP */\r
+#ifndef isprint\r
+#define in_range(c, lo, up)  ((u8_t)c >= lo && (u8_t)c <= up)\r
+#define isprint(c)           in_range(c, 0x20, 0x7f)\r
+#define isdigit(c)           in_range(c, '0', '9')\r
+#define isxdigit(c)          (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F'))\r
+#define islower(c)           in_range(c, 'a', 'z')\r
+#define isspace(c)           (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v')\r
+#endif\r
+\r
+/**\r
+ * Ascii internet address interpretation routine.\r
+ * The value returned is in network order.\r
+ *\r
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")\r
+ * @return ip address in network order\r
+ */\r
+u32_t\r
+inet_addr(const char *cp)\r
+{\r
+  struct in_addr val;\r
+\r
+  if (inet_aton(cp, &val)) {\r
+    return (val.s_addr);\r
+  }\r
+  return (INADDR_NONE);\r
+}\r
+\r
+/**\r
+ * Check whether "cp" is a valid ascii representation\r
+ * of an Internet address and convert to a binary address.\r
+ * Returns 1 if the address is valid, 0 if not.\r
+ * This replaces inet_addr, the return value from which\r
+ * cannot distinguish between failure and a local broadcast address.\r
+ *\r
+ * @param cp IP address in ascii represenation (e.g. "127.0.0.1")\r
+ * @param addr pointer to which to save the ip address in network order\r
+ * @return 1 if cp could be converted to addr, 0 on failure\r
+ */\r
+int\r
+inet_aton(const char *cp, struct in_addr *addr)\r
+{\r
+  u32_t val;\r
+  int base, n, c;\r
+  u32_t parts[4];\r
+  u32_t *pp = parts;\r
+\r
+  c = *cp;\r
+  for (;;) {\r
+    /*\r
+     * Collect number up to ``.''.\r
+     * Values are specified as for C:\r
+     * 0x=hex, 0=octal, 1-9=decimal.\r
+     */\r
+    if (!isdigit(c))\r
+      return (0);\r
+    val = 0;\r
+    base = 10;\r
+    if (c == '0') {\r
+      c = *++cp;\r
+      if (c == 'x' || c == 'X') {\r
+        base = 16;\r
+        c = *++cp;\r
+      } else\r
+        base = 8;\r
+    }\r
+    for (;;) {\r
+      if (isdigit(c)) {\r
+        val = (val * base) + (int)(c - '0');\r
+        c = *++cp;\r
+      } else if (base == 16 && isxdigit(c)) {\r
+        val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A'));\r
+        c = *++cp;\r
+      } else\r
+        break;\r
+    }\r
+    if (c == '.') {\r
+      /*\r
+       * Internet format:\r
+       *  a.b.c.d\r
+       *  a.b.c   (with c treated as 16 bits)\r
+       *  a.b (with b treated as 24 bits)\r
+       */\r
+      if (pp >= parts + 3)\r
+        return (0);\r
+      *pp++ = val;\r
+      c = *++cp;\r
+    } else\r
+      break;\r
+  }\r
+  /*\r
+   * Check for trailing characters.\r
+   */\r
+  if (c != '\0' && (!isprint(c) || !isspace(c)))\r
+    return (0);\r
+  /*\r
+   * Concoct the address according to\r
+   * the number of parts specified.\r
+   */\r
+  n = pp - parts + 1;\r
+  switch (n) {\r
+\r
+  case 0:\r
+    return (0);       /* initial nondigit */\r
+\r
+  case 1:             /* a -- 32 bits */\r
+    break;\r
+\r
+  case 2:             /* a.b -- 8.24 bits */\r
+    if (val > 0xffffffUL)\r
+      return (0);\r
+    val |= parts[0] << 24;\r
+    break;\r
+\r
+  case 3:             /* a.b.c -- 8.8.16 bits */\r
+    if (val > 0xffff)\r
+      return (0);\r
+    val |= (parts[0] << 24) | (parts[1] << 16);\r
+    break;\r
+\r
+  case 4:             /* a.b.c.d -- 8.8.8.8 bits */\r
+    if (val > 0xff)\r
+      return (0);\r
+    val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8);\r
+    break;\r
+  }\r
+  if (addr)\r
+    addr->s_addr = htonl(val);\r
+  return (1);\r
+}\r
+\r
+/**\r
+ * Convert numeric IP address into decimal dotted ASCII representation.\r
+ * returns ptr to static buffer; not reentrant!\r
+ *\r
+ * @param addr ip address in network order to convert\r
+ * @return pointer to a global static (!) buffer that holds the ASCII\r
+ *         represenation of addr\r
+ */\r
+char *\r
+inet_ntoa(struct in_addr addr)\r
+{\r
+  static char str[16];\r
+  u32_t s_addr = addr.s_addr;\r
+  char inv[3];\r
+  char *rp;\r
+  u8_t *ap;\r
+  u8_t rem;\r
+  u8_t n;\r
+  u8_t i;\r
+\r
+  rp = str;\r
+  ap = (u8_t *)&s_addr;\r
+  for(n = 0; n < 4; n++) {\r
+    i = 0;\r
+    do {\r
+      rem = *ap % (u8_t)10;\r
+      *ap /= (u8_t)10;\r
+      inv[i++] = '0' + rem;\r
+    } while(*ap);\r
+    while(i--)\r
+      *rp++ = inv[i];\r
+    *rp++ = '.';\r
+    ap++;\r
+  }\r
+  *--rp = 0;\r
+  return str;\r
+}\r
+\r
+/**\r
+ * These are reference implementations of the byte swapping functions.\r
+ * Again with the aim of being simple, correct and fully portable.\r
+ * Byte swapping is the second thing you would want to optimize. You will\r
+ * need to port it to your architecture and in your cc.h:\r
+ *\r
+ * #define LWIP_PLATFORM_BYTESWAP 1\r
+ * #define LWIP_PLATFORM_HTONS(x) <your_htons>\r
+ * #define LWIP_PLATFORM_HTONL(x) <your_htonl>\r
+ *\r
+ * Note ntohs() and ntohl() are merely references to the htonx counterparts.\r
+ */\r
+\r
+#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN)\r
+\r
+/**\r
+ * Convert an u16_t from host- to network byte order.\r
+ *\r
+ * @param n u16_t in host byte order\r
+ * @return n in network byte order\r
+ */\r
+u16_t\r
+htons(u16_t n)\r
+{\r
+  return ((n & 0xff) << 8) | ((n & 0xff00) >> 8);\r
+}\r
+\r
+/**\r
+ * Convert an u16_t from network- to host byte order.\r
+ *\r
+ * @param n u16_t in network byte order\r
+ * @return n in host byte order\r
+ */\r
+u16_t\r
+ntohs(u16_t n)\r
+{\r
+  return htons(n);\r
+}\r
+\r
+/**\r
+ * Convert an u32_t from host- to network byte order.\r
+ *\r
+ * @param n u32_t in host byte order\r
+ * @return n in network byte order\r
+ */\r
+u32_t\r
+htonl(u32_t n)\r
+{\r
+  return ((n & 0xff) << 24) |\r
+    ((n & 0xff00) << 8) |\r
+    ((n & 0xff0000UL) >> 8) |\r
+    ((n & 0xff000000UL) >> 24);\r
+}\r
+\r
+/**\r
+ * Convert an u32_t from network- to host byte order.\r
+ *\r
+ * @param n u32_t in network byte order\r
+ * @return n in host byte order\r
+ */\r
+u32_t\r
+ntohl(u32_t n)\r
+{\r
+  return htonl(n);\r
+}\r
+\r
+#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/inet_chksum.c
new file mode 100644 (file)
index 0000000..095bef6
--- /dev/null
@@ -0,0 +1,423 @@
+/**\r
+ * @file\r
+ * Incluse internet checksum functions.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/inet.h"\r
+\r
+#include <string.h>\r
+\r
+/* These are some reference implementations of the checksum algorithm, with the\r
+ * aim of being simple, correct and fully portable. Checksumming is the\r
+ * first thing you would want to optimize for your platform. If you create\r
+ * your own version, link it in and in your cc.h put:\r
+ *\r
+ * #define LWIP_CHKSUM <your_checksum_routine>\r
+ *\r
+ * Or you can select from the implementations below by defining\r
+ * LWIP_CHKSUM_ALGORITHM to 1, 2 or 3.\r
+ */\r
+\r
+#ifndef LWIP_CHKSUM\r
+# define LWIP_CHKSUM lwip_standard_chksum\r
+# ifndef LWIP_CHKSUM_ALGORITHM\r
+#  define LWIP_CHKSUM_ALGORITHM 1\r
+# endif\r
+#endif\r
+/* If none set: */\r
+#ifndef LWIP_CHKSUM_ALGORITHM\r
+# define LWIP_CHKSUM_ALGORITHM 0\r
+#endif\r
+\r
+#if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */\r
+/**\r
+ * lwip checksum\r
+ *\r
+ * @param dataptr points to start of data to be summed at any boundary\r
+ * @param len length of data to be summed\r
+ * @return host order (!) lwip checksum (non-inverted Internet sum)\r
+ *\r
+ * @note accumulator size limits summable length to 64k\r
+ * @note host endianess is irrelevant (p3 RFC1071)\r
+ */\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc;\r
+  u16_t src;\r
+  u8_t *octetptr;\r
+\r
+  acc = 0;\r
+  /* dataptr may be at odd or even addresses */\r
+  octetptr = (u8_t*)dataptr;\r
+  while (len > 1)\r
+  {\r
+    /* declare first octet as most significant\r
+       thus assume network order, ignoring host order */\r
+    src = (*octetptr) << 8;\r
+    octetptr++;\r
+    /* declare second octet as least significant */\r
+    src |= (*octetptr);\r
+    octetptr++;\r
+    acc += src;\r
+    len -= 2;\r
+  }\r
+  if (len > 0)\r
+  {\r
+    /* accumulate remaining octet */\r
+    src = (*octetptr) << 8;\r
+    acc += src;\r
+  }\r
+  /* add deferred carry bits */\r
+  acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
+  if ((acc & 0xffff0000) != 0) {\r
+    acc = (acc >> 16) + (acc & 0x0000ffffUL);\r
+  }\r
+  /* This maybe a little confusing: reorder sum using htons()\r
+     instead of ntohs() since it has a little less call overhead.\r
+     The caller must invert bits for Internet sum ! */\r
+  return htons((u16_t)acc);\r
+}\r
+#endif\r
+\r
+#if (LWIP_CHKSUM_ALGORITHM == 2) /* Alternative version #2 */\r
+/*\r
+ * Curt McDowell\r
+ * Broadcom Corp.\r
+ * csm@broadcom.com\r
+ *\r
+ * IP checksum two bytes at a time with support for\r
+ * unaligned buffer.\r
+ * Works for len up to and including 0x20000.\r
+ * by Curt McDowell, Broadcom Corp. 12/08/2005\r
+ *\r
+ * @param dataptr points to start of data to be summed at any boundary\r
+ * @param len length of data to be summed\r
+ * @return host order (!) lwip checksum (non-inverted Internet sum)\r
+ */\r
+\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, int len)\r
+{\r
+  u8_t *pb = dataptr;\r
+  u16_t *ps, t = 0;\r
+  u32_t sum = 0;\r
+  int odd = ((u32_t)pb & 1);\r
+\r
+  /* Get aligned to u16_t */\r
+  if (odd && len > 0) {\r
+    ((u8_t *)&t)[1] = *pb++;\r
+    len--;\r
+  }\r
+\r
+  /* Add the bulk of the data */\r
+  ps = (u16_t *)pb;\r
+  while (len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  /* Consume left-over byte, if any */\r
+  if (len > 0)\r
+    ((u8_t *)&t)[0] = *(u8_t *)ps;;\r
+\r
+  /* Add end bytes */\r
+  sum += t;\r
+\r
+  /*  Fold 32-bit sum to 16 bits */\r
+  while ((sum >> 16) != 0)\r
+    sum = (sum & 0xffff) + (sum >> 16);\r
+\r
+  /* Swap if alignment was odd */\r
+  if (odd)\r
+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
+\r
+  return sum;\r
+}\r
+#endif\r
+\r
+#if (LWIP_CHKSUM_ALGORITHM == 3) /* Alternative version #3 */\r
+/**\r
+ * An optimized checksum routine. Basically, it uses loop-unrolling on\r
+ * the checksum loop, treating the head and tail bytes specially, whereas\r
+ * the inner loop acts on 8 bytes at a time.\r
+ *\r
+ * @arg start of buffer to be checksummed. May be an odd byte address.\r
+ * @len number of bytes in the buffer to be checksummed.\r
+ * @return host order (!) lwip checksum (non-inverted Internet sum)\r
+ *\r
+ * by Curt McDowell, Broadcom Corp. December 8th, 2005\r
+ */\r
+\r
+static u16_t\r
+lwip_standard_chksum(void *dataptr, int len)\r
+{\r
+  u8_t *pb = dataptr;\r
+  u16_t *ps, t = 0;\r
+  u32_t *pl;\r
+  u32_t sum = 0, tmp;\r
+  /* starts at odd byte address? */\r
+  int odd = ((u32_t)pb & 1);\r
+\r
+  if (odd && len > 0) {\r
+    ((u8_t *)&t)[1] = *pb++;\r
+    len--;\r
+  }\r
+\r
+  ps = (u16_t *)pb;\r
+\r
+  if (((u32_t)ps & 3) && len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  pl = (u32_t *)ps;\r
+\r
+  while (len > 7)  {\r
+    tmp = sum + *pl++;          /* ping */\r
+    if (tmp < sum)\r
+      tmp++;                    /* add back carry */\r
+\r
+    sum = tmp + *pl++;          /* pong */\r
+    if (sum < tmp)\r
+      sum++;                    /* add back carry */\r
+\r
+    len -= 8;\r
+  }\r
+\r
+  /* make room in upper bits */\r
+  sum = (sum >> 16) + (sum & 0xffff);\r
+\r
+  ps = (u16_t *)pl;\r
+\r
+  /* 16-bit aligned word remaining? */\r
+  while (len > 1) {\r
+    sum += *ps++;\r
+    len -= 2;\r
+  }\r
+\r
+  /* dangling tail byte remaining? */\r
+  if (len > 0)                  /* include odd byte */\r
+    ((u8_t *)&t)[0] = *(u8_t *)ps;\r
+\r
+  sum += t;                     /* add end bytes */\r
+\r
+  while ((sum >> 16) != 0)      /* combine halves */\r
+    sum = (sum >> 16) + (sum & 0xffff);\r
+\r
+  if (odd)\r
+    sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);\r
+\r
+  return sum;\r
+}\r
+#endif\r
+\r
+/* inet_chksum_pseudo:\r
+ *\r
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
+ * IP addresses are expected to be in network byte order.\r
+ *\r
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)\r
+ * @param src source ip address (used for checksum of pseudo header)\r
+ * @param dst destination ip address (used for checksum of pseudo header)\r
+ * @param proto ip protocol (used for checksum of pseudo header)\r
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)\r
+ * @return checksum (as u16_t) to be saved directly in the protocol header\r
+ */\r
+u16_t\r
+inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  /* iterate through all pbuf in chain */\r
+  for(q = p; q != NULL; q = q->next) {\r
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",\r
+      (void *)q, (void *)q->next));\r
+    acc += LWIP_CHKSUM(q->payload, q->len);\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+    while ((acc >> 16) != 0) {\r
+      acc = (acc & 0xffffUL) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+    }\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+  }\r
+  acc += (src->addr & 0xffffUL);\r
+  acc += ((src->addr >> 16) & 0xffffUL);\r
+  acc += (dest->addr & 0xffffUL);\r
+  acc += ((dest->addr >> 16) & 0xffffUL);\r
+  acc += (u32_t)htons((u16_t)proto);\r
+  acc += (u32_t)htons(proto_len);\r
+\r
+  while ((acc >> 16) != 0) {\r
+    acc = (acc & 0xffffUL) + (acc >> 16);\r
+  }\r
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));\r
+  return (u16_t)~(acc & 0xffffUL);\r
+}\r
+\r
+/* inet_chksum_pseudo:\r
+ *\r
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
+ * IP addresses are expected to be in network byte order.\r
+ *\r
+ * @param p chain of pbufs over that a checksum should be calculated (ip data part)\r
+ * @param src source ip address (used for checksum of pseudo header)\r
+ * @param dst destination ip address (used for checksum of pseudo header)\r
+ * @param proto ip protocol (used for checksum of pseudo header)\r
+ * @param proto_len length of the ip data part (used for checksum of pseudo header)\r
+ * @return checksum (as u16_t) to be saved directly in the protocol header\r
+ */\r
+u16_t\r
+inet_chksum_pseudo_partial(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len, u16_t chksum_len)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+  u16_t chklen;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  /* iterate through all pbuf in chain */\r
+  for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {\r
+    LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",\r
+      (void *)q, (void *)q->next));\r
+    chklen = q->len;\r
+    if (chklen > chksum_len) {\r
+      chklen = chksum_len;\r
+    }\r
+    acc += LWIP_CHKSUM(q->payload, chklen);\r
+    chksum_len -= chklen;\r
+    LWIP_ASSERT("delete me", chksum_len < 0x7fff);\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+    while ((acc >> 16) != 0) {\r
+      acc = (acc & 0xffffUL) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+    }\r
+    /*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);\r
+  }\r
+  acc += (src->addr & 0xffffUL);\r
+  acc += ((src->addr >> 16) & 0xffffUL);\r
+  acc += (dest->addr & 0xffffUL);\r
+  acc += ((dest->addr >> 16) & 0xffffUL);\r
+  acc += (u32_t)htons((u16_t)proto);\r
+  acc += (u32_t)htons(proto_len);\r
+\r
+  while ((acc >> 16) != 0) {\r
+    acc = (acc & 0xffffUL) + (acc >> 16);\r
+  }\r
+  LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));\r
+  return (u16_t)~(acc & 0xffffUL);\r
+}\r
+\r
+/* inet_chksum:\r
+ *\r
+ * Calculates the Internet checksum over a portion of memory. Used primarily for IP\r
+ * and ICMP.\r
+ *\r
+ * @param dataptr start of the buffer to calculate the checksum (no alignment needed)\r
+ * @param len length of the buffer to calculate the checksum\r
+ * @return checksum (as u16_t) to be saved directly in the protocol header\r
+ */\r
+\r
+u16_t\r
+inet_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc;\r
+\r
+  acc = LWIP_CHKSUM(dataptr, len);\r
+  while ((acc >> 16) != 0) {\r
+    acc = (acc & 0xffff) + (acc >> 16);\r
+  }\r
+  return (u16_t)~(acc & 0xffff);\r
+}\r
+\r
+/**\r
+ * Calculate a checksum over a chain of pbufs (without pseudo-header, much like\r
+ * inet_chksum only pbufs are used).\r
+ *\r
+ * @param p pbuf chain over that the checksum should be calculated\r
+ * @return checksum (as u16_t) to be saved directly in the protocol header\r
+ */\r
+u16_t\r
+inet_chksum_pbuf(struct pbuf *p)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {\r
+    acc += LWIP_CHKSUM(q->payload, q->len);\r
+    while ((acc >> 16) != 0) {\r
+      acc = (acc & 0xffffUL) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);\r
+    }\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);\r
+  }\r
+  return (u16_t)~(acc & 0xffffUL);\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip.c
new file mode 100644 (file)
index 0000000..11da757
--- /dev/null
@@ -0,0 +1,614 @@
+/**\r
+ * @file\r
+ * This is the IPv4 layer implementation for incoming and outgoing IP traffic.\r
+ *\r
+ * @see ip_frag.c\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/dhcp.h"\r
+#include "lwip/stats.h"\r
+#include "arch/perf.h"\r
+\r
+/**\r
+ * Finds the appropriate network interface for a given IP address. It\r
+ * searches the list of network interfaces linearly. A match is found\r
+ * if the masked IP address of the network interface equals the masked\r
+ * IP address given to the function.\r
+ *\r
+ * @param dest the destination IP address for which to find the route\r
+ * @return the netif on which to send to reach dest\r
+ */\r
+struct netif *\r
+ip_route(struct ip_addr *dest)\r
+{\r
+  struct netif *netif;\r
+\r
+  /* iterate through netifs */\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+    /* network mask matches? */\r
+    if (netif_is_up(netif)) {\r
+      if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\r
+        /* return netif on which to forward IP packet */\r
+        return netif;\r
+      }\r
+    }\r
+  }\r
+  if ((netif_default == NULL) || (!netif_is_up(netif_default))) {\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));\r
+    IP_STATS_INC(ip.rterr);\r
+    snmp_inc_ipoutnoroutes();\r
+    return NULL;\r
+  }\r
+  /* no matching netif found, use default netif */\r
+  return netif_default;\r
+}\r
+\r
+#if IP_FORWARD\r
+/**\r
+ * Forwards an IP packet. It finds an appropriate route for the\r
+ * packet, decrements the TTL value of the packet, adjusts the\r
+ * checksum and outputs the packet on the appropriate interface.\r
+ *\r
+ * @param p the packet to forward (p->payload points to IP header)\r
+ * @param iphdr the IP header of the input packet\r
+ * @param inp the netif on which this packet was received\r
+ * @return the netif on which the packet was sent (NULL if it wasn't sent)\r
+ */\r
+static struct netif *\r
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp)\r
+{\r
+  struct netif *netif;\r
+\r
+  PERF_START;\r
+  /* Find network interface where to forward this IP packet to. */\r
+  netif = ip_route((struct ip_addr *)&(iphdr->dest));\r
+  if (netif == NULL) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n",\r
+                      iphdr->dest.addr));\r
+    snmp_inc_ipoutnoroutes();\r
+    return (struct netif *)NULL;\r
+  }\r
+  /* Do not forward packets onto the same network interface on which\r
+   * they arrived. */\r
+  if (netif == inp) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n"));\r
+    snmp_inc_ipoutnoroutes();\r
+    return (struct netif *)NULL;\r
+  }\r
+\r
+  /* decrement TTL */\r
+  IPH_TTL_SET(iphdr, IPH_TTL(iphdr) - 1);\r
+  /* send ICMP if TTL == 0 */\r
+  if (IPH_TTL(iphdr) == 0) {\r
+    snmp_inc_ipinhdrerrors();\r
+#if LWIP_ICMP\r
+    /* Don't send ICMP messages in response to ICMP messages */\r
+    if (IPH_PROTO(iphdr) != IP_PROTO_ICMP) {\r
+      icmp_time_exceeded(p, ICMP_TE_TTL);\r
+    }\r
+#endif /* LWIP_ICMP */\r
+    return (struct netif *)NULL;\r
+  }\r
+\r
+  /* Incrementally update the IP checksum. */\r
+  if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) {\r
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1);\r
+  } else {\r
+    IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100));\r
+  }\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n",\r
+                    iphdr->dest.addr));\r
+\r
+  IP_STATS_INC(ip.fw);\r
+  IP_STATS_INC(ip.xmit);\r
+  snmp_inc_ipforwdatagrams();\r
+\r
+  PERF_STOP("ip_forward");\r
+  /* transmit pbuf on chosen interface */\r
+  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));\r
+  return netif;\r
+}\r
+#endif /* IP_FORWARD */\r
+\r
+/**\r
+ * This function is called by the network interface device driver when\r
+ * an IP packet is received. The function does the basic checks of the\r
+ * IP header such as packet size being at least larger than the header\r
+ * size etc. If the packet was not destined for us, the packet is\r
+ * forwarded (using ip_forward). The IP checksum is always checked.\r
+ *\r
+ * Finally, the packet is sent to the upper layer protocol input function.\r
+ *\r
+ * @param p the received IP packet (p->payload points to IP header)\r
+ * @param inp the netif on which this packet was received\r
+ * @return ERR_OK if the packet was processed (could return ERR_* if it wasn't\r
+ *         processed, but currently always returns ERR_OK)\r
+ */\r
+err_t\r
+ip_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct ip_hdr *iphdr;\r
+  struct netif *netif;\r
+  u16_t iphdr_hlen;\r
+  u16_t iphdr_len;\r
+#if LWIP_DHCP\r
+  int check_ip_src=1;\r
+#endif /* LWIP_DHCP */\r
+\r
+  IP_STATS_INC(ip.recv);\r
+  snmp_inc_ipinreceives();\r
+\r
+  /* identify the IP header */\r
+  iphdr = p->payload;\r
+  if (IPH_V(iphdr) != 4) {\r
+    LWIP_DEBUGF(IP_DEBUG | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));\r
+    ip_debug_print(p);\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.err);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipinhdrerrors();\r
+    return ERR_OK;\r
+  }\r
+\r
+  /* obtain IP header length in number of 32-bit words */\r
+  iphdr_hlen = IPH_HL(iphdr);\r
+  /* calculate IP header length in bytes */\r
+  iphdr_hlen *= 4;\r
+  /* obtain ip length in bytes */\r
+  iphdr_len = ntohs(IPH_LEN(iphdr));\r
+\r
+  /* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */\r
+  if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {\r
+    if (iphdr_hlen > p->len)\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",\r
+                               iphdr_hlen, p->len));\r
+    if (iphdr_len > p->tot_len)\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "\r
+                               "IP packet dropped.\n",\r
+                               iphdr_len, p->tot_len));\r
+    /* free (drop) packet pbufs */\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.lenerr);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipindiscards();\r
+    return ERR_OK;\r
+  }\r
+\r
+  /* verify checksum */\r
+#if CHECKSUM_CHECK_IP\r
+  if (inet_chksum(iphdr, iphdr_hlen) != 0) {\r
+\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));\r
+    ip_debug_print(p);\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.chkerr);\r
+    IP_STATS_INC(ip.drop);\r
+    snmp_inc_ipinhdrerrors();\r
+    return ERR_OK;\r
+  }\r
+#endif\r
+\r
+  /* Trim pbuf. This should have been done at the netif layer,\r
+   * but we'll do it anyway just to be sure that its done. */\r
+  pbuf_realloc(p, iphdr_len);\r
+\r
+  /* match packet against an interface, i.e. is this packet for us? */\r
+#if LWIP_IGMP\r
+  if (ip_addr_ismulticast(&(iphdr->dest))) {\r
+    if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) {\r
+      netif = inp;\r
+    } else {\r
+      netif = NULL;\r
+    }\r
+  } else\r
+#endif /* LWIP_IGMP */\r
+  {\r
+    /* start trying with inp. if that's not acceptable, start walking the\r
+       list of configured netifs.\r
+       'first' is used as a boolean to mark whether we started walking the list */\r
+    int first = 1;\r
+    netif = inp;\r
+    do {\r
+      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",\r
+          iphdr->dest.addr, netif->ip_addr.addr,\r
+          iphdr->dest.addr & netif->netmask.addr,\r
+          netif->ip_addr.addr & netif->netmask.addr,\r
+          iphdr->dest.addr & ~(netif->netmask.addr)));\r
+\r
+      /* interface is up and configured? */\r
+      if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) {\r
+        /* unicast to this interface address? */\r
+        if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) ||\r
+            /* or broadcast on this interface network address? */\r
+            ip_addr_isbroadcast(&(iphdr->dest), netif)) {\r
+          LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n",\r
+              netif->name[0], netif->name[1]));\r
+          /* break out of for loop */\r
+          break;\r
+        }\r
+      }\r
+      if (first) {\r
+        first = 0;\r
+        netif = netif_list;\r
+      } else {\r
+        netif = netif->next;\r
+      }\r
+      if (netif == inp) {\r
+        netif = netif->next;\r
+      }\r
+    } while(netif != NULL);\r
+  }\r
+\r
+#if LWIP_DHCP\r
+  /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed\r
+   * using link layer addressing (such as Ethernet MAC) so we must not filter on IP.\r
+   * According to RFC 1542 section 3.1.1, referred by RFC 2131).\r
+   */\r
+  if (netif == NULL) {\r
+    /* remote port is DHCP server? */\r
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDP) {\r
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",\r
+        ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));\r
+      if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {\r
+        LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));\r
+        netif = inp;\r
+        check_ip_src = 0;\r
+      }\r
+    }\r
+  }\r
+#endif /* LWIP_DHCP */\r
+\r
+  /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */\r
+#if LWIP_DHCP\r
+  if (check_ip_src)\r
+#endif /* LWIP_DHCP */\r
+  {  if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||\r
+         (ip_addr_ismulticast(&(iphdr->src)))) {\r
+      /* packet source is not valid */\r
+      LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));\r
+      /* free (drop) packet pbufs */\r
+      pbuf_free(p);\r
+      IP_STATS_INC(ip.drop);\r
+      snmp_inc_ipinaddrerrors();\r
+      snmp_inc_ipindiscards();\r
+      return ERR_OK;\r
+    }\r
+  }\r
+\r
+  /* packet not for us? */\r
+  if (netif == NULL) {\r
+    /* packet not for us, route or discard */\r
+    LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));\r
+#if IP_FORWARD\r
+    /* non-broadcast packet? */\r
+    if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) {\r
+      /* try to forward IP packet on (other) interfaces */\r
+      ip_forward(p, iphdr, inp);\r
+    } else\r
+#endif /* IP_FORWARD */\r
+    {\r
+      snmp_inc_ipinaddrerrors();\r
+      snmp_inc_ipindiscards();\r
+    }\r
+    pbuf_free(p);\r
+    return ERR_OK;\r
+  }\r
+  /* packet consists of multiple fragments? */\r
+  if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) {\r
+#if IP_REASSEMBLY /* packet fragment reassembly code present? */\r
+    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",\r
+      ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8));\r
+    /* reassemble the packet*/\r
+    p = ip_reass(p);\r
+    /* packet not fully reassembled yet? */\r
+    if (p == NULL) {\r
+      return ERR_OK;\r
+    }\r
+    iphdr = p->payload;\r
+#else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",\r
+      ntohs(IPH_OFFSET(iphdr))));\r
+    IP_STATS_INC(ip.opterr);\r
+    IP_STATS_INC(ip.drop);\r
+    /* unsupported protocol feature */\r
+    snmp_inc_ipinunknownprotos();\r
+    return ERR_OK;\r
+#endif /* IP_REASSEMBLY */\r
+  }\r
+\r
+#if IP_OPTIONS_ALLOWED == 0 /* no support for IP options in the IP header? */\r
+\r
+#if LWIP_IGMP\r
+  /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */\r
+  if((iphdr_hlen > IP_HLEN &&  (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) {\r
+#else\r
+  if (iphdr_hlen > IP_HLEN) {\r
+#endif /* LWIP_IGMP */\r
+    LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.opterr);\r
+    IP_STATS_INC(ip.drop);\r
+    /* unsupported protocol feature */\r
+    snmp_inc_ipinunknownprotos();\r
+    return ERR_OK;\r
+  }\r
+#endif /* IP_OPTIONS_ALLOWED == 0 */\r
+\r
+  /* send to upper layers */\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: \n"));\r
+  ip_debug_print(p);\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));\r
+\r
+#if LWIP_RAW\r
+  /* raw input did not eat the packet? */\r
+  if (raw_input(p, inp) == 0)\r
+#endif /* LWIP_RAW */\r
+  {\r
+\r
+    switch (IPH_PROTO(iphdr)) {\r
+#if LWIP_UDP\r
+    case IP_PROTO_UDP:\r
+#if LWIP_UDPLITE\r
+    case IP_PROTO_UDPLITE:\r
+#endif /* LWIP_UDPLITE */\r
+      snmp_inc_ipindelivers();\r
+      udp_input(p, inp);\r
+      break;\r
+#endif /* LWIP_UDP */\r
+#if LWIP_TCP\r
+    case IP_PROTO_TCP:\r
+      snmp_inc_ipindelivers();\r
+      tcp_input(p, inp);\r
+      break;\r
+#endif /* LWIP_TCP */\r
+#if LWIP_ICMP\r
+    case IP_PROTO_ICMP:\r
+      snmp_inc_ipindelivers();\r
+      icmp_input(p, inp);\r
+      break;\r
+#endif /* LWIP_ICMP */\r
+#if LWIP_IGMP\r
+    case IP_PROTO_IGMP:\r
+      igmp_input(p,inp,&(iphdr->dest));\r
+      break;\r
+#endif /* LWIP_IGMP */\r
+    default:\r
+#if LWIP_ICMP\r
+      /* send ICMP destination protocol unreachable unless is was a broadcast */\r
+      if (!ip_addr_isbroadcast(&(iphdr->dest), inp) &&\r
+          !ip_addr_ismulticast(&(iphdr->dest))) {\r
+        p->payload = iphdr;\r
+        icmp_dest_unreach(p, ICMP_DUR_PROTO);\r
+      }\r
+#endif /* LWIP_ICMP */\r
+      pbuf_free(p);\r
+\r
+      LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));\r
+\r
+      IP_STATS_INC(ip.proterr);\r
+      IP_STATS_INC(ip.drop);\r
+      snmp_inc_ipinunknownprotos();\r
+    }\r
+  }\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Sends an IP packet on a network interface. This function constructs\r
+ * the IP header and calculates the IP header checksum. If the source\r
+ * IP address is NULL, the IP address of the outgoing network\r
+ * interface is filled in as source address.\r
+ * If the destination IP address is IP_HDRINCL, p is assumed to already\r
+ * include an IP header and p->payload points to it instead of the data.\r
+ *\r
+ * @param p the packet to send (p->payload points to the data, e.g. next\r
+            protocol header; if dest == IP_HDRINCL, p already includes an IP\r
+            header and p->payload points to that IP header)\r
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\r
+ *         IP  address of the netif used to send is used as source address)\r
+ * @param dest the destination IP address to send the packet to\r
+ * @param ttl the TTL value to be set in the IP header\r
+ * @param tos the TOS value to be set in the IP header\r
+ * @param proto the PROTOCOL to be set in the IP header\r
+ * @param netif the netif on which to send this packet\r
+ * @return ERR_OK if the packet was sent OK\r
+ *         ERR_BUF if p doesn't have enough space for IP/LINK headers\r
+ *         returns errors returned by netif->output\r
+ *\r
+ * @note ip_id: RFC791 "some host may be able to simply use\r
+ *  unique identifiers independent of destination"\r
+ */\r
+err_t\r
+ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+             u8_t ttl, u8_t tos,\r
+             u8_t proto, struct netif *netif)\r
+{\r
+  struct ip_hdr *iphdr;\r
+  static u16_t ip_id = 0;\r
+\r
+  snmp_inc_ipoutrequests();\r
+\r
+  /* Should the IP header be generated or is it already included in p? */\r
+  if (dest != IP_HDRINCL) {\r
+    /* generate IP header */\r
+    if (pbuf_header(p, IP_HLEN)) {\r
+      LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));\r
+\r
+      IP_STATS_INC(ip.err);\r
+      snmp_inc_ipoutdiscards();\r
+      return ERR_BUF;\r
+    }\r
+\r
+    iphdr = p->payload;\r
+    LWIP_ASSERT("check that first pbuf can hold struct ip_hdr",\r
+               (p->len >= sizeof(struct ip_hdr)));\r
+\r
+    IPH_TTL_SET(iphdr, ttl);\r
+    IPH_PROTO_SET(iphdr, proto);\r
+\r
+    ip_addr_set(&(iphdr->dest), dest);\r
+\r
+    IPH_VHLTOS_SET(iphdr, 4, IP_HLEN / 4, tos);\r
+    IPH_LEN_SET(iphdr, htons(p->tot_len));\r
+    IPH_OFFSET_SET(iphdr, 0);\r
+    IPH_ID_SET(iphdr, htons(ip_id));\r
+    ++ip_id;\r
+\r
+    if (ip_addr_isany(src)) {\r
+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));\r
+    } else {\r
+      ip_addr_set(&(iphdr->src), src);\r
+    }\r
+\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+#if CHECKSUM_GEN_IP\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+#endif\r
+  } else {\r
+    /* IP header already included in p */\r
+    iphdr = p->payload;\r
+    dest = &(iphdr->dest);\r
+  }\r
+\r
+#if IP_FRAG\r
+  /* don't fragment if interface has mtu set to 0 [loopif] */\r
+  if (netif->mtu && (p->tot_len > netif->mtu))\r
+    return ip_frag(p,netif,dest);\r
+#endif\r
+\r
+  IP_STATS_INC(ip.xmit);\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));\r
+  ip_debug_print(p);\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));\r
+\r
+  return netif->output(netif, p, dest);\r
+}\r
+\r
+/**\r
+ * Simple interface to ip_output_if. It finds the outgoing network\r
+ * interface and calls upon ip_output_if to do the actual work.\r
+ *\r
+ * @param p the packet to send (p->payload points to the data, e.g. next\r
+            protocol header; if dest == IP_HDRINCL, p already includes an IP\r
+            header and p->payload points to that IP header)\r
+ * @param src the source IP address to send from (if src == IP_ADDR_ANY, the\r
+ *         IP  address of the netif used to send is used as source address)\r
+ * @param dest the destination IP address to send the packet to\r
+ * @param ttl the TTL value to be set in the IP header\r
+ * @param tos the TOS value to be set in the IP header\r
+ * @param proto the PROTOCOL to be set in the IP header\r
+ *\r
+ * @return ERR_RTE if no route is found\r
+ *         see ip_output_if() for more return values\r
+ */\r
+err_t\r
+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+          u8_t ttl, u8_t tos, u8_t proto)\r
+{\r
+  struct netif *netif;\r
+\r
+  if ((netif = ip_route(dest)) == NULL) {\r
+    return ERR_RTE;\r
+  }\r
+\r
+  return ip_output_if(p, src, dest, ttl, tos, proto, netif);\r
+}\r
+\r
+#if IP_DEBUG\r
+/* Print an IP header by using LWIP_DEBUGF\r
+ * @param p an IP packet, p->payload pointing to the IP header\r
+ */\r
+void\r
+ip_debug_print(struct pbuf *p)\r
+{\r
+  struct ip_hdr *iphdr = p->payload;\r
+  u8_t *payload;\r
+\r
+  payload = (u8_t *)iphdr + IP_HLEN;\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |%2"S16_F" |  0x%02"X16_F" |     %5"U16_F"     | (v, hl, tos, len)\n",\r
+                    IPH_V(iphdr),\r
+                    IPH_HL(iphdr),\r
+                    IPH_TOS(iphdr),\r
+                    ntohs(IPH_LEN(iphdr))));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      |%"U16_F"%"U16_F"%"U16_F"|    %4"U16_F"   | (id, flags, offset)\n",\r
+                    ntohs(IPH_ID(iphdr)),\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 15 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 14 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) >> 13 & 1,\r
+                    ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |    0x%04"X16_F"     | (ttl, proto, chksum)\n",\r
+                    IPH_TTL(iphdr),\r
+                    IPH_PROTO(iphdr),\r
+                    ntohs(IPH_CHKSUM(iphdr))));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (src)\n",\r
+                    ip4_addr1(&iphdr->src),\r
+                    ip4_addr2(&iphdr->src),\r
+                    ip4_addr3(&iphdr->src),\r
+                    ip4_addr4(&iphdr->src)));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  |  %3"U16_F"  | (dest)\n",\r
+                    ip4_addr1(&iphdr->dest),\r
+                    ip4_addr2(&iphdr->dest),\r
+                    ip4_addr3(&iphdr->dest),\r
+                    ip4_addr4(&iphdr->dest)));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+#endif /* IP_DEBUG */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_addr.c
new file mode 100644 (file)
index 0000000..7a96c2f
--- /dev/null
@@ -0,0 +1,84 @@
+/**\r
+ * @file\r
+ * This is the IPv4 address tools implementation.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/netif.h"\r
+\r
+#define IP_ADDR_ANY_VALUE 0x00000000UL\r
+#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL\r
+\r
+/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */\r
+const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };\r
+const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };\r
+\r
+/**\r
+ * Determine if an address is a broadcast address on a network interface\r
+ *\r
+ * @param addr address to be checked\r
+ * @param netif the network interface against which the address is checked\r
+ * @return returns non-zero if the address is a broadcast address\r
+ */\r
+u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)\r
+{\r
+  u32_t addr2test;\r
+\r
+  addr2test = addr->addr;\r
+  /* all ones (broadcast) or all zeroes (old skool broadcast) */\r
+  if ((~addr2test == IP_ADDR_ANY_VALUE) ||\r
+      (addr2test == IP_ADDR_ANY_VALUE))\r
+    return 1;\r
+  /* no broadcast support on this network interface? */\r
+  else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)\r
+    /* the given address cannot be a broadcast address\r
+     * nor can we check against any broadcast addresses */\r
+    return 0;\r
+  /* address matches network interface address exactly? => no broadcast */\r
+  else if (addr2test == netif->ip_addr.addr)\r
+    return 0;\r
+  /*  on the same (sub) network... */\r
+  else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))\r
+         /* ...and host identifier bits are all ones? =>... */\r
+          && ((addr2test & ~netif->netmask.addr) ==\r
+           (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))\r
+    /* => network broadcast address */\r
+    return 1;\r
+  else\r
+    return 0;\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv4/ip_frag.c
new file mode 100644 (file)
index 0000000..5cca281
--- /dev/null
@@ -0,0 +1,783 @@
+/**\r
+ * @file\r
+ * This is the IPv4 packet segmentation and reassembly implementation.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Jani Monoses <jani@iv.ro>\r
+ *         Simon Goldschmidt\r
+ * original reassembly code by Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/icmp.h"\r
+\r
+#include <string.h>\r
+\r
+#if IP_REASSEMBLY\r
+/**\r
+ * The IP reassembly code currently has the following limitations:\r
+ * - IP header options are not supported\r
+ * - fragments must not overlap (e.g. due to different routes),\r
+ *   currently, overlapping or duplicate fragments are thrown away\r
+ *   if IP_REASS_CHECK_OVERLAP=1 (the default)!\r
+ *\r
+ * @todo: work with IP header options\r
+ */\r
+\r
+/** Setting this to 0, you can turn off checking the fragments for overlapping\r
+ * regions. The code gets a little smaller. Only use this if you know that\r
+ * overlapping won't occur on your network! */\r
+#ifndef IP_REASS_CHECK_OVERLAP\r
+#define IP_REASS_CHECK_OVERLAP 1\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+\r
+/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is\r
+ * full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.\r
+ * Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA\r
+ * is set to 1, so one datagram can be reassembled at a time, only. */\r
+#ifndef IP_REASS_FREE_OLDEST\r
+#define IP_REASS_FREE_OLDEST 1\r
+#endif /* IP_REASS_FREE_OLDEST */\r
+\r
+#define IP_REASS_FLAG_LASTFRAG 0x01\r
+\r
+/** This is a helper struct which holds the starting\r
+ * offset and the ending offset of this fragment to\r
+ * easily chain the fragments.\r
+ */\r
+struct ip_reass_helper {\r
+  struct pbuf *next_pbuf;\r
+  u16_t start;\r
+  u16_t end;\r
+};\r
+\r
+#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB)  \\r
+  (ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \\r
+   ip_addr_cmp(&(iphdrA)->dest, &(iphdrB)->dest) && \\r
+   IPH_ID(iphdrA) == IPH_ID(iphdrB)) ? 1 : 0\r
+\r
+/* global variables */\r
+static struct ip_reassdata *reassdatagrams;\r
+static u16_t ip_reass_pbufcount;\r
+\r
+/* function prototypes */\r
+static void ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);\r
+static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev);\r
+\r
+/**\r
+ * Reassembly timer base function\r
+ * for both NO_SYS == 0 and 1 (!).\r
+ *\r
+ * Should be called every 1000 msec (defined by IP_TMR_INTERVAL).\r
+ */\r
+void\r
+ip_reass_tmr(void)\r
+{\r
+  struct ip_reassdata *r, *prev = NULL;\r
+\r
+  r = reassdatagrams;\r
+  while (r != NULL) {\r
+    /* Decrement the timer. Once it reaches 0,\r
+     * clean up the incomplete fragment assembly */\r
+    if (r->timer > 0) {\r
+      r->timer--;\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer dec %"U16_F"\n",(u16_t)r->timer));\r
+      prev = r;\r
+      r = r->next;\r
+    } else {\r
+      /* reassembly timed out */\r
+      struct ip_reassdata *tmp;\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass_tmr: timer timed out\n"));\r
+      tmp = r;\r
+      /* get the next pointer before freeing */\r
+      r = r->next;\r
+      /* free the helper struct and all enqueued pbufs */\r
+      ip_reass_free_complete_datagram(tmp, prev);\r
+     }\r
+   }\r
+}\r
+\r
+/**\r
+ * Free a datagram (struct ip_reassdata) and all its pbufs.\r
+ * Updates the total count of enqueued pbufs (ip_reass_pbufcount),\r
+ * SNMP counters and sends an ICMP time exceeded packet.\r
+ *\r
+ * @param ipr datagram to free\r
+ * @param prev the previous datagram in the linked list\r
+ * @return the number of pbufs freed\r
+ */\r
+static int\r
+ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)\r
+{\r
+  int pbufs_freed = 0;\r
+  struct pbuf *p;\r
+  struct ip_reass_helper *iprh;\r
+\r
+  LWIP_ASSERT("prev != ipr", prev != ipr);\r
+  if (prev != NULL) {\r
+    LWIP_ASSERT("prev->next == ipr", prev->next == ipr);\r
+  }\r
+\r
+  snmp_inc_ipreasmfails();\r
+#if LWIP_ICMP\r
+  iprh = (struct ip_reass_helper *)ipr->p->payload;\r
+  if (iprh->start == 0) {\r
+    /* The first fragment was received, send ICMP time exceeded. */\r
+    /* First, de-queue the first pbuf from r->p. */\r
+    p = ipr->p;\r
+    ipr->p = iprh->next_pbuf;\r
+    /* Then, copy the original header into it. */\r
+    SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN);\r
+    icmp_time_exceeded(p, ICMP_TE_FRAG);\r
+    pbufs_freed += pbuf_clen(p);\r
+    pbuf_free(p);\r
+  }\r
+#endif /* LWIP_ICMP */\r
+\r
+  /* First, free all received pbufs.  The individual pbufs need to be released\r
+     separately as they have not yet been chained */\r
+  p = ipr->p;\r
+  while (p != NULL) {\r
+    struct pbuf *pcur;\r
+    iprh = (struct ip_reass_helper *)p->payload;\r
+    pcur = p;\r
+    /* get the next pointer before freeing */\r
+    p = iprh->next_pbuf;\r
+    pbufs_freed += pbuf_clen(pcur);\r
+    pbuf_free(pcur);\r
+  }\r
+  /* Then, unchain the struct ip_reassdata from the list and free it. */\r
+  ip_reass_dequeue_datagram(ipr, prev);\r
+  LWIP_ASSERT("ip_reass_pbufcount >= clen", ip_reass_pbufcount >= pbufs_freed);\r
+  ip_reass_pbufcount -= pbufs_freed;\r
+\r
+  return pbufs_freed;\r
+}\r
+\r
+#if IP_REASS_FREE_OLDEST\r
+/**\r
+ * Free the oldest datagram to make room for enqueueing new fragments.\r
+ * The datagram 'fraghdr' belongs to is not freed!\r
+ *\r
+ * @param fraghdr IP header of the current fragment\r
+ * @param pbufs_needed number of pbufs needed to enqueue\r
+ *        (used for freeing other datagrams if not enough space)\r
+ * @return the number of pbufs freed\r
+ */\r
+static int\r
+ip_reass_remove_oldest_datagram(struct ip_hdr *fraghdr, int pbufs_needed)\r
+{\r
+  /* @todo Can't we simply remove the last datagram in the\r
+   *       linked list behind reassdatagrams?\r
+   */\r
+  struct ip_reassdata *r, *oldest, *prev;\r
+  int pbufs_freed = 0, pbufs_freed_current;\r
+  int other_datagrams;\r
+\r
+  /* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,\r
+   * but don't free the datagram that 'fraghdr' belongs to! */\r
+  do {\r
+    oldest = NULL;\r
+    prev = NULL;\r
+    other_datagrams = 0;\r
+    r = reassdatagrams;\r
+    while (r != NULL) {\r
+      if (!IP_ADDRESSES_AND_ID_MATCH(&r->iphdr, fraghdr)) {\r
+        /* Not the same datagram as fraghdr */\r
+        other_datagrams++;\r
+        if (oldest == NULL) {\r
+          oldest = r;\r
+        } else if (r->timer <= oldest->timer) {\r
+          /* older than the previous oldest */\r
+          oldest = r;\r
+        }\r
+      }\r
+      if (r->next != NULL) {\r
+        prev = r;\r
+      }\r
+      r = r->next;\r
+    }\r
+    if (oldest != NULL) {\r
+      pbufs_freed_current = ip_reass_free_complete_datagram(oldest, prev);\r
+      pbufs_freed += pbufs_freed_current;\r
+    }\r
+  } while ((pbufs_freed < pbufs_needed) && (other_datagrams > 1));\r
+  return pbufs_freed;\r
+}\r
+#endif /* IP_REASS_FREE_OLDEST */\r
+\r
+/**\r
+ * Enqueues a new fragment into the fragment queue\r
+ * @param fraghdr points to the new fragments IP hdr\r
+ * @param clen number of pbufs needed to enqueue (used for freeing other datagrams if not enough space)\r
+ * @return A pointer to the queue location into which the fragment was enqueued\r
+ */\r
+static struct ip_reassdata*\r
+ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen)\r
+{\r
+  struct ip_reassdata* ipr;\r
+  /* No matching previous fragment found, allocate a new reassdata struct */\r
+  ipr = memp_malloc(MEMP_REASSDATA);\r
+  if (ipr == NULL) {\r
+#if IP_REASS_FREE_OLDEST\r
+    if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) {\r
+      ipr = memp_malloc(MEMP_REASSDATA);\r
+    }\r
+    if (ipr == NULL)\r
+#endif /* IP_REASS_FREE_OLDEST */\r
+    {\r
+      IPFRAG_STATS_INC(ip_frag.memerr);\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,("Failed to alloc reassdata struct\n"));\r
+      return NULL;\r
+    }\r
+  }\r
+  memset(ipr, 0, sizeof(struct ip_reassdata));\r
+  ipr->timer = IP_REASS_MAXAGE;\r
+\r
+  /* enqueue the new structure to the front of the list */\r
+  ipr->next = reassdatagrams;\r
+  reassdatagrams = ipr;\r
+  /* copy the ip header for later tests and input */\r
+  /* @todo: no ip options supported? */\r
+  SMEMCPY(&(ipr->iphdr), fraghdr, IP_HLEN);\r
+  return ipr;\r
+}\r
+\r
+/**\r
+ * Dequeues a datagram from the datagram queue. Doesn't deallocate the pbufs.\r
+ * @param ipr points to the queue entry to dequeue\r
+ */\r
+static void\r
+ip_reass_dequeue_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev)\r
+{\r
+\r
+  /* dequeue the reass struct  */\r
+  if (reassdatagrams == ipr) {\r
+    /* it was the first in the list */\r
+    reassdatagrams = ipr->next;\r
+  } else {\r
+    /* it wasn't the first, so it must have a valid 'prev' */\r
+    LWIP_ASSERT("sanity check linked list", prev != NULL);\r
+    prev->next = ipr->next;\r
+  }\r
+\r
+  /* now we can free the ip_reass struct */\r
+  memp_free(MEMP_REASSDATA, ipr);\r
+}\r
+\r
+/**\r
+ * Chain a new pbuf into the pbuf list that composes the datagram.  The pbuf list\r
+ * will grow over time as  new pbufs are rx.\r
+ * Also checks that the datagram passes basic continuity checks (if the last\r
+ * fragment was received at least once).\r
+ * @param root_p points to the 'root' pbuf for the current datagram being assembled.\r
+ * @param new_p points to the pbuf for the current fragment\r
+ * @return 0 if invalid, >0 otherwise\r
+ */\r
+static int\r
+ip_reass_chain_frag_into_datagram_and_validate(struct ip_reassdata *ipr, struct pbuf *new_p)\r
+{\r
+  struct ip_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;\r
+  struct pbuf *q;\r
+  u16_t offset,len;\r
+  struct ip_hdr *fraghdr;\r
+  int valid = 1;\r
+\r
+  /* Extract length and fragment offset from current fragment */\r
+  fraghdr = (struct ip_hdr*)new_p->payload;\r
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;\r
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;\r
+\r
+  /* overwrite the fragment's ip header from the pbuf with our helper struct,\r
+   * and setup the embedded helper structure. */\r
+  /* make sure the struct ip_reass_helper fits into the IP header */\r
+  LWIP_ASSERT("sizeof(struct ip_reass_helper) <= IP_HLEN",\r
+              sizeof(struct ip_reass_helper) <= IP_HLEN);\r
+  iprh = (struct ip_reass_helper*)new_p->payload;\r
+  iprh->next_pbuf = NULL;\r
+  iprh->start = offset;\r
+  iprh->end = offset + len;\r
+\r
+  /* Iterate through until we either get to the end of the list (append),\r
+   * or we find on with a larger offset (insert). */\r
+  for (q = ipr->p; q != NULL;) {\r
+    iprh_tmp = (struct ip_reass_helper*)q->payload;\r
+    if (iprh->start < iprh_tmp->start) {\r
+      /* the new pbuf should be inserted before this */\r
+      iprh->next_pbuf = q;\r
+      if (iprh_prev != NULL) {\r
+        /* not the fragment with the lowest offset */\r
+#if IP_REASS_CHECK_OVERLAP\r
+        if ((iprh->start < iprh_prev->end) || (iprh->end > iprh_tmp->start)) {\r
+          /* fragment overlaps with previous or following, throw away */\r
+          goto freepbuf;\r
+        }\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+        iprh_prev->next_pbuf = new_p;\r
+      } else {\r
+        /* fragment with the lowest offset */\r
+        ipr->p = new_p;\r
+      }\r
+      break;\r
+    } else if(iprh->start == iprh_tmp->start) {\r
+      /* received the same datagram twice: no need to keep the datagram */\r
+      goto freepbuf;\r
+#if IP_REASS_CHECK_OVERLAP\r
+    } else if(iprh->start < iprh_tmp->end) {\r
+      /* overlap: no need to keep the new datagram */\r
+      goto freepbuf;\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+    } else {\r
+      /* Check if the fragments received so far have no wholes. */\r
+      if (iprh_prev != NULL) {\r
+        if (iprh_prev->end != iprh_tmp->start) {\r
+          /* There is a fragment missing between the current\r
+           * and the previous fragment */\r
+          valid = 0;\r
+        }\r
+      }\r
+    }\r
+    q = iprh_tmp->next_pbuf;\r
+    iprh_prev = iprh_tmp;\r
+  }\r
+\r
+  /* If q is NULL, then we made it to the end of the list. Determine what to do now */\r
+  if (q == NULL) {\r
+    if (iprh_prev != NULL) {\r
+      /* this is (for now), the fragment with the highest offset:\r
+       * chain it to the last fragment */\r
+#if IP_REASS_CHECK_OVERLAP\r
+      LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+      iprh_prev->next_pbuf = new_p;\r
+      if (iprh_prev->end != iprh->start) {\r
+        valid = 0;\r
+      }\r
+    } else {\r
+#if IP_REASS_CHECK_OVERLAP\r
+      LWIP_ASSERT("no previous fragment, this must be the first fragment!",\r
+        ipr->p == NULL);\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+      /* this is the first fragment we ever received for this ip datagram */\r
+      ipr->p = new_p;\r
+    }\r
+  }\r
+\r
+  /* At this point, the validation part begins: */\r
+  /* If we already received the last fragment */\r
+  if ((ipr->flags & IP_REASS_FLAG_LASTFRAG) != 0) {\r
+    /* and had no wholes so far */\r
+    if (valid) {\r
+      /* then check if the rest of the fragments is here */\r
+      /* Check if the queue starts with the first datagram */\r
+      if (((struct ip_reass_helper*)ipr->p->payload)->start != 0) {\r
+        valid = 0;\r
+      } else {\r
+        /* and check that there are no wholes after this datagram */\r
+        iprh_prev = iprh;\r
+        q = iprh->next_pbuf;\r
+        while (q != NULL) {\r
+          iprh = (struct ip_reass_helper*)q->payload;\r
+          if (iprh_prev->end != iprh->start) {\r
+            valid = 0;\r
+            break;\r
+          }\r
+          iprh_prev = iprh;\r
+          q = iprh->next_pbuf;\r
+        }\r
+        /* if still valid, all fragments are received\r
+         * (because to the MF==0 already arrived */\r
+        if (valid) {\r
+          LWIP_ASSERT("sanity check", ipr->p != NULL);\r
+          LWIP_ASSERT("sanity check",\r
+            ((struct ip_reass_helper*)ipr->p->payload) != iprh);\r
+          LWIP_ASSERT("validate_datagram:next_pbuf!=NULL",\r
+            iprh->next_pbuf == NULL);\r
+          LWIP_ASSERT("validate_datagram:datagram end!=datagram len",\r
+            iprh->end == ipr->datagram_len);\r
+        }\r
+      }\r
+    }\r
+    /* If valid is 0 here, there are some fragments missing in the middle\r
+     * (since MF == 0 has already arrived). Such datagrams simply time out if\r
+     * no more fragments are received... */\r
+    return valid;\r
+  }\r
+  /* If we come here, not all fragments were received, yet! */\r
+  return 0; /* not yet valid! */\r
+#if IP_REASS_CHECK_OVERLAP\r
+freepbuf:\r
+  ip_reass_pbufcount -= pbuf_clen(new_p);\r
+  pbuf_free(new_p);\r
+  return 0;\r
+#endif /* IP_REASS_CHECK_OVERLAP */\r
+}\r
+\r
+/**\r
+ * Reassembles incoming IP fragments into an IP datagram.\r
+ *\r
+ * @param p points to a pbuf chain of the fragment\r
+ * @return NULL if reassembly is incomplete, ? otherwise\r
+ */\r
+struct pbuf *\r
+ip_reass(struct pbuf *p)\r
+{\r
+  struct pbuf *r;\r
+  struct ip_hdr *fraghdr;\r
+  struct ip_reassdata *ipr;\r
+  struct ip_reass_helper *iprh;\r
+  u16_t offset, len;\r
+  u8_t clen;\r
+  struct ip_reassdata *ipr_prev = NULL;\r
+\r
+  IPFRAG_STATS_INC(ip_frag.recv);\r
+  snmp_inc_ipreasmreqds();\r
+\r
+  fraghdr = (struct ip_hdr*)p->payload;\r
+\r
+  if ((IPH_HL(fraghdr) * 4) != IP_HLEN) {\r
+    LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: IP options currently not supported!\n"));\r
+    IPFRAG_STATS_INC(ip_frag.err);\r
+    goto nullreturn;\r
+  }\r
+\r
+  offset = (ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) * 8;\r
+  len = ntohs(IPH_LEN(fraghdr)) - IPH_HL(fraghdr) * 4;\r
+\r
+  /* Check if we are allowed to enqueue more datagrams. */\r
+  clen = pbuf_clen(p);\r
+  if ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {\r
+#if IP_REASS_FREE_OLDEST\r
+    if (!ip_reass_remove_oldest_datagram(fraghdr, clen) ||\r
+        ((ip_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS))\r
+#endif /* IP_REASS_FREE_OLDEST */\r
+    {\r
+      /* No datagram could be freed and still too many pbufs enqueued */\r
+      LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: Overflow condition: pbufct=%d, clen=%d, MAX=%d\n",\r
+        ip_reass_pbufcount, clen, IP_REASS_MAX_PBUFS));\r
+      IPFRAG_STATS_INC(ip_frag.memerr);\r
+      /* @todo: send ICMP time exceeded here? */\r
+      /* drop this pbuf */\r
+      goto nullreturn;\r
+    }\r
+  }\r
+\r
+  /* Look for the datagram the fragment belongs to in the current datagram queue,\r
+   * remembering the previous in the queue for later dequeueing. */\r
+  for (ipr = reassdatagrams; ipr != NULL; ipr = ipr->next) {\r
+    /* Check if the incoming fragment matches the one currently present\r
+       in the reassembly buffer. If so, we proceed with copying the\r
+       fragment into the buffer. */\r
+    if (IP_ADDRESSES_AND_ID_MATCH(&ipr->iphdr, fraghdr)) {\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_reass: matching previous fragment ID=%"X16_F"\n",\r
+        ntohs(IPH_ID(fraghdr))));\r
+      IPFRAG_STATS_INC(ip_frag.cachehit);\r
+      break;\r
+    }\r
+    ipr_prev = ipr;\r
+  }\r
+\r
+  if (ipr == NULL) {\r
+  /* Enqueue a new datagram into the datagram queue */\r
+    ipr = ip_reass_enqueue_new_datagram(fraghdr, clen);\r
+    /* Bail if unable to enqueue */\r
+    if(ipr == NULL) {\r
+      goto nullreturn;\r
+    }\r
+  } else {\r
+    if (((ntohs(IPH_OFFSET(fraghdr)) & IP_OFFMASK) == 0) &&\r
+      ((ntohs(IPH_OFFSET(&ipr->iphdr)) & IP_OFFMASK) != 0)) {\r
+      /* ipr->iphdr is not the header from the first fragment, but fraghdr is\r
+       * -> copy fraghdr into ipr->iphdr since we want to have the header\r
+       * of the first fragment (for ICMP time exceeded and later, for copying\r
+       * all options, if supported)*/\r
+      SMEMCPY(&ipr->iphdr, fraghdr, IP_HLEN);\r
+    }\r
+  }\r
+  /* Track the current number of pbufs current 'in-flight', in order to limit\r
+  the number of fragments that may be enqueued at any one time */\r
+  ip_reass_pbufcount += clen;\r
+\r
+  /* At this point, we have either created a new entry or pointing\r
+   * to an existing one */\r
+\r
+  /* check for 'no more fragments', and update queue entry*/\r
+  if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) {\r
+    ipr->flags |= IP_REASS_FLAG_LASTFRAG;\r
+    ipr->datagram_len = offset + len;\r
+    LWIP_DEBUGF(IP_REASS_DEBUG,\r
+     ("ip_reass: last fragment seen, total len %"S16_F"\n",\r
+      ipr->datagram_len));\r
+  }\r
+  /* find the right place to insert this pbuf */\r
+  /* @todo: trim pbufs if fragments are overlapping */\r
+  if (ip_reass_chain_frag_into_datagram_and_validate(ipr, p)) {\r
+    /* the totally last fragment (flag more fragments = 0) was received at least\r
+     * once AND all fragments are received */\r
+    ipr->datagram_len += IP_HLEN;\r
+\r
+    /* save the second pbuf before copying the header over the pointer */\r
+    r = ((struct ip_reass_helper*)ipr->p->payload)->next_pbuf;\r
+\r
+    /* copy the original ip header back to the first pbuf */\r
+    fraghdr = (struct ip_hdr*)(ipr->p->payload);\r
+    SMEMCPY(fraghdr, &ipr->iphdr, IP_HLEN);\r
+    IPH_LEN_SET(fraghdr, htons(ipr->datagram_len));\r
+    IPH_OFFSET_SET(fraghdr, 0);\r
+    IPH_CHKSUM_SET(fraghdr, 0);\r
+    /* @todo: do we need to set calculate the correct checksum? */\r
+    IPH_CHKSUM_SET(fraghdr, inet_chksum(fraghdr, IP_HLEN));\r
+\r
+    p = ipr->p;\r
+\r
+    /* chain together the pbufs contained within the reass_data list. */\r
+    while(r != NULL) {\r
+      iprh = (struct ip_reass_helper*)r->payload;\r
+\r
+      /* hide the ip header for every succeding fragment */\r
+      pbuf_header(r, -IP_HLEN);\r
+      pbuf_cat(p, r);\r
+      r = iprh->next_pbuf;\r
+    }\r
+    /* release the sources allocate for the fragment queue entry */\r
+    ip_reass_dequeue_datagram(ipr, ipr_prev);\r
+\r
+    /* and adjust the number of pbufs currently queued for reassembly. */\r
+    ip_reass_pbufcount -= pbuf_clen(p);\r
+\r
+    /* Return the pbuf chain */\r
+    return p;\r
+  }\r
+  /* the datagram is not (yet?) reassembled completely */\r
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass_pbufcount: %d out\n", ip_reass_pbufcount));\r
+  return NULL;\r
+\r
+nullreturn:\r
+  LWIP_DEBUGF(IP_REASS_DEBUG,("ip_reass: nullreturn\n"));\r
+  IPFRAG_STATS_INC(ip_frag.drop);\r
+  pbuf_free(p);\r
+  return NULL;\r
+}\r
+#endif /* IP_REASSEMBLY */\r
+\r
+#if IP_FRAG\r
+#if IP_FRAG_USES_STATIC_BUF\r
+static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];\r
+#endif /* IP_FRAG_USES_STATIC_BUF */\r
+\r
+/**\r
+ * Fragment an IP datagram if too large for the netif.\r
+ *\r
+ * Chop the datagram in MTU sized chunks and send them in order\r
+ * by using a fixed size static memory buffer (PBUF_REF) or\r
+ * point PBUF_REFs into p (depending on IP_FRAG_USES_STATIC_BUF).\r
+ *\r
+ * @param p ip packet to send\r
+ * @param netif the netif on which to send\r
+ * @param dest destination ip address to which to send\r
+ *\r
+ * @return ERR_OK if sent successfully, err_t otherwise\r
+ */\r
+err_t\r
+ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest)\r
+{\r
+  struct pbuf *rambuf;\r
+#if IP_FRAG_USES_STATIC_BUF\r
+  struct pbuf *header;\r
+#else\r
+  struct pbuf *newpbuf;\r
+  struct ip_hdr *original_iphdr;\r
+#endif\r
+  struct ip_hdr *iphdr;\r
+  u16_t nfb;\r
+  u16_t left, cop;\r
+  u16_t mtu = netif->mtu;\r
+  u16_t ofo, omf;\r
+  u16_t last;\r
+  u16_t poff = IP_HLEN;\r
+  u16_t tmp;\r
+#if !IP_FRAG_USES_STATIC_BUF\r
+  u16_t newpbuflen = 0;\r
+  u16_t left_to_copy;\r
+#endif\r
+\r
+  /* Get a RAM based MTU sized pbuf */\r
+#if IP_FRAG_USES_STATIC_BUF\r
+  /* When using a static buffer, we use a PBUF_REF, which we will\r
+   * use to reference the packet (without link header).\r
+   * Layer and length is irrelevant.\r
+   */\r
+  rambuf = pbuf_alloc(PBUF_LINK, 0, PBUF_REF);\r
+  if (rambuf == NULL) {\r
+    LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc(PBUF_LINK, 0, PBUF_REF) failed\n"));\r
+    return ERR_MEM;\r
+  }\r
+  rambuf->tot_len = rambuf->len = mtu;\r
+  rambuf->payload = LWIP_MEM_ALIGN((void *)buf);\r
+\r
+  /* Copy the IP header in it */\r
+  iphdr = rambuf->payload;\r
+  SMEMCPY(iphdr, p->payload, IP_HLEN);\r
+#else /* IP_FRAG_USES_STATIC_BUF */\r
+  original_iphdr = p->payload;\r
+  iphdr = original_iphdr;\r
+#endif /* IP_FRAG_USES_STATIC_BUF */\r
+\r
+  /* Save original offset */\r
+  tmp = ntohs(IPH_OFFSET(iphdr));\r
+  ofo = tmp & IP_OFFMASK;\r
+  omf = tmp & IP_MF;\r
+\r
+  left = p->tot_len - IP_HLEN;\r
+\r
+  nfb = (mtu - IP_HLEN) / 8;\r
+\r
+  while (left) {\r
+    last = (left <= mtu - IP_HLEN);\r
+\r
+    /* Set new offset and MF flag */\r
+    tmp = omf | (IP_OFFMASK & (ofo));\r
+    if (!last)\r
+      tmp = tmp | IP_MF;\r
+\r
+    /* Fill this fragment */\r
+    cop = last ? left : nfb * 8;\r
+\r
+#if IP_FRAG_USES_STATIC_BUF\r
+    poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff);\r
+#else /* IP_FRAG_USES_STATIC_BUF */\r
+    /* When not using a static buffer, create a chain of pbufs.\r
+     * The first will be a PBUF_RAM holding the link and IP header.\r
+     * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,\r
+     * but limited to the size of an mtu.\r
+     */\r
+    rambuf = pbuf_alloc(PBUF_LINK, IP_HLEN, PBUF_RAM);\r
+    if (rambuf == NULL) {\r
+      return ERR_MEM;\r
+    }\r
+    LWIP_ASSERT("this needs a pbuf in one piece!",\r
+                (p->len >= (IP_HLEN)));\r
+    SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN);\r
+    iphdr = rambuf->payload;\r
+\r
+    /* Can just adjust p directly for needed offset. */\r
+    p->payload = (u8_t *)p->payload + poff;\r
+    p->len -= poff;\r
+\r
+    left_to_copy = cop;\r
+    while (left_to_copy) {\r
+      newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len;\r
+      /* Is this pbuf already empty? */\r
+      if (!newpbuflen) {\r
+        p = p->next;\r
+        continue;\r
+      }\r
+      newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF);\r
+      if (newpbuf == NULL) {\r
+        pbuf_free(rambuf);\r
+        return ERR_MEM;\r
+      }\r
+      /* Mirror this pbuf, although we might not need all of it. */\r
+      newpbuf->payload = p->payload;\r
+      newpbuf->len = newpbuf->tot_len = newpbuflen;\r
+      /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain\r
+       * so that it is removed when pbuf_dechain is later called on rambuf.\r
+       */\r
+      pbuf_cat(rambuf, newpbuf);\r
+      left_to_copy -= newpbuflen;\r
+      if (left_to_copy)\r
+        p = p->next;\r
+    }\r
+    poff = newpbuflen;\r
+#endif /* IP_FRAG_USES_STATIC_BUF */\r
+\r
+    /* Correct header */\r
+    IPH_OFFSET_SET(iphdr, htons(tmp));\r
+    IPH_LEN_SET(iphdr, htons(cop + IP_HLEN));\r
+    IPH_CHKSUM_SET(iphdr, 0);\r
+    IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN));\r
+\r
+#if IP_FRAG_USES_STATIC_BUF\r
+    if (last)\r
+      pbuf_realloc(rambuf, left + IP_HLEN);\r
+\r
+    /* This part is ugly: we alloc a RAM based pbuf for\r
+     * the link level header for each chunk and then\r
+     * free it.A PBUF_ROM style pbuf for which pbuf_header\r
+     * worked would make things simpler.\r
+     */\r
+    header = pbuf_alloc(PBUF_LINK, 0, PBUF_RAM);\r
+    if (header != NULL) {\r
+      pbuf_chain(header, rambuf);\r
+      netif->output(netif, header, dest);\r
+      IPFRAG_STATS_INC(ip_frag.xmit);\r
+      snmp_inc_ipfragcreates();\r
+      pbuf_free(header);\r
+    } else {\r
+      LWIP_DEBUGF(IP_REASS_DEBUG, ("ip_frag: pbuf_alloc() for header failed\n"));\r
+      pbuf_free(rambuf);\r
+      return ERR_MEM;\r
+    }\r
+#else /* IP_FRAG_USES_STATIC_BUF */\r
+    /* No need for separate header pbuf - we allowed room for it in rambuf\r
+     * when allocated.\r
+     */\r
+    netif->output(netif, rambuf, dest);\r
+    IPFRAG_STATS_INC(ip_frag.xmit);\r
+\r
+    /* Unfortunately we can't reuse rambuf - the hardware may still be\r
+     * using the buffer. Instead we free it (and the ensuing chain) and\r
+     * recreate it next time round the loop. If we're lucky the hardware\r
+     * will have already sent the packet, the free will really free, and\r
+     * there will be zero memory penalty.\r
+     */\r
+\r
+    pbuf_free(rambuf);\r
+#endif /* IP_FRAG_USES_STATIC_BUF */\r
+    left -= cop;\r
+    ofo += nfb;\r
+  }\r
+#if IP_FRAG_USES_STATIC_BUF\r
+  pbuf_free(rambuf);\r
+#endif /* IP_FRAG_USES_STATIC_BUF */\r
+  snmp_inc_ipfragoks();\r
+  return ERR_OK;\r
+}\r
+#endif /* IP_FRAG */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv6/README b/Demo/Common/ethernet/lwIP_130/src/core/ipv6/README
new file mode 100644 (file)
index 0000000..a59caef
--- /dev/null
@@ -0,0 +1 @@
+IPv6 support in lwIP is very experimental.\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv6/icmp6.c
new file mode 100644 (file)
index 0000000..1661ace
--- /dev/null
@@ -0,0 +1,179 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/* Some ICMP messages should be passed to the transport protocols. This\r
+   is not implemented. */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/icmp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/def.h"\r
+#include "lwip/stats.h"\r
+\r
+void\r
+icmp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  u8_t type;\r
+  struct icmp_echo_hdr *iecho;\r
+  struct ip_hdr *iphdr;\r
+  struct ip_addr tmpaddr;\r
+\r
+  ICMP_STATS_INC(icmp.recv);\r
+\r
+  /* TODO: check length before accessing payload! */\r
+\r
+  type = ((u8_t *)p->payload)[0];\r
+\r
+  switch (type) {\r
+  case ICMP6_ECHO:\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));\r
+\r
+    if (p->tot_len < sizeof(struct icmp_echo_hdr)) {\r
+      LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));\r
+\r
+      pbuf_free(p);\r
+      ICMP_STATS_INC(icmp.lenerr);\r
+      return;\r
+    }\r
+    iecho = p->payload;\r
+    iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);\r
+    if (inet_chksum_pbuf(p) != 0) {\r
+      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)));\r
+      ICMP_STATS_INC(icmp.chkerr);\r
+    /*      return;*/\r
+    }\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));\r
+    ip_addr_set(&tmpaddr, &(iphdr->src));\r
+    ip_addr_set(&(iphdr->src), &(iphdr->dest));\r
+    ip_addr_set(&(iphdr->dest), &tmpaddr);\r
+    iecho->type = ICMP6_ER;\r
+    /* adjust the checksum */\r
+    if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {\r
+      iecho->chksum += htons(ICMP6_ECHO << 8) + 1;\r
+    } else {\r
+      iecho->chksum += htons(ICMP6_ECHO << 8);\r
+    }\r
+    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)));\r
+    ICMP_STATS_INC(icmp.xmit);\r
+\r
+    /*    LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/\r
+    ip_output_if (p, &(iphdr->src), IP_HDRINCL,\r
+     iphdr->hoplim, IP_PROTO_ICMP, inp);\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));\r
+    ICMP_STATS_INC(icmp.proterr);\r
+    ICMP_STATS_INC(icmp.drop);\r
+  }\r
+\r
+  pbuf_free(p);\r
+}\r
+\r
+void\r
+icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_dur_hdr *idur;\r
+\r
+  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */\r
+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);\r
+  /* ICMP header + IP header + 8 bytes of data */\r
+  if (q == NULL) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold icmp message",\r
+             (q->len >= (8 + IP_HLEN + 8)));\r
+\r
+  iphdr = p->payload;\r
+\r
+  idur = q->payload;\r
+  idur->type = (u8_t)ICMP6_DUR;\r
+  idur->icode = (u8_t)t;\r
+\r
+  SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);\r
+\r
+  /* calculate checksum */\r
+  idur->chksum = 0;\r
+  idur->chksum = inet_chksum(idur, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+\r
+  ip_output(q, NULL,\r
+      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+void\r
+icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)\r
+{\r
+  struct pbuf *q;\r
+  struct ip_hdr *iphdr;\r
+  struct icmp_te_hdr *tehdr;\r
+\r
+  LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));\r
+\r
+  /* @todo: can this be PBUF_LINK instead of PBUF_IP? */\r
+  q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);\r
+  /* ICMP header + IP header + 8 bytes of data */\r
+  if (q == NULL) {\r
+    LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold icmp message",\r
+             (q->len >= (8 + IP_HLEN + 8)));\r
+\r
+  iphdr = p->payload;\r
+\r
+  tehdr = q->payload;\r
+  tehdr->type = (u8_t)ICMP6_TE;\r
+  tehdr->icode = (u8_t)t;\r
+\r
+  /* copy fields from original packet */\r
+  SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);\r
+\r
+  /* calculate checksum */\r
+  tehdr->chksum = 0;\r
+  tehdr->chksum = inet_chksum(tehdr, q->len);\r
+  ICMP_STATS_INC(icmp.xmit);\r
+  ip_output(q, NULL,\r
+      (struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);\r
+  pbuf_free(q);\r
+}\r
+\r
+#endif /* LWIP_ICMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv6/inet6.c
new file mode 100644 (file)
index 0000000..8214f05
--- /dev/null
@@ -0,0 +1,163 @@
+/**\r
+ * @file\r
+ * Functions common to all TCP/IPv6 modules, such as the Internet checksum and the\r
+ * byte order functions.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/inet.h"\r
+\r
+/* chksum:\r
+ *\r
+ * Sums up all 16 bit words in a memory portion. Also includes any odd byte.\r
+ * This function is used by the other checksum functions.\r
+ *\r
+ * For now, this is not optimized. Must be optimized for the particular processor\r
+ * arcitecture on which it is to run. Preferebly coded in assembler.\r
+ */\r
+\r
+static u32_t\r
+chksum(void *dataptr, u16_t len)\r
+{\r
+  u16_t *sdataptr = dataptr;\r
+  u32_t acc;\r
+  \r
+  \r
+  for(acc = 0; len > 1; len -= 2) {\r
+    acc += *sdataptr++;\r
+  }\r
+\r
+  /* add up any odd byte */\r
+  if (len == 1) {\r
+    acc += htons((u16_t)(*(u8_t *)dataptr) << 8);\r
+  }\r
+\r
+  return acc;\r
+\r
+}\r
+\r
+/* inet_chksum_pseudo:\r
+ *\r
+ * Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.\r
+ */\r
+\r
+u16_t\r
+inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u32_t proto_len)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped, i;\r
+\r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {    \r
+    acc += chksum(q->payload, q->len);\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }\r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+    }\r
+  }\r
+\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+  }\r
+  \r
+  for(i = 0; i < 8; i++) {\r
+    acc += ((u16_t *)src->addr)[i] & 0xffff;\r
+    acc += ((u16_t *)dest->addr)[i] & 0xffff;\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }\r
+  }\r
+  acc += (u16_t)htons((u16_t)proto);\r
+  acc += ((u16_t *)&proto_len)[0] & 0xffff;\r
+  acc += ((u16_t *)&proto_len)[1] & 0xffff;\r
+\r
+  while (acc >> 16) {\r
+    acc = (acc & 0xffff) + (acc >> 16);\r
+  }\r
+  return ~(acc & 0xffff);\r
+}\r
+\r
+/* inet_chksum:\r
+ *\r
+ * Calculates the Internet checksum over a portion of memory. Used primarely for IP\r
+ * and ICMP.\r
+ */\r
+\r
+u16_t\r
+inet_chksum(void *dataptr, u16_t len)\r
+{\r
+  u32_t acc, sum;\r
+\r
+  acc = chksum(dataptr, len);\r
+  sum = (acc & 0xffff) + (acc >> 16);\r
+  sum += (sum >> 16);\r
+  return ~(sum & 0xffff);\r
+}\r
+\r
+u16_t\r
+inet_chksum_pbuf(struct pbuf *p)\r
+{\r
+  u32_t acc;\r
+  struct pbuf *q;\r
+  u8_t swapped;\r
+  \r
+  acc = 0;\r
+  swapped = 0;\r
+  for(q = p; q != NULL; q = q->next) {\r
+    acc += chksum(q->payload, q->len);\r
+    while (acc >> 16) {\r
+      acc = (acc & 0xffff) + (acc >> 16);\r
+    }    \r
+    if (q->len % 2 != 0) {\r
+      swapped = 1 - swapped;\r
+      acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);\r
+    }\r
+  }\r
\r
+  if (swapped) {\r
+    acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);\r
+  }\r
+  return ~(acc & 0xffff);\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6.c
new file mode 100644 (file)
index 0000000..46bc3ad
--- /dev/null
@@ -0,0 +1,375 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+\r
+/* ip.c\r
+ *\r
+ * This is the code for the IP layer for IPv6.\r
+ *\r
+ */\r
+\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include "lwip/stats.h"\r
+\r
+#include "arch/perf.h"\r
+\r
+/* ip_init:\r
+ *\r
+ * Initializes the IP layer.\r
+ */\r
+\r
+void\r
+ip_init(void)\r
+{\r
+}\r
+\r
+/* ip_route:\r
+ *\r
+ * Finds the appropriate network interface for a given IP address. It searches the\r
+ * list of network interfaces linearly. A match is found if the masked IP address of\r
+ * the network interface equals the masked IP address given to the function.\r
+ */\r
+\r
+struct netif *\r
+ip_route(struct ip_addr *dest)\r
+{\r
+  struct netif *netif;\r
+\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+    if (ip_addr_netcmp(dest, &(netif->ip_addr), &(netif->netmask))) {\r
+      return netif;\r
+    }\r
+  }\r
+\r
+  return netif_default;\r
+}\r
+\r
+/* ip_forward:\r
+ *\r
+ * Forwards an IP packet. It finds an appropriate route for the packet, decrements\r
+ * the TTL value of the packet, adjusts the checksum and outputs the packet on the\r
+ * appropriate interface.\r
+ */\r
+\r
+static void\r
+ip_forward(struct pbuf *p, struct ip_hdr *iphdr)\r
+{\r
+  struct netif *netif;\r
+\r
+  PERF_START;\r
+\r
+  if ((netif = ip_route((struct ip_addr *)&(iphdr->dest))) == NULL) {\r
+\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_input: no forwarding route found for "));\r
+#if IP_DEBUG\r
+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));\r
+#endif /* IP_DEBUG */\r
+    LWIP_DEBUGF(IP_DEBUG, ("\n"));\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  /* Decrement TTL and send ICMP if ttl == 0. */\r
+  if (--iphdr->hoplim == 0) {\r
+#if LWIP_ICMP\r
+    /* Don't send ICMP messages in response to ICMP messages */\r
+    if (iphdr->nexthdr != IP_PROTO_ICMP) {\r
+      icmp_time_exceeded(p, ICMP_TE_TTL);\r
+    }\r
+#endif /* LWIP_ICMP */\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  /* Incremental update of the IP checksum. */\r
+  /*  if (iphdr->chksum >= htons(0xffff - 0x100)) {\r
+    iphdr->chksum += htons(0x100) + 1;\r
+  } else {\r
+    iphdr->chksum += htons(0x100);\r
+    }*/\r
+\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to "));\r
+#if IP_DEBUG\r
+  ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));\r
+#endif /* IP_DEBUG */\r
+  LWIP_DEBUGF(IP_DEBUG, ("\n"));\r
+\r
+  IP_STATS_INC(ip.fw);\r
+  IP_STATS_INC(ip.xmit);\r
+\r
+  PERF_STOP("ip_forward");\r
+\r
+  netif->output(netif, p, (struct ip_addr *)&(iphdr->dest));\r
+}\r
+\r
+/* ip_input:\r
+ *\r
+ * This function is called by the network interface device driver when an IP packet is\r
+ * received. The function does the basic checks of the IP header such as packet size\r
+ * being at least larger than the header size etc. If the packet was not destined for\r
+ * us, the packet is forwarded (using ip_forward). The IP checksum is always checked.\r
+ *\r
+ * Finally, the packet is sent to the upper layer protocol input function.\r
+ */\r
+\r
+void\r
+ip_input(struct pbuf *p, struct netif *inp) {\r
+  struct ip_hdr *iphdr;\r
+  struct netif *netif;\r
+\r
+\r
+  PERF_START;\r
+\r
+#if IP_DEBUG\r
+  ip_debug_print(p);\r
+#endif /* IP_DEBUG */\r
+\r
+\r
+  IP_STATS_INC(ip.recv);\r
+\r
+  /* identify the IP header */\r
+  iphdr = p->payload;\r
+\r
+\r
+  if (iphdr->v != 6) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("IP packet dropped due to bad version number\n"));\r
+#if IP_DEBUG\r
+    ip_debug_print(p);\r
+#endif /* IP_DEBUG */\r
+    pbuf_free(p);\r
+    IP_STATS_INC(ip.err);\r
+    IP_STATS_INC(ip.drop);\r
+    return;\r
+  }\r
+\r
+  /* is this packet for us? */\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+#if IP_DEBUG\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest "));\r
+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));\r
+    LWIP_DEBUGF(IP_DEBUG, ("netif->ip_addr "));\r
+    ip_addr_debug_print(IP_DEBUG, ((struct ip_addr *)&(iphdr->dest)));\r
+    LWIP_DEBUGF(IP_DEBUG, ("\n"));\r
+#endif /* IP_DEBUG */\r
+    if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr))) {\r
+      break;\r
+    }\r
+  }\r
+\r
+\r
+  if (netif == NULL) {\r
+    /* packet not for us, route or discard */\r
+#if IP_FORWARD\r
+    ip_forward(p, iphdr);\r
+#endif\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  pbuf_realloc(p, IP_HLEN + ntohs(iphdr->len));\r
+\r
+  /* send to upper layers */\r
+#if IP_DEBUG\r
+  /*  LWIP_DEBUGF("ip_input: \n");\r
+  ip_debug_print(p);\r
+  LWIP_DEBUGF("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/\r
+#endif /* IP_DEBUG */\r
+\r
+  if(pbuf_header(p, -IP_HLEN)) {\r
+    LWIP_ASSERT("Can't move over header in packet", 0);\r
+    return;\r
+  }\r
+\r
+  switch (iphdr->nexthdr) {\r
+  case IP_PROTO_UDP:\r
+    udp_input(p, inp);\r
+    break;\r
+  case IP_PROTO_TCP:\r
+    tcp_input(p, inp);\r
+    break;\r
+#if LWIP_ICMP\r
+  case IP_PROTO_ICMP:\r
+    icmp_input(p, inp);\r
+    break;\r
+#endif /* LWIP_ICMP */\r
+  default:\r
+#if LWIP_ICMP\r
+    /* send ICMP destination protocol unreachable */\r
+    icmp_dest_unreach(p, ICMP_DUR_PROTO);\r
+#endif /* LWIP_ICMP */\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(IP_DEBUG, ("Unsupported transport protocol %"U16_F"\n",\r
+          iphdr->nexthdr));\r
+\r
+    IP_STATS_INC(ip.proterr);\r
+    IP_STATS_INC(ip.drop);\r
+  }\r
+  PERF_STOP("ip_input");\r
+}\r
+\r
+\r
+/* ip_output_if:\r
+ *\r
+ * Sends an IP packet on a network interface. This function constructs the IP header\r
+ * and calculates the IP header checksum. If the source IP address is NULL,\r
+ * the IP address of the outgoing network interface is filled in as source address.\r
+ */\r
+\r
+err_t\r
+ip_output_if (struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t ttl,\r
+       u8_t proto, struct netif *netif)\r
+{\r
+  struct ip_hdr *iphdr;\r
+\r
+  PERF_START;\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));\r
+  if (pbuf_header(p, IP_HLEN)) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: not enough room for IP header in pbuf\n"));\r
+    IP_STATS_INC(ip.err);\r
+\r
+    return ERR_BUF;\r
+  }\r
+  LWIP_DEBUGF(IP_DEBUG, ("len %"U16_F" tot_len %"U16_F"\n", p->len, p->tot_len));\r
+\r
+  iphdr = p->payload;\r
+\r
+\r
+  if (dest != IP_HDRINCL) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("!IP_HDRLINCL\n"));\r
+    iphdr->hoplim = ttl;\r
+    iphdr->nexthdr = proto;\r
+    iphdr->len = htons(p->tot_len - IP_HLEN);\r
+    ip_addr_set(&(iphdr->dest), dest);\r
+\r
+    iphdr->v = 6;\r
+\r
+    if (ip_addr_isany(src)) {\r
+      ip_addr_set(&(iphdr->src), &(netif->ip_addr));\r
+    } else {\r
+      ip_addr_set(&(iphdr->src), src);\r
+    }\r
+\r
+  } else {\r
+    dest = &(iphdr->dest);\r
+  }\r
+\r
+  IP_STATS_INC(ip.xmit);\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c (len %"U16_F")\n", netif->name[0], netif->name[1], p->tot_len));\r
+#if IP_DEBUG\r
+  ip_debug_print(p);\r
+#endif /* IP_DEBUG */\r
+\r
+  PERF_STOP("ip_output_if");\r
+  return netif->output(netif, p, dest);\r
+}\r
+\r
+/* ip_output:\r
+ *\r
+ * Simple interface to ip_output_if. It finds the outgoing network interface and\r
+ * calls upon ip_output_if to do the actual work.\r
+ */\r
+\r
+err_t\r
+ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+    u8_t ttl, u8_t proto)\r
+{\r
+  struct netif *netif;\r
+  if ((netif = ip_route(dest)) == NULL) {\r
+    LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr));\r
+    IP_STATS_INC(ip.rterr);\r
+    return ERR_RTE;\r
+  }\r
+\r
+  return ip_output_if (p, src, dest, ttl, proto, netif);\r
+}\r
+\r
+#if IP_DEBUG\r
+void\r
+ip_debug_print(struct pbuf *p)\r
+{\r
+  struct ip_hdr *iphdr = p->payload;\r
+\r
+  LWIP_DEBUGF(IP_DEBUG, ("IP header:\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|%2"S16_F" |  %"X16_F"%"X16_F"  |      %"X16_F"%"X16_F"           | (v, traffic class, flow label)\n",\r
+        iphdr->v,\r
+        iphdr->tclass1, iphdr->tclass2,\r
+        iphdr->flow1, iphdr->flow2));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|    %5"U16_F"      | %2"U16_F"  |  %2"U16_F"   | (len, nexthdr, hoplim)\n",\r
+        ntohs(iphdr->len),\r
+        iphdr->nexthdr,\r
+        iphdr->hoplim));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",\r
+        (ntohl(iphdr->src.addr[0]) >> 16) & 0xffff,\r
+        ntohl(iphdr->src.addr[0]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",\r
+        (ntohl(iphdr->src.addr[1]) >> 16) & 0xffff,\r
+        ntohl(iphdr->src.addr[1]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",\r
+        (ntohl(iphdr->src.addr[2]) >> 16) & 0xffff,\r
+        ntohl(iphdr->src.addr[2]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (src)\n",\r
+        (ntohl(iphdr->src.addr[3]) >> 16) & 0xffff,\r
+        ntohl(iphdr->src.addr[3]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",\r
+        (ntohl(iphdr->dest.addr[0]) >> 16) & 0xffff,\r
+        ntohl(iphdr->dest.addr[0]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",\r
+        (ntohl(iphdr->dest.addr[1]) >> 16) & 0xffff,\r
+        ntohl(iphdr->dest.addr[1]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",\r
+        (ntohl(iphdr->dest.addr[2]) >> 16) & 0xffff,\r
+        ntohl(iphdr->dest.addr[2]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("|       %4"X32_F"      |       %4"X32_F"     | (dest)\n",\r
+        (ntohl(iphdr->dest.addr[3]) >> 16) & 0xffff,\r
+        ntohl(iphdr->dest.addr[3]) & 0xffff));\r
+  LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+#endif /* IP_DEBUG */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c b/Demo/Common/ethernet/lwIP_130/src/core/ipv6/ip6_addr.c
new file mode 100644 (file)
index 0000000..d898526
--- /dev/null
@@ -0,0 +1,72 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/inet.h"\r
+\r
+u8_t\r
+ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,\r
+                struct ip_addr *mask)\r
+{\r
+  return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&\r
+         (addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&\r
+         (addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&\r
+         (addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));\r
+        \r
+}\r
+\r
+u8_t\r
+ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)\r
+{\r
+  return(addr1->addr[0] == addr2->addr[0] &&\r
+         addr1->addr[1] == addr2->addr[1] &&\r
+         addr1->addr[2] == addr2->addr[2] &&\r
+         addr1->addr[3] == addr2->addr[3]);\r
+}\r
+\r
+void\r
+ip_addr_set(struct ip_addr *dest, struct ip_addr *src)\r
+{\r
+  SMEMCPY(dest, src, sizeof(struct ip_addr));\r
+  /*  dest->addr[0] = src->addr[0];\r
+  dest->addr[1] = src->addr[1];\r
+  dest->addr[2] = src->addr[2];\r
+  dest->addr[3] = src->addr[3];*/\r
+}\r
+\r
+u8_t\r
+ip_addr_isany(struct ip_addr *addr)\r
+{\r
+  if (addr == NULL) return 1;\r
+  return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/mem.c b/Demo/Common/ethernet/lwIP_130/src/core/mem.c
new file mode 100644 (file)
index 0000000..fbe3fa2
--- /dev/null
@@ -0,0 +1,577 @@
+/**\r
+ * @file\r
+ * Dynamic memory manager\r
+ *\r
+ * This is a lightweight replacement for the standard C library malloc().\r
+ *\r
+ * If you want to use the standard C library malloc() instead, define\r
+ * MEM_LIBC_MALLOC to 1 in your lwipopts.h\r
+ *\r
+ * To let mem_malloc() use pools (prevents fragmentation and is much faster than\r
+ * a heap but might waste some memory), define MEM_USE_POOLS to 1, define\r
+ * MEM_USE_CUSTOM_POOLS to 1 and create a file "lwippools.h" that includes a list\r
+ * of pools like this (more pools can be added between _START and _END):\r
+ *\r
+ * Define three pools with sizes 256, 512, and 1512 bytes\r
+ * LWIP_MALLOC_MEMPOOL_START\r
+ * LWIP_MALLOC_MEMPOOL(20, 256)\r
+ * LWIP_MALLOC_MEMPOOL(10, 512)\r
+ * LWIP_MALLOC_MEMPOOL(5, 1512)\r
+ * LWIP_MALLOC_MEMPOOL_END\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *         Simon Goldschmidt\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if !MEM_LIBC_MALLOC /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/stats.h"\r
+\r
+#include <string.h>\r
+\r
+#if MEM_USE_POOLS\r
+/* lwIP head implemented with different sized pools */\r
+\r
+/**\r
+ * This structure is used to save the pool one element came from.\r
+ */\r
+struct mem_helper\r
+{\r
+   memp_t poolnr;\r
+};\r
+\r
+/**\r
+ * Allocate memory: determine the smallest pool that is big enough\r
+ * to contain an element of 'size' and get an element from that pool.\r
+ *\r
+ * @param size the size in bytes of the memory needed\r
+ * @return a pointer to the allocated memory or NULL if the pool is empty\r
+ */\r
+void *\r
+mem_malloc(mem_size_t size)\r
+{\r
+  struct mem_helper *element;\r
+  memp_t poolnr;\r
+\r
+  for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) {\r
+    /* is this pool big enough to hold an element of the required size\r
+       plus a struct mem_helper that saves the pool this element came from? */\r
+    if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {\r
+      break;\r
+    }\r
+  }\r
+  if (poolnr > MEMP_POOL_LAST) {\r
+    LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);\r
+    return NULL;\r
+  }\r
+  element = (struct mem_helper*)memp_malloc(poolnr);\r
+  if (element == NULL) {\r
+    /* No need to DEBUGF or ASSERT: This error is already\r
+       taken care of in memp.c */\r
+    /** @todo: we could try a bigger pool if this one is empty! */\r
+    return NULL;\r
+  }\r
+\r
+  /* save the pool number this element came from */\r
+  element->poolnr = poolnr;\r
+  /* and return a pointer to the memory directly after the struct mem_helper */\r
+  element++;\r
+\r
+  return element;\r
+}\r
+\r
+/**\r
+ * Free memory previously allocated by mem_malloc. Loads the pool number\r
+ * and calls memp_free with that pool number to put the element back into\r
+ * its pool\r
+ *\r
+ * @param rmem the memory element to free\r
+ */\r
+void\r
+mem_free(void *rmem)\r
+{\r
+  struct mem_helper *hmem = (struct mem_helper*)rmem;\r
+\r
+  LWIP_ASSERT("rmem != NULL", (rmem != NULL));\r
+  LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));\r
+\r
+  /* get the original struct mem_helper */\r
+  hmem--;\r
+\r
+  LWIP_ASSERT("hmem != NULL", (hmem != NULL));\r
+  LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));\r
+  LWIP_ASSERT("hmem->poolnr < MEMP_MAX", (hmem->poolnr < MEMP_MAX));\r
+\r
+  /* and put it in the pool we saved earlier */\r
+  memp_free(hmem->poolnr, hmem);\r
+}\r
+\r
+#else /* MEM_USE_POOLS */\r
+/* lwIP replacement for your libc malloc() */\r
+\r
+/**\r
+ * The heap is made up as a list of structs of this type.\r
+ * This does not have to be aligned since for getting its size,\r
+ * we only use the macro SIZEOF_STRUCT_MEM, which automatically alignes.\r
+ */\r
+struct mem {\r
+  /** index (-> ram[next]) of the next struct */\r
+  mem_size_t next;\r
+  /** index (-> ram[next]) of the next struct */\r
+  mem_size_t prev;\r
+  /** 1: this area is used; 0: this area is unused */\r
+  u8_t used;\r
+};\r
+\r
+/** All allocated blocks will be MIN_SIZE bytes big, at least!\r
+ * MIN_SIZE can be overridden to suit your needs. Smaller values save space,\r
+ * larger values could prevent too small blocks to fragment the RAM too much. */\r
+#ifndef MIN_SIZE\r
+#define MIN_SIZE             12\r
+#endif /* MIN_SIZE */\r
+/* some alignment macros: we define them here for better source code layout */\r
+#define MIN_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MIN_SIZE)\r
+#define SIZEOF_STRUCT_MEM    LWIP_MEM_ALIGN_SIZE(sizeof(struct mem))\r
+#define MEM_SIZE_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEM_SIZE)\r
+\r
+/** the heap. we need one struct mem at the end and some room for alignment */\r
+static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];\r
+/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */\r
+static u8_t *ram;\r
+/** the last entry, always unused! */\r
+static struct mem *ram_end;\r
+/** pointer to the lowest free block, this is used for faster search */\r
+static struct mem *lfree;\r
+/** concurrent access protection */\r
+static sys_sem_t mem_sem;\r
+\r
+/**\r
+ * "Plug holes" by combining adjacent empty struct mems.\r
+ * After this function is through, there should not exist\r
+ * one empty struct mem pointing to another empty struct mem.\r
+ *\r
+ * @param mem this points to a struct mem which just has been freed\r
+ * @internal this function is only called by mem_free() and mem_realloc()\r
+ *\r
+ * This assumes access to the heap is protected by the calling function\r
+ * already.\r
+ */\r
+static void\r
+plug_holes(struct mem *mem)\r
+{\r
+  struct mem *nmem;\r
+  struct mem *pmem;\r
+\r
+  LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);\r
+  LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);\r
+  LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);\r
+\r
+  /* plug hole forward */\r
+  LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED);\r
+\r
+  nmem = (struct mem *)&ram[mem->next];\r
+  if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {\r
+    /* if mem->next is unused and not end of ram, combine mem and mem->next */\r
+    if (lfree == nmem) {\r
+      lfree = mem;\r
+    }\r
+    mem->next = nmem->next;\r
+    ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;\r
+  }\r
+\r
+  /* plug hole backward */\r
+  pmem = (struct mem *)&ram[mem->prev];\r
+  if (pmem != mem && pmem->used == 0) {\r
+    /* if mem->prev is unused, combine mem and mem->prev */\r
+    if (lfree == mem) {\r
+      lfree = pmem;\r
+    }\r
+    pmem->next = mem->next;\r
+    ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;\r
+  }\r
+}\r
+\r
+/**\r
+ * Zero the heap and initialize start, end and lowest-free\r
+ */\r
+void\r
+mem_init(void)\r
+{\r
+  struct mem *mem;\r
+\r
+  LWIP_ASSERT("Sanity check alignment",\r
+    (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0);\r
+\r
+  /* align the heap */\r
+  ram = LWIP_MEM_ALIGN(ram_heap);\r
+  /* initialize the start of the heap */\r
+  mem = (struct mem *)ram;\r
+  mem->next = MEM_SIZE_ALIGNED;\r
+  mem->prev = 0;\r
+  mem->used = 0;\r
+  /* initialize the end of the heap */\r
+  ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];\r
+  ram_end->used = 1;\r
+  ram_end->next = MEM_SIZE_ALIGNED;\r
+  ram_end->prev = MEM_SIZE_ALIGNED;\r
+\r
+  mem_sem = sys_sem_new(1);\r
+\r
+  /* initialize the lowest-free pointer to the start of the heap */\r
+  lfree = (struct mem *)ram;\r
+\r
+#if MEM_STATS\r
+  lwip_stats.mem.avail = MEM_SIZE_ALIGNED;\r
+#endif /* MEM_STATS */\r
+}\r
+\r
+/**\r
+ * Put a struct mem back on the heap\r
+ *\r
+ * @param rmem is the data portion of a struct mem as returned by a previous\r
+ *             call to mem_malloc()\r
+ */\r
+void\r
+mem_free(void *rmem)\r
+{\r
+  struct mem *mem;\r
+\r
+  if (rmem == NULL) {\r
+    LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));\r
+    return;\r
+  }\r
+  LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);\r
+\r
+  /* protect the heap from concurrent access */\r
+  sys_arch_sem_wait(mem_sem, 0);\r
+\r
+  LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&\r
+    (u8_t *)rmem < (u8_t *)ram_end);\r
+\r
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\r
+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));\r
+#if MEM_STATS\r
+    ++lwip_stats.mem.err;\r
+#endif /* MEM_STATS */\r
+    sys_sem_signal(mem_sem);\r
+    return;\r
+  }\r
+  /* Get the corresponding struct mem ... */\r
+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\r
+  /* ... which has to be in a used state ... */\r
+  LWIP_ASSERT("mem_free: mem->used", mem->used);\r
+  /* ... and is now unused. */\r
+  mem->used = 0;\r
+\r
+  if (mem < lfree) {\r
+    /* the newly freed struct is now the lowest */\r
+    lfree = mem;\r
+  }\r
+\r
+#if MEM_STATS\r
+  lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);\r
+#endif /* MEM_STATS */\r
+\r
+  /* finally, see if prev or next are free also */\r
+  plug_holes(mem);\r
+  sys_sem_signal(mem_sem);\r
+}\r
+\r
+/**\r
+ * In contrast to its name, mem_realloc can only shrink memory, not expand it.\r
+ * Since the only use (for now) is in pbuf_realloc (which also can only shrink),\r
+ * this shouldn't be a problem!\r
+ *\r
+ * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked\r
+ * @param newsize required size after shrinking (needs to be smaller than or\r
+ *                equal to the previous size)\r
+ * @return for compatibility reasons: is always == rmem, at the moment\r
+ */\r
+void *\r
+mem_realloc(void *rmem, mem_size_t newsize)\r
+{\r
+  mem_size_t size;\r
+  mem_size_t ptr, ptr2;\r
+  struct mem *mem, *mem2;\r
+\r
+  /* Expand the size of the allocated memory region so that we can\r
+     adjust for alignment. */\r
+  newsize = LWIP_MEM_ALIGN_SIZE(newsize);\r
+\r
+  if(newsize < MIN_SIZE_ALIGNED) {\r
+    /* every data block must be at least MIN_SIZE_ALIGNED long */\r
+    newsize = MIN_SIZE_ALIGNED;\r
+  }\r
+\r
+  if (newsize > MEM_SIZE_ALIGNED) {\r
+    return NULL;\r
+  }\r
+\r
+  LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&\r
+   (u8_t *)rmem < (u8_t *)ram_end);\r
+\r
+  if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {\r
+    LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));\r
+    return rmem;\r
+  }\r
+  /* Get the corresponding struct mem ... */\r
+  mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);\r
+  /* ... and its offset pointer */\r
+  ptr = (u8_t *)mem - ram;\r
+\r
+  size = mem->next - ptr - SIZEOF_STRUCT_MEM;\r
+  LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size);\r
+  if (newsize > size) {\r
+    /* not supported */\r
+    return NULL;\r
+  }\r
+  if (newsize == size) {\r
+    /* No change in size, simply return */\r
+    return rmem;\r
+  }\r
+\r
+  /* protect the heap from concurrent access */\r
+  sys_arch_sem_wait(mem_sem, 0);\r
+\r
+#if MEM_STATS\r
+  lwip_stats.mem.used -= (size - newsize);\r
+#endif /* MEM_STATS */\r
+\r
+  mem2 = (struct mem *)&ram[mem->next];\r
+  if(mem2->used == 0) {\r
+    /* The next struct is unused, we can simply move it at little */\r
+    mem_size_t next;\r
+    /* remember the old next pointer */\r
+    next = mem2->next;\r
+    /* create new struct mem which is moved directly after the shrinked mem */\r
+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;\r
+    if (lfree == mem2) {\r
+      lfree = (struct mem *)&ram[ptr2];\r
+    }\r
+    mem2 = (struct mem *)&ram[ptr2];\r
+    mem2->used = 0;\r
+    /* restore the next pointer */\r
+    mem2->next = next;\r
+    /* link it back to mem */\r
+    mem2->prev = ptr;\r
+    /* link mem to it */\r
+    mem->next = ptr2;\r
+    /* last thing to restore linked list: as we have moved mem2,\r
+     * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not\r
+     * the end of the heap */\r
+    if (mem2->next != MEM_SIZE_ALIGNED) {\r
+      ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+    }\r
+    /* no need to plug holes, we've already done that */\r
+  } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {\r
+    /* Next struct is used but there's room for another struct mem with\r
+     * at least MIN_SIZE_ALIGNED of data.\r
+     * Old size ('size') must be big enough to contain at least 'newsize' plus a struct mem\r
+     * ('SIZEOF_STRUCT_MEM') with some data ('MIN_SIZE_ALIGNED').\r
+     * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty\r
+     *       region that couldn't hold data, but when mem->next gets freed,\r
+     *       the 2 regions would be combined, resulting in more free memory */\r
+    ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;\r
+    mem2 = (struct mem *)&ram[ptr2];\r
+    if (mem2 < lfree) {\r
+      lfree = mem2;\r
+    }\r
+    mem2->used = 0;\r
+    mem2->next = mem->next;\r
+    mem2->prev = ptr;\r
+    mem->next = ptr2;\r
+    if (mem2->next != MEM_SIZE_ALIGNED) {\r
+      ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+    }\r
+    /* the original mem->next is used, so no need to plug holes! */\r
+  }\r
+  /* else {\r
+    next struct mem is used but size between mem and mem2 is not big enough\r
+    to create another struct mem\r
+    -> don't do anyhting.\r
+    -> the remaining space stays unused since it is too small\r
+  } */\r
+  sys_sem_signal(mem_sem);\r
+  return rmem;\r
+}\r
+\r
+/**\r
+ * Adam's mem_malloc() plus solution for bug #17922\r
+ * Allocate a block of memory with a minimum of 'size' bytes.\r
+ *\r
+ * @param size is the minimum size of the requested block in bytes.\r
+ * @return pointer to allocated memory or NULL if no free memory was found.\r
+ *\r
+ * Note that the returned value will always be aligned (as defined by MEM_ALIGNMENT).\r
+ */\r
+void *\r
+mem_malloc(mem_size_t size)\r
+{\r
+  mem_size_t ptr, ptr2;\r
+  struct mem *mem, *mem2;\r
+\r
+  if (size == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  /* Expand the size of the allocated memory region so that we can\r
+     adjust for alignment. */\r
+  size = LWIP_MEM_ALIGN_SIZE(size);\r
+\r
+  if(size < MIN_SIZE_ALIGNED) {\r
+    /* every data block must be at least MIN_SIZE_ALIGNED long */\r
+    size = MIN_SIZE_ALIGNED;\r
+  }\r
+\r
+  if (size > MEM_SIZE_ALIGNED) {\r
+    return NULL;\r
+  }\r
+\r
+  /* protect the heap from concurrent access */\r
+  sys_arch_sem_wait(mem_sem, 0);\r
+\r
+  /* Scan through the heap searching for a free block that is big enough,\r
+   * beginning with the lowest free block.\r
+   */\r
+  for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;\r
+       ptr = ((struct mem *)&ram[ptr])->next) {\r
+    mem = (struct mem *)&ram[ptr];\r
+\r
+    if ((!mem->used) &&\r
+        (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {\r
+      /* mem is not used and at least perfect fit is possible:\r
+       * mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */\r
+\r
+      if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {\r
+        /* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing\r
+         * at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')\r
+         * -> split large block, create empty remainder,\r
+         * remainder must be large enough to contain MIN_SIZE_ALIGNED data: if\r
+         * mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,\r
+         * struct mem would fit in but no data between mem2 and mem2->next\r
+         * @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty\r
+         *       region that couldn't hold data, but when mem->next gets freed,\r
+         *       the 2 regions would be combined, resulting in more free memory\r
+         */\r
+        ptr2 = ptr + SIZEOF_STRUCT_MEM + size;\r
+        /* create mem2 struct */\r
+        mem2 = (struct mem *)&ram[ptr2];\r
+        mem2->used = 0;\r
+        mem2->next = mem->next;\r
+        mem2->prev = ptr;\r
+        /* and insert it between mem and mem->next */\r
+        mem->next = ptr2;\r
+        mem->used = 1;\r
+\r
+        if (mem2->next != MEM_SIZE_ALIGNED) {\r
+          ((struct mem *)&ram[mem2->next])->prev = ptr2;\r
+        }\r
+#if MEM_STATS\r
+        lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);\r
+        if (lwip_stats.mem.max < lwip_stats.mem.used) {\r
+          lwip_stats.mem.max = lwip_stats.mem.used;\r
+        }\r
+#endif /* MEM_STATS */\r
+      } else {\r
+        /* (a mem2 struct does no fit into the user data space of mem and mem->next will always\r
+         * be used at this point: if not we have 2 unused structs in a row, plug_holes should have\r
+         * take care of this).\r
+         * -> near fit or excact fit: do not split, no mem2 creation\r
+         * also can't move mem->next directly behind mem, since mem->next\r
+         * will always be used at this point!\r
+         */\r
+        mem->used = 1;\r
+#if MEM_STATS\r
+        lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram);\r
+        if (lwip_stats.mem.max < lwip_stats.mem.used) {\r
+          lwip_stats.mem.max = lwip_stats.mem.used;\r
+        }\r
+#endif /* MEM_STATS */\r
+      }\r
+\r
+      if (mem == lfree) {\r
+        /* Find next free block after mem and update lowest free pointer */\r
+        while (lfree->used && lfree != ram_end) {\r
+          lfree = (struct mem *)&ram[lfree->next];\r
+        }\r
+        LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));\r
+      }\r
+      sys_sem_signal(mem_sem);\r
+      LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",\r
+       (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);\r
+      LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",\r
+       (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);\r
+      LWIP_ASSERT("mem_malloc: sanity check alignment",\r
+        (((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);\r
+\r
+      return (u8_t *)mem + SIZEOF_STRUCT_MEM;\r
+    }\r
+  }\r
+  LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));\r
+#if MEM_STATS\r
+  ++lwip_stats.mem.err;\r
+#endif /* MEM_STATS */\r
+  sys_sem_signal(mem_sem);\r
+  return NULL;\r
+}\r
+\r
+#endif /* MEM_USE_POOLS */\r
+/**\r
+ * Contiguously allocates enough space for count objects that are size bytes\r
+ * of memory each and returns a pointer to the allocated memory.\r
+ *\r
+ * The allocated memory is filled with bytes of value zero.\r
+ *\r
+ * @param count number of objects to allocate\r
+ * @param size size of the objects to allocate\r
+ * @return pointer to allocated memory / NULL pointer if there is an error\r
+ */\r
+void *mem_calloc(mem_size_t count, mem_size_t size)\r
+{\r
+  void *p;\r
+\r
+  /* allocate 'count' objects of size 'size' */\r
+  p = mem_malloc(count * size);\r
+  if (p) {\r
+    /* zero the memory */\r
+    memset(p, 0, count * size);\r
+  }\r
+  return p;\r
+}\r
+\r
+#endif /* !MEM_LIBC_MALLOC */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/memp.c b/Demo/Common/ethernet/lwIP_130/src/core/memp.c
new file mode 100644 (file)
index 0000000..d43e479
--- /dev/null
@@ -0,0 +1,380 @@
+/**\r
+ * @file\r
+ * Dynamic pool memory manager\r
+ *\r
+ * lwIP has dedicated pools for many structures (netconn, protocol control blocks,\r
+ * packet buffers, ...). All these pools are managed here.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/api.h"\r
+#include "lwip/api_msg.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/stats.h"\r
+#include "netif/etharp.h"\r
+#include "lwip/ip_frag.h"\r
+\r
+#include <string.h>\r
+\r
+struct memp {\r
+  struct memp *next;\r
+#if MEMP_OVERFLOW_CHECK\r
+  const char *file;\r
+  int line;\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+};\r
+\r
+#if MEMP_OVERFLOW_CHECK\r
+/* if MEMP_OVERFLOW_CHECK is turned on, we reserve some bytes at the beginning\r
+ * and at the end of each element, initialize them as 0xcd and check\r
+ * them later. */\r
+/* If MEMP_OVERFLOW_CHECK is >= 2, on every call to memp_malloc or memp_free,\r
+ * every single element in each pool is checked!\r
+ * This is VERY SLOW but also very helpful. */\r
+/* MEMP_SANITY_REGION_BEFORE and MEMP_SANITY_REGION_AFTER can be overridden in\r
+ * lwipopts.h to change the amount reserved for checking. */\r
+#ifndef MEMP_SANITY_REGION_BEFORE\r
+#define MEMP_SANITY_REGION_BEFORE  16\r
+#endif /* MEMP_SANITY_REGION_BEFORE*/\r
+#if MEMP_SANITY_REGION_BEFORE > 0\r
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_BEFORE)\r
+#else\r
+#define MEMP_SANITY_REGION_BEFORE_ALIGNED    0\r
+#endif /* MEMP_SANITY_REGION_BEFORE*/\r
+#ifndef MEMP_SANITY_REGION_AFTER\r
+#define MEMP_SANITY_REGION_AFTER   16\r
+#endif /* MEMP_SANITY_REGION_AFTER*/\r
+#if MEMP_SANITY_REGION_AFTER > 0\r
+#define MEMP_SANITY_REGION_AFTER_ALIGNED     LWIP_MEM_ALIGN_SIZE(MEMP_SANITY_REGION_AFTER)\r
+#else\r
+#define MEMP_SANITY_REGION_AFTER_ALIGNED     0\r
+#endif /* MEMP_SANITY_REGION_AFTER*/\r
+\r
+/* MEMP_SIZE: save space for struct memp and for sanity check */\r
+#define MEMP_SIZE          (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEMP_SANITY_REGION_BEFORE_ALIGNED)\r
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x) + MEMP_SANITY_REGION_AFTER_ALIGNED)\r
+\r
+#else /* MEMP_OVERFLOW_CHECK */\r
+\r
+/* No sanity checks\r
+ * We don't need to preserve the struct memp while not allocated, so we\r
+ * can save a little space and set MEMP_SIZE to 0.\r
+ */\r
+#define MEMP_SIZE           0\r
+#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))\r
+\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+\r
+/** This array holds the first free element of each pool.\r
+ *  Elements form a linked list. */\r
+static struct memp *memp_tab[MEMP_MAX];\r
+\r
+/** This array holds the element sizes of each pool. */\r
+#if !MEM_USE_POOLS\r
+static\r
+#endif\r
+const u16_t memp_sizes[MEMP_MAX] = {\r
+#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_ALIGN_SIZE(size),\r
+#include "lwip/memp_std.h"\r
+};\r
+\r
+/** This array holds the number of elements in each pool. */\r
+static const u16_t memp_num[MEMP_MAX] = {\r
+#define LWIP_MEMPOOL(name,num,size,desc)  (num),\r
+#include "lwip/memp_std.h"\r
+};\r
+\r
+/** This array holds a textual description of each pool. */\r
+#ifdef LWIP_DEBUG\r
+static const char *memp_desc[MEMP_MAX] = {\r
+#define LWIP_MEMPOOL(name,num,size,desc)  (desc),\r
+#include "lwip/memp_std.h"\r
+};\r
+#endif /* LWIP_DEBUG */\r
+\r
+/** This is the actual memory used by the pools. */\r
+static u8_t memp_memory[MEM_ALIGNMENT - 1\r
+#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )\r
+#include "lwip/memp_std.h"\r
+];\r
+\r
+#if MEMP_SANITY_CHECK\r
+/**\r
+ * Check that memp-lists don't form a circle\r
+ */\r
+static int\r
+memp_sanity(void)\r
+{\r
+  s16_t i, c;\r
+  struct memp *m, *n;\r
+\r
+  for (i = 0; i < MEMP_MAX; i++) {\r
+    for (m = memp_tab[i]; m != NULL; m = m->next) {\r
+      c = 1;\r
+      for (n = memp_tab[i]; n != NULL; n = n->next) {\r
+        if (n == m && --c < 0) {\r
+          return 0;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  return 1;\r
+}\r
+#endif /* MEMP_SANITY_CHECK*/\r
+#if MEMP_OVERFLOW_CHECK\r
+/**\r
+ * Check if a memp element was victim of an overflow\r
+ * (e.g. the restricted area after it has been altered)\r
+ *\r
+ * @param p the memp element to check\r
+ * @param memp_size the element size of the pool p comes from\r
+ */\r
+static void\r
+memp_overflow_check_element(struct memp *p, u16_t memp_size)\r
+{\r
+  u16_t k;\r
+  u8_t *m;\r
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0\r
+  m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;\r
+  for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {\r
+    if (m[k] != 0xcd) {\r
+      LWIP_ASSERT("detected memp underflow!", 0);\r
+    }\r
+  }\r
+#endif\r
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0\r
+  m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED;\r
+  for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {\r
+    if (m[k] != 0xcd) {\r
+      LWIP_ASSERT("detected memp overflow!", 0);\r
+    }\r
+  }\r
+#endif\r
+}\r
+\r
+/**\r
+ * Do an overflow check for all elements in every pool.\r
+ *\r
+ * @see memp_overflow_check_element for a description of the check\r
+ */\r
+static void\r
+memp_overflow_check_all(void)\r
+{\r
+  u16_t i, j;\r
+  struct memp *p;\r
+\r
+  p = LWIP_MEM_ALIGN(memp_memory);\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    p = p;\r
+    for (j = 0; j < memp_num[i]; ++j) {\r
+      memp_overflow_check_element(p, memp_sizes[i]);\r
+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Initialize the restricted areas of all memp elements in every pool.\r
+ */\r
+static void\r
+memp_overflow_init(void)\r
+{\r
+  u16_t i, j;\r
+  struct memp *p;\r
+  u8_t *m;\r
+\r
+  p = LWIP_MEM_ALIGN(memp_memory);\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    p = p;\r
+    for (j = 0; j < memp_num[i]; ++j) {\r
+#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0\r
+      m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;\r
+      memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);\r
+#endif\r
+#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0\r
+      m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER_ALIGNED;\r
+      memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);\r
+#endif\r
+      p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);\r
+    }\r
+  }\r
+}\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+\r
+/**\r
+ * Initialize this module.\r
+ *\r
+ * Carves out memp_memory into linked lists for each pool-type.\r
+ */\r
+void\r
+memp_init(void)\r
+{\r
+  struct memp *memp;\r
+  u16_t i, j;\r
+\r
+#if MEMP_STATS\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    lwip_stats.memp[i].used = lwip_stats.memp[i].max =\r
+      lwip_stats.memp[i].err = 0;\r
+    lwip_stats.memp[i].avail = memp_num[i];\r
+  }\r
+#endif /* MEMP_STATS */\r
+\r
+  memp = LWIP_MEM_ALIGN(memp_memory);\r
+  /* for every pool: */\r
+  for (i = 0; i < MEMP_MAX; ++i) {\r
+    memp_tab[i] = NULL;\r
+    /* create a linked list of memp elements */\r
+    for (j = 0; j < memp_num[i]; ++j) {\r
+      memp->next = memp_tab[i];\r
+      memp_tab[i] = memp;\r
+      memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]);\r
+    }\r
+  }\r
+#if MEMP_OVERFLOW_CHECK\r
+  memp_overflow_init();\r
+  /* check everything a first time to see if it worked */\r
+  memp_overflow_check_all();\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+}\r
+\r
+/**\r
+ * Get an element from a specific pool.\r
+ *\r
+ * @param type the pool to get an element from\r
+ *\r
+ * the debug version has two more parameters:\r
+ * @param file file name calling this function\r
+ * @param line number of line where this function is called\r
+ *\r
+ * @return a pointer to the allocated memory or a NULL pointer on error\r
+ */\r
+void *\r
+#if !MEMP_OVERFLOW_CHECK\r
+memp_malloc(memp_t type)\r
+#else\r
+memp_malloc_fn(memp_t type, const char* file, const int line)\r
+#endif\r
+{\r
+  struct memp *memp;\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+\r
+  LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);\r
+\r
+  SYS_ARCH_PROTECT(old_level);\r
+#if MEMP_OVERFLOW_CHECK >= 2\r
+  memp_overflow_check_all();\r
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */\r
+\r
+  memp = memp_tab[type];\r
+\r
+  if (memp != NULL) {\r
+    memp_tab[type] = memp->next;\r
+#if MEMP_OVERFLOW_CHECK\r
+    memp->next = NULL;\r
+    memp->file = file;\r
+    memp->line = line;\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+#if MEMP_STATS\r
+    ++lwip_stats.memp[type].used;\r
+    if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {\r
+      lwip_stats.memp[type].max = lwip_stats.memp[type].used;\r
+    }\r
+#endif /* MEMP_STATS */\r
+    LWIP_ASSERT("memp_malloc: memp properly aligned",\r
+                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);\r
+    memp = (struct memp*)((u8_t*)memp + MEMP_SIZE);\r
+  } else {\r
+    LWIP_DEBUGF(MEMP_DEBUG | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));\r
+#if MEMP_STATS\r
+    ++lwip_stats.memp[type].err;\r
+#endif /* MEMP_STATS */\r
+  }\r
+\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+\r
+  return memp;\r
+}\r
+\r
+/**\r
+ * Put an element back into its pool.\r
+ *\r
+ * @param type the pool where to put mem\r
+ * @param mem the memp element to free\r
+ */\r
+void\r
+memp_free(memp_t type, void *mem)\r
+{\r
+  struct memp *memp;\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+\r
+  if (mem == NULL) {\r
+    return;\r
+  }\r
+  LWIP_ASSERT("memp_free: mem properly aligned",\r
+                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);\r
+\r
+  memp = (struct memp *)((u8_t*)mem - MEMP_SIZE);\r
+\r
+  SYS_ARCH_PROTECT(old_level);\r
+#if MEMP_OVERFLOW_CHECK\r
+#if MEMP_OVERFLOW_CHECK >= 2\r
+  memp_overflow_check_all();\r
+#else\r
+  memp_overflow_check_element(memp, memp_sizes[type]);\r
+#endif /* MEMP_OVERFLOW_CHECK >= 2 */\r
+#endif /* MEMP_OVERFLOW_CHECK */\r
+\r
+#if MEMP_STATS\r
+  lwip_stats.memp[type].used--;\r
+#endif /* MEMP_STATS */\r
+\r
+  memp->next = memp_tab[type];\r
+  memp_tab[type] = memp;\r
+\r
+#if MEMP_SANITY_CHECK\r
+  LWIP_ASSERT("memp sanity", memp_sanity());\r
+#endif /* MEMP_SANITY_CHECK */\r
+\r
+  SYS_ARCH_UNPROTECT(old_level);\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/netif.c b/Demo/Common/ethernet/lwIP_130/src/core/netif.c
new file mode 100644 (file)
index 0000000..362c6ae
--- /dev/null
@@ -0,0 +1,499 @@
+/**\r
+ * @file\r
+ * lwIP network interface abstraction\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/igmp.h"\r
+#include "netif/etharp.h"\r
+\r
+#if LWIP_NETIF_STATUS_CALLBACK\r
+#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); }\r
+#else\r
+#define NETIF_STATUS_CALLBACK(n) { /* NOP */ }\r
+#endif /* LWIP_NETIF_STATUS_CALLBACK */\r
+\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); }\r
+#else\r
+#define NETIF_LINK_CALLBACK(n) { /* NOP */ }\r
+#endif /* LWIP_NETIF_LINK_CALLBACK */\r
+\r
+struct netif *netif_list;\r
+struct netif *netif_default;\r
+\r
+/**\r
+ * Add a network interface to the list of lwIP netifs.\r
+ *\r
+ * @param netif a pre-allocated netif structure\r
+ * @param ipaddr IP address for the new netif\r
+ * @param netmask network mask for the new netif\r
+ * @param gw default gateway IP address for the new netif\r
+ * @param state opaque data passed to the new netif\r
+ * @param init callback function that initializes the interface\r
+ * @param input callback function that is called to pass\r
+ * ingress packets up in the protocol layer stack.\r
+ *\r
+ * @return netif, or NULL if failed.\r
+ */\r
+struct netif *\r
+netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+  struct ip_addr *gw,\r
+  void *state,\r
+  err_t (* init)(struct netif *netif),\r
+  err_t (* input)(struct pbuf *p, struct netif *netif))\r
+{\r
+  static u8_t netifnum = 0;\r
+\r
+  /* reset new interface configuration state */\r
+  netif->ip_addr.addr = 0;\r
+  netif->netmask.addr = 0;\r
+  netif->gw.addr = 0;\r
+  netif->flags = 0;\r
+#if LWIP_DHCP\r
+  /* netif not under DHCP control by default */\r
+  netif->dhcp = NULL;\r
+#endif /* LWIP_DHCP */\r
+#if LWIP_AUTOIP\r
+  /* netif not under AutoIP control by default */\r
+  netif->autoip = NULL;\r
+#endif /* LWIP_AUTOIP */\r
+#if LWIP_NETIF_STATUS_CALLBACK\r
+  netif->status_callback = NULL;\r
+#endif /* LWIP_NETIF_STATUS_CALLBACK */\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+  netif->link_callback = NULL;\r
+#endif /* LWIP_NETIF_LINK_CALLBACK */\r
+#if LWIP_IGMP\r
+  netif->igmp_mac_filter = NULL;\r
+#endif /* LWIP_IGMP */\r
+\r
+  /* remember netif specific state information data */\r
+  netif->state = state;\r
+  netif->num = netifnum++;\r
+  netif->input = input;\r
+#if LWIP_NETIF_HWADDRHINT\r
+  netif->addr_hint = NULL;\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+\r
+  netif_set_addr(netif, ipaddr, netmask, gw);\r
+\r
+  /* call user specified initialization function for netif */\r
+  if (init(netif) != ERR_OK) {\r
+    return NULL;\r
+  }\r
+\r
+  /* add this netif to the list */\r
+  netif->next = netif_list;\r
+  netif_list = netif;\r
+  snmp_inc_iflist();\r
+\r
+#if LWIP_IGMP\r
+  /* start IGMP processing */\r
+  if (netif->flags & NETIF_FLAG_IGMP) {\r
+    igmp_start( netif);\r
+  }\r
+#endif /* LWIP_IGMP */\r
+\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: added interface %c%c IP addr ",\r
+    netif->name[0], netif->name[1]));\r
+  ip_addr_debug_print(NETIF_DEBUG, ipaddr);\r
+  LWIP_DEBUGF(NETIF_DEBUG, (" netmask "));\r
+  ip_addr_debug_print(NETIF_DEBUG, netmask);\r
+  LWIP_DEBUGF(NETIF_DEBUG, (" gw "));\r
+  ip_addr_debug_print(NETIF_DEBUG, gw);\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("\n"));\r
+  return netif;\r
+}\r
+\r
+/**\r
+ * Change IP address configuration for a network interface (including netmask\r
+ * and default gateway).\r
+ *\r
+ * @param netif the network interface to change\r
+ * @param ipaddr the new IP address\r
+ * @param netmask the new netmask\r
+ * @param gw the new default gateway\r
+ */\r
+void\r
+netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+    struct ip_addr *gw)\r
+{\r
+  netif_set_ipaddr(netif, ipaddr);\r
+  netif_set_netmask(netif, netmask);\r
+  netif_set_gw(netif, gw);\r
+}\r
+\r
+/**\r
+ * Remove a network interface from the list of lwIP netifs.\r
+ *\r
+ * @param netif the network interface to remove\r
+ */\r
+void netif_remove(struct netif * netif)\r
+{\r
+  if ( netif == NULL ) return;\r
+\r
+#if LWIP_IGMP\r
+  /* stop IGMP processing */\r
+  if (netif->flags & NETIF_FLAG_IGMP) {\r
+    igmp_stop( netif);\r
+  }\r
+#endif /* LWIP_IGMP */\r
+\r
+  snmp_delete_ipaddridx_tree(netif);\r
+\r
+  /*  is it the first netif? */\r
+  if (netif_list == netif) {\r
+    netif_list = netif->next;\r
+    snmp_dec_iflist();\r
+  }\r
+  else {\r
+    /*  look for netif further down the list */\r
+    struct netif * tmpNetif;\r
+    for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) {\r
+      if (tmpNetif->next == netif) {\r
+        tmpNetif->next = netif->next;\r
+        snmp_dec_iflist();\r
+        break;\r
+      }\r
+    }\r
+    if (tmpNetif == NULL)\r
+      return; /*  we didn't find any netif today */\r
+  }\r
+  /* this netif is default? */\r
+  if (netif_default == netif)\r
+    /* reset default netif */\r
+    netif_set_default(NULL);\r
+  LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") );\r
+}\r
+\r
+/**\r
+ * Find a network interface by searching for its name\r
+ *\r
+ * @param name the name of the netif (like netif->name) plus concatenated number\r
+ * in ascii representation (e.g. 'en0')\r
+ */\r
+struct netif *\r
+netif_find(char *name)\r
+{\r
+  struct netif *netif;\r
+  u8_t num;\r
+\r
+  if (name == NULL) {\r
+    return NULL;\r
+  }\r
+\r
+  num = name[2] - '0';\r
+\r
+  for(netif = netif_list; netif != NULL; netif = netif->next) {\r
+    if (num == netif->num &&\r
+       name[0] == netif->name[0] &&\r
+       name[1] == netif->name[1]) {\r
+      LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: found %c%c\n", name[0], name[1]));\r
+      return netif;\r
+    }\r
+  }\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif_find: didn't find %c%c\n", name[0], name[1]));\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Change the IP address of a network interface\r
+ *\r
+ * @param netif the network interface to change\r
+ * @param ipaddr the new IP address\r
+ *\r
+ * @note call netif_set_addr() if you also want to change netmask and\r
+ * default gateway\r
+ */\r
+void\r
+netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)\r
+{\r
+  /* TODO: Handling of obsolete pcbs */\r
+  /* See:  http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */\r
+#if LWIP_TCP\r
+  struct tcp_pcb *pcb;\r
+  struct tcp_pcb_listen *lpcb;\r
+\r
+  /* address is actually being changed? */\r
+  if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0)\r
+  {\r
+    /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */\r
+    LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: netif address being changed\n"));\r
+    pcb = tcp_active_pcbs;\r
+    while (pcb != NULL) {\r
+      /* PCB bound to current local interface address? */\r
+      if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {\r
+        /* this connection must be aborted */\r
+        struct tcp_pcb *next = pcb->next;\r
+        LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));\r
+        tcp_abort(pcb);\r
+        pcb = next;\r
+      } else {\r
+        pcb = pcb->next;\r
+      }\r
+    }\r
+    for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\r
+      /* PCB bound to current local interface address? */\r
+      if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&\r
+          (ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {\r
+        /* The PCB is listening to the old ipaddr and\r
+         * is set to listen to the new one instead */\r
+        ip_addr_set(&(lpcb->local_ip), ipaddr);\r
+      }\r
+    }\r
+  }\r
+#endif\r
+  snmp_delete_ipaddridx_tree(netif);\r
+  snmp_delete_iprteidx_tree(0,netif);\r
+  /* set new IP address to netif */\r
+  ip_addr_set(&(netif->ip_addr), ipaddr);\r
+  snmp_insert_ipaddridx_tree(netif);\r
+  snmp_insert_iprteidx_tree(0,netif);\r
+\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->ip_addr),\r
+    ip4_addr2(&netif->ip_addr),\r
+    ip4_addr3(&netif->ip_addr),\r
+    ip4_addr4(&netif->ip_addr)));\r
+}\r
+\r
+/**\r
+ * Change the default gateway for a network interface\r
+ *\r
+ * @param netif the network interface to change\r
+ * @param gw the new default gateway\r
+ *\r
+ * @note call netif_set_addr() if you also want to change ip address and netmask\r
+ */\r
+void\r
+netif_set_gw(struct netif *netif, struct ip_addr *gw)\r
+{\r
+  ip_addr_set(&(netif->gw), gw);\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->gw),\r
+    ip4_addr2(&netif->gw),\r
+    ip4_addr3(&netif->gw),\r
+    ip4_addr4(&netif->gw)));\r
+}\r
+\r
+/**\r
+ * Change the netmask of a network interface\r
+ *\r
+ * @param netif the network interface to change\r
+ * @param netmask the new netmask\r
+ *\r
+ * @note call netif_set_addr() if you also want to change ip address and\r
+ * default gateway\r
+ */\r
+void\r
+netif_set_netmask(struct netif *netif, struct ip_addr *netmask)\r
+{\r
+  snmp_delete_iprteidx_tree(0, netif);\r
+  /* set new netmask to netif */\r
+  ip_addr_set(&(netif->netmask), netmask);\r
+  snmp_insert_iprteidx_tree(0, netif);\r
+  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",\r
+    netif->name[0], netif->name[1],\r
+    ip4_addr1(&netif->netmask),\r
+    ip4_addr2(&netif->netmask),\r
+    ip4_addr3(&netif->netmask),\r
+    ip4_addr4(&netif->netmask)));\r
+}\r
+\r
+/**\r
+ * Set a network interface as the default network interface\r
+ * (used to output all packets for which no specific route is found)\r
+ *\r
+ * @param netif the default network interface\r
+ */\r
+void\r
+netif_set_default(struct netif *netif)\r
+{\r
+  if (netif == NULL)\r
+  {\r
+    /* remove default route */\r
+    snmp_delete_iprteidx_tree(1, netif);\r
+  }\r
+  else\r
+  {\r
+    /* install default route */\r
+    snmp_insert_iprteidx_tree(1, netif);\r
+  }\r
+  netif_default = netif;\r
+  LWIP_DEBUGF(NETIF_DEBUG, ("netif: setting default interface %c%c\n",\r
+           netif ? netif->name[0] : '\'', netif ? netif->name[1] : '\''));\r
+}\r
+\r
+/**\r
+ * Bring an interface up, available for processing\r
+ * traffic.\r
+ *\r
+ * @note: Enabling DHCP on a down interface will make it come\r
+ * up once configured.\r
+ *\r
+ * @see dhcp_start()\r
+ */\r
+void netif_set_up(struct netif *netif)\r
+{\r
+  if ( !(netif->flags & NETIF_FLAG_UP )) {\r
+    netif->flags |= NETIF_FLAG_UP;\r
+\r
+#if LWIP_SNMP\r
+    snmp_get_sysuptime(&netif->ts);\r
+#endif /* LWIP_SNMP */\r
+\r
+    NETIF_LINK_CALLBACK(netif);\r
+    NETIF_STATUS_CALLBACK(netif);\r
+\r
+#if LWIP_ARP\r
+    /** For Ethernet network interfaces, we would like to send a\r
+     *  "gratuitous ARP"; this is an ARP packet sent by a node in order\r
+     *  to spontaneously cause other nodes to update an entry in their\r
+     *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.\r
+     */\r
+    if (netif->flags & NETIF_FLAG_ETHARP) {\r
+      etharp_query(netif, &(netif->ip_addr), NULL);\r
+    }\r
+#endif /* LWIP_ARP */\r
+\r
+  }\r
+}\r
+\r
+/**\r
+ * Bring an interface down, disabling any traffic processing.\r
+ *\r
+ * @note: Enabling DHCP on a down interface will make it come\r
+ * up once configured.\r
+ *\r
+ * @see dhcp_start()\r
+ */\r
+void netif_set_down(struct netif *netif)\r
+{\r
+  if ( netif->flags & NETIF_FLAG_UP )\r
+    {\r
+      netif->flags &= ~NETIF_FLAG_UP;\r
+#if LWIP_SNMP\r
+      snmp_get_sysuptime(&netif->ts);\r
+#endif\r
+\r
+      NETIF_LINK_CALLBACK(netif);\r
+      NETIF_STATUS_CALLBACK(netif);\r
+    }\r
+}\r
+\r
+/**\r
+ * Ask if an interface is up\r
+ */\r
+u8_t netif_is_up(struct netif *netif)\r
+{\r
+  return (netif->flags & NETIF_FLAG_UP)?1:0;\r
+}\r
+\r
+#if LWIP_NETIF_STATUS_CALLBACK\r
+/**\r
+ * Set callback to be called when interface is brought up/down\r
+ */\r
+void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif ))\r
+{\r
+    if ( netif )\r
+        netif->status_callback = status_callback;\r
+}\r
+#endif /* LWIP_NETIF_STATUS_CALLBACK */\r
+\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+/**\r
+ * Called by a driver when its link goes up\r
+ */\r
+void netif_set_link_up(struct netif *netif )\r
+{\r
+  netif->flags |= NETIF_FLAG_LINK_UP;\r
+\r
+#if LWIP_ARP\r
+  /** For Ethernet network interfaces, we would like to send a\r
+   *  "gratuitous ARP"; this is an ARP packet sent by a node in order\r
+   *  to spontaneously cause other nodes to update an entry in their\r
+   *  ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.\r
+   */\r
+  if (netif->flags & NETIF_FLAG_ETHARP) {\r
+    etharp_query(netif, &(netif->ip_addr), NULL);\r
+  }\r
+#endif /* LWIP_ARP */\r
+\r
+#if LWIP_IGMP\r
+  /* resend IGMP memberships */\r
+  if (netif->flags & NETIF_FLAG_IGMP) {\r
+    igmp_report_groups( netif);\r
+  }\r
+#endif /* LWIP_IGMP */\r
+\r
+  NETIF_LINK_CALLBACK(netif);\r
+}\r
+\r
+/**\r
+ * Called by a driver when its link goes down\r
+ */\r
+void netif_set_link_down(struct netif *netif )\r
+{\r
+  netif->flags &= ~NETIF_FLAG_LINK_UP;\r
+  NETIF_LINK_CALLBACK(netif);\r
+}\r
+\r
+/**\r
+ * Ask if a link is up\r
+ */\r
+u8_t netif_is_link_up(struct netif *netif)\r
+{\r
+  return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0;\r
+}\r
+\r
+/**\r
+ * Set callback to be called when link is brought up/down\r
+ */\r
+void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif ))\r
+{\r
+    if ( netif )\r
+        netif->link_callback = link_callback;\r
+}\r
+#endif /* LWIP_NETIF_LINK_CALLBACK */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/pbuf.c b/Demo/Common/ethernet/lwIP_130/src/core/pbuf.c
new file mode 100644 (file)
index 0000000..ecd5e16
--- /dev/null
@@ -0,0 +1,777 @@
+/**\r
+ * @file\r
+ * Packet buffer management\r
+ *\r
+ * Packets are built from the pbuf data structure. It supports dynamic\r
+ * memory allocation for packet contents or can reference externally\r
+ * managed packet contents both in RAM and ROM. Quick allocation for\r
+ * incoming packets is provided through pools with fixed sized pbufs.\r
+ *\r
+ * A packet may span over multiple pbufs, chained as a singly linked\r
+ * list. This is called a "pbuf chain".\r
+ *\r
+ * Multiple packets may be queued, also using this singly linked list.\r
+ * This is called a "packet queue".\r
+ *\r
+ * So, a packet queue consists of one or more pbuf chains, each of\r
+ * which consist of one or more pbufs. CURRENTLY, PACKET QUEUES ARE\r
+ * NOT SUPPORTED!!! Use helper structs to queue multiple packets.\r
+ *\r
+ * The differences between a pbuf chain and a packet queue are very\r
+ * precise but subtle.\r
+ *\r
+ * The last pbuf of a packet has a ->tot_len field that equals the\r
+ * ->len field. It can be found by traversing the list. If the last\r
+ * pbuf of a packet has a ->next field other than NULL, more packets\r
+ * are on the queue.\r
+ *\r
+ * Therefore, looping through a pbuf of a single packet, has an\r
+ * loop end condition (tot_len == p->len), NOT (next == NULL).\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/stats.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include "arch/perf.h"\r
+\r
+#include <string.h>\r
+\r
+#define SIZEOF_STRUCT_PBUF        LWIP_MEM_ALIGN_SIZE(sizeof(struct pbuf))\r
+/* Since the pool is created in memp, PBUF_POOL_BUFSIZE will be automatically\r
+   aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */\r
+#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)\r
+\r
+/**\r
+ * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).\r
+ *\r
+ * The actual memory allocated for the pbuf is determined by the\r
+ * layer at which the pbuf is allocated and the requested size\r
+ * (from the size parameter).\r
+ *\r
+ * @param layer flag to define header size\r
+ * @param length size of the pbuf's payload\r
+ * @param type this parameter decides how and where the pbuf\r
+ * should be allocated as follows:\r
+ *\r
+ * - PBUF_RAM: buffer memory for pbuf is allocated as one large\r
+ *             chunk. This includes protocol headers as well.\r
+ * - PBUF_ROM: no buffer memory is allocated for the pbuf, even for\r
+ *             protocol headers. Additional headers must be prepended\r
+ *             by allocating another pbuf and chain in to the front of\r
+ *             the ROM pbuf. It is assumed that the memory used is really\r
+ *             similar to ROM in that it is immutable and will not be\r
+ *             changed. Memory which is dynamic should generally not\r
+ *             be attached to PBUF_ROM pbufs. Use PBUF_REF instead.\r
+ * - PBUF_REF: no buffer memory is allocated for the pbuf, even for\r
+ *             protocol headers. It is assumed that the pbuf is only\r
+ *             being used in a single thread. If the pbuf gets queued,\r
+ *             then pbuf_take should be called to copy the buffer.\r
+ * - PBUF_POOL: the pbuf is allocated as a pbuf chain, with pbufs from\r
+ *              the pbuf pool that is allocated during pbuf_init().\r
+ *\r
+ * @return the allocated pbuf. If multiple pbufs where allocated, this\r
+ * is the first pbuf of a pbuf chain.\r
+ */\r
+struct pbuf *\r
+pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)\r
+{\r
+  struct pbuf *p, *q, *r;\r
+  u16_t offset;\r
+  s32_t rem_len; /* remaining length */\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));\r
+\r
+  /* determine header offset */\r
+  offset = 0;\r
+  switch (layer) {\r
+  case PBUF_TRANSPORT:\r
+    /* add room for transport (often TCP) layer header */\r
+    offset += PBUF_TRANSPORT_HLEN;\r
+    /* FALLTHROUGH */\r
+  case PBUF_IP:\r
+    /* add room for IP layer header */\r
+    offset += PBUF_IP_HLEN;\r
+    /* FALLTHROUGH */\r
+  case PBUF_LINK:\r
+    /* add room for link layer header */\r
+    offset += PBUF_LINK_HLEN;\r
+    break;\r
+  case PBUF_RAW:\r
+    break;\r
+  default:\r
+    LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);\r
+    return NULL;\r
+  }\r
+\r
+  switch (type) {\r
+  case PBUF_POOL:\r
+    /* allocate head of pbuf chain into p */\r
+      p = memp_malloc(MEMP_PBUF_POOL);\r
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));\r
+    if (p == NULL) {\r
+      return NULL;\r
+    }\r
+    p->type = type;\r
+    p->next = NULL;\r
+\r
+    /* make the payload pointer point 'offset' bytes into pbuf data memory */\r
+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + (SIZEOF_STRUCT_PBUF + offset)));\r
+    LWIP_ASSERT("pbuf_alloc: pbuf p->payload properly aligned",\r
+            ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
+    /* the total length of the pbuf chain is the requested size */\r
+    p->tot_len = length;\r
+    /* set the length of the first pbuf in the chain */\r
+    p->len = LWIP_MIN(length, PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset));\r
+    LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",\r
+                ((u8_t*)p->payload + p->len <=\r
+                 (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));\r
+    /* set reference count (needed here in case we fail) */\r
+    p->ref = 1;\r
+\r
+    /* now allocate the tail of the pbuf chain */\r
+\r
+    /* remember first pbuf for linkage in next iteration */\r
+    r = p;\r
+    /* remaining length to be allocated */\r
+    rem_len = length - p->len;\r
+    /* any remaining pbufs to be allocated? */\r
+    while (rem_len > 0) {\r
+      q = memp_malloc(MEMP_PBUF_POOL);\r
+      if (q == NULL) {\r
+        /* free chain so far allocated */\r
+        pbuf_free(p);\r
+        /* bail out unsuccesfully */\r
+        return NULL;\r
+      }\r
+      q->type = type;\r
+      q->flags = 0;\r
+      q->next = NULL;\r
+      /* make previous pbuf point to this pbuf */\r
+      r->next = q;\r
+      /* set total length of this pbuf and next in chain */\r
+      LWIP_ASSERT("rem_len < max_u16_t", rem_len < 0xffff);\r
+      q->tot_len = (u16_t)rem_len;\r
+      /* this pbuf length is pool size, unless smaller sized tail */\r
+      q->len = LWIP_MIN((u16_t)rem_len, PBUF_POOL_BUFSIZE_ALIGNED);\r
+      q->payload = (void *)((u8_t *)q + SIZEOF_STRUCT_PBUF);\r
+      LWIP_ASSERT("pbuf_alloc: pbuf q->payload properly aligned",\r
+              ((mem_ptr_t)q->payload % MEM_ALIGNMENT) == 0);\r
+      LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",\r
+                  ((u8_t*)p->payload + p->len <=\r
+                   (u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));\r
+      q->ref = 1;\r
+      /* calculate remaining length to be allocated */\r
+      rem_len -= q->len;\r
+      /* remember this pbuf for linkage in next iteration */\r
+      r = q;\r
+    }\r
+    /* end of chain */\r
+    /*r->next = NULL;*/\r
+\r
+    break;\r
+  case PBUF_RAM:\r
+    /* If pbuf is to be allocated in RAM, allocate memory for it. */\r
+    p = (struct pbuf*)mem_malloc(LWIP_MEM_ALIGN_SIZE(SIZEOF_STRUCT_PBUF + offset) + LWIP_MEM_ALIGN_SIZE(length));\r
+    if (p == NULL) {\r
+      return NULL;\r
+    }\r
+    /* Set up internal structure of the pbuf. */\r
+    p->payload = LWIP_MEM_ALIGN((void *)((u8_t *)p + SIZEOF_STRUCT_PBUF + offset));\r
+    p->len = p->tot_len = length;\r
+    p->next = NULL;\r
+    p->type = type;\r
+\r
+    LWIP_ASSERT("pbuf_alloc: pbuf->payload properly aligned",\r
+           ((mem_ptr_t)p->payload % MEM_ALIGNMENT) == 0);\r
+    break;\r
+  /* pbuf references existing (non-volatile static constant) ROM payload? */\r
+  case PBUF_ROM:\r
+  /* pbuf references existing (externally allocated) RAM payload? */\r
+  case PBUF_REF:\r
+    /* only allocate memory for the pbuf structure */\r
+    p = memp_malloc(MEMP_PBUF);\r
+    if (p == NULL) {\r
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",\r
+                  (type == PBUF_ROM) ? "ROM" : "REF"));\r
+      return NULL;\r
+    }\r
+    /* caller must set this field properly, afterwards */\r
+    p->payload = NULL;\r
+    p->len = p->tot_len = length;\r
+    p->next = NULL;\r
+    p->type = type;\r
+    break;\r
+  default:\r
+    LWIP_ASSERT("pbuf_alloc: erroneous type", 0);\r
+    return NULL;\r
+  }\r
+  /* set reference count */\r
+  p->ref = 1;\r
+  /* set flags */\r
+  p->flags = 0;\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));\r
+  return p;\r
+}\r
+\r
+\r
+/**\r
+ * Shrink a pbuf chain to a desired length.\r
+ *\r
+ * @param p pbuf to shrink.\r
+ * @param new_len desired new length of pbuf chain\r
+ *\r
+ * Depending on the desired length, the first few pbufs in a chain might\r
+ * be skipped and left unchanged. The new last pbuf in the chain will be\r
+ * resized, and any remaining pbufs will be freed.\r
+ *\r
+ * @note If the pbuf is ROM/REF, only the ->tot_len and ->len fields are adjusted.\r
+ * @note May not be called on a packet queue.\r
+ *\r
+ * @note Despite its name, pbuf_realloc cannot grow the size of a pbuf (chain).\r
+ */\r
+void\r
+pbuf_realloc(struct pbuf *p, u16_t new_len)\r
+{\r
+  struct pbuf *q;\r
+  u16_t rem_len; /* remaining length */\r
+  s32_t grow;\r
+\r
+  LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||\r
+              p->type == PBUF_ROM ||\r
+              p->type == PBUF_RAM ||\r
+              p->type == PBUF_REF);\r
+\r
+  /* desired length larger than current length? */\r
+  if (new_len >= p->tot_len) {\r
+    /* enlarging not yet supported */\r
+    return;\r
+  }\r
+\r
+  /* the pbuf chain grows by (new_len - p->tot_len) bytes\r
+   * (which may be negative in case of shrinking) */\r
+  grow = new_len - p->tot_len;\r
+\r
+  /* first, step over any pbufs that should remain in the chain */\r
+  rem_len = new_len;\r
+  q = p;\r
+  /* should this pbuf be kept? */\r
+  while (rem_len > q->len) {\r
+    /* decrease remaining length by pbuf length */\r
+    rem_len -= q->len;\r
+    /* decrease total length indicator */\r
+    LWIP_ASSERT("grow < max_u16_t", grow < 0xffff);\r
+    q->tot_len += (u16_t)grow;\r
+    /* proceed to next pbuf in chain */\r
+    q = q->next;\r
+  }\r
+  /* we have now reached the new last pbuf (in q) */\r
+  /* rem_len == desired length for pbuf q */\r
+\r
+  /* shrink allocated memory for PBUF_RAM */\r
+  /* (other types merely adjust their length fields */\r
+  if ((q->type == PBUF_RAM) && (rem_len != q->len)) {\r
+    /* reallocate and adjust the length of the pbuf that will be split */\r
+    q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len);\r
+    LWIP_ASSERT("mem_realloc give q == NULL", q != NULL);\r
+  }\r
+  /* adjust length fields for new last pbuf */\r
+  q->len = rem_len;\r
+  q->tot_len = q->len;\r
+\r
+  /* any remaining pbufs in chain? */\r
+  if (q->next != NULL) {\r
+    /* free remaining pbufs in chain */\r
+    pbuf_free(q->next);\r
+  }\r
+  /* q is last packet in chain */\r
+  q->next = NULL;\r
+\r
+}\r
+\r
+/**\r
+ * Adjusts the payload pointer to hide or reveal headers in the payload.\r
+ *\r
+ * Adjusts the ->payload pointer so that space for a header\r
+ * (dis)appears in the pbuf payload.\r
+ *\r
+ * The ->payload, ->tot_len and ->len fields are adjusted.\r
+ *\r
+ * @param p pbuf to change the header size.\r
+ * @param header_size_increment Number of bytes to increment header size which\r
+ * increases the size of the pbuf. New space is on the front.\r
+ * (Using a negative value decreases the header size.)\r
+ * If hdr_size_inc is 0, this function does nothing and returns succesful.\r
+ *\r
+ * PBUF_ROM and PBUF_REF type buffers cannot have their sizes increased, so\r
+ * the call will fail. A check is made that the increase in header size does\r
+ * not move the payload pointer in front of the start of the buffer.\r
+ * @return non-zero on failure, zero on success.\r
+ *\r
+ */\r
+u8_t\r
+pbuf_header(struct pbuf *p, s16_t header_size_increment)\r
+{\r
+  u16_t type;\r
+  void *payload;\r
+  u16_t increment_magnitude;\r
+\r
+  LWIP_ASSERT("p != NULL", p != NULL);\r
+  if ((header_size_increment == 0) || (p == NULL))\r
+    return 0;\r
+\r
+  if (header_size_increment < 0){\r
+    increment_magnitude = -header_size_increment;\r
+    /* Check that we aren't going to move off the end of the pbuf */\r
+    LWIP_ERROR("increment_magnitude <= p->len", (increment_magnitude <= p->len), return 1;);\r
+  } else {\r
+    increment_magnitude = header_size_increment;\r
+#if 0\r
+    /* Can't assert these as some callers speculatively call\r
+         pbuf_header() to see if it's OK.  Will return 1 below instead. */\r
+    /* Check that we've got the correct type of pbuf to work with */\r
+    LWIP_ASSERT("p->type == PBUF_RAM || p->type == PBUF_POOL",\r
+                p->type == PBUF_RAM || p->type == PBUF_POOL);\r
+    /* Check that we aren't going to move off the beginning of the pbuf */\r
+    LWIP_ASSERT("p->payload - increment_magnitude >= p + SIZEOF_STRUCT_PBUF",\r
+                (u8_t *)p->payload - increment_magnitude >= (u8_t *)p + SIZEOF_STRUCT_PBUF);\r
+#endif\r
+  }\r
+\r
+  type = p->type;\r
+  /* remember current payload pointer */\r
+  payload = p->payload;\r
+\r
+  /* pbuf types containing payloads? */\r
+  if (type == PBUF_RAM || type == PBUF_POOL) {\r
+    /* set new payload pointer */\r
+    p->payload = (u8_t *)p->payload - header_size_increment;\r
+    /* boundary check fails? */\r
+    if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",\r
+        (void *)p->payload,\r
+        (void *)(p + 1)));\\r
+      /* restore old payload pointer */\r
+      p->payload = payload;\r
+      /* bail out unsuccesfully */\r
+      return 1;\r
+    }\r
+  /* pbuf types refering to external payloads? */\r
+  } else if (type == PBUF_REF || type == PBUF_ROM) {\r
+    /* hide a header in the payload? */\r
+    if ((header_size_increment < 0) && (increment_magnitude <= p->len)) {\r
+      /* increase payload pointer */\r
+      p->payload = (u8_t *)p->payload - header_size_increment;\r
+    } else {\r
+      /* cannot expand payload to front (yet!)\r
+       * bail out unsuccesfully */\r
+      return 1;\r
+    }\r
+  }\r
+  else {\r
+    /* Unknown type */\r
+    LWIP_ASSERT("bad pbuf type", 0);\r
+    return 1;\r
+  }\r
+  /* modify pbuf length fields */\r
+  p->len += header_size_increment;\r
+  p->tot_len += header_size_increment;\r
+\r
+  LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",\r
+    (void *)payload, (void *)p->payload, header_size_increment));\r
+\r
+  return 0;\r
+}\r
+\r
+/**\r
+ * Dereference a pbuf chain or queue and deallocate any no-longer-used\r
+ * pbufs at the head of this chain or queue.\r
+ *\r
+ * Decrements the pbuf reference count. If it reaches zero, the pbuf is\r
+ * deallocated.\r
+ *\r
+ * For a pbuf chain, this is repeated for each pbuf in the chain,\r
+ * up to the first pbuf which has a non-zero reference count after\r
+ * decrementing. So, when all reference counts are one, the whole\r
+ * chain is free'd.\r
+ *\r
+ * @param p The pbuf (chain) to be dereferenced.\r
+ *\r
+ * @return the number of pbufs that were de-allocated\r
+ * from the head of the chain.\r
+ *\r
+ * @note MUST NOT be called on a packet queue (Not verified to work yet).\r
+ * @note the reference counter of a pbuf equals the number of pointers\r
+ * that refer to the pbuf (or into the pbuf).\r
+ *\r
+ * @internal examples:\r
+ *\r
+ * Assuming existing chains a->b->c with the following reference\r
+ * counts, calling pbuf_free(a) results in:\r
+ *\r
+ * 1->2->3 becomes ...1->3\r
+ * 3->3->3 becomes 2->3->3\r
+ * 1->1->2 becomes ......1\r
+ * 2->1->1 becomes 1->1->1\r
+ * 1->1->1 becomes .......\r
+ *\r
+ */\r
+u8_t\r
+pbuf_free(struct pbuf *p)\r
+{\r
+  u16_t type;\r
+  struct pbuf *q;\r
+  u8_t count;\r
+\r
+  if (p == NULL) {\r
+    LWIP_ASSERT("p != NULL", p != NULL);\r
+    /* if assertions are disabled, proceed with debug output */\r
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));\r
+    return 0;\r
+  }\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));\r
+\r
+  PERF_START;\r
+\r
+  LWIP_ASSERT("pbuf_free: sane type",\r
+    p->type == PBUF_RAM || p->type == PBUF_ROM ||\r
+    p->type == PBUF_REF || p->type == PBUF_POOL);\r
+\r
+  count = 0;\r
+  /* de-allocate all consecutive pbufs from the head of the chain that\r
+   * obtain a zero reference count after decrementing*/\r
+  while (p != NULL) {\r
+    u16_t ref;\r
+    SYS_ARCH_DECL_PROTECT(old_level);\r
+    /* Since decrementing ref cannot be guaranteed to be a single machine operation\r
+     * we must protect it. We put the new ref into a local variable to prevent\r
+     * further protection. */\r
+    SYS_ARCH_PROTECT(old_level);\r
+    /* all pbufs in a chain are referenced at least once */\r
+    LWIP_ASSERT("pbuf_free: p->ref > 0", p->ref > 0);\r
+    /* decrease reference count (number of pointers to pbuf) */\r
+    ref = --(p->ref);\r
+    SYS_ARCH_UNPROTECT(old_level);\r
+    /* this pbuf is no longer referenced to? */\r
+    if (ref == 0) {\r
+      /* remember next pbuf in chain for next iteration */\r
+      q = p->next;\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));\r
+      type = p->type;\r
+      /* is this a pbuf from the pool? */\r
+      if (type == PBUF_POOL) {\r
+        memp_free(MEMP_PBUF_POOL, p);\r
+      /* is this a ROM or RAM referencing pbuf? */\r
+      } else if (type == PBUF_ROM || type == PBUF_REF) {\r
+        memp_free(MEMP_PBUF, p);\r
+      /* type == PBUF_RAM */\r
+      } else {\r
+        mem_free(p);\r
+      }\r
+      count++;\r
+      /* proceed to next pbuf */\r
+      p = q;\r
+    /* p->ref > 0, this pbuf is still referenced to */\r
+    /* (and so the remaining pbufs in chain as well) */\r
+    } else {\r
+      LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));\r
+      /* stop walking through the chain */\r
+      p = NULL;\r
+    }\r
+  }\r
+  PERF_STOP("pbuf_free");\r
+  /* return number of de-allocated pbufs */\r
+  return count;\r
+}\r
+\r
+/**\r
+ * Count number of pbufs in a chain\r
+ *\r
+ * @param p first pbuf of chain\r
+ * @return the number of pbufs in a chain\r
+ */\r
+\r
+u8_t\r
+pbuf_clen(struct pbuf *p)\r
+{\r
+  u8_t len;\r
+\r
+  len = 0;\r
+  while (p != NULL) {\r
+    ++len;\r
+    p = p->next;\r
+  }\r
+  return len;\r
+}\r
+\r
+/**\r
+ * Increment the reference count of the pbuf.\r
+ *\r
+ * @param p pbuf to increase reference counter of\r
+ *\r
+ */\r
+void\r
+pbuf_ref(struct pbuf *p)\r
+{\r
+  SYS_ARCH_DECL_PROTECT(old_level);\r
+  /* pbuf given? */\r
+  if (p != NULL) {\r
+    SYS_ARCH_PROTECT(old_level);\r
+    ++(p->ref);\r
+    SYS_ARCH_UNPROTECT(old_level);\r
+  }\r
+}\r
+\r
+/**\r
+ * Concatenate two pbufs (each may be a pbuf chain) and take over\r
+ * the caller's reference of the tail pbuf.\r
+ *\r
+ * @note The caller MAY NOT reference the tail pbuf afterwards.\r
+ * Use pbuf_chain() for that purpose.\r
+ *\r
+ * @see pbuf_chain()\r
+ */\r
+\r
+void\r
+pbuf_cat(struct pbuf *h, struct pbuf *t)\r
+{\r
+  struct pbuf *p;\r
+\r
+  LWIP_ERROR("(h != NULL) && (t != NULL) (programmer violates API)",\r
+             ((h != NULL) && (t != NULL)), return;);\r
+\r
+  /* proceed to last pbuf of chain */\r
+  for (p = h; p->next != NULL; p = p->next) {\r
+    /* add total length of second chain to all totals of first chain */\r
+    p->tot_len += t->tot_len;\r
+  }\r
+  /* { p is last pbuf of first h chain, p->next == NULL } */\r
+  LWIP_ASSERT("p->tot_len == p->len (of last pbuf in chain)", p->tot_len == p->len);\r
+  LWIP_ASSERT("p->next == NULL", p->next == NULL);\r
+  /* add total length of second chain to last pbuf total of first chain */\r
+  p->tot_len += t->tot_len;\r
+  /* chain last pbuf of head (p) with first of tail (t) */\r
+  p->next = t;\r
+  /* p->next now references t, but the caller will drop its reference to t,\r
+   * so netto there is no change to the reference count of t.\r
+   */\r
+}\r
+\r
+/**\r
+ * Chain two pbufs (or pbuf chains) together.\r
+ *\r
+ * The caller MUST call pbuf_free(t) once it has stopped\r
+ * using it. Use pbuf_cat() instead if you no longer use t.\r
+ *\r
+ * @param h head pbuf (chain)\r
+ * @param t tail pbuf (chain)\r
+ * @note The pbufs MUST belong to the same packet.\r
+ * @note MAY NOT be called on a packet queue.\r
+ *\r
+ * The ->tot_len fields of all pbufs of the head chain are adjusted.\r
+ * The ->next field of the last pbuf of the head chain is adjusted.\r
+ * The ->ref field of the first pbuf of the tail chain is adjusted.\r
+ *\r
+ */\r
+void\r
+pbuf_chain(struct pbuf *h, struct pbuf *t)\r
+{\r
+  pbuf_cat(h, t);\r
+  /* t is now referenced by h */\r
+  pbuf_ref(t);\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));\r
+}\r
+\r
+/**\r
+ * Dechains the first pbuf from its succeeding pbufs in the chain.\r
+ *\r
+ * Makes p->tot_len field equal to p->len.\r
+ * @param p pbuf to dechain\r
+ * @return remainder of the pbuf chain, or NULL if it was de-allocated.\r
+ * @note May not be called on a packet queue.\r
+ */\r
+struct pbuf *\r
+pbuf_dechain(struct pbuf *p)\r
+{\r
+  struct pbuf *q;\r
+  u8_t tail_gone = 1;\r
+  /* tail */\r
+  q = p->next;\r
+  /* pbuf has successor in chain? */\r
+  if (q != NULL) {\r
+    /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
+    LWIP_ASSERT("p->tot_len == p->len + q->tot_len", q->tot_len == p->tot_len - p->len);\r
+    /* enforce invariant if assertion is disabled */\r
+    q->tot_len = p->tot_len - p->len;\r
+    /* decouple pbuf from remainder */\r
+    p->next = NULL;\r
+    /* total length of pbuf p is its own length only */\r
+    p->tot_len = p->len;\r
+    /* q is no longer referenced by p, free it */\r
+    LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));\r
+    tail_gone = pbuf_free(q);\r
+    if (tail_gone > 0) {\r
+      LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,\r
+                  ("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));\r
+    }\r
+    /* return remaining tail or NULL if deallocated */\r
+  }\r
+  /* assert tot_len invariant: (p->tot_len == p->len + (p->next? p->next->tot_len: 0) */\r
+  LWIP_ASSERT("p->tot_len == p->len", p->tot_len == p->len);\r
+  return ((tail_gone > 0) ? NULL : q);\r
+}\r
+\r
+/**\r
+ *\r
+ * Create PBUF_RAM copies of pbufs.\r
+ *\r
+ * Used to queue packets on behalf of the lwIP stack, such as\r
+ * ARP based queueing.\r
+ *\r
+ * @note You MUST explicitly use p = pbuf_take(p);\r
+ *\r
+ * @note Only one packet is copied, no packet queue!\r
+ *\r
+ * @param p_to pbuf source of the copy\r
+ * @param p_from pbuf destination of the copy\r
+ *\r
+ * @return ERR_OK if pbuf was copied\r
+ *         ERR_ARG if one of the pbufs is NULL or p_to is not big\r
+ *                 enough to hold p_from\r
+ */\r
+err_t\r
+pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)\r
+{\r
+  u16_t offset_to=0, offset_from=0, len;\r
+\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",\r
+    (void*)p_to, (void*)p_from));\r
+\r
+  /* is the target big enough to hold the source? */\r
+  LWIP_ERROR("pbuf_copy: target not big enough to hold source", ((p_to != NULL) &&\r
+             (p_from != NULL) && (p_to->tot_len >= p_from->tot_len)), return ERR_ARG;);\r
+\r
+  /* iterate through pbuf chain */\r
+  do\r
+  {\r
+    LWIP_ASSERT("p_to != NULL", p_to != NULL);\r
+    /* copy one part of the original chain */\r
+    if ((p_to->len - offset_to) >= (p_from->len - offset_from)) {\r
+      /* complete current p_from fits into current p_to */\r
+      len = p_from->len - offset_from;\r
+    } else {\r
+      /* current p_from does not fit into current p_to */\r
+      len = p_to->len - offset_to;\r
+    }\r
+    MEMCPY((u8_t*)p_to->payload + offset_to, (u8_t*)p_from->payload + offset_from, len);\r
+    offset_to += len;\r
+    offset_from += len;\r
+    LWIP_ASSERT("offset_to <= p_to->len", offset_to <= p_to->len);\r
+    if (offset_to == p_to->len) {\r
+      /* on to next p_to (if any) */\r
+      offset_to = 0;\r
+      p_to = p_to->next;\r
+    }\r
+    LWIP_ASSERT("offset_from <= p_from->len", offset_from <= p_from->len);\r
+    if (offset_from >= p_from->len) {\r
+      /* on to next p_from (if any) */\r
+      offset_from = 0;\r
+      p_from = p_from->next;\r
+    }\r
+\r
+    if((p_from != NULL) && (p_from->len == p_from->tot_len)) {\r
+      /* don't copy more than one packet! */\r
+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",\r
+                 (p_from->next == NULL), return ERR_VAL;);\r
+    }\r
+    if((p_to != NULL) && (p_to->len == p_to->tot_len)) {\r
+      /* don't copy more than one packet! */\r
+      LWIP_ERROR("pbuf_copy() does not allow packet queues!\n",\r
+                  (p_to->next == NULL), return ERR_VAL;);\r
+    }\r
+  } while (p_from);\r
+  LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Copy (part of) the contents of a packet buffer\r
+ * to an application supplied buffer.\r
+ *\r
+ * @param buf the pbuf from which to copy data\r
+ * @param dataptr the application supplied buffer\r
+ * @param len length of data to copy (dataptr must be big enough)\r
+ * @param offset offset into the packet buffer from where to begin copying len bytes\r
+ */\r
+u16_t\r
+pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)\r
+{\r
+  struct pbuf *p;\r
+  u16_t left;\r
+  u16_t buf_copy_len;\r
+  u16_t copied_total = 0;\r
+\r
+  LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);\r
+  LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);\r
+\r
+  left = 0;\r
+\r
+  if((buf == NULL) || (dataptr == NULL)) {\r
+    return 0;\r
+  }\r
+\r
+  /* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */\r
+  for(p = buf; len != 0 && p != NULL; p = p->next) {\r
+    if ((offset != 0) && (offset >= p->len)) {\r
+      /* don't copy from this buffer -> on to the next */\r
+      offset -= p->len;\r
+    } else {\r
+      /* copy from this buffer. maybe only partially. */\r
+      buf_copy_len = p->len - offset;\r
+      if (buf_copy_len > len)\r
+          buf_copy_len = len;\r
+      /* copy the necessary parts of the buffer */\r
+      MEMCPY(&((char*)dataptr)[left], &((char*)p->payload)[offset], buf_copy_len);\r
+      copied_total += buf_copy_len;\r
+      left += buf_copy_len;\r
+      len -= buf_copy_len;\r
+      offset = 0;\r
+    }\r
+  }\r
+  return copied_total;\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/raw.c b/Demo/Common/ethernet/lwIP_130/src/core/raw.c
new file mode 100644 (file)
index 0000000..2ba693b
--- /dev/null
@@ -0,0 +1,336 @@
+/**\r
+ * @file\r
+ * Implementation of raw protocol PCBs for low-level handling of\r
+ * different types of protocols besides (or overriding) those\r
+ * already available in lwIP.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/raw.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "arch/perf.h"\r
+\r
+#include <string.h>\r
+\r
+/** The list of RAW PCBs */\r
+static struct raw_pcb *raw_pcbs;\r
+\r
+/**\r
+ * Determine if in incoming IP packet is covered by a RAW PCB\r
+ * and if so, pass it to a user-provided receive callback function.\r
+ *\r
+ * Given an incoming IP datagram (as a chain of pbufs) this function\r
+ * finds a corresponding RAW PCB and calls the corresponding receive\r
+ * callback function.\r
+ *\r
+ * @param p pbuf to be demultiplexed to a RAW PCB.\r
+ * @param inp network interface on which the datagram was received.\r
+ * @return - 1 if the packet has been eaten by a RAW PCB receive\r
+ *           callback function. The caller MAY NOT not reference the\r
+ *           packet any longer, and MAY NOT call pbuf_free().\r
+ * @return - 0 if packet is not eaten (pbuf is still referenced by the\r
+ *           caller).\r
+ *\r
+ */\r
+u8_t\r
+raw_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct raw_pcb *pcb, *prev;\r
+  struct ip_hdr *iphdr;\r
+  s16_t proto;\r
+  u8_t eaten = 0;\r
+\r
+  LWIP_UNUSED_ARG(inp);\r
+\r
+  iphdr = p->payload;\r
+  proto = IPH_PROTO(iphdr);\r
+\r
+  prev = NULL;\r
+  pcb = raw_pcbs;\r
+  /* loop through all raw pcbs until the packet is eaten by one */\r
+  /* this allows multiple pcbs to match against the packet by design */\r
+  while ((eaten == 0) && (pcb != NULL)) {\r
+    if (pcb->protocol == proto) {\r
+      /* receive callback function available? */\r
+      if (pcb->recv != NULL) {\r
+        /* the receive callback function did not eat the packet? */\r
+        if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)\r
+        {\r
+          /* receive function ate the packet */\r
+          p = NULL;\r
+          eaten = 1;\r
+          if (prev != NULL) {\r
+          /* move the pcb to the front of raw_pcbs so that is\r
+             found faster next time */\r
+            prev->next = pcb->next;\r
+            pcb->next = raw_pcbs;\r
+            raw_pcbs = pcb;\r
+          }\r
+        }\r
+      }\r
+      /* no receive callback function was set for this raw PCB */\r
+      /* drop the packet */\r
+    }\r
+    prev = pcb;\r
+    pcb = pcb->next;\r
+  }\r
+  return eaten;\r
+}\r
+\r
+/**\r
+ * Bind a RAW PCB.\r
+ *\r
+ * @param pcb RAW PCB to be bound with a local address ipaddr.\r
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\r
+ * bind to all local interfaces.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_USE. The specified IP address is already bound to by\r
+ * another RAW PCB.\r
+ *\r
+ * @see raw_disconnect()\r
+ */\r
+err_t\r
+raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr)\r
+{\r
+  ip_addr_set(&pcb->local_ip, ipaddr);\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Connect an RAW PCB. This function is required by upper layers\r
+ * of lwip. Using the raw api you could use raw_sendto() instead\r
+ *\r
+ * This will associate the RAW PCB with the remote address.\r
+ *\r
+ * @param pcb RAW PCB to be connected with remote address ipaddr and port.\r
+ * @param ipaddr remote IP address to connect with.\r
+ *\r
+ * @return lwIP error code\r
+ *\r
+ * @see raw_disconnect() and raw_sendto()\r
+ */\r
+err_t\r
+raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr)\r
+{\r
+  ip_addr_set(&pcb->remote_ip, ipaddr);\r
+  return ERR_OK;\r
+}\r
+\r
+\r
+/**\r
+ * Set the callback function for received packets that match the\r
+ * raw PCB's protocol and binding.\r
+ *\r
+ * The callback function MUST either\r
+ * - eat the packet by calling pbuf_free() and returning non-zero. The\r
+ *   packet will not be passed to other raw PCBs or other protocol layers.\r
+ * - not free the packet, and return zero. The packet will be matched\r
+ *   against further PCBs and/or forwarded to another protocol layers.\r
+ *\r
+ * @return non-zero if the packet was free()d, zero if the packet remains\r
+ * available for others.\r
+ */\r
+void\r
+raw_recv(struct raw_pcb *pcb,\r
+         u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p,\r
+                      struct ip_addr *addr),\r
+         void *recv_arg)\r
+{\r
+  /* remember recv() callback and user data */\r
+  pcb->recv = recv;\r
+  pcb->recv_arg = recv_arg;\r
+}\r
+\r
+/**\r
+ * Send the raw IP packet to the given address. Note that actually you cannot\r
+ * modify the IP headers (this is inconsistent with the receive callback where\r
+ * you actually get the IP headers), you can only specify the IP payload here.\r
+ * It requires some more changes in lwIP. (there will be a raw_send() function\r
+ * then.)\r
+ *\r
+ * @param pcb the raw pcb which to send\r
+ * @param p the IP payload to send\r
+ * @param ipaddr the destination address of the IP packet\r
+ *\r
+ */\r
+err_t\r
+raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)\r
+{\r
+  err_t err;\r
+  struct netif *netif;\r
+  struct ip_addr *src_ip;\r
+  struct pbuf *q; /* q will be sent down the stack */\r
+\r
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));\r
+\r
+  /* not enough space to add an IP header to first pbuf in given p chain? */\r
+  if (pbuf_header(p, IP_HLEN)) {\r
+    /* allocate header in new pbuf */\r
+    q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);\r
+    /* new header pbuf could not be allocated? */\r
+    if (q == NULL) {\r
+      LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* chain header q in front of given pbuf p */\r
+    pbuf_chain(q, p);\r
+    /* { first pbuf q points to header pbuf } */\r
+    LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));\r
+  }  else {\r
+    /* first pbuf q equals given pbuf */\r
+    q = p;\r
+    if(pbuf_header(q, -IP_HLEN)) {\r
+      LWIP_ASSERT("Can't restore header we just removed!", 0);\r
+      return ERR_MEM;\r
+    }\r
+  }\r
+\r
+  if ((netif = ip_route(ipaddr)) == NULL) {\r
+    LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));\r
+    /* free any temporary header pbuf allocated by pbuf_header() */\r
+    if (q != p) {\r
+      pbuf_free(q);\r
+    }\r
+    return ERR_RTE;\r
+  }\r
+\r
+  if (ip_addr_isany(&pcb->local_ip)) {\r
+    /* use outgoing network interface IP address as source address */\r
+    src_ip = &(netif->ip_addr);\r
+  } else {\r
+    /* use RAW PCB local IP address as source address */\r
+    src_ip = &(pcb->local_ip);\r
+  }\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+  netif->addr_hint = &(pcb->addr_hint);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+  err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);\r
+#if LWIP_NETIF_HWADDRHINT\r
+  netif->addr_hint = NULL;\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+\r
+  /* did we chain a header earlier? */\r
+  if (q != p) {\r
+    /* free the header */\r
+    pbuf_free(q);\r
+  }\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Send the raw IP packet to the address given by raw_connect()\r
+ *\r
+ * @param pcb the raw pcb which to send\r
+ * @param p the IP payload to send\r
+ *\r
+ */\r
+err_t\r
+raw_send(struct raw_pcb *pcb, struct pbuf *p)\r
+{\r
+  return raw_sendto(pcb, p, &pcb->remote_ip);\r
+}\r
+\r
+/**\r
+ * Remove an RAW PCB.\r
+ *\r
+ * @param pcb RAW PCB to be removed. The PCB is removed from the list of\r
+ * RAW PCB's and the data structure is freed from memory.\r
+ *\r
+ * @see raw_new()\r
+ */\r
+void\r
+raw_remove(struct raw_pcb *pcb)\r
+{\r
+  struct raw_pcb *pcb2;\r
+  /* pcb to be removed is first in list? */\r
+  if (raw_pcbs == pcb) {\r
+    /* make list start at 2nd pcb */\r
+    raw_pcbs = raw_pcbs->next;\r
+    /* pcb not 1st in list */\r
+  } else {\r
+    for(pcb2 = raw_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\r
+      /* find pcb in raw_pcbs list */\r
+      if (pcb2->next != NULL && pcb2->next == pcb) {\r
+        /* remove pcb from list */\r
+        pcb2->next = pcb->next;\r
+      }\r
+    }\r
+  }\r
+  memp_free(MEMP_RAW_PCB, pcb);\r
+}\r
+\r
+/**\r
+ * Create a RAW PCB.\r
+ *\r
+ * @return The RAW PCB which was created. NULL if the PCB data structure\r
+ * could not be allocated.\r
+ *\r
+ * @param proto the protocol number of the IPs payload (e.g. IP_PROTO_ICMP)\r
+ *\r
+ * @see raw_remove()\r
+ */\r
+struct raw_pcb *\r
+raw_new(u8_t proto) {\r
+  struct raw_pcb *pcb;\r
+\r
+  LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_new\n"));\r
+\r
+  pcb = memp_malloc(MEMP_RAW_PCB);\r
+  /* could allocate RAW PCB? */\r
+  if (pcb != NULL) {\r
+    /* initialize PCB to all zeroes */\r
+    memset(pcb, 0, sizeof(struct raw_pcb));\r
+    pcb->protocol = proto;\r
+    pcb->ttl = RAW_TTL;\r
+    pcb->next = raw_pcbs;\r
+    raw_pcbs = pcb;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+#endif /* LWIP_RAW */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_dec.c
new file mode 100644 (file)
index 0000000..87288ac
--- /dev/null
@@ -0,0 +1,657 @@
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) decoding\r
+ *\r
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/snmp_asn1.h"\r
+\r
+/**\r
+ * Retrieves type field from incoming pbuf chain.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded type field\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded type field\r
+ * @param type return ASN1 type\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      *type = *msg_ptr;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes length field from incoming pbuf chain into host length.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded length\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded length\r
+ * @param octets_used returns number of octets used by the length code\r
+ * @param length return host order length, upto 64k\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (*msg_ptr < 0x80)\r
+      {\r
+        /* primitive definite length format */\r
+        *octets_used = 1;\r
+        *length = *msg_ptr;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x80)\r
+      {\r
+        /* constructed indefinite length format, termination with two zero octets */\r
+        u8_t zeros;\r
+        u8_t i;\r
+\r
+        *length = 0;\r
+        zeros = 0;\r
+        while (zeros != 2)\r
+        {\r
+          i = 2;\r
+          while (i > 0)\r
+          {\r
+            i--;\r
+            (*length) += 1;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+            if (*msg_ptr == 0)\r
+            {\r
+              zeros++;\r
+              if (zeros == 2)\r
+              {\r
+                /* stop while (i > 0) */\r
+                i = 0;\r
+              }\r
+            }\r
+            else\r
+            {\r
+              zeros = 0;\r
+            }\r
+          }\r
+        }\r
+        *octets_used = 1;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x81)\r
+      {\r
+        /* constructed definite length format, one octet */\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        *length = *msg_ptr;\r
+        *octets_used = 2;\r
+        return ERR_OK;\r
+      }\r
+      else if (*msg_ptr == 0x82)\r
+      {\r
+        u8_t i;\r
+\r
+        /* constructed definite length format, two octets */\r
+        i = 2;\r
+        while (i > 0)\r
+        {\r
+          i--;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+          if (i == 0)\r
+          {\r
+            /* least significant length octet */\r
+            *length |= *msg_ptr;\r
+          }\r
+          else\r
+          {\r
+            /* most significant length octet */\r
+            *length = (*msg_ptr) << 8;\r
+          }\r
+        }\r
+        *octets_used = 3;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        /* constructed definite length format 3..127 octets, this is too big (>64k) */\r
+        /**  @todo: do we need to accept inefficient codings with many leading zero's? */\r
+        *octets_used = 1 + ((*msg_ptr) & 0x7f);\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes positive integer (counter, gauge, timeticks) into u32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded integer\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer\r
+ * @param len length of the coded integer field\r
+ * @param value return host order integer\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ *\r
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded\r
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value\r
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!\r
+ */\r
+err_t\r
+snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      if ((len > 0) && (len < 6))\r
+      {\r
+        /* start from zero */\r
+        *value = 0;\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          /* negative, expecting zero sign bit! */\r
+          return ERR_ARG;\r
+        }\r
+        else\r
+        {\r
+          /* positive */\r
+          if ((len > 1) && (*msg_ptr == 0))\r
+          {\r
+            /* skip leading "sign byte" octet 0x00 */\r
+            len--;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+        }\r
+        /* OR octets with value */\r
+        while (len > 1)\r
+        {\r
+          len--;\r
+          *value |= *msg_ptr;\r
+          *value <<= 8;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        *value |= *msg_ptr;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes integer into s32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded integer\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded integer\r
+ * @param len length of the coded integer field\r
+ * @param value return host order integer\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ *\r
+ * @note ASN coded integers are _always_ signed!\r
+ */\r
+err_t\r
+snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+  u8_t *lsb_ptr = (u8_t*)value;\r
+#endif\r
+#if BYTE_ORDER == BIG_ENDIAN\r
+  u8_t *lsb_ptr = (u8_t*)value + sizeof(s32_t) - 1;\r
+#endif\r
+  u8_t sign;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      if ((len > 0) && (len < 5))\r
+      {\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          /* negative, start from -1 */\r
+          *value = -1;\r
+          sign = 1;\r
+        }\r
+        else\r
+        {\r
+          /* positive, start from 0 */\r
+          *value = 0;\r
+          sign = 0;\r
+        }\r
+        /* OR/AND octets with value */\r
+        while (len > 1)\r
+        {\r
+          len--;\r
+          if (sign)\r
+          {\r
+            *lsb_ptr &= *msg_ptr;\r
+            *value <<= 8;\r
+            *lsb_ptr |= 255;\r
+          }\r
+          else\r
+          {\r
+            *lsb_ptr |= *msg_ptr;\r
+            *value <<= 8;\r
+          }\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        if (sign)\r
+        {\r
+          *lsb_ptr &= *msg_ptr;\r
+        }\r
+        else\r
+        {\r
+          *lsb_ptr |= *msg_ptr;\r
+        }\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        return ERR_ARG;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes object identifier from incoming message into array of s32_t.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded object identifier\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded object identifier\r
+ * @param len length of the coded object identifier\r
+ * @param oid return object identifier struct\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+  s32_t *oid_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      oid->len = 0;\r
+      oid_ptr = &oid->id[0];\r
+      if (len > 0)\r
+      {\r
+        /* first compressed octet */\r
+        if (*msg_ptr == 0x2B)\r
+        {\r
+          /* (most) common case 1.3 (iso.org) */\r
+          *oid_ptr = 1;\r
+          oid_ptr++;\r
+          *oid_ptr = 3;\r
+          oid_ptr++;\r
+        }\r
+        else if (*msg_ptr < 40)\r
+        {\r
+          *oid_ptr = 0;\r
+          oid_ptr++;\r
+          *oid_ptr = *msg_ptr;\r
+          oid_ptr++;\r
+        }\r
+        else if (*msg_ptr < 80)\r
+        {\r
+          *oid_ptr = 1;\r
+          oid_ptr++;\r
+          *oid_ptr = (*msg_ptr) - 40;\r
+          oid_ptr++;\r
+        }\r
+        else\r
+        {\r
+          *oid_ptr = 2;\r
+          oid_ptr++;\r
+          *oid_ptr = (*msg_ptr) - 80;\r
+          oid_ptr++;\r
+        }\r
+        oid->len = 2;\r
+      }\r
+      else\r
+      {\r
+        /* accepting zero length identifiers e.g. for\r
+           getnext operation. uncommon but valid */\r
+        return ERR_OK;\r
+      }\r
+      len--;\r
+      if (len > 0)\r
+      {\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      while ((len > 0) && (oid->len < LWIP_SNMP_OBJ_ID_LEN))\r
+      {\r
+        /* sub-identifier uses multiple octets */\r
+        if (*msg_ptr & 0x80)\r
+        {\r
+          s32_t sub_id = 0;\r
+\r
+          while ((*msg_ptr & 0x80) && (len > 1))\r
+          {\r
+            len--;\r
+            sub_id = (sub_id << 7) + (*msg_ptr & ~0x80);\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          if (!(*msg_ptr & 0x80) && (len > 0))\r
+          {\r
+            /* last octet sub-identifier */\r
+            len--;\r
+            sub_id = (sub_id << 7) + *msg_ptr;\r
+            *oid_ptr = sub_id;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* !(*msg_ptr & 0x80) sub-identifier uses single octet */\r
+          len--;\r
+          *oid_ptr = *msg_ptr;\r
+        }\r
+        if (len > 0)\r
+        {\r
+          /* remaining oid bytes available ... */\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        oid_ptr++;\r
+        oid->len++;\r
+      }\r
+      if (len == 0)\r
+      {\r
+        /* len == 0, end of oid */\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        /* len > 0, oid->len == LWIP_SNMP_OBJ_ID_LEN or malformed encoding */\r
+        return ERR_ARG;\r
+      }\r
+\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Decodes (copies) raw data (ip-addresses, octet strings, opaque encoding)\r
+ * from incoming message into array.\r
+ *\r
+ * @param p points to a pbuf holding an ASN1 coded raw data\r
+ * @param ofs points to the offset within the pbuf chain of the ASN1 coded raw data\r
+ * @param len length of the coded raw data (zero is valid, e.g. empty string!)\r
+ * @param raw_len length of the raw return value\r
+ * @param raw return raw bytes\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) decode\r
+ */\r
+err_t\r
+snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  if (len > 0)\r
+  {\r
+    plen = 0;\r
+    while (p != NULL)\r
+    {\r
+      base = plen;\r
+      plen += p->len;\r
+      if (ofs < plen)\r
+      {\r
+        msg_ptr = p->payload;\r
+        msg_ptr += ofs - base;\r
+        if (raw_len >= len)\r
+        {\r
+          while (len > 1)\r
+          {\r
+            /* copy len - 1 octets */\r
+            len--;\r
+            *raw = *msg_ptr;\r
+            raw++;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          /* copy last octet */\r
+          *raw = *msg_ptr;\r
+          return ERR_OK;\r
+        }\r
+        else\r
+        {\r
+          /* raw_len < len, not enough dst space */\r
+          return ERR_ARG;\r
+        }\r
+      }\r
+      p = p->next;\r
+    }\r
+    /* p == NULL, ofs >= plen */\r
+    return ERR_ARG;\r
+  }\r
+  else\r
+  {\r
+    /* len == 0, empty string */\r
+    return ERR_OK;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/asn1_enc.c
new file mode 100644 (file)
index 0000000..ac29636
--- /dev/null
@@ -0,0 +1,611 @@
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) encoding\r
+ *\r
+ * @todo not optimised (yet), favor correctness over speed, favor speed over size\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/snmp_asn1.h"\r
+\r
+/**\r
+ * Returns octet count for length.\r
+ *\r
+ * @param length\r
+ * @param octets_needed points to the return value\r
+ */\r
+void\r
+snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed)\r
+{\r
+  if (length < 0x80U)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (length < 0x100U)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an u32_t.\r
+ *\r
+ * @param value\r
+ * @param octets_needed points to the return value\r
+ *\r
+ * @note ASN coded integers are _always_ signed. E.g. +0xFFFF is coded\r
+ * as 0x00,0xFF,0xFF. Note the leading sign octet. A positive value\r
+ * of 0xFFFFFFFF is preceded with 0x00 and the length is 5 octets!!\r
+ */\r
+void\r
+snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed)\r
+{\r
+  if (value < 0x80UL)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (value < 0x8000UL)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else if (value < 0x800000UL)\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+  else if (value < 0x80000000UL)\r
+  {\r
+    *octets_needed = 4;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 5;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an s32_t.\r
+ *\r
+ * @param value\r
+ * @param octets_needed points to the return value\r
+ *\r
+ * @note ASN coded integers are _always_ signed.\r
+ */\r
+void\r
+snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed)\r
+{\r
+  if (value < 0)\r
+  {\r
+    value = ~value;\r
+  }\r
+  if (value < 0x80L)\r
+  {\r
+    *octets_needed = 1;\r
+  }\r
+  else if (value < 0x8000L)\r
+  {\r
+    *octets_needed = 2;\r
+  }\r
+  else if (value < 0x800000L)\r
+  {\r
+    *octets_needed = 3;\r
+  }\r
+  else\r
+  {\r
+    *octets_needed = 4;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns octet count for an object identifier.\r
+ *\r
+ * @param ident_len object identifier array length\r
+ * @param ident points to object identifier array\r
+ * @param octets_needed points to the return value\r
+ */\r
+void\r
+snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed)\r
+{\r
+  s32_t sub_id;\r
+  u8_t cnt;\r
+\r
+  cnt = 0;\r
+  if (ident_len > 1)\r
+  {\r
+    /* compressed prefix in one octet */\r
+    cnt++;\r
+    ident_len -= 2;\r
+    ident += 2;\r
+  }\r
+  while(ident_len > 0)\r
+  {\r
+    ident_len--;\r
+    sub_id = *ident;\r
+\r
+    sub_id >>= 7;\r
+    cnt++;\r
+    while(sub_id > 0)\r
+    {\r
+      sub_id >>= 7;\r
+      cnt++;\r
+    }\r
+    ident++;\r
+  }\r
+  *octets_needed = cnt;\r
+}\r
+\r
+/**\r
+ * Encodes ASN type field into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param type input ASN1 type\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+      *msg_ptr = type;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes host order length field into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode length into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param length is the host order length to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (length < 0x80)\r
+      {\r
+        *msg_ptr = length;\r
+        return ERR_OK;\r
+      }\r
+      else if (length < 0x100)\r
+      {\r
+        *msg_ptr = 0x81;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        *msg_ptr = length;\r
+        return ERR_OK;\r
+      }\r
+      else\r
+      {\r
+        u8_t i;\r
+\r
+        /* length >= 0x100 && length <= 0xFFFF */\r
+        *msg_ptr = 0x82;\r
+        i = 2;\r
+        while (i > 0)\r
+        {\r
+          i--;\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+          if (i == 0)\r
+          {\r
+            /* least significant length octet */\r
+            *msg_ptr = length;\r
+          }\r
+          else\r
+          {\r
+            /* most significant length octet */\r
+            *msg_ptr = length >> 8;\r
+          }\r
+        }\r
+        return ERR_OK;\r
+      }\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes u32_t (counter, gauge, timeticks) into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param octets_needed encoding length (from snmp_asn1_enc_u32t_cnt())\r
+ * @param value is the host order u32_t value to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ *\r
+ * @see snmp_asn1_enc_u32t_cnt()\r
+ */\r
+err_t\r
+snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (octets_needed == 5)\r
+      {\r
+        /* not enough bits in 'value' add leading 0x00 */\r
+        octets_needed--;\r
+        *msg_ptr = 0x00;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      while (octets_needed > 1)\r
+      {\r
+        octets_needed--;\r
+        *msg_ptr = value >> (octets_needed << 3);\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      /* (only) one least significant octet */\r
+      *msg_ptr = value;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes s32_t integer into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode value into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param octets_needed encoding length (from snmp_asn1_enc_s32t_cnt())\r
+ * @param value is the host order s32_t value to be encoded\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ *\r
+ * @see snmp_asn1_enc_s32t_cnt()\r
+ */\r
+err_t\r
+snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      while (octets_needed > 1)\r
+      {\r
+        octets_needed--;\r
+        *msg_ptr = value >> (octets_needed << 3);\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      /* (only) one least significant octet */\r
+      *msg_ptr = value;\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes object identifier into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode oid into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param ident_len object identifier array length\r
+ * @param ident points to object identifier array\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      if (ident_len > 1)\r
+      {\r
+        if ((ident[0] == 1) && (ident[1] == 3))\r
+        {\r
+          /* compressed (most common) prefix .iso.org */\r
+          *msg_ptr = 0x2b;\r
+        }\r
+        else\r
+        {\r
+          /* calculate prefix */\r
+          *msg_ptr = (ident[0] * 40) + ident[1];\r
+        }\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+        ident_len -= 2;\r
+        ident += 2;\r
+      }\r
+      else\r
+      {\r
+/* @bug:  allow empty varbinds for symmetry (we must decode them for getnext), allow partial compression??  */\r
+        /* ident_len <= 1, at least we need zeroDotZero (0.0) (ident_len == 2) */\r
+        return ERR_ARG;\r
+      }\r
+      while (ident_len > 0)\r
+      {\r
+        s32_t sub_id;\r
+        u8_t shift, tail;\r
+\r
+        ident_len--;\r
+        sub_id = *ident;\r
+        tail = 0;\r
+        shift = 28;\r
+        while(shift > 0)\r
+        {\r
+          u8_t code;\r
+\r
+          code = sub_id >> shift;\r
+          if ((code != 0) || (tail != 0))\r
+          {\r
+            tail = 1;\r
+            *msg_ptr = code | 0x80;\r
+            ofs += 1;\r
+            if (ofs >= plen)\r
+            {\r
+              /* next octet in next pbuf */\r
+              p = p->next;\r
+              if (p == NULL) { return ERR_ARG; }\r
+              msg_ptr = p->payload;\r
+              plen += p->len;\r
+            }\r
+            else\r
+            {\r
+              /* next octet in same pbuf */\r
+              msg_ptr++;\r
+            }\r
+          }\r
+          shift -= 7;\r
+        }\r
+        *msg_ptr = (u8_t)sub_id & 0x7F;\r
+        if (ident_len > 0)\r
+        {\r
+          ofs += 1;\r
+          if (ofs >= plen)\r
+          {\r
+            /* next octet in next pbuf */\r
+            p = p->next;\r
+            if (p == NULL) { return ERR_ARG; }\r
+            msg_ptr = p->payload;\r
+            plen += p->len;\r
+          }\r
+          else\r
+          {\r
+            /* next octet in same pbuf */\r
+            msg_ptr++;\r
+          }\r
+        }\r
+        /* proceed to next sub-identifier */\r
+        ident++;\r
+      }\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+/**\r
+ * Encodes raw data (octet string, opaque) into a pbuf chained ASN1 msg.\r
+ *\r
+ * @param p points to output pbuf to encode raw data into\r
+ * @param ofs points to the offset within the pbuf chain\r
+ * @param raw_len raw data length\r
+ * @param raw points raw data\r
+ * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode\r
+ */\r
+err_t\r
+snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw)\r
+{\r
+  u16_t plen, base;\r
+  u8_t *msg_ptr;\r
+\r
+  plen = 0;\r
+  while (p != NULL)\r
+  {\r
+    base = plen;\r
+    plen += p->len;\r
+    if (ofs < plen)\r
+    {\r
+      msg_ptr = p->payload;\r
+      msg_ptr += ofs - base;\r
+\r
+      while (raw_len > 1)\r
+      {\r
+        /* copy raw_len - 1 octets */\r
+        raw_len--;\r
+        *msg_ptr = *raw;\r
+        raw++;\r
+        ofs += 1;\r
+        if (ofs >= plen)\r
+        {\r
+          /* next octet in next pbuf */\r
+          p = p->next;\r
+          if (p == NULL) { return ERR_ARG; }\r
+          msg_ptr = p->payload;\r
+          plen += p->len;\r
+        }\r
+        else\r
+        {\r
+          /* next octet in same pbuf */\r
+          msg_ptr++;\r
+        }\r
+      }\r
+      if (raw_len > 0)\r
+      {\r
+        /* copy last or single octet */\r
+        *msg_ptr = *raw;\r
+      }\r
+      return ERR_OK;\r
+    }\r
+    p = p->next;\r
+  }\r
+  /* p == NULL, ofs >= plen */\r
+  return ERR_ARG;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib2.c
new file mode 100644 (file)
index 0000000..0e582c1
--- /dev/null
@@ -0,0 +1,4126 @@
+/**\r
+ * @file\r
+ * Management Information Base II (RFC1213) objects and functions.\r
+ *\r
+ * @note the object identifiers for this MIB-2 and private MIB tree\r
+ * must be kept in sorted ascending order. This to ensure correct getnext operation.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/snmp.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_frag.h"\r
+#include "lwip/tcp.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_structs.h"\r
+#include "netif/etharp.h"\r
+\r
+/**\r
+ * IANA assigned enterprise ID for lwIP is 26381\r
+ * @see http://www.iana.org/assignments/enterprise-numbers\r
+ *\r
+ * @note this enterprise ID is assigned to the lwIP project,\r
+ * all object identifiers living under this ID are assigned\r
+ * by the lwIP maintainers (contact Christiaan Simons)!\r
+ * @note don't change this define, use snmp_set_sysobjid()\r
+ *\r
+ * If you need to create your own private MIB you'll need\r
+ * to apply for your own enterprise ID with IANA:\r
+ * http://www.iana.org/numbers.html\r
+ */\r
+#define SNMP_ENTERPRISE_ID 26381\r
+#define SNMP_SYSOBJID_LEN 7\r
+#define SNMP_SYSOBJID {1, 3, 6, 1, 4, 1, SNMP_ENTERPRISE_ID}\r
+\r
+#ifndef SNMP_SYSSERVICES\r
+#define SNMP_SYSSERVICES ((1 << 6) | (1 << 3) | ((IP_FORWARD) << 2))\r
+#endif\r
+\r
+#ifndef SNMP_GET_SYSUPTIME\r
+#define SNMP_GET_SYSUPTIME(sysuptime)\r
+#endif\r
+\r
+static void system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void system_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t system_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void system_set_value(struct obj_def *od, u16_t len, void *value);\r
+static void interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void interfaces_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ifentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+#if !SNMP_SAFE_REQUESTS\r
+static u8_t ifentry_set_test (struct obj_def *od, u16_t len, void *value);\r
+static void ifentry_set_value (struct obj_def *od, u16_t len, void *value);\r
+#endif /* SNMP_SAFE_REQUESTS */\r
+static void atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void atentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void icmp_get_value(struct obj_def *od, u16_t len, void *value);\r
+#if LWIP_TCP\r
+static void tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void tcp_get_value(struct obj_def *od, u16_t len, void *value);\r
+#ifdef THIS_SEEMS_UNUSED\r
+static void tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+#endif\r
+#endif\r
+static void udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void udp_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void udpentry_get_value(struct obj_def *od, u16_t len, void *value);\r
+static void snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+static void snmp_get_value(struct obj_def *od, u16_t len, void *value);\r
+static u8_t snmp_set_test(struct obj_def *od, u16_t len, void *value);\r
+static void snmp_set_value(struct obj_def *od, u16_t len, void *value);\r
+\r
+\r
+/* snmp .1.3.6.1.2.1.11 */\r
+const mib_scalar_node snmp_scalar = {\r
+  &snmp_get_object_def,\r
+  &snmp_get_value,\r
+  &snmp_set_test,\r
+  &snmp_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t snmp_ids[28] = {\r
+  1, 2, 3, 4, 5, 6, 8, 9, 10, 11, 12, 13, 14, 15, 16,\r
+  17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30\r
+};\r
+struct mib_node* const snmp_nodes[28] = {\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar,\r
+  (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar\r
+};\r
+const struct mib_array_node snmp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  28,\r
+  snmp_ids,\r
+  snmp_nodes\r
+};\r
+\r
+/* dot3 and EtherLike MIB not planned. (transmission .1.3.6.1.2.1.10) */\r
+/* historical (some say hysterical). (cmot .1.3.6.1.2.1.9) */\r
+/* lwIP has no EGP, thus may not implement it. (egp .1.3.6.1.2.1.8) */\r
+\r
+/* udp .1.3.6.1.2.1.7 */\r
+/** index root node for udpTable */\r
+struct mib_list_rootnode udp_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t udpentry_ids[2] = { 1, 2 };\r
+struct mib_node* const udpentry_nodes[2] = {\r
+  (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root,\r
+};\r
+const struct mib_array_node udpentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  udpentry_ids,\r
+  udpentry_nodes\r
+};\r
+\r
+s32_t udptable_id = 1;\r
+struct mib_node* udptable_node = (struct mib_node* const)&udpentry;\r
+struct mib_ram_array_node udptable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &udptable_id,\r
+  &udptable_node\r
+};\r
+\r
+const mib_scalar_node udp_scalar = {\r
+  &udp_get_object_def,\r
+  &udp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const udp_nodes[5] = {\r
+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,\r
+  (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar,\r
+  (struct mib_node* const)&udptable\r
+};\r
+const struct mib_array_node udp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  udp_ids,\r
+  udp_nodes\r
+};\r
+\r
+/* tcp .1.3.6.1.2.1.6 */\r
+#if LWIP_TCP\r
+/* only if the TCP protocol is available may implement this group */\r
+/** index root node for tcpConnTable */\r
+struct mib_list_rootnode tcpconntree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const tcpconnentry_nodes[5] = {\r
+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,\r
+  (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root,\r
+  (struct mib_node* const)&tcpconntree_root\r
+};\r
+const struct mib_array_node tcpconnentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  tcpconnentry_ids,\r
+  tcpconnentry_nodes\r
+};\r
+\r
+s32_t tcpconntable_id = 1;\r
+struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry;\r
+struct mib_ram_array_node tcpconntable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+/** @todo update maxlength when inserting / deleting from table\r
+   0 when table is empty, 1 when more than one entry */\r
+  0,\r
+  &tcpconntable_id,\r
+  &tcpconntable_node\r
+};\r
+\r
+const mib_scalar_node tcp_scalar = {\r
+  &tcp_get_object_def,\r
+  &tcp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 };\r
+struct mib_node* const tcp_nodes[15] = {\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar,\r
+  (struct mib_node* const)&tcp_scalar\r
+};\r
+const struct mib_array_node tcp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  15,\r
+  tcp_ids,\r
+  tcp_nodes\r
+};\r
+#endif\r
+\r
+/* icmp .1.3.6.1.2.1.5 */\r
+const mib_scalar_node icmp_scalar = {\r
+  &icmp_get_object_def,\r
+  &icmp_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const icmp_nodes[26] = {\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar,\r
+  (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar\r
+};\r
+const struct mib_array_node icmp = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  26,\r
+  icmp_ids,\r
+  icmp_nodes\r
+};\r
+\r
+/** index root node for ipNetToMediaTable */\r
+struct mib_list_rootnode ipntomtree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 };\r
+struct mib_node* const ipntomentry_nodes[4] = {\r
+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root,\r
+  (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root\r
+};\r
+const struct mib_array_node ipntomentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  4,\r
+  ipntomentry_ids,\r
+  ipntomentry_nodes\r
+};\r
+\r
+s32_t ipntomtable_id = 1;\r
+struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry;\r
+struct mib_ram_array_node ipntomtable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &ipntomtable_id,\r
+  &ipntomtable_node\r
+};\r
+\r
+/** index root node for ipRouteTable */\r
+struct mib_list_rootnode iprtetree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };\r
+struct mib_node* const iprteentry_nodes[13] = {\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root,\r
+  (struct mib_node* const)&iprtetree_root\r
+};\r
+const struct mib_array_node iprteentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  13,\r
+  iprteentry_ids,\r
+  iprteentry_nodes\r
+};\r
+\r
+s32_t iprtetable_id = 1;\r
+struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry;\r
+struct mib_ram_array_node iprtetable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &iprtetable_id,\r
+  &iprtetable_node\r
+};\r
+\r
+/** index root node for ipAddrTable */\r
+struct mib_list_rootnode ipaddrtree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 };\r
+struct mib_node* const ipaddrentry_nodes[5] = {\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root,\r
+  (struct mib_node* const)&ipaddrtree_root\r
+};\r
+const struct mib_array_node ipaddrentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  5,\r
+  ipaddrentry_ids,\r
+  ipaddrentry_nodes\r
+};\r
+\r
+s32_t ipaddrtable_id = 1;\r
+struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry;\r
+struct mib_ram_array_node ipaddrtable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &ipaddrtable_id,\r
+  &ipaddrtable_node\r
+};\r
+\r
+/* ip .1.3.6.1.2.1.4 */\r
+const mib_scalar_node ip_scalar = {\r
+  &ip_get_object_def,\r
+  &ip_get_value,\r
+  &ip_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const ip_nodes[23] = {\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar,\r
+  (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable,\r
+  (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable,\r
+  (struct mib_node* const)&ip_scalar\r
+};\r
+const struct mib_array_node mib2_ip = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  23,\r
+  ip_ids,\r
+  ip_nodes\r
+};\r
+\r
+/** index root node for atTable */\r
+struct mib_list_rootnode arptree_root = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+const s32_t atentry_ids[3] = { 1, 2, 3 };\r
+struct mib_node* const atentry_nodes[3] = {\r
+  (struct mib_node* const)&arptree_root,\r
+  (struct mib_node* const)&arptree_root,\r
+  (struct mib_node* const)&arptree_root\r
+};\r
+const struct mib_array_node atentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  3,\r
+  atentry_ids,\r
+  atentry_nodes\r
+};\r
+\r
+const s32_t attable_id = 1;\r
+struct mib_node* const attable_node = (struct mib_node* const)&atentry;\r
+const struct mib_array_node attable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  &attable_id,\r
+  &attable_node\r
+};\r
+\r
+/* at .1.3.6.1.2.1.3 */\r
+s32_t at_id = 1;\r
+struct mib_node* mib2_at_node = (struct mib_node* const)&attable;\r
+struct mib_ram_array_node at = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &at_id,\r
+  &mib2_at_node\r
+};\r
+\r
+/** index root node for ifTable */\r
+struct mib_list_rootnode iflist_root = {\r
+  &ifentry_get_object_def,\r
+  &ifentry_get_value,\r
+#if SNMP_SAFE_REQUESTS\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+#else /* SNMP_SAFE_REQUESTS */\r
+  &ifentry_set_test,\r
+  &ifentry_set_value,\r
+#endif /* SNMP_SAFE_REQUESTS */\r
+  MIB_NODE_LR,\r
+  0,\r
+  NULL,\r
+  NULL,\r
+  0\r
+};\r
+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 };\r
+struct mib_node* const ifentry_nodes[22] = {\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root,\r
+  (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root\r
+};\r
+const struct mib_array_node ifentry = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  22,\r
+  ifentry_ids,\r
+  ifentry_nodes\r
+};\r
+\r
+s32_t iftable_id = 1;\r
+struct mib_node* iftable_node = (struct mib_node* const)&ifentry;\r
+struct mib_ram_array_node iftable = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_RA,\r
+  0,\r
+  &iftable_id,\r
+  &iftable_node\r
+};\r
+\r
+/* interfaces .1.3.6.1.2.1.2 */\r
+const mib_scalar_node interfaces_scalar = {\r
+  &interfaces_get_object_def,\r
+  &interfaces_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t interfaces_ids[2] = { 1, 2 };\r
+struct mib_node* const interfaces_nodes[2] = {\r
+  (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable\r
+};\r
+const struct mib_array_node interfaces = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  interfaces_ids,\r
+  interfaces_nodes\r
+};\r
+\r
+\r
+/*             0 1 2 3 4 5 6 */\r
+/* system .1.3.6.1.2.1.1 */\r
+const mib_scalar_node sys_tem_scalar = {\r
+  &system_get_object_def,\r
+  &system_get_value,\r
+  &system_set_test,\r
+  &system_set_value,\r
+  MIB_NODE_SC,\r
+  0\r
+};\r
+const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 };\r
+struct mib_node* const sys_tem_nodes[7] = {\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar,\r
+  (struct mib_node* const)&sys_tem_scalar\r
+};\r
+/* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */\r
+const struct mib_array_node sys_tem = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  7,\r
+  sys_tem_ids,\r
+  sys_tem_nodes\r
+};\r
+\r
+/* mib-2 .1.3.6.1.2.1 */\r
+#if LWIP_TCP\r
+#define MIB2_GROUPS 8\r
+#else\r
+#define MIB2_GROUPS 7\r
+#endif\r
+const s32_t mib2_ids[MIB2_GROUPS] =\r
+{\r
+  1,\r
+  2,\r
+  3,\r
+  4,\r
+  5,\r
+#if LWIP_TCP\r
+  6,\r
+#endif\r
+  7,\r
+  11\r
+};\r
+struct mib_node* const mib2_nodes[MIB2_GROUPS] = {\r
+  (struct mib_node* const)&sys_tem,\r
+  (struct mib_node* const)&interfaces,\r
+  (struct mib_node* const)&at,\r
+  (struct mib_node* const)&mib2_ip,\r
+  (struct mib_node* const)&icmp,\r
+#if LWIP_TCP\r
+  (struct mib_node* const)&tcp,\r
+#endif\r
+  (struct mib_node* const)&udp,\r
+  (struct mib_node* const)&snmp\r
+};\r
+\r
+const struct mib_array_node mib2 = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  MIB2_GROUPS,\r
+  mib2_ids,\r
+  mib2_nodes\r
+};\r
+\r
+/* mgmt .1.3.6.1.2 */\r
+const s32_t mgmt_ids[1] = { 1 };\r
+struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 };\r
+const struct mib_array_node mgmt = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  mgmt_ids,\r
+  mgmt_nodes\r
+};\r
+\r
+/* internet .1.3.6.1 */\r
+#if SNMP_PRIVATE_MIB\r
+s32_t internet_ids[2] = { 2, 4 };\r
+struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private };\r
+const struct mib_array_node internet = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  2,\r
+  internet_ids,\r
+  internet_nodes\r
+};\r
+#else\r
+const s32_t internet_ids[1] = { 2 };\r
+struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt };\r
+const struct mib_array_node internet = {\r
+  &noleafs_get_object_def,\r
+  &noleafs_get_value,\r
+  &noleafs_set_test,\r
+  &noleafs_set_value,\r
+  MIB_NODE_AR,\r
+  1,\r
+  internet_ids,\r
+  internet_nodes\r
+};\r
+#endif\r
+\r
+/** mib-2.system.sysObjectID  */\r
+static struct snmp_obj_id sysobjid = {SNMP_SYSOBJID_LEN, SNMP_SYSOBJID};\r
+/** enterprise ID for generic TRAPs, .iso.org.dod.internet.mgmt.mib-2.snmp */\r
+static struct snmp_obj_id snmpgrp_id = {7,{1,3,6,1,2,1,11}};\r
+/** mib-2.system.sysServices */\r
+static const s32_t sysservices = SNMP_SYSSERVICES;\r
+\r
+/** mib-2.system.sysDescr */\r
+static const u8_t sysdescr_len_default = 4;\r
+static const u8_t sysdescr_default[] = "lwIP";\r
+static u8_t* sysdescr_len_ptr = (u8_t*)&sysdescr_len_default;\r
+static u8_t* sysdescr_ptr = (u8_t*)&sysdescr_default[0];\r
+/** mib-2.system.sysContact */\r
+static const u8_t syscontact_len_default = 0;\r
+static const u8_t syscontact_default[] = "";\r
+static u8_t* syscontact_len_ptr = (u8_t*)&syscontact_len_default;\r
+static u8_t* syscontact_ptr = (u8_t*)&syscontact_default[0];\r
+/** mib-2.system.sysName */\r
+static const u8_t sysname_len_default = 8;\r
+static const u8_t sysname_default[] = "FQDN-unk";\r
+static u8_t* sysname_len_ptr = (u8_t*)&sysname_len_default;\r
+static u8_t* sysname_ptr = (u8_t*)&sysname_default[0];\r
+/** mib-2.system.sysLocation */\r
+static const u8_t syslocation_len_default = 0;\r
+static const u8_t syslocation_default[] = "";\r
+static u8_t* syslocation_len_ptr = (u8_t*)&syslocation_len_default;\r
+static u8_t* syslocation_ptr = (u8_t*)&syslocation_default[0];\r
+/** mib-2.snmp.snmpEnableAuthenTraps */\r
+static const u8_t snmpenableauthentraps_default = 2; /* disabled */\r
+static u8_t* snmpenableauthentraps_ptr = (u8_t*)&snmpenableauthentraps_default;\r
+\r
+/** mib-2.interfaces.ifTable.ifEntry.ifSpecific (zeroDotZero) */\r
+static const struct snmp_obj_id ifspecific = {2, {0, 0}};\r
+/** mib-2.ip.ipRouteTable.ipRouteEntry.ipRouteInfo (zeroDotZero) */\r
+static const struct snmp_obj_id iprouteinfo = {2, {0, 0}};\r
+\r
+\r
+\r
+/* mib-2.system counter(s) */\r
+static u32_t sysuptime = 0;\r
+\r
+/* mib-2.ip counter(s) */\r
+static u32_t ipinreceives = 0,\r
+             ipinhdrerrors = 0,\r
+             ipinaddrerrors = 0,\r
+             ipforwdatagrams = 0,\r
+             ipinunknownprotos = 0,\r
+             ipindiscards = 0,\r
+             ipindelivers = 0,\r
+             ipoutrequests = 0,\r
+             ipoutdiscards = 0,\r
+             ipoutnoroutes = 0,\r
+             ipreasmreqds = 0,\r
+             ipreasmoks = 0,\r
+             ipreasmfails = 0,\r
+             ipfragoks = 0,\r
+             ipfragfails = 0,\r
+             ipfragcreates = 0,\r
+             iproutingdiscards = 0;\r
+/* mib-2.icmp counter(s) */\r
+static u32_t icmpinmsgs = 0,\r
+             icmpinerrors = 0,\r
+             icmpindestunreachs = 0,\r
+             icmpintimeexcds = 0,\r
+             icmpinparmprobs = 0,\r
+             icmpinsrcquenchs = 0,\r
+             icmpinredirects = 0,\r
+             icmpinechos = 0,\r
+             icmpinechoreps = 0,\r
+             icmpintimestamps = 0,\r
+             icmpintimestampreps = 0,\r
+             icmpinaddrmasks = 0,\r
+             icmpinaddrmaskreps = 0,\r
+             icmpoutmsgs = 0,\r
+             icmpouterrors = 0,\r
+             icmpoutdestunreachs = 0,\r
+             icmpouttimeexcds = 0,\r
+             icmpoutparmprobs = 0,\r
+             icmpoutsrcquenchs = 0,\r
+             icmpoutredirects = 0,\r
+             icmpoutechos = 0,\r
+             icmpoutechoreps = 0,\r
+             icmpouttimestamps = 0,\r
+             icmpouttimestampreps = 0,\r
+             icmpoutaddrmasks = 0,\r
+             icmpoutaddrmaskreps = 0;\r
+/* mib-2.tcp counter(s) */\r
+static u32_t tcpactiveopens = 0,\r
+             tcppassiveopens = 0,\r
+             tcpattemptfails = 0,\r
+             tcpestabresets = 0,\r
+             tcpinsegs = 0,\r
+             tcpoutsegs = 0,\r
+             tcpretranssegs = 0,\r
+             tcpinerrs = 0,\r
+             tcpoutrsts = 0;\r
+/* mib-2.udp counter(s) */\r
+static u32_t udpindatagrams = 0,\r
+             udpnoports = 0,\r
+             udpinerrors = 0,\r
+             udpoutdatagrams = 0;\r
+/* mib-2.snmp counter(s) */\r
+static u32_t snmpinpkts = 0,\r
+             snmpoutpkts = 0,\r
+             snmpinbadversions = 0,\r
+             snmpinbadcommunitynames = 0,\r
+             snmpinbadcommunityuses = 0,\r
+             snmpinasnparseerrs = 0,\r
+             snmpintoobigs = 0,\r
+             snmpinnosuchnames = 0,\r
+             snmpinbadvalues = 0,\r
+             snmpinreadonlys = 0,\r
+             snmpingenerrs = 0,\r
+             snmpintotalreqvars = 0,\r
+             snmpintotalsetvars = 0,\r
+             snmpingetrequests = 0,\r
+             snmpingetnexts = 0,\r
+             snmpinsetrequests = 0,\r
+             snmpingetresponses = 0,\r
+             snmpintraps = 0,\r
+             snmpouttoobigs = 0,\r
+             snmpoutnosuchnames = 0,\r
+             snmpoutbadvalues = 0,\r
+             snmpoutgenerrs = 0,\r
+             snmpoutgetrequests = 0,\r
+             snmpoutgetnexts = 0,\r
+             snmpoutsetrequests = 0,\r
+             snmpoutgetresponses = 0,\r
+             snmpouttraps = 0;\r
+\r
+\r
+\r
+/* prototypes of the following functions are in lwip/src/include/lwip/snmp.h */\r
+/**\r
+ * Copy octet string.\r
+ *\r
+ * @param dst points to destination\r
+ * @param src points to source\r
+ * @param n number of octets to copy.\r
+ */\r
+void ocstrncpy(u8_t *dst, u8_t *src, u8_t n)\r
+{\r
+  while (n > 0)\r
+  {\r
+    n--;\r
+    *dst++ = *src++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Copy object identifier (s32_t) array.\r
+ *\r
+ * @param dst points to destination\r
+ * @param src points to source\r
+ * @param n number of sub identifiers to copy.\r
+ */\r
+void objectidncpy(s32_t *dst, s32_t *src, u8_t n)\r
+{\r
+  while(n > 0)\r
+  {\r
+    n--;\r
+    *dst++ = *src++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysDescr pointers.\r
+ *\r
+ * @param str if non-NULL then copy str pointer\r
+ * @param len points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_sysdesr(u8_t *str, u8_t *len)\r
+{\r
+  if (str != NULL)\r
+  {\r
+    sysdescr_ptr = str;\r
+    sysdescr_len_ptr = len;\r
+  }\r
+}\r
+\r
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid)\r
+{\r
+  *oid = &sysobjid;\r
+}\r
+\r
+/**\r
+ * Initializes sysObjectID value.\r
+ *\r
+ * @param oid points to stuct snmp_obj_id to copy\r
+ */\r
+void snmp_set_sysobjid(struct snmp_obj_id *oid)\r
+{\r
+  sysobjid = *oid;\r
+}\r
+\r
+/**\r
+ * Must be called at regular 10 msec interval from a timer interrupt\r
+ * or signal handler depending on your runtime environment.\r
+ */\r
+void snmp_inc_sysuptime(void)\r
+{\r
+  sysuptime++;\r
+}\r
+\r
+void snmp_add_sysuptime(u32_t value)\r
+{\r
+  sysuptime+=value;\r
+}\r
+\r
+void snmp_get_sysuptime(u32_t *value)\r
+{\r
+  SNMP_GET_SYSUPTIME(sysuptime);\r
+  *value = sysuptime;\r
+}\r
+\r
+/**\r
+ * Initializes sysContact pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param ocstr if non-NULL then copy str pointer\r
+ * @param ocstrlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    syscontact_ptr = ocstr;\r
+    syscontact_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysName pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param ocstr if non-NULL then copy str pointer\r
+ * @param ocstrlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    sysname_ptr = ocstr;\r
+    sysname_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+/**\r
+ * Initializes sysLocation pointers,\r
+ * e.g. ptrs to non-volatile memory external to lwIP.\r
+ *\r
+ * @param ocstr if non-NULL then copy str pointer\r
+ * @param ocstrlen points to string length, excluding zero terminator\r
+ */\r
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen)\r
+{\r
+  if (ocstr != NULL)\r
+  {\r
+    syslocation_ptr = ocstr;\r
+    syslocation_len_ptr = ocstrlen;\r
+  }\r
+}\r
+\r
+\r
+void snmp_add_ifinoctets(struct netif *ni, u32_t value)\r
+{\r
+  ni->ifinoctets += value;\r
+}\r
+\r
+void snmp_inc_ifinucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifinucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifinnucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifinnucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifindiscards(struct netif *ni)\r
+{\r
+  (ni->ifindiscards)++;\r
+}\r
+\r
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value)\r
+{\r
+  ni->ifoutoctets += value;\r
+}\r
+\r
+void snmp_inc_ifoutucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifoutucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifoutnucastpkts(struct netif *ni)\r
+{\r
+  (ni->ifoutnucastpkts)++;\r
+}\r
+\r
+void snmp_inc_ifoutdiscards(struct netif *ni)\r
+{\r
+  (ni->ifoutdiscards)++;\r
+}\r
+\r
+void snmp_inc_iflist(void)\r
+{\r
+  struct mib_list_node *if_node = NULL;\r
+\r
+  snmp_mib_node_insert(&iflist_root, iflist_root.count + 1, &if_node);\r
+  /* enable getnext traversal on filled table */\r
+  iftable.maxlength = 1;\r
+}\r
+\r
+void snmp_dec_iflist(void)\r
+{\r
+  snmp_mib_node_delete(&iflist_root, iflist_root.tail);\r
+  /* disable getnext traversal on empty table */\r
+  if(iflist_root.count == 0) iftable.maxlength = 0;\r
+}\r
+\r
+/**\r
+ * Inserts ARP table indexes (.xIfIndex.xNetAddress)\r
+ * into arp table index trees (both atTable and ipNetToMediaTable).\r
+ */\r
+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip)\r
+{\r
+  struct mib_list_rootnode *at_rn;\r
+  struct mib_list_node *at_node;\r
+  struct ip_addr hip;\r
+  s32_t arpidx[5];\r
+  u8_t level, tree;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  snmp_netiftoifindex(ni, &arpidx[0]);\r
+  hip.addr = ntohl(ip->addr);\r
+  snmp_iptooid(&hip, &arpidx[1]);\r
+\r
+  for (tree = 0; tree < 2; tree++)\r
+  {\r
+    if (tree == 0)\r
+    {\r
+      at_rn = &arptree_root;\r
+    }\r
+    else\r
+    {\r
+      at_rn = &ipntomtree_root;\r
+    }\r
+    for (level = 0; level < 5; level++)\r
+    {\r
+      at_node = NULL;\r
+      snmp_mib_node_insert(at_rn, arpidx[level], &at_node);\r
+      if ((level != 4) && (at_node != NULL))\r
+      {\r
+        if (at_node->nptr == NULL)\r
+        {\r
+          at_rn = snmp_mib_lrn_alloc();\r
+          at_node->nptr = (struct mib_node*)at_rn;\r
+          if (at_rn != NULL)\r
+          {\r
+            if (level == 3)\r
+            {\r
+              if (tree == 0)\r
+              {\r
+                at_rn->get_object_def = atentry_get_object_def;\r
+                at_rn->get_value = atentry_get_value;\r
+              }\r
+              else\r
+              {\r
+                at_rn->get_object_def = ip_ntomentry_get_object_def;\r
+                at_rn->get_value = ip_ntomentry_get_value;\r
+              }\r
+              at_rn->set_test = noleafs_set_test;\r
+              at_rn->set_value = noleafs_set_value;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            /* at_rn == NULL, malloc failure */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_arpidx_tree() insert failed, mem full"));\r
+            break;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          at_rn = (struct mib_list_rootnode*)at_node->nptr;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  /* enable getnext traversal on filled tables */\r
+  at.maxlength = 1;\r
+  ipntomtable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ARP table indexes (.xIfIndex.xNetAddress)\r
+ * from arp table index trees.\r
+ */\r
+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip)\r
+{\r
+  struct mib_list_rootnode *at_rn, *next, *del_rn[5];\r
+  struct mib_list_node *at_n, *del_n[5];\r
+  struct ip_addr hip;\r
+  s32_t arpidx[5];\r
+  u8_t fc, tree, level, del_cnt;\r
+\r
+  snmp_netiftoifindex(ni, &arpidx[0]);\r
+  hip.addr = ntohl(ip->addr);\r
+  snmp_iptooid(&hip, &arpidx[1]);\r
+\r
+  for (tree = 0; tree < 2; tree++)\r
+  {\r
+    /* mark nodes for deletion */\r
+    if (tree == 0)\r
+    {\r
+      at_rn = &arptree_root;\r
+    }\r
+    else\r
+    {\r
+      at_rn = &ipntomtree_root;\r
+    }\r
+    level = 0;\r
+    del_cnt = 0;\r
+    while ((level < 5) && (at_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(at_rn, arpidx[level], &at_n);\r
+      if (fc == 0)\r
+      {\r
+        /* arpidx[level] does not exist */\r
+        del_cnt = 0;\r
+        at_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = at_rn;\r
+        del_n[del_cnt] = at_n;\r
+        del_cnt++;\r
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        at_rn = (struct mib_list_rootnode*)(at_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      at_rn = del_rn[del_cnt];\r
+      at_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(at_rn, at_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty tables */\r
+  if(arptree_root.count == 0) at.maxlength = 0;\r
+  if(ipntomtree_root.count == 0) ipntomtable.maxlength = 0;\r
+}\r
+\r
+void snmp_inc_ipinreceives(void)\r
+{\r
+  ipinreceives++;\r
+}\r
+\r
+void snmp_inc_ipinhdrerrors(void)\r
+{\r
+  ipinhdrerrors++;\r
+}\r
+\r
+void snmp_inc_ipinaddrerrors(void)\r
+{\r
+  ipinaddrerrors++;\r
+}\r
+\r
+void snmp_inc_ipforwdatagrams(void)\r
+{\r
+  ipforwdatagrams++;\r
+}\r
+\r
+void snmp_inc_ipinunknownprotos(void)\r
+{\r
+  ipinunknownprotos++;\r
+}\r
+\r
+void snmp_inc_ipindiscards(void)\r
+{\r
+  ipindiscards++;\r
+}\r
+\r
+void snmp_inc_ipindelivers(void)\r
+{\r
+  ipindelivers++;\r
+}\r
+\r
+void snmp_inc_ipoutrequests(void)\r
+{\r
+  ipoutrequests++;\r
+}\r
+\r
+void snmp_inc_ipoutdiscards(void)\r
+{\r
+  ipoutdiscards++;\r
+}\r
+\r
+void snmp_inc_ipoutnoroutes(void)\r
+{\r
+  ipoutnoroutes++;\r
+}\r
+\r
+void snmp_inc_ipreasmreqds(void)\r
+{\r
+  ipreasmreqds++;\r
+}\r
+\r
+void snmp_inc_ipreasmoks(void)\r
+{\r
+  ipreasmoks++;\r
+}\r
+\r
+void snmp_inc_ipreasmfails(void)\r
+{\r
+  ipreasmfails++;\r
+}\r
+\r
+void snmp_inc_ipfragoks(void)\r
+{\r
+  ipfragoks++;\r
+}\r
+\r
+void snmp_inc_ipfragfails(void)\r
+{\r
+  ipfragfails++;\r
+}\r
+\r
+void snmp_inc_ipfragcreates(void)\r
+{\r
+  ipfragcreates++;\r
+}\r
+\r
+void snmp_inc_iproutingdiscards(void)\r
+{\r
+  iproutingdiscards++;\r
+}\r
+\r
+/**\r
+ * Inserts ipAddrTable indexes (.ipAdEntAddr)\r
+ * into index tree.\r
+ */\r
+void snmp_insert_ipaddridx_tree(struct netif *ni)\r
+{\r
+  struct mib_list_rootnode *ipa_rn;\r
+  struct mib_list_node *ipa_node;\r
+  struct ip_addr ip;\r
+  s32_t ipaddridx[4];\r
+  u8_t level;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  ip.addr = ntohl(ni->ip_addr.addr);\r
+  snmp_iptooid(&ip, &ipaddridx[0]);\r
+\r
+  level = 0;\r
+  ipa_rn = &ipaddrtree_root;\r
+  while (level < 4)\r
+  {\r
+    ipa_node = NULL;\r
+    snmp_mib_node_insert(ipa_rn, ipaddridx[level], &ipa_node);\r
+    if ((level != 3) && (ipa_node != NULL))\r
+    {\r
+      if (ipa_node->nptr == NULL)\r
+      {\r
+        ipa_rn = snmp_mib_lrn_alloc();\r
+        ipa_node->nptr = (struct mib_node*)ipa_rn;\r
+        if (ipa_rn != NULL)\r
+        {\r
+          if (level == 2)\r
+          {\r
+            ipa_rn->get_object_def = ip_addrentry_get_object_def;\r
+            ipa_rn->get_value = ip_addrentry_get_value;\r
+            ipa_rn->set_test = noleafs_set_test;\r
+            ipa_rn->set_value = noleafs_set_value;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* ipa_rn == NULL, malloc failure */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_ipaddridx_tree() insert failed, mem full"));\r
+          break;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        ipa_rn = (struct mib_list_rootnode*)ipa_node->nptr;\r
+      }\r
+    }\r
+    level++;\r
+  }\r
+  /* enable getnext traversal on filled table */\r
+  ipaddrtable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ipAddrTable indexes (.ipAdEntAddr)\r
+ * from index tree.\r
+ */\r
+void snmp_delete_ipaddridx_tree(struct netif *ni)\r
+{\r
+  struct mib_list_rootnode *ipa_rn, *next, *del_rn[4];\r
+  struct mib_list_node *ipa_n, *del_n[4];\r
+  struct ip_addr ip;\r
+  s32_t ipaddridx[4];\r
+  u8_t fc, level, del_cnt;\r
+\r
+  LWIP_ASSERT("ni != NULL", ni != NULL);\r
+  ip.addr = ntohl(ni->ip_addr.addr);\r
+  snmp_iptooid(&ip, &ipaddridx[0]);\r
+\r
+  /* mark nodes for deletion */\r
+  level = 0;\r
+  del_cnt = 0;\r
+  ipa_rn = &ipaddrtree_root;\r
+  while ((level < 4) && (ipa_rn != NULL))\r
+  {\r
+    fc = snmp_mib_node_find(ipa_rn, ipaddridx[level], &ipa_n);\r
+    if (fc == 0)\r
+    {\r
+      /* ipaddridx[level] does not exist */\r
+      del_cnt = 0;\r
+      ipa_rn = NULL;\r
+    }\r
+    else if (fc == 1)\r
+    {\r
+      del_rn[del_cnt] = ipa_rn;\r
+      del_n[del_cnt] = ipa_n;\r
+      del_cnt++;\r
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);\r
+    }\r
+    else if (fc == 2)\r
+    {\r
+      /* reset delete (2 or more childs) */\r
+      del_cnt = 0;\r
+      ipa_rn = (struct mib_list_rootnode*)(ipa_n->nptr);\r
+    }\r
+    level++;\r
+  }\r
+  /* delete marked index nodes */\r
+  while (del_cnt > 0)\r
+  {\r
+    del_cnt--;\r
+\r
+    ipa_rn = del_rn[del_cnt];\r
+    ipa_n = del_n[del_cnt];\r
+\r
+    next = snmp_mib_node_delete(ipa_rn, ipa_n);\r
+    if (next != NULL)\r
+    {\r
+      LWIP_ASSERT("next_count == 0",next->count == 0);\r
+      snmp_mib_lrn_free(next);\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (ipaddrtree_root.count == 0) ipaddrtable.maxlength = 0;\r
+}\r
+\r
+/**\r
+ * Inserts ipRouteTable indexes (.ipRouteDest)\r
+ * into index tree.\r
+ *\r
+ * @param dflt non-zero for the default rte, zero for network rte\r
+ * @param ni points to network interface for this rte\r
+ *\r
+ * @todo record sysuptime for _this_ route when it is installed\r
+ *   (needed for ipRouteAge) in the netif.\r
+ */\r
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni)\r
+{\r
+  u8_t insert = 0;\r
+  struct ip_addr dst;\r
+\r
+  if (dflt != 0)\r
+  {\r
+    /* the default route 0.0.0.0 */\r
+    dst.addr = 0;\r
+    insert = 1;\r
+  }\r
+  else\r
+  {\r
+    /* route to the network address */\r
+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);\r
+    /* exclude 0.0.0.0 network (reserved for default rte) */\r
+    if (dst.addr != 0) insert = 1;\r
+  }\r
+  if (insert)\r
+  {\r
+    struct mib_list_rootnode *iprte_rn;\r
+    struct mib_list_node *iprte_node;\r
+    s32_t iprteidx[4];\r
+    u8_t level;\r
+\r
+    snmp_iptooid(&dst, &iprteidx[0]);\r
+    level = 0;\r
+    iprte_rn = &iprtetree_root;\r
+    while (level < 4)\r
+    {\r
+      iprte_node = NULL;\r
+      snmp_mib_node_insert(iprte_rn, iprteidx[level], &iprte_node);\r
+      if ((level != 3) && (iprte_node != NULL))\r
+      {\r
+        if (iprte_node->nptr == NULL)\r
+        {\r
+          iprte_rn = snmp_mib_lrn_alloc();\r
+          iprte_node->nptr = (struct mib_node*)iprte_rn;\r
+          if (iprte_rn != NULL)\r
+          {\r
+            if (level == 2)\r
+            {\r
+              iprte_rn->get_object_def = ip_rteentry_get_object_def;\r
+              iprte_rn->get_value = ip_rteentry_get_value;\r
+              iprte_rn->set_test = noleafs_set_test;\r
+              iprte_rn->set_value = noleafs_set_value;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            /* iprte_rn == NULL, malloc failure */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_iprteidx_tree() insert failed, mem full"));\r
+            break;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          iprte_rn = (struct mib_list_rootnode*)iprte_node->nptr;\r
+        }\r
+      }\r
+      level++;\r
+    }\r
+  }\r
+  /* enable getnext traversal on filled table */\r
+  iprtetable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes ipRouteTable indexes (.ipRouteDest)\r
+ * from index tree.\r
+ *\r
+ * @param dflt non-zero for the default rte, zero for network rte\r
+ * @param ni points to network interface for this rte or NULL\r
+ *   for default route to be removed.\r
+ */\r
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni)\r
+{\r
+  u8_t delete = 0;\r
+  struct ip_addr dst;\r
+\r
+  if (dflt != 0)\r
+  {\r
+    /* the default route 0.0.0.0 */\r
+    dst.addr = 0;\r
+    delete = 1;\r
+  }\r
+  else\r
+  {\r
+    /* route to the network address */\r
+    dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr);\r
+    /* exclude 0.0.0.0 network (reserved for default rte) */\r
+    if (dst.addr != 0) delete = 1;\r
+  }\r
+  if (delete)\r
+  {\r
+    struct mib_list_rootnode *iprte_rn, *next, *del_rn[4];\r
+    struct mib_list_node *iprte_n, *del_n[4];\r
+    s32_t iprteidx[4];\r
+    u8_t fc, level, del_cnt;\r
+\r
+    snmp_iptooid(&dst, &iprteidx[0]);\r
+    /* mark nodes for deletion */\r
+    level = 0;\r
+    del_cnt = 0;\r
+    iprte_rn = &iprtetree_root;\r
+    while ((level < 4) && (iprte_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(iprte_rn, iprteidx[level], &iprte_n);\r
+      if (fc == 0)\r
+      {\r
+        /* iprteidx[level] does not exist */\r
+        del_cnt = 0;\r
+        iprte_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = iprte_rn;\r
+        del_n[del_cnt] = iprte_n;\r
+        del_cnt++;\r
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        iprte_rn = (struct mib_list_rootnode*)(iprte_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      iprte_rn = del_rn[del_cnt];\r
+      iprte_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(iprte_rn, iprte_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (iprtetree_root.count == 0) iprtetable.maxlength = 0;\r
+}\r
+\r
+\r
+void snmp_inc_icmpinmsgs(void)\r
+{\r
+  icmpinmsgs++;\r
+}\r
+\r
+void snmp_inc_icmpinerrors(void)\r
+{\r
+  icmpinerrors++;\r
+}\r
+\r
+void snmp_inc_icmpindestunreachs(void)\r
+{\r
+  icmpindestunreachs++;\r
+}\r
+\r
+void snmp_inc_icmpintimeexcds(void)\r
+{\r
+  icmpintimeexcds++;\r
+}\r
+\r
+void snmp_inc_icmpinparmprobs(void)\r
+{\r
+  icmpinparmprobs++;\r
+}\r
+\r
+void snmp_inc_icmpinsrcquenchs(void)\r
+{\r
+  icmpinsrcquenchs++;\r
+}\r
+\r
+void snmp_inc_icmpinredirects(void)\r
+{\r
+  icmpinredirects++;\r
+}\r
+\r
+void snmp_inc_icmpinechos(void)\r
+{\r
+  icmpinechos++;\r
+}\r
+\r
+void snmp_inc_icmpinechoreps(void)\r
+{\r
+  icmpinechoreps++;\r
+}\r
+\r
+void snmp_inc_icmpintimestamps(void)\r
+{\r
+  icmpintimestamps++;\r
+}\r
+\r
+void snmp_inc_icmpintimestampreps(void)\r
+{\r
+  icmpintimestampreps++;\r
+}\r
+\r
+void snmp_inc_icmpinaddrmasks(void)\r
+{\r
+  icmpinaddrmasks++;\r
+}\r
+\r
+void snmp_inc_icmpinaddrmaskreps(void)\r
+{\r
+  icmpinaddrmaskreps++;\r
+}\r
+\r
+void snmp_inc_icmpoutmsgs(void)\r
+{\r
+  icmpoutmsgs++;\r
+}\r
+\r
+void snmp_inc_icmpouterrors(void)\r
+{\r
+  icmpouterrors++;\r
+}\r
+\r
+void snmp_inc_icmpoutdestunreachs(void)\r
+{\r
+  icmpoutdestunreachs++;\r
+}\r
+\r
+void snmp_inc_icmpouttimeexcds(void)\r
+{\r
+  icmpouttimeexcds++;\r
+}\r
+\r
+void snmp_inc_icmpoutparmprobs(void)\r
+{\r
+  icmpoutparmprobs++;\r
+}\r
+\r
+void snmp_inc_icmpoutsrcquenchs(void)\r
+{\r
+  icmpoutsrcquenchs++;\r
+}\r
+\r
+void snmp_inc_icmpoutredirects(void)\r
+{\r
+  icmpoutredirects++;\r
+}\r
+\r
+void snmp_inc_icmpoutechos(void)\r
+{\r
+  icmpoutechos++;\r
+}\r
+\r
+void snmp_inc_icmpoutechoreps(void)\r
+{\r
+  icmpoutechoreps++;\r
+}\r
+\r
+void snmp_inc_icmpouttimestamps(void)\r
+{\r
+  icmpouttimestamps++;\r
+}\r
+\r
+void snmp_inc_icmpouttimestampreps(void)\r
+{\r
+  icmpouttimestampreps++;\r
+}\r
+\r
+void snmp_inc_icmpoutaddrmasks(void)\r
+{\r
+  icmpoutaddrmasks++;\r
+}\r
+\r
+void snmp_inc_icmpoutaddrmaskreps(void)\r
+{\r
+  icmpoutaddrmaskreps++;\r
+}\r
+\r
+void snmp_inc_tcpactiveopens(void)\r
+{\r
+  tcpactiveopens++;\r
+}\r
+\r
+void snmp_inc_tcppassiveopens(void)\r
+{\r
+  tcppassiveopens++;\r
+}\r
+\r
+void snmp_inc_tcpattemptfails(void)\r
+{\r
+  tcpattemptfails++;\r
+}\r
+\r
+void snmp_inc_tcpestabresets(void)\r
+{\r
+  tcpestabresets++;\r
+}\r
+\r
+void snmp_inc_tcpinsegs(void)\r
+{\r
+  tcpinsegs++;\r
+}\r
+\r
+void snmp_inc_tcpoutsegs(void)\r
+{\r
+  tcpoutsegs++;\r
+}\r
+\r
+void snmp_inc_tcpretranssegs(void)\r
+{\r
+  tcpretranssegs++;\r
+}\r
+\r
+void snmp_inc_tcpinerrs(void)\r
+{\r
+  tcpinerrs++;\r
+}\r
+\r
+void snmp_inc_tcpoutrsts(void)\r
+{\r
+  tcpoutrsts++;\r
+}\r
+\r
+void snmp_inc_udpindatagrams(void)\r
+{\r
+  udpindatagrams++;\r
+}\r
+\r
+void snmp_inc_udpnoports(void)\r
+{\r
+  udpnoports++;\r
+}\r
+\r
+void snmp_inc_udpinerrors(void)\r
+{\r
+  udpinerrors++;\r
+}\r
+\r
+void snmp_inc_udpoutdatagrams(void)\r
+{\r
+  udpoutdatagrams++;\r
+}\r
+\r
+/**\r
+ * Inserts udpTable indexes (.udpLocalAddress.udpLocalPort)\r
+ * into index tree.\r
+ */\r
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb)\r
+{\r
+  struct mib_list_rootnode *udp_rn;\r
+  struct mib_list_node *udp_node;\r
+  struct ip_addr ip;\r
+  s32_t udpidx[5];\r
+  u8_t level;\r
+\r
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);\r
+  ip.addr = ntohl(pcb->local_ip.addr);\r
+  snmp_iptooid(&ip, &udpidx[0]);\r
+  udpidx[4] = pcb->local_port;\r
+\r
+  udp_rn = &udp_root;\r
+  for (level = 0; level < 5; level++)\r
+  {\r
+    udp_node = NULL;\r
+    snmp_mib_node_insert(udp_rn, udpidx[level], &udp_node);\r
+    if ((level != 4) && (udp_node != NULL))\r
+    {\r
+      if (udp_node->nptr == NULL)\r
+      {\r
+        udp_rn = snmp_mib_lrn_alloc();\r
+        udp_node->nptr = (struct mib_node*)udp_rn;\r
+        if (udp_rn != NULL)\r
+        {\r
+          if (level == 3)\r
+          {\r
+            udp_rn->get_object_def = udpentry_get_object_def;\r
+            udp_rn->get_value = udpentry_get_value;\r
+            udp_rn->set_test = noleafs_set_test;\r
+            udp_rn->set_value = noleafs_set_value;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* udp_rn == NULL, malloc failure */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_insert_udpidx_tree() insert failed, mem full"));\r
+          break;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        udp_rn = (struct mib_list_rootnode*)udp_node->nptr;\r
+      }\r
+    }\r
+  }\r
+  udptable.maxlength = 1;\r
+}\r
+\r
+/**\r
+ * Removes udpTable indexes (.udpLocalAddress.udpLocalPort)\r
+ * from index tree.\r
+ */\r
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb)\r
+{\r
+  struct mib_list_rootnode *udp_rn, *next, *del_rn[5];\r
+  struct mib_list_node *udp_n, *del_n[5];\r
+  struct ip_addr ip;\r
+  s32_t udpidx[5];\r
+  u8_t bindings, fc, level, del_cnt;\r
+\r
+  LWIP_ASSERT("pcb != NULL", pcb != NULL);\r
+  ip.addr = ntohl(pcb->local_ip.addr);\r
+  snmp_iptooid(&ip, &udpidx[0]);\r
+  udpidx[4] = pcb->local_port;\r
+\r
+  /* count PCBs for a given binding\r
+     (e.g. when reusing ports or for temp output PCBs) */\r
+  bindings = 0;\r
+  pcb = udp_pcbs;\r
+  while ((pcb != NULL))\r
+  {\r
+    if ((pcb->local_ip.addr == ip.addr) &&\r
+        (pcb->local_port == udpidx[4]))\r
+    {\r
+      bindings++;\r
+    }\r
+    pcb = pcb->next;\r
+  }\r
+  if (bindings == 1)\r
+  {\r
+    /* selectively remove */\r
+    /* mark nodes for deletion */\r
+    level = 0;\r
+    del_cnt = 0;\r
+    udp_rn = &udp_root;\r
+    while ((level < 5) && (udp_rn != NULL))\r
+    {\r
+      fc = snmp_mib_node_find(udp_rn, udpidx[level], &udp_n);\r
+      if (fc == 0)\r
+      {\r
+        /* udpidx[level] does not exist */\r
+        del_cnt = 0;\r
+        udp_rn = NULL;\r
+      }\r
+      else if (fc == 1)\r
+      {\r
+        del_rn[del_cnt] = udp_rn;\r
+        del_n[del_cnt] = udp_n;\r
+        del_cnt++;\r
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);\r
+      }\r
+      else if (fc == 2)\r
+      {\r
+        /* reset delete (2 or more childs) */\r
+        del_cnt = 0;\r
+        udp_rn = (struct mib_list_rootnode*)(udp_n->nptr);\r
+      }\r
+      level++;\r
+    }\r
+    /* delete marked index nodes */\r
+    while (del_cnt > 0)\r
+    {\r
+      del_cnt--;\r
+\r
+      udp_rn = del_rn[del_cnt];\r
+      udp_n = del_n[del_cnt];\r
+\r
+      next = snmp_mib_node_delete(udp_rn, udp_n);\r
+      if (next != NULL)\r
+      {\r
+        LWIP_ASSERT("next_count == 0",next->count == 0);\r
+        snmp_mib_lrn_free(next);\r
+      }\r
+    }\r
+  }\r
+  /* disable getnext traversal on empty table */\r
+  if (udp_root.count == 0) udptable.maxlength = 0;\r
+}\r
+\r
+\r
+void snmp_inc_snmpinpkts(void)\r
+{\r
+  snmpinpkts++;\r
+}\r
+\r
+void snmp_inc_snmpoutpkts(void)\r
+{\r
+  snmpoutpkts++;\r
+}\r
+\r
+void snmp_inc_snmpinbadversions(void)\r
+{\r
+  snmpinbadversions++;\r
+}\r
+\r
+void snmp_inc_snmpinbadcommunitynames(void)\r
+{\r
+  snmpinbadcommunitynames++;\r
+}\r
+\r
+void snmp_inc_snmpinbadcommunityuses(void)\r
+{\r
+  snmpinbadcommunityuses++;\r
+}\r
+\r
+void snmp_inc_snmpinasnparseerrs(void)\r
+{\r
+  snmpinasnparseerrs++;\r
+}\r
+\r
+void snmp_inc_snmpintoobigs(void)\r
+{\r
+  snmpintoobigs++;\r
+}\r
+\r
+void snmp_inc_snmpinnosuchnames(void)\r
+{\r
+  snmpinnosuchnames++;\r
+}\r
+\r
+void snmp_inc_snmpinbadvalues(void)\r
+{\r
+  snmpinbadvalues++;\r
+}\r
+\r
+void snmp_inc_snmpinreadonlys(void)\r
+{\r
+  snmpinreadonlys++;\r
+}\r
+\r
+void snmp_inc_snmpingenerrs(void)\r
+{\r
+  snmpingenerrs++;\r
+}\r
+\r
+void snmp_add_snmpintotalreqvars(u8_t value)\r
+{\r
+  snmpintotalreqvars += value;\r
+}\r
+\r
+void snmp_add_snmpintotalsetvars(u8_t value)\r
+{\r
+  snmpintotalsetvars += value;\r
+}\r
+\r
+void snmp_inc_snmpingetrequests(void)\r
+{\r
+  snmpingetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpingetnexts(void)\r
+{\r
+  snmpingetnexts++;\r
+}\r
+\r
+void snmp_inc_snmpinsetrequests(void)\r
+{\r
+  snmpinsetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpingetresponses(void)\r
+{\r
+  snmpingetresponses++;\r
+}\r
+\r
+void snmp_inc_snmpintraps(void)\r
+{\r
+  snmpintraps++;\r
+}\r
+\r
+void snmp_inc_snmpouttoobigs(void)\r
+{\r
+  snmpouttoobigs++;\r
+}\r
+\r
+void snmp_inc_snmpoutnosuchnames(void)\r
+{\r
+  snmpoutnosuchnames++;\r
+}\r
+\r
+void snmp_inc_snmpoutbadvalues(void)\r
+{\r
+  snmpoutbadvalues++;\r
+}\r
+\r
+void snmp_inc_snmpoutgenerrs(void)\r
+{\r
+  snmpoutgenerrs++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetrequests(void)\r
+{\r
+  snmpoutgetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetnexts(void)\r
+{\r
+  snmpoutgetnexts++;\r
+}\r
+\r
+void snmp_inc_snmpoutsetrequests(void)\r
+{\r
+  snmpoutsetrequests++;\r
+}\r
+\r
+void snmp_inc_snmpoutgetresponses(void)\r
+{\r
+  snmpoutgetresponses++;\r
+}\r
+\r
+void snmp_inc_snmpouttraps(void)\r
+{\r
+  snmpouttraps++;\r
+}\r
+\r
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid)\r
+{\r
+  *oid = &snmpgrp_id;\r
+}\r
+\r
+void snmp_set_snmpenableauthentraps(u8_t *value)\r
+{\r
+  if (value != NULL)\r
+  {\r
+    snmpenableauthentraps_ptr = value;\r
+  }\r
+}\r
+\r
+void snmp_get_snmpenableauthentraps(u8_t *value)\r
+{\r
+  *value = *snmpenableauthentraps_ptr;\r
+}\r
+\r
+void\r
+noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  if (ident_len){}\r
+  if (ident){}\r
+  od->instance = MIB_OBJECT_NONE;\r
+}\r
+\r
+void\r
+noleafs_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+}\r
+\r
+u8_t\r
+noleafs_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+  /* can't set */\r
+  return 0;\r
+}\r
+\r
+void\r
+noleafs_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (od){}\r
+  if (len){}\r
+  if (value){}\r
+}\r
+\r
+\r
+/**\r
+ * Returns systems object definitions.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* sysDescr */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *sysdescr_len_ptr;\r
+        break;\r
+      case 2: /* sysObjectID */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = sysobjid.len * sizeof(s32_t);\r
+        break;\r
+      case 3: /* sysUpTime */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 4: /* sysContact */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *syscontact_len_ptr;\r
+        break;\r
+      case 5: /* sysName */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *sysname_len_ptr;\r
+        break;\r
+      case 6: /* sysLocation */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = *syslocation_len_ptr;\r
+        break;\r
+      case 7: /* sysServices */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("system_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns system object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+system_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* sysDescr */\r
+      ocstrncpy(value,sysdescr_ptr,len);\r
+      break;\r
+    case 2: /* sysObjectID */\r
+      objectidncpy((s32_t*)value,(s32_t*)sysobjid.id,len / sizeof(s32_t));\r
+      break;\r
+    case 3: /* sysUpTime */\r
+      {\r
+        snmp_get_sysuptime(value);\r
+      }\r
+      break;\r
+    case 4: /* sysContact */\r
+      ocstrncpy(value,syscontact_ptr,len);\r
+      break;\r
+    case 5: /* sysName */\r
+      ocstrncpy(value,sysname_ptr,len);\r
+      break;\r
+    case 6: /* sysLocation */\r
+      ocstrncpy(value,syslocation_ptr,len);\r
+      break;\r
+    case 7: /* sysServices */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = sysservices;\r
+      }\r
+      break;\r
+  };\r
+}\r
+\r
+static u8_t\r
+system_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+\r
+  if (value) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 4: /* sysContact */\r
+      if ((syscontact_ptr != syscontact_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 5: /* sysName */\r
+      if ((sysname_ptr != sysname_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 6: /* sysLocation */\r
+      if ((syslocation_ptr != syslocation_default) &&\r
+          (len <= 255))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+  };\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+system_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 4: /* sysContact */\r
+      ocstrncpy(syscontact_ptr,value,len);\r
+      *syscontact_len_ptr = len;\r
+      break;\r
+    case 5: /* sysName */\r
+      ocstrncpy(sysname_ptr,value,len);\r
+      *sysname_len_ptr = len;\r
+      break;\r
+    case 6: /* sysLocation */\r
+      ocstrncpy(syslocation_ptr,value,len);\r
+      *syslocation_len_ptr = len;\r
+      break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Returns interfaces.ifnumber object definition.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.index\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+interfaces_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+    od->v_len = sizeof(s32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("interfaces_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns interfaces.ifnumber object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+interfaces_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  if (len){}\r
+  if (od->id_inst_ptr[0] == 1)\r
+  {\r
+    s32_t *sint_ptr = value;\r
+    *sint_ptr = iflist_root.count;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns ifentry object definitions.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.index\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* ifIndex */\r
+      case 3: /* ifType */\r
+      case 4: /* ifMtu */\r
+      case 8: /* ifOperStatus */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* ifDescr */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        /** @todo this should be some sort of sizeof(struct netif.name) */\r
+        od->v_len = 2;\r
+        break;\r
+      case 5: /* ifSpeed */\r
+      case 21: /* ifOutQLen */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 6: /* ifPhysAddress */\r
+        {\r
+          struct netif *netif;\r
+\r
+          snmp_ifindextonetif(ident[1], &netif);\r
+          od->instance = MIB_OBJECT_TAB;\r
+          od->access = MIB_OBJECT_READ_ONLY;\r
+          od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+          od->v_len = netif->hwaddr_len;\r
+        }\r
+        break;\r
+      case 7: /* ifAdminStatus */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 9: /* ifLastChange */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 10: /* ifInOctets */\r
+      case 11: /* ifInUcastPkts */\r
+      case 12: /* ifInNUcastPkts */\r
+      case 13: /* ifInDiscarts */\r
+      case 14: /* ifInErrors */\r
+      case 15: /* ifInUnkownProtos */\r
+      case 16: /* ifOutOctets */\r
+      case 17: /* ifOutUcastPkts */\r
+      case 18: /* ifOutNUcastPkts */\r
+      case 19: /* ifOutDiscarts */\r
+      case 20: /* ifOutErrors */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 22: /* ifSpecific */\r
+        /** @note returning zeroDotZero (0.0) no media specific MIB support */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = ifspecific.len * sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ifentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+/**\r
+ * Returns ifentry object value.\r
+ *\r
+ * @param ident_len the address length (2)\r
+ * @param ident points to objectname.0 (object id trailer)\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value into.\r
+ */\r
+static void\r
+ifentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  u8_t id;\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ifIndex */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = od->id_inst_ptr[1];\r
+      }\r
+      break;\r
+    case 2: /* ifDescr */\r
+      ocstrncpy(value,(u8_t*)netif->name,len);\r
+      break;\r
+    case 3: /* ifType */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = netif->link_type;\r
+      }\r
+      break;\r
+    case 4: /* ifMtu */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = netif->mtu;\r
+      }\r
+      break;\r
+    case 5: /* ifSpeed */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->link_speed;\r
+      }\r
+      break;\r
+    case 6: /* ifPhysAddress */\r
+      ocstrncpy(value,netif->hwaddr,len);\r
+      break;\r
+    case 7: /* ifAdminStatus */\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        if (netif_is_up(netif))\r
+        {\r
+          if (netif_is_link_up(netif))\r
+          {\r
+            *sint_ptr = 1; /* up */\r
+          }\r
+          else\r
+          {\r
+            *sint_ptr = 7; /* lowerLayerDown */\r
+          }\r
+        }\r
+        else\r
+        {\r
+          *sint_ptr = 2; /* down */\r
+        }\r
+      }\r
+      break;\r
+#endif\r
+    case 8: /* ifOperStatus */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        if (netif_is_up(netif))\r
+        {\r
+          *sint_ptr = 1;\r
+        }\r
+        else\r
+        {\r
+          *sint_ptr = 2;\r
+        }\r
+      }\r
+      break;\r
+    case 9: /* ifLastChange */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ts;\r
+      }\r
+      break;\r
+    case 10: /* ifInOctets */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinoctets;\r
+      }\r
+      break;\r
+    case 11: /* ifInUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinucastpkts;\r
+      }\r
+      break;\r
+    case 12: /* ifInNUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifinnucastpkts;\r
+      }\r
+      break;\r
+    case 13: /* ifInDiscarts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifindiscards;\r
+      }\r
+      break;\r
+    case 14: /* ifInErrors */\r
+    case 15: /* ifInUnkownProtos */\r
+      /** @todo add these counters! */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 16: /* ifOutOctets */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutoctets;\r
+      }\r
+      break;\r
+    case 17: /* ifOutUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutucastpkts;\r
+      }\r
+      break;\r
+    case 18: /* ifOutNUcastPkts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutnucastpkts;\r
+      }\r
+      break;\r
+    case 19: /* ifOutDiscarts */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = netif->ifoutdiscards;\r
+      }\r
+      break;\r
+    case 20: /* ifOutErrors */\r
+       /** @todo add this counter! */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 21: /* ifOutQLen */\r
+      /** @todo figure out if this must be 0 (no queue) or 1? */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = 0;\r
+      }\r
+      break;\r
+    case 22: /* ifSpecific */\r
+      objectidncpy((s32_t*)value,(s32_t*)ifspecific.id,len / sizeof(s32_t));\r
+      break;\r
+  };\r
+}\r
+\r
+#if !SNMP_SAFE_REQUESTS\r
+static u8_t\r
+ifentry_set_test (struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  u8_t id, set_ok;\r
+\r
+  set_ok = 0;\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 7: /* ifAdminStatus */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        if (*sint_ptr == 1 || *sint_ptr == 2)\r
+          set_ok = 1;\r
+      }\r
+      break;\r
+  }\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+ifentry_set_value (struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  u8_t id;\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 7: /* ifAdminStatus */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        if (*sint_ptr == 1)\r
+        {\r
+          netif_set_up(netif);\r
+        }\r
+        else if (*sint_ptr == 2)\r
+        {\r
+          netif_set_down(netif);\r
+         }\r
+      }\r
+      break;\r
+  }\r
+}\r
+#endif /* SNMP_SAFE_REQUESTS */\r
+\r
+/**\r
+ * Returns atentry object definitions.\r
+ *\r
+ * @param ident_len the address length (6)\r
+ * @param ident points to objectname.atifindex.atnetaddress\r
+ * @param od points to object definition.\r
+ */\r
+static void\r
+atentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    switch (ident[0])\r
+    {\r
+      case 1: /* atIfIndex */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* atPhysAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */\r
+        break;\r
+      case 3: /* atNetAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("atentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+atentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+#if LWIP_ARP\r
+  u8_t id;\r
+  struct eth_addr* ethaddr_ret;\r
+  struct ip_addr* ipaddr_ret;\r
+#endif /* LWIP_ARP */\r
+  struct ip_addr ip;\r
+  struct netif *netif;\r
+\r
+  if (len) {}\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+\r
+#if LWIP_ARP /** @todo implement a netif_find_addr */\r
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* atIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = od->id_inst_ptr[1];\r
+        }\r
+        break;\r
+      case 2: /* atPhysAddress */\r
+        {\r
+          struct eth_addr *dst = value;\r
+\r
+          *dst = *ethaddr_ret;\r
+        }\r
+        break;\r
+      case 3: /* atNetAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          *dst = *ipaddr_ret;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+#endif /* LWIP_ARP */\r
+}\r
+\r
+static void\r
+ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id));\r
+    switch (id)\r
+    {\r
+      case 1: /* ipForwarding */\r
+      case 2: /* ipDefaultTTL */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 3: /* ipInReceives */\r
+      case 4: /* ipInHdrErrors */\r
+      case 5: /* ipInAddrErrors */\r
+      case 6: /* ipForwDatagrams */\r
+      case 7: /* ipInUnknownProtos */\r
+      case 8: /* ipInDiscards */\r
+      case 9: /* ipInDelivers */\r
+      case 10: /* ipOutRequests */\r
+      case 11: /* ipOutDiscards */\r
+      case 12: /* ipOutNoRoutes */\r
+      case 14: /* ipReasmReqds */\r
+      case 15: /* ipReasmOKs */\r
+      case 16: /* ipReasmFails */\r
+      case 17: /* ipFragOKs */\r
+      case 18: /* ipFragFails */\r
+      case 19: /* ipFragCreates */\r
+      case 23: /* ipRoutingDiscards */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 13: /* ipReasmTimeout */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  if (len) {}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ipForwarding */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+#if IP_FORWARD\r
+        /* forwarding */\r
+        *sint_ptr = 1;\r
+#else\r
+        /* not-forwarding */\r
+        *sint_ptr = 2;\r
+#endif\r
+      }\r
+      break;\r
+    case 2: /* ipDefaultTTL */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+        *sint_ptr = IP_DEFAULT_TTL;\r
+      }\r
+      break;\r
+    case 3: /* ipInReceives */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinreceives;\r
+      }\r
+      break;\r
+    case 4: /* ipInHdrErrors */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinhdrerrors;\r
+      }\r
+      break;\r
+    case 5: /* ipInAddrErrors */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinaddrerrors;\r
+      }\r
+      break;\r
+    case 6: /* ipForwDatagrams */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipforwdatagrams;\r
+      }\r
+      break;\r
+    case 7: /* ipInUnknownProtos */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipinunknownprotos;\r
+      }\r
+      break;\r
+    case 8: /* ipInDiscards */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipindiscards;\r
+      }\r
+      break;\r
+    case 9: /* ipInDelivers */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipindelivers;\r
+      }\r
+      break;\r
+    case 10: /* ipOutRequests */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutrequests;\r
+      }\r
+      break;\r
+    case 11: /* ipOutDiscards */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutdiscards;\r
+      }\r
+      break;\r
+    case 12: /* ipOutNoRoutes */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipoutnoroutes;\r
+      }\r
+      break;\r
+    case 13: /* ipReasmTimeout */\r
+      {\r
+        s32_t *sint_ptr = value;\r
+#if IP_REASSEMBLY\r
+        *sint_ptr = IP_REASS_MAXAGE;\r
+#else\r
+        *sint_ptr = 0;\r
+#endif\r
+      }\r
+      break;\r
+    case 14: /* ipReasmReqds */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmreqds;\r
+      }\r
+      break;\r
+    case 15: /* ipReasmOKs */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmoks;\r
+      }\r
+      break;\r
+    case 16: /* ipReasmFails */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipreasmfails;\r
+      }\r
+      break;\r
+    case 17: /* ipFragOKs */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragoks;\r
+      }\r
+      break;\r
+    case 18: /* ipFragFails */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragfails;\r
+      }\r
+      break;\r
+    case 19: /* ipFragCreates */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = ipfragcreates;\r
+      }\r
+      break;\r
+    case 23: /* ipRoutingDiscards */\r
+      /** @todo can lwIP discard routes at all?? hardwire this to 0?? */\r
+      {\r
+        u32_t *uint_ptr = value;\r
+        *uint_ptr = iproutingdiscards;\r
+      }\r
+      break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Test ip object value before setting.\r
+ *\r
+ * @param od is the object definition\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value from.\r
+ *\r
+ * @note we allow set if the value matches the hardwired value,\r
+ *   otherwise return badvalue.\r
+ */\r
+static u8_t\r
+ip_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+  s32_t *sint_ptr = value;\r
+\r
+  if (len) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* ipForwarding */\r
+#if IP_FORWARD\r
+      /* forwarding */\r
+      if (*sint_ptr == 1)\r
+#else\r
+      /* not-forwarding */\r
+      if (*sint_ptr == 2)\r
+#endif\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+    case 2: /* ipDefaultTTL */\r
+      if (*sint_ptr == IP_DEFAULT_TTL)\r
+      {\r
+        set_ok = 1;\r
+      }\r
+      break;\r
+  };\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (4) */\r
+  ident_len += 4;\r
+  ident -= 4;\r
+\r
+  if (ident_len == 5)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipAdEntAddr */\r
+      case 3: /* ipAdEntNetMask */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* ipAdEntIfIndex */\r
+      case 4: /* ipAdEntBcastAddr */\r
+      case 5: /* ipAdEntReasmMaxSize */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_addrentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  u16_t ifidx;\r
+  struct ip_addr ip;\r
+  struct netif *netif = netif_list;\r
+\r
+  if (len) {}\r
+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+  ifidx = 0;\r
+  while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr))\r
+  {\r
+    netif = netif->next;\r
+    ifidx++;\r
+  }\r
+\r
+  if (netif != NULL)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipAdEntAddr */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = netif->ip_addr;\r
+        }\r
+        break;\r
+      case 2: /* ipAdEntIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = ifidx + 1;\r
+        }\r
+        break;\r
+      case 3: /* ipAdEntNetMask */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = netif->netmask;\r
+        }\r
+        break;\r
+      case 4: /* ipAdEntBcastAddr */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          /* lwIP oddity, there's no broadcast\r
+            address in the netif we can rely on */\r
+          *sint_ptr = ip_addr_broadcast.addr & 1;\r
+        }\r
+        break;\r
+      case 5: /* ipAdEntReasmMaxSize */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+#if IP_REASSEMBLY\r
+          /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs,\r
+           * but only if receiving one fragmented packet at a time.\r
+           * The current solution is to calculate for 2 simultaneous packets...\r
+           */\r
+          *sint_ptr = (IP_HLEN + ((IP_REASS_MAX_PBUFS/2) *\r
+            (PBUF_POOL_BUFSIZE - PBUF_LINK_HLEN - IP_HLEN)));\r
+#else\r
+          /** @todo returning MTU would be a bad thing and\r
+             returning a wild guess like '576' isn't good either */\r
+          *sint_ptr = 0;\r
+#endif\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * @note\r
+ * lwIP IP routing is currently using the network addresses in netif_list.\r
+ * if no suitable network IP is found in netif_list, the default_netif is used.\r
+ */\r
+static void\r
+ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (4) */\r
+  ident_len += 4;\r
+  ident -= 4;\r
+\r
+  if (ident_len == 5)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipRouteDest */\r
+      case 7: /* ipRouteNextHop */\r
+      case 11: /* ipRouteMask */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* ipRouteIfIndex */\r
+      case 3: /* ipRouteMetric1 */\r
+      case 4: /* ipRouteMetric2 */\r
+      case 5: /* ipRouteMetric3 */\r
+      case 6: /* ipRouteMetric4 */\r
+      case 8: /* ipRouteType */\r
+      case 10: /* ipRouteAge */\r
+      case 12: /* ipRouteMetric5 */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 9: /* ipRouteProto */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 13: /* ipRouteInfo */\r
+        /** @note returning zeroDotZero (0.0) no routing protocol specific MIB */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID);\r
+        od->v_len = iprouteinfo.len * sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_rteentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct netif *netif;\r
+  struct ip_addr dest;\r
+  s32_t *ident;\r
+  u8_t id;\r
+\r
+  ident = od->id_inst_ptr;\r
+  snmp_oidtoip(&ident[1], &dest);\r
+  dest.addr = htonl(dest.addr);\r
+\r
+  if (dest.addr == 0)\r
+  {\r
+    /* ip_route() uses default netif for default route */\r
+    netif = netif_default;\r
+  }\r
+  else\r
+  {\r
+    /* not using ip_route(), need exact match! */\r
+    netif = netif_list;\r
+    while ((netif != NULL) &&\r
+            !ip_addr_netcmp(&dest, &(netif->ip_addr), &(netif->netmask)) )\r
+    {\r
+      netif = netif->next;\r
+    }\r
+  }\r
+  if (netif != NULL)\r
+  {\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipRouteDest */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte has 0.0.0.0 dest */\r
+            dst->addr = 0;\r
+          }\r
+          else\r
+          {\r
+            /* netifs have netaddress dest */\r
+            dst->addr = netif->ip_addr.addr & netif->netmask.addr;\r
+          }\r
+        }\r
+        break;\r
+      case 2: /* ipRouteIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          snmp_netiftoifindex(netif, sint_ptr);\r
+        }\r
+        break;\r
+      case 3: /* ipRouteMetric1 */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte has metric 1 */\r
+            *sint_ptr = 1;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes have metric 0 */\r
+            *sint_ptr = 0;\r
+          }\r
+        }\r
+        break;\r
+      case 4: /* ipRouteMetric2 */\r
+      case 5: /* ipRouteMetric3 */\r
+      case 6: /* ipRouteMetric4 */\r
+      case 12: /* ipRouteMetric5 */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* not used */\r
+          *sint_ptr = -1;\r
+        }\r
+        break;\r
+      case 7: /* ipRouteNextHop */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte: gateway */\r
+            *dst = netif->gw;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes: netif ip_addr  */\r
+            *dst = netif->ip_addr;\r
+          }\r
+        }\r
+        break;\r
+      case 8: /* ipRouteType */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte is indirect */\r
+            *sint_ptr = 4;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes are direct */\r
+            *sint_ptr = 3;\r
+          }\r
+        }\r
+        break;\r
+      case 9: /* ipRouteProto */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* locally defined routes */\r
+          *sint_ptr = 2;\r
+        }\r
+        break;\r
+      case 10: /* ipRouteAge */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /** @todo (sysuptime - timestamp last change) / 100\r
+              @see snmp_insert_iprteidx_tree() */\r
+          *sint_ptr = 0;\r
+        }\r
+        break;\r
+      case 11: /* ipRouteMask */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          if (dest.addr == 0)\r
+          {\r
+            /* default rte use 0.0.0.0 mask */\r
+            dst->addr = 0;\r
+          }\r
+          else\r
+          {\r
+            /* other rtes use netmask */\r
+            *dst = netif->netmask;\r
+          }\r
+        }\r
+        break;\r
+      case 13: /* ipRouteInfo */\r
+        objectidncpy((s32_t*)value,(s32_t*)iprouteinfo.id,len / sizeof(s32_t));\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipNetToMediaIfIndex */\r
+      case 4: /* ipNetToMediaType */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* ipNetToMediaPhysAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR);\r
+        od->v_len = 6; /** @todo try to use netif::hwaddr_len */\r
+        break;\r
+      case 3: /* ipNetToMediaNetAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("ip_ntomentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+#if LWIP_ARP\r
+  u8_t id;\r
+  struct eth_addr* ethaddr_ret;\r
+  struct ip_addr* ipaddr_ret;\r
+#endif /* LWIP_ARP */\r
+  struct ip_addr ip;\r
+  struct netif *netif;\r
+\r
+  if (len) {}\r
+\r
+  snmp_ifindextonetif(od->id_inst_ptr[1], &netif);\r
+  snmp_oidtoip(&od->id_inst_ptr[2], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+\r
+#if LWIP_ARP /** @todo implement a netif_find_addr */\r
+  if (etharp_find_addr(netif, &ip, &ethaddr_ret, &ipaddr_ret) > -1)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* ipNetToMediaIfIndex */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = od->id_inst_ptr[1];\r
+        }\r
+        break;\r
+      case 2: /* ipNetToMediaPhysAddress */\r
+        {\r
+          struct eth_addr *dst = value;\r
+\r
+          *dst = *ethaddr_ret;\r
+        }\r
+        break;\r
+      case 3: /* ipNetToMediaNetAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+\r
+          *dst = *ipaddr_ret;\r
+        }\r
+        break;\r
+      case 4: /* ipNetToMediaType */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          /* dynamic (?) */\r
+          *sint_ptr = 3;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+#endif /* LWIP_ARP */\r
+}\r
+\r
+static void\r
+icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if ((ident_len == 2) &&\r
+      (ident[0] > 0) && (ident[0] < 27))\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+    od->v_len = sizeof(u32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("icmp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+icmp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* icmpInMsgs */\r
+      *uint_ptr = icmpinmsgs;\r
+      break;\r
+    case 2: /* icmpInErrors */\r
+      *uint_ptr = icmpinerrors;\r
+      break;\r
+    case 3: /* icmpInDestUnreachs */\r
+      *uint_ptr = icmpindestunreachs;\r
+      break;\r
+    case 4: /* icmpInTimeExcds */\r
+      *uint_ptr = icmpintimeexcds;\r
+      break;\r
+    case 5: /* icmpInParmProbs */\r
+      *uint_ptr = icmpinparmprobs;\r
+      break;\r
+    case 6: /* icmpInSrcQuenchs */\r
+      *uint_ptr = icmpinsrcquenchs;\r
+      break;\r
+    case 7: /* icmpInRedirects */\r
+      *uint_ptr = icmpinredirects;\r
+      break;\r
+    case 8: /* icmpInEchos */\r
+      *uint_ptr = icmpinechos;\r
+      break;\r
+    case 9: /* icmpInEchoReps */\r
+      *uint_ptr = icmpinechoreps;\r
+      break;\r
+    case 10: /* icmpInTimestamps */\r
+      *uint_ptr = icmpintimestamps;\r
+      break;\r
+    case 11: /* icmpInTimestampReps */\r
+      *uint_ptr = icmpintimestampreps;\r
+      break;\r
+    case 12: /* icmpInAddrMasks */\r
+      *uint_ptr = icmpinaddrmasks;\r
+      break;\r
+    case 13: /* icmpInAddrMaskReps */\r
+      *uint_ptr = icmpinaddrmaskreps;\r
+      break;\r
+    case 14: /* icmpOutMsgs */\r
+      *uint_ptr = icmpoutmsgs;\r
+      break;\r
+    case 15: /* icmpOutErrors */\r
+      *uint_ptr = icmpouterrors;\r
+      break;\r
+    case 16: /* icmpOutDestUnreachs */\r
+      *uint_ptr = icmpoutdestunreachs;\r
+      break;\r
+    case 17: /* icmpOutTimeExcds */\r
+      *uint_ptr = icmpouttimeexcds;\r
+      break;\r
+    case 18: /* icmpOutParmProbs */\r
+      *uint_ptr = icmpoutparmprobs;\r
+      break;\r
+    case 19: /* icmpOutSrcQuenchs */\r
+      *uint_ptr = icmpoutsrcquenchs;\r
+      break;\r
+    case 20: /* icmpOutRedirects */\r
+      *uint_ptr = icmpoutredirects;\r
+      break;\r
+    case 21: /* icmpOutEchos */\r
+      *uint_ptr = icmpoutechos;\r
+      break;\r
+    case 22: /* icmpOutEchoReps */\r
+      *uint_ptr = icmpoutechoreps;\r
+      break;\r
+    case 23: /* icmpOutTimestamps */\r
+      *uint_ptr = icmpouttimestamps;\r
+      break;\r
+    case 24: /* icmpOutTimestampReps */\r
+      *uint_ptr = icmpouttimestampreps;\r
+      break;\r
+    case 25: /* icmpOutAddrMasks */\r
+      *uint_ptr = icmpoutaddrmasks;\r
+      break;\r
+    case 26: /* icmpOutAddrMaskReps */\r
+      *uint_ptr = icmpoutaddrmaskreps;\r
+      break;\r
+  }\r
+}\r
+\r
+#if LWIP_TCP\r
+/** @todo tcp grp */\r
+static void\r
+tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  u8_t id;\r
+\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));\r
+\r
+    switch (id)\r
+    {\r
+      case 1: /* tcpRtoAlgorithm */\r
+      case 2: /* tcpRtoMin */\r
+      case 3: /* tcpRtoMax */\r
+      case 4: /* tcpMaxConn */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 5: /* tcpActiveOpens */\r
+      case 6: /* tcpPassiveOpens */\r
+      case 7: /* tcpAttemptFails */\r
+      case 8: /* tcpEstabResets */\r
+      case 10: /* tcpInSegs */\r
+      case 11: /* tcpOutSegs */\r
+      case 12: /* tcpRetransSegs */\r
+      case 14: /* tcpInErrs */\r
+      case 15: /* tcpOutRsts */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 9: /* tcpCurrEstab */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+tcp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  s32_t *sint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* tcpRtoAlgorithm, vanj(4) */\r
+      *sint_ptr = 4;\r
+      break;\r
+    case 2: /* tcpRtoMin */\r
+      /* @todo not the actual value, a guess,\r
+          needs to be calculated */\r
+      *sint_ptr = 1000;\r
+      break;\r
+    case 3: /* tcpRtoMax */\r
+      /* @todo not the actual value, a guess,\r
+         needs to be calculated */\r
+      *sint_ptr = 60000;\r
+      break;\r
+    case 4: /* tcpMaxConn */\r
+      *sint_ptr = MEMP_NUM_TCP_PCB;\r
+      break;\r
+    case 5: /* tcpActiveOpens */\r
+      *uint_ptr = tcpactiveopens;\r
+      break;\r
+    case 6: /* tcpPassiveOpens */\r
+      *uint_ptr = tcppassiveopens;\r
+      break;\r
+    case 7: /* tcpAttemptFails */\r
+      *uint_ptr = tcpattemptfails;\r
+      break;\r
+    case 8: /* tcpEstabResets */\r
+      *uint_ptr = tcpestabresets;\r
+      break;\r
+    case 9: /* tcpCurrEstab */\r
+      {\r
+        u16_t tcpcurrestab = 0;\r
+        struct tcp_pcb *pcb = tcp_active_pcbs;\r
+        while (pcb != NULL)\r
+        {\r
+          if ((pcb->state == ESTABLISHED) ||\r
+              (pcb->state == CLOSE_WAIT))\r
+          {\r
+            tcpcurrestab++;\r
+          }\r
+          pcb = pcb->next;\r
+        }\r
+        *uint_ptr = tcpcurrestab;\r
+      }\r
+      break;\r
+    case 10: /* tcpInSegs */\r
+      *uint_ptr = tcpinsegs;\r
+      break;\r
+    case 11: /* tcpOutSegs */\r
+      *uint_ptr = tcpoutsegs;\r
+      break;\r
+    case 12: /* tcpRetransSegs */\r
+      *uint_ptr = tcpretranssegs;\r
+      break;\r
+    case 14: /* tcpInErrs */\r
+      *uint_ptr = tcpinerrs;\r
+      break;\r
+    case 15: /* tcpOutRsts */\r
+      *uint_ptr = tcpoutrsts;\r
+      break;\r
+  }\r
+}\r
+#ifdef THIS_SEEMS_UNUSED\r
+static void\r
+tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (10) */\r
+  ident_len += 10;\r
+  ident -= 10;\r
+\r
+  if (ident_len == 11)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id));\r
+\r
+    switch (id)\r
+    {\r
+      case 1: /* tcpConnState */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      case 2: /* tcpConnLocalAddress */\r
+      case 4: /* tcpConnRemAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 3: /* tcpConnLocalPort */\r
+      case 5: /* tcpConnRemPort */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("tcpconnentry_get_object_def: no such object\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  struct ip_addr lip, rip;\r
+  u16_t lport, rport;\r
+  s32_t *ident;\r
+\r
+  ident = od->id_inst_ptr;\r
+  snmp_oidtoip(&ident[1], &lip);\r
+  lip.addr = htonl(lip.addr);\r
+  lport = ident[5];\r
+  snmp_oidtoip(&ident[6], &rip);\r
+  rip.addr = htonl(rip.addr);\r
+  rport = ident[10];\r
+\r
+  /** @todo find matching PCB */\r
+}\r
+#endif /* if 0 */\r
+#endif\r
+\r
+static void\r
+udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if ((ident_len == 2) &&\r
+      (ident[0] > 0) && (ident[0] < 6))\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    od->instance = MIB_OBJECT_SCALAR;\r
+    od->access = MIB_OBJECT_READ_ONLY;\r
+    od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+    od->v_len = sizeof(u32_t);\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+udp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+    case 1: /* udpInDatagrams */\r
+      *uint_ptr = udpindatagrams;\r
+      break;\r
+    case 2: /* udpNoPorts */\r
+      *uint_ptr = udpnoports;\r
+      break;\r
+    case 3: /* udpInErrors */\r
+      *uint_ptr = udpinerrors;\r
+      break;\r
+    case 4: /* udpOutDatagrams */\r
+      *uint_ptr = udpoutdatagrams;\r
+      break;\r
+  }\r
+}\r
+\r
+static void\r
+udpentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (5) */\r
+  ident_len += 5;\r
+  ident -= 5;\r
+\r
+  if (ident_len == 6)\r
+  {\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    switch (ident[0])\r
+    {\r
+      case 1: /* udpLocalAddress */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR);\r
+        od->v_len = 4;\r
+        break;\r
+      case 2: /* udpLocalPort */\r
+        od->instance = MIB_OBJECT_TAB;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("udpentry_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+udpentry_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+  struct udp_pcb *pcb;\r
+  struct ip_addr ip;\r
+  u16_t port;\r
+\r
+  if (len){}\r
+  snmp_oidtoip(&od->id_inst_ptr[1], &ip);\r
+  ip.addr = htonl(ip.addr);\r
+  port = od->id_inst_ptr[5];\r
+\r
+  pcb = udp_pcbs;\r
+  while ((pcb != NULL) &&\r
+         !((pcb->local_ip.addr == ip.addr) &&\r
+           (pcb->local_port == port)))\r
+  {\r
+    pcb = pcb->next;\r
+  }\r
+\r
+  if (pcb != NULL)\r
+  {\r
+    id = od->id_inst_ptr[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* udpLocalAddress */\r
+        {\r
+          struct ip_addr *dst = value;\r
+          *dst = pcb->local_ip;\r
+        }\r
+        break;\r
+      case 2: /* udpLocalPort */\r
+        {\r
+          s32_t *sint_ptr = value;\r
+          *sint_ptr = pcb->local_port;\r
+        }\r
+        break;\r
+    }\r
+  }\r
+}\r
+\r
+static void\r
+snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od)\r
+{\r
+  /* return to object name, adding index depth (1) */\r
+  ident_len += 1;\r
+  ident -= 1;\r
+  if (ident_len == 2)\r
+  {\r
+    u8_t id;\r
+\r
+    od->id_inst_len = ident_len;\r
+    od->id_inst_ptr = ident;\r
+\r
+    id = ident[0];\r
+    switch (id)\r
+    {\r
+      case 1: /* snmpInPkts */\r
+      case 2: /* snmpOutPkts */\r
+      case 3: /* snmpInBadVersions */\r
+      case 4: /* snmpInBadCommunityNames */\r
+      case 5: /* snmpInBadCommunityUses */\r
+      case 6: /* snmpInASNParseErrs */\r
+      case 8: /* snmpInTooBigs */\r
+      case 9: /* snmpInNoSuchNames */\r
+      case 10: /* snmpInBadValues */\r
+      case 11: /* snmpInReadOnlys */\r
+      case 12: /* snmpInGenErrs */\r
+      case 13: /* snmpInTotalReqVars */\r
+      case 14: /* snmpInTotalSetVars */\r
+      case 15: /* snmpInGetRequests */\r
+      case 16: /* snmpInGetNexts */\r
+      case 17: /* snmpInSetRequests */\r
+      case 18: /* snmpInGetResponses */\r
+      case 19: /* snmpInTraps */\r
+      case 20: /* snmpOutTooBigs */\r
+      case 21: /* snmpOutNoSuchNames */\r
+      case 22: /* snmpOutBadValues */\r
+      case 24: /* snmpOutGenErrs */\r
+      case 25: /* snmpOutGetRequests */\r
+      case 26: /* snmpOutGetNexts */\r
+      case 27: /* snmpOutSetRequests */\r
+      case 28: /* snmpOutGetResponses */\r
+      case 29: /* snmpOutTraps */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_ONLY;\r
+        od->asn_type = (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER);\r
+        od->v_len = sizeof(u32_t);\r
+        break;\r
+      case 30: /* snmpEnableAuthenTraps */\r
+        od->instance = MIB_OBJECT_SCALAR;\r
+        od->access = MIB_OBJECT_READ_WRITE;\r
+        od->asn_type = (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG);\r
+        od->v_len = sizeof(s32_t);\r
+        break;\r
+      default:\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no such object\n"));\r
+        od->instance = MIB_OBJECT_NONE;\r
+        break;\r
+    };\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("snmp_get_object_def: no scalar\n"));\r
+    od->instance = MIB_OBJECT_NONE;\r
+  }\r
+}\r
+\r
+static void\r
+snmp_get_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u32_t *uint_ptr = value;\r
+  u8_t id;\r
+\r
+  if (len){}\r
+  id = od->id_inst_ptr[0];\r
+  switch (id)\r
+  {\r
+      case 1: /* snmpInPkts */\r
+        *uint_ptr = snmpinpkts;\r
+        break;\r
+      case 2: /* snmpOutPkts */\r
+        *uint_ptr = snmpoutpkts;\r
+        break;\r
+      case 3: /* snmpInBadVersions */\r
+        *uint_ptr = snmpinbadversions;\r
+        break;\r
+      case 4: /* snmpInBadCommunityNames */\r
+        *uint_ptr = snmpinbadcommunitynames;\r
+        break;\r
+      case 5: /* snmpInBadCommunityUses */\r
+        *uint_ptr = snmpinbadcommunityuses;\r
+        break;\r
+      case 6: /* snmpInASNParseErrs */\r
+        *uint_ptr = snmpinasnparseerrs;\r
+        break;\r
+      case 8: /* snmpInTooBigs */\r
+        *uint_ptr = snmpintoobigs;\r
+        break;\r
+      case 9: /* snmpInNoSuchNames */\r
+        *uint_ptr = snmpinnosuchnames;\r
+        break;\r
+      case 10: /* snmpInBadValues */\r
+        *uint_ptr = snmpinbadvalues;\r
+        break;\r
+      case 11: /* snmpInReadOnlys */\r
+        *uint_ptr = snmpinreadonlys;\r
+        break;\r
+      case 12: /* snmpInGenErrs */\r
+        *uint_ptr = snmpingenerrs;\r
+        break;\r
+      case 13: /* snmpInTotalReqVars */\r
+        *uint_ptr = snmpintotalreqvars;\r
+        break;\r
+      case 14: /* snmpInTotalSetVars */\r
+        *uint_ptr = snmpintotalsetvars;\r
+        break;\r
+      case 15: /* snmpInGetRequests */\r
+        *uint_ptr = snmpingetrequests;\r
+        break;\r
+      case 16: /* snmpInGetNexts */\r
+        *uint_ptr = snmpingetnexts;\r
+        break;\r
+      case 17: /* snmpInSetRequests */\r
+        *uint_ptr = snmpinsetrequests;\r
+        break;\r
+      case 18: /* snmpInGetResponses */\r
+        *uint_ptr = snmpingetresponses;\r
+        break;\r
+      case 19: /* snmpInTraps */\r
+        *uint_ptr = snmpintraps;\r
+        break;\r
+      case 20: /* snmpOutTooBigs */\r
+        *uint_ptr = snmpouttoobigs;\r
+        break;\r
+      case 21: /* snmpOutNoSuchNames */\r
+        *uint_ptr = snmpoutnosuchnames;\r
+        break;\r
+      case 22: /* snmpOutBadValues */\r
+        *uint_ptr = snmpoutbadvalues;\r
+        break;\r
+      case 24: /* snmpOutGenErrs */\r
+        *uint_ptr = snmpoutgenerrs;\r
+        break;\r
+      case 25: /* snmpOutGetRequests */\r
+        *uint_ptr = snmpoutgetrequests;\r
+        break;\r
+      case 26: /* snmpOutGetNexts */\r
+        *uint_ptr = snmpoutgetnexts;\r
+        break;\r
+      case 27: /* snmpOutSetRequests */\r
+        *uint_ptr = snmpoutsetrequests;\r
+        break;\r
+      case 28: /* snmpOutGetResponses */\r
+        *uint_ptr = snmpoutgetresponses;\r
+        break;\r
+      case 29: /* snmpOutTraps */\r
+        *uint_ptr = snmpouttraps;\r
+        break;\r
+      case 30: /* snmpEnableAuthenTraps */\r
+        *uint_ptr = *snmpenableauthentraps_ptr;\r
+        break;\r
+  };\r
+}\r
+\r
+/**\r
+ * Test snmp object value before setting.\r
+ *\r
+ * @param od is the object definition\r
+ * @param len return value space (in bytes)\r
+ * @param value points to (varbind) space to copy value from.\r
+ */\r
+static u8_t\r
+snmp_set_test(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id, set_ok;\r
+\r
+  if (len) {}\r
+  set_ok = 0;\r
+  id = od->id_inst_ptr[0];\r
+  if (id == 30)\r
+  {\r
+    /* snmpEnableAuthenTraps */\r
+    s32_t *sint_ptr = value;\r
+\r
+    if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default)\r
+    {\r
+      /* we should have writable non-volatile mem here */\r
+      if ((*sint_ptr == 1) || (*sint_ptr == 2))\r
+      {\r
+        set_ok = 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* const or hardwired value */\r
+      if (*sint_ptr == snmpenableauthentraps_default)\r
+      {\r
+        set_ok = 1;\r
+      }\r
+    }\r
+  }\r
+  return set_ok;\r
+}\r
+\r
+static void\r
+snmp_set_value(struct obj_def *od, u16_t len, void *value)\r
+{\r
+  u8_t id;\r
+\r
+  if (len) {}\r
+  id = od->id_inst_ptr[0];\r
+  if (id == 30)\r
+  {\r
+    /* snmpEnableAuthenTraps */\r
+    s32_t *sint_ptr = value;\r
+    *snmpenableauthentraps_ptr = *sint_ptr;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/mib_structs.c
new file mode 100644 (file)
index 0000000..cff50b5
--- /dev/null
@@ -0,0 +1,1183 @@
+/**\r
+ * @file\r
+ * MIB tree access/construction functions.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/snmp_structs.h"\r
+#include "lwip/mem.h"\r
+\r
+/** .iso.org.dod.internet address prefix, @see snmp_iso_*() */\r
+const s32_t prefix[4] = {1, 3, 6, 1};\r
+\r
+#define NODE_STACK_SIZE (LWIP_SNMP_OBJ_ID_LEN)\r
+/** node stack entry (old news?) */\r
+struct nse\r
+{\r
+  /** right child */\r
+  struct mib_node* r_ptr;\r
+  /** right child identifier */\r
+  s32_t r_id;\r
+  /** right child next level */\r
+  u8_t r_nl;\r
+};\r
+static u8_t node_stack_cnt;\r
+static struct nse node_stack[NODE_STACK_SIZE];\r
+\r
+/**\r
+ * Pushes nse struct onto stack.\r
+ */\r
+static void\r
+push_node(struct nse* node)\r
+{\r
+  LWIP_ASSERT("node_stack_cnt < NODE_STACK_SIZE",node_stack_cnt < NODE_STACK_SIZE);\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("push_node() node=%p id=%"S32_F"\n",(void*)(node->r_ptr),node->r_id));\r
+  if (node_stack_cnt < NODE_STACK_SIZE)\r
+  {\r
+    node_stack[node_stack_cnt] = *node;\r
+    node_stack_cnt++;\r
+  }\r
+}\r
+\r
+/**\r
+ * Pops nse struct from stack.\r
+ */\r
+static void\r
+pop_node(struct nse* node)\r
+{\r
+  if (node_stack_cnt > 0)\r
+  {\r
+    node_stack_cnt--;\r
+    *node = node_stack[node_stack_cnt];\r
+  }\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("pop_node() node=%p id=%"S32_F"\n",(void *)(node->r_ptr),node->r_id));\r
+}\r
+\r
+/**\r
+ * Conversion from ifIndex to lwIP netif\r
+ * @param ifindex is a s32_t object sub-identifier\r
+ * @param netif points to returned netif struct pointer\r
+ */\r
+void\r
+snmp_ifindextonetif(s32_t ifindex, struct netif **netif)\r
+{\r
+  struct netif *nif = netif_list;\r
+  u16_t i, ifidx;\r
+\r
+  ifidx = ifindex - 1;\r
+  i = 0;\r
+  while ((nif != NULL) && (i < ifidx))\r
+  {\r
+    nif = nif->next;\r
+    i++;\r
+  }\r
+  *netif = nif;\r
+}\r
+\r
+/**\r
+ * Conversion from lwIP netif to ifIndex\r
+ * @param netif points to a netif struct\r
+ * @param ifidx points to s32_t object sub-identifier\r
+ */\r
+void\r
+snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)\r
+{\r
+  struct netif *nif = netif_list;\r
+  u16_t i;\r
+\r
+  i = 0;\r
+  while (nif != netif)\r
+  {\r
+    nif = nif->next;\r
+    i++;\r
+  }\r
+  *ifidx = i+1;\r
+}\r
+\r
+/**\r
+ * Conversion from oid to lwIP ip_addr\r
+ * @param ident points to s32_t ident[4] input\r
+ * @param ip points to output struct\r
+ */\r
+void\r
+snmp_oidtoip(s32_t *ident, struct ip_addr *ip)\r
+{\r
+  u32_t ipa;\r
+\r
+  ipa = ident[0];\r
+  ipa <<= 8;\r
+  ipa |= ident[1];\r
+  ipa <<= 8;\r
+  ipa |= ident[2];\r
+  ipa <<= 8;\r
+  ipa |= ident[3];\r
+  ip->addr = ipa;\r
+}\r
+\r
+/**\r
+ * Conversion from lwIP ip_addr to oid\r
+ * @param ip points to input struct\r
+ * @param ident points to s32_t ident[4] output\r
+ */\r
+void\r
+snmp_iptooid(struct ip_addr *ip, s32_t *ident)\r
+{\r
+  u32_t ipa;\r
+\r
+  ipa = ip->addr;\r
+  ident[0] = (ipa >> 24) & 0xff;\r
+  ident[1] = (ipa >> 16) & 0xff;\r
+  ident[2] = (ipa >> 8) & 0xff;\r
+  ident[3] = ipa & 0xff;\r
+}\r
+\r
+struct mib_list_node *\r
+snmp_mib_ln_alloc(s32_t id)\r
+{\r
+  struct mib_list_node *ln;\r
+\r
+  ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node));\r
+  if (ln != NULL)\r
+  {\r
+    ln->prev = NULL;\r
+    ln->next = NULL;\r
+    ln->objid = id;\r
+    ln->nptr = NULL;\r
+  }\r
+  return ln;\r
+}\r
+\r
+void\r
+snmp_mib_ln_free(struct mib_list_node *ln)\r
+{\r
+  mem_free(ln);\r
+}\r
+\r
+struct mib_list_rootnode *\r
+snmp_mib_lrn_alloc(void)\r
+{\r
+  struct mib_list_rootnode *lrn;\r
+\r
+  lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode));\r
+  if (lrn != NULL)\r
+  {\r
+    lrn->get_object_def = noleafs_get_object_def;\r
+    lrn->get_value = noleafs_get_value;\r
+    lrn->set_test = noleafs_set_test;\r
+    lrn->set_value = noleafs_set_value;\r
+    lrn->node_type = MIB_NODE_LR;\r
+    lrn->maxlength = 0;\r
+    lrn->head = NULL;\r
+    lrn->tail = NULL;\r
+    lrn->count = 0;\r
+  }\r
+  return lrn;\r
+}\r
+\r
+void\r
+snmp_mib_lrn_free(struct mib_list_rootnode *lrn)\r
+{\r
+  mem_free(lrn);\r
+}\r
+\r
+/**\r
+ * Inserts node in idx list in a sorted\r
+ * (ascending order) fashion and\r
+ * allocates the node if needed.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param objid is the object sub identifier\r
+ * @param insn points to a pointer to the inserted node\r
+ *   used for constructing the tree.\r
+ * @return -1 if failed, 1 if inserted, 2 if present.\r
+ */\r
+s8_t\r
+snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn)\r
+{\r
+  struct mib_list_node *nn;\r
+  s8_t insert;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+\r
+  /* -1 = malloc failure, 0 = not inserted, 1 = inserted, 2 = was present */\r
+  insert = 0;\r
+  if (rn->head == NULL)\r
+  {\r
+    /* empty list, add first node */\r
+    LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc empty list objid==%"S32_F"\n",objid));\r
+    nn = snmp_mib_ln_alloc(objid);\r
+    if (nn != NULL)\r
+    {\r
+      rn->head = nn;\r
+      rn->tail = nn;\r
+      *insn = nn;\r
+      insert = 1;\r
+    }\r
+    else\r
+    {\r
+      insert = -1;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    struct mib_list_node *n;\r
+    /* at least one node is present */\r
+    n = rn->head;\r
+    while ((n != NULL) && (insert == 0))\r
+    {\r
+      if (n->objid == objid)\r
+      {\r
+        /* node is already there */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("node already there objid==%"S32_F"\n",objid));\r
+        *insn = n;\r
+        insert = 2;\r
+      }\r
+      else if (n->objid < objid)\r
+      {\r
+        if (n->next == NULL)\r
+        {\r
+          /* alloc and insert at the tail */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins tail objid==%"S32_F"\n",objid));\r
+          nn = snmp_mib_ln_alloc(objid);\r
+          if (nn != NULL)\r
+          {\r
+            nn->next = NULL;\r
+            nn->prev = n;\r
+            n->next = nn;\r
+            rn->tail = nn;\r
+            *insn = nn;\r
+            insert = 1;\r
+          }\r
+          else\r
+          {\r
+            /* insertion failure */\r
+            insert = -1;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* there's more to explore: traverse list */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("traverse list\n"));\r
+          n = n->next;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* n->objid > objid */\r
+        /* alloc and insert between n->prev and n */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("alloc ins n->prev, objid==%"S32_F", n\n",objid));\r
+        nn = snmp_mib_ln_alloc(objid);\r
+        if (nn != NULL)\r
+        {\r
+          if (n->prev == NULL)\r
+          {\r
+            /* insert at the head */\r
+            nn->next = n;\r
+            nn->prev = NULL;\r
+            rn->head = nn;\r
+            n->prev = nn;\r
+          }\r
+          else\r
+          {\r
+            /* insert in the middle */\r
+            nn->next = n;\r
+            nn->prev = n->prev;\r
+            n->prev->next = nn;\r
+            n->prev = nn;\r
+          }\r
+          *insn = nn;\r
+          insert = 1;\r
+        }\r
+        else\r
+        {\r
+          /* insertion failure */\r
+          insert = -1;\r
+        }\r
+      }\r
+    }\r
+  }\r
+  if (insert == 1)\r
+  {\r
+    rn->count += 1;\r
+  }\r
+  LWIP_ASSERT("insert != 0",insert != 0);\r
+  return insert;\r
+}\r
+\r
+/**\r
+ * Finds node in idx list and returns deletion mark.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param objid  is the object sub identifier\r
+ * @param fn returns pointer to found node\r
+ * @return 0 if not found, 1 if deletable,\r
+ *   2 can't delete (2 or more children), 3 not a list_node\r
+ */\r
+s8_t\r
+snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn)\r
+{\r
+  s8_t fc;\r
+  struct mib_list_node *n;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+  n = rn->head;\r
+  while ((n != NULL) && (n->objid != objid))\r
+  {\r
+    n = n->next;\r
+  }\r
+  if (n == NULL)\r
+  {\r
+    fc = 0;\r
+  }\r
+  else if (n->nptr == NULL)\r
+  {\r
+    /* leaf, can delete node */\r
+    fc = 1;\r
+  }\r
+  else\r
+  {\r
+    struct mib_list_rootnode *r;\r
+\r
+    if (n->nptr->node_type == MIB_NODE_LR)\r
+    {\r
+      r = (struct mib_list_rootnode *)n->nptr;\r
+      if (r->count > 1)\r
+      {\r
+        /* can't delete node */\r
+        fc = 2;\r
+      }\r
+      else\r
+      {\r
+        /* count <= 1, can delete node */\r
+        fc = 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* other node type */\r
+      fc = 3;\r
+    }\r
+  }\r
+  *fn = n;\r
+  return fc;\r
+}\r
+\r
+/**\r
+ * Removes node from idx list\r
+ * if it has a single child left.\r
+ *\r
+ * @param rn points to the root node\r
+ * @param n points to the node to delete\r
+ * @return the nptr to be freed by caller\r
+ */\r
+struct mib_list_rootnode *\r
+snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n)\r
+{\r
+  struct mib_list_rootnode *next;\r
+\r
+  LWIP_ASSERT("rn != NULL",rn != NULL);\r
+  LWIP_ASSERT("n != NULL",n != NULL);\r
+\r
+  /* caller must remove this sub-tree */\r
+  next = (struct mib_list_rootnode*)(n->nptr);\r
+  rn->count -= 1;\r
+\r
+  if (n == rn->head)\r
+  {\r
+    rn->head = n->next;\r
+    if (n->next != NULL)\r
+    {\r
+      /* not last node, new list begin */\r
+      n->next->prev = NULL;\r
+    }\r
+  }\r
+  else if (n == rn->tail)\r
+  {\r
+    rn->tail = n->prev;\r
+    if (n->prev != NULL)\r
+    {\r
+      /* not last node, new list end */\r
+      n->prev->next = NULL;\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /* node must be in the middle */\r
+    n->prev->next = n->next;\r
+    n->next->prev = n->prev;\r
+  }\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("free list objid==%"S32_F"\n",n->objid));\r
+  snmp_mib_ln_free(n);\r
+  if (rn->count == 0)\r
+  {\r
+    rn->head = NULL;\r
+    rn->tail = NULL;\r
+  }\r
+  return next;\r
+}\r
+\r
+\r
+\r
+/**\r
+ * Searches tree for the supplied (scalar?) object identifier.\r
+ *\r
+ * @param node points to the root of the tree ('.internet')\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @param np points to the found object instance (rerurn)\r
+ * @return pointer to the requested parent (!) node if success, NULL otherwise\r
+ */\r
+struct mib_node *\r
+snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np)\r
+{\r
+  u8_t node_type, ext_level;\r
+\r
+  ext_level = 0;\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("node==%p *ident==%"S32_F"\n",(void*)node,*ident));\r
+  while (node != NULL)\r
+  {\r
+    node_type = node->node_type;\r
+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      u16_t i;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* array node (internal ROM or RAM, fixed length) */\r
+        an = (struct mib_array_node *)node;\r
+        i = 0;\r
+        while ((i < an->maxlength) && (an->objid[i] != *ident))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < an->maxlength)\r
+        {\r
+          /* found it, if available proceed to child, otherwise inspect leaf */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));\r
+          if (an->nptr[i] == NULL)\r
+          {\r
+            /* a scalar leaf OR table,\r
+               inspect remaining instance number / table index */\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)an;\r
+          }\r
+          else\r
+          {\r
+            /* follow next child pointer */\r
+            ident++;\r
+            ident_len--;\r
+            node = an->nptr[i];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed, identifier mismatch (nosuchname) */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("an search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      struct mib_list_node *ln;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* list root node (internal 'RAM', variable length) */\r
+        lrn = (struct mib_list_rootnode *)node;\r
+        ln = lrn->head;\r
+        /* iterate over list, head to tail */\r
+        while ((ln != NULL) && (ln->objid != *ident))\r
+        {\r
+          ln = ln->next;\r
+        }\r
+        if (ln != NULL)\r
+        {\r
+          /* found it, proceed to child */;\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));\r
+          if (ln->nptr == NULL)\r
+          {\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)lrn;\r
+          }\r
+          else\r
+          {\r
+            /* follow next child pointer */\r
+            ident_len--;\r
+            ident++;\r
+            node = ln->nptr;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      u16_t i, len;\r
+\r
+      if (ident_len > 0)\r
+      {\r
+        /* external node (addressing and access via functions) */\r
+        en = (struct mib_external_node *)node;\r
+\r
+        i = 0;\r
+        len = en->level_length(en->addr_inf,ext_level);\r
+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) != 0))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < len)\r
+        {\r
+          s32_t debug_id;\r
+\r
+          en->get_objid(en->addr_inf,ext_level,i,&debug_id);\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid==%"S32_F" *ident==%"S32_F"\n",debug_id,*ident));\r
+          if ((ext_level + 1) == en->tree_levels)\r
+          {\r
+            np->ident_len = ident_len;\r
+            np->ident = ident;\r
+            return (struct mib_node*)en;\r
+          }\r
+          else\r
+          {\r
+            /* found it, proceed to child */\r
+            ident_len--;\r
+            ident++;\r
+            ext_level++;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* search failed */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed *ident==%"S32_F"\n",*ident));\r
+          return NULL;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("en search failed, short object identifier\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else if (node_type == MIB_NODE_SC)\r
+    {\r
+      mib_scalar_node *sn;\r
+\r
+      sn = (mib_scalar_node *)node;\r
+      if ((ident_len == 1) && (*ident == 0))\r
+      {\r
+        np->ident_len = ident_len;\r
+        np->ident = ident;\r
+        return (struct mib_node*)sn;\r
+      }\r
+      else\r
+      {\r
+        /* search failed, short object identifier (nosuchname) */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed, invalid object identifier length\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* unknown node_type */\r
+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node_type %"U16_F" unkown\n",(u16_t)node_type));\r
+      return NULL;\r
+    }\r
+  }\r
+  /* done, found nothing */\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("search failed node==%p\n",(void*)node));\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Test table for presence of at least one table entry.\r
+ */\r
+static u8_t\r
+empty_table(struct mib_node *node)\r
+{\r
+  u8_t node_type;\r
+  u8_t empty = 0;\r
+\r
+  if (node != NULL)\r
+  {\r
+    node_type = node->node_type;\r
+    if (node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      lrn = (struct mib_list_rootnode *)node;\r
+      if ((lrn->count == 0) || (lrn->head == NULL))\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+    else if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      an = (struct mib_array_node *)node;\r
+      if ((an->maxlength == 0) || (an->nptr == NULL))\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+    else if (node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      en = (struct mib_external_node *)node;\r
+      if (en->tree_levels == 0)\r
+      {\r
+        empty = 1;\r
+      }\r
+    }\r
+  }\r
+  return empty;\r
+}\r
+\r
+/**\r
+ * Tree expansion.\r
+ */\r
+struct mib_node *\r
+snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)\r
+{\r
+  u8_t node_type, ext_level, climb_tree;\r
+\r
+  ext_level = 0;\r
+  /* reset node stack */\r
+  node_stack_cnt = 0;\r
+  while (node != NULL)\r
+  {\r
+    climb_tree = 0;\r
+    node_type = node->node_type;\r
+    if ((node_type == MIB_NODE_AR) || (node_type == MIB_NODE_RA))\r
+    {\r
+      struct mib_array_node *an;\r
+      u16_t i;\r
+\r
+      /* array node (internal ROM or RAM, fixed length) */\r
+      an = (struct mib_array_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        i = 0;\r
+        while ((i < an->maxlength) && (an->objid[i] < *ident))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < an->maxlength)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("an->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,an->objid[i],*ident));\r
+          /* add identifier to oidret */\r
+          oidret->id[oidret->len] = an->objid[i];\r
+          (oidret->len)++;\r
+\r
+          if (an->nptr[i] == NULL)\r
+          {\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));\r
+            /* leaf node (e.g. in a fixed size table) */\r
+            if (an->objid[i] > *ident)\r
+            {\r
+              return (struct mib_node*)an;\r
+            }\r
+            else if ((i + 1) < an->maxlength)\r
+            {\r
+              /* an->objid[i] == *ident */\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = an->objid[i + 1];\r
+              (oidret->len)++;\r
+              return (struct mib_node*)an;\r
+            }\r
+            else\r
+            {\r
+              /* (i + 1) == an->maxlength */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            u8_t j;\r
+            struct nse cur_node;\r
+\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));\r
+            /* non-leaf, store right child ptr and id */\r
+            j = i + 1;\r
+            while ((j < an->maxlength) && (empty_table(an->nptr[j])))\r
+            {\r
+              j++;\r
+            }\r
+            if (j < an->maxlength)\r
+            {\r
+              cur_node.r_ptr = an->nptr[j];\r
+              cur_node.r_id = an->objid[j];\r
+              cur_node.r_nl = 0;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (an->objid[i] == *ident)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* an->objid[i] < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* follow next child pointer */\r
+            node = an->nptr[i];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* i == an->maxlength */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        u8_t j;\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        j = 0;\r
+        while ((j < an->maxlength) && empty_table(an->nptr[j]))\r
+        {\r
+          j++;\r
+        }\r
+        if (j < an->maxlength)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left an->objid[j]==%"S32_F"\n",an->objid[j]));\r
+          oidret->id[oidret->len] = an->objid[j];\r
+          (oidret->len)++;\r
+          if (an->nptr[j] == NULL)\r
+          {\r
+            /* leaf node */\r
+            return (struct mib_node*)an;\r
+          }\r
+          else\r
+          {\r
+            /* no leaf, continue */\r
+            node = an->nptr[j];\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* j == an->maxlength */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_LR)\r
+    {\r
+      struct mib_list_rootnode *lrn;\r
+      struct mib_list_node *ln;\r
+\r
+      /* list root node (internal 'RAM', variable length) */\r
+      lrn = (struct mib_list_rootnode *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        ln = lrn->head;\r
+        /* iterate over list, head to tail */\r
+        while ((ln != NULL) && (ln->objid < *ident))\r
+        {\r
+          ln = ln->next;\r
+        }\r
+        if (ln != NULL)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("ln->objid==%"S32_F" *ident==%"S32_F"\n",ln->objid,*ident));\r
+          oidret->id[oidret->len] = ln->objid;\r
+          (oidret->len)++;\r
+          if (ln->nptr == NULL)\r
+          {\r
+            /* leaf node */\r
+            if (ln->objid > *ident)\r
+            {\r
+              return (struct mib_node*)lrn;\r
+            }\r
+            else if (ln->next != NULL)\r
+            {\r
+              /* ln->objid == *ident */\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = ln->next->objid;\r
+              (oidret->len)++;\r
+              return (struct mib_node*)lrn;\r
+            }\r
+            else\r
+            {\r
+              /* ln->next == NULL */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            struct mib_list_node *jn;\r
+            struct nse cur_node;\r
+\r
+            /* non-leaf, store right child ptr and id */\r
+            jn = ln->next;\r
+            while ((jn != NULL) && empty_table(jn->nptr))\r
+            {\r
+              jn = jn->next;\r
+            }\r
+            if (jn != NULL)\r
+            {\r
+              cur_node.r_ptr = jn->nptr;\r
+              cur_node.r_id = jn->objid;\r
+              cur_node.r_nl = 0;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (ln->objid == *ident)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* ln->objid < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* follow next child pointer */\r
+            node = ln->nptr;\r
+          }\r
+\r
+        }\r
+        else\r
+        {\r
+          /* ln == NULL */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        struct mib_list_node *jn;\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        jn = lrn->head;\r
+        while ((jn != NULL) && empty_table(jn->nptr))\r
+        {\r
+          jn = jn->next;\r
+        }\r
+        if (jn != NULL)\r
+        {\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("left jn->objid==%"S32_F"\n",jn->objid));\r
+          oidret->id[oidret->len] = jn->objid;\r
+          (oidret->len)++;\r
+          if (jn->nptr == NULL)\r
+          {\r
+            /* leaf node */\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("jn->nptr == NULL\n"));\r
+            return (struct mib_node*)lrn;\r
+          }\r
+          else\r
+          {\r
+            /* no leaf, continue */\r
+            node = jn->nptr;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* jn == NULL */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_EX)\r
+    {\r
+      struct mib_external_node *en;\r
+      s32_t ex_id;\r
+\r
+      /* external node (addressing and access via functions) */\r
+      en = (struct mib_external_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        u16_t i, len;\r
+\r
+        i = 0;\r
+        len = en->level_length(en->addr_inf,ext_level);\r
+        while ((i < len) && (en->ident_cmp(en->addr_inf,ext_level,i,*ident) < 0))\r
+        {\r
+          i++;\r
+        }\r
+        if (i < len)\r
+        {\r
+          /* add identifier to oidret */\r
+          en->get_objid(en->addr_inf,ext_level,i,&ex_id);\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("en->objid[%"U16_F"]==%"S32_F" *ident==%"S32_F"\n",i,ex_id,*ident));\r
+          oidret->id[oidret->len] = ex_id;\r
+          (oidret->len)++;\r
+\r
+          if ((ext_level + 1) == en->tree_levels)\r
+          {\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("leaf node\n"));\r
+            /* leaf node */\r
+            if (ex_id > *ident)\r
+            {\r
+              return (struct mib_node*)en;\r
+            }\r
+            else if ((i + 1) < len)\r
+            {\r
+              /* ex_id == *ident */\r
+              en->get_objid(en->addr_inf,ext_level,i + 1,&ex_id);\r
+              (oidret->len)--;\r
+              oidret->id[oidret->len] = ex_id;\r
+              (oidret->len)++;\r
+              return (struct mib_node*)en;\r
+            }\r
+            else\r
+            {\r
+              /* (i + 1) == len */\r
+              (oidret->len)--;\r
+              climb_tree = 1;\r
+            }\r
+          }\r
+          else\r
+          {\r
+            u8_t j;\r
+            struct nse cur_node;\r
+\r
+            LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n"));\r
+            /* non-leaf, store right child ptr and id */\r
+            j = i + 1;\r
+            if (j < len)\r
+            {\r
+              /* right node is the current external node */\r
+              cur_node.r_ptr = node;\r
+              en->get_objid(en->addr_inf,ext_level,j,&cur_node.r_id);\r
+              cur_node.r_nl = ext_level + 1;\r
+            }\r
+            else\r
+            {\r
+              cur_node.r_ptr = NULL;\r
+            }\r
+            push_node(&cur_node);\r
+            if (en->ident_cmp(en->addr_inf,ext_level,i,*ident) == 0)\r
+            {\r
+              ident_len--;\r
+              ident++;\r
+            }\r
+            else\r
+            {\r
+              /* external id < *ident */\r
+              ident_len = 0;\r
+            }\r
+            /* proceed to child */\r
+            ext_level++;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          /* i == len (en->level_len()) */\r
+          climb_tree = 1;\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* ident_len == 0, complete with leftmost '.thing' */\r
+        en->get_objid(en->addr_inf,ext_level,0,&ex_id);\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("left en->objid==%"S32_F"\n",ex_id));\r
+        oidret->id[oidret->len] = ex_id;\r
+        (oidret->len)++;\r
+        if ((ext_level + 1) == en->tree_levels)\r
+        {\r
+          /* leaf node */\r
+          LWIP_DEBUGF(SNMP_MIB_DEBUG,("(ext_level + 1) == en->tree_levels\n"));\r
+          return (struct mib_node*)en;\r
+        }\r
+        else\r
+        {\r
+          /* no leaf, proceed to child */\r
+          ext_level++;\r
+        }\r
+      }\r
+    }\r
+    else if(node_type == MIB_NODE_SC)\r
+    {\r
+      mib_scalar_node *sn;\r
+\r
+      /* scalar node  */\r
+      sn = (mib_scalar_node *)node;\r
+      if (ident_len > 0)\r
+      {\r
+        /* at .0 */\r
+        climb_tree = 1;\r
+      }\r
+      else\r
+      {\r
+        /* ident_len == 0, complete object identifier */\r
+        oidret->id[oidret->len] = 0;\r
+        (oidret->len)++;\r
+        /* leaf node */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("completed scalar leaf\n"));\r
+        return (struct mib_node*)sn;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* unknown/unhandled node_type */\r
+      LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node_type %"U16_F" unkown\n",(u16_t)node_type));\r
+      return NULL;\r
+    }\r
+\r
+    if (climb_tree)\r
+    {\r
+      struct nse child;\r
+\r
+      /* find right child ptr */\r
+      child.r_ptr = NULL;\r
+      child.r_id = 0;\r
+      child.r_nl = 0;\r
+      while ((node_stack_cnt > 0) && (child.r_ptr == NULL))\r
+      {\r
+        pop_node(&child);\r
+        /* trim returned oid */\r
+        (oidret->len)--;\r
+      }\r
+      if (child.r_ptr != NULL)\r
+      {\r
+        /* incoming ident is useless beyond this point */\r
+        ident_len = 0;\r
+        oidret->id[oidret->len] = child.r_id;\r
+        oidret->len++;\r
+        node = child.r_ptr;\r
+        ext_level = child.r_nl;\r
+      }\r
+      else\r
+      {\r
+        /* tree ends here ... */\r
+        LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed, tree ends here\n"));\r
+        return NULL;\r
+      }\r
+    }\r
+  }\r
+  /* done, found nothing */\r
+  LWIP_DEBUGF(SNMP_MIB_DEBUG,("expand failed node==%p\n",(void*)node));\r
+  return NULL;\r
+}\r
+\r
+/**\r
+ * Test object identifier for the iso.org.dod.internet prefix.\r
+ *\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @return 1 if it matches, 0 otherwise\r
+ */\r
+u8_t\r
+snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident)\r
+{\r
+  if ((ident_len > 3) &&\r
+      (ident[0] == 1) && (ident[1] == 3) &&\r
+      (ident[2] == 6) && (ident[3] == 1))\r
+  {\r
+    return 1;\r
+  }\r
+  else\r
+  {\r
+    return 0;\r
+  }\r
+}\r
+\r
+/**\r
+ * Expands object identifier to the iso.org.dod.internet\r
+ * prefix for use in getnext operation.\r
+ *\r
+ * @param ident_len the length of the supplied object identifier\r
+ * @param ident points to the array of sub identifiers\r
+ * @param oidret points to returned expanded object identifier\r
+ * @return 1 if it matches, 0 otherwise\r
+ *\r
+ * @note ident_len 0 is allowed, expanding to the first known object id!!\r
+ */\r
+u8_t\r
+snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret)\r
+{\r
+  const s32_t *prefix_ptr;\r
+  s32_t *ret_ptr;\r
+  u8_t i;\r
+\r
+  i = 0;\r
+  prefix_ptr = &prefix[0];\r
+  ret_ptr = &oidret->id[0];\r
+  ident_len = ((ident_len < 4)?ident_len:4);\r
+  while ((i < ident_len) && ((*ident) <= (*prefix_ptr)))\r
+  {\r
+    *ret_ptr++ = *prefix_ptr++;\r
+    ident++;\r
+    i++;\r
+  }\r
+  if (i == ident_len)\r
+  {\r
+    /* match, complete missing bits */\r
+    while (i < 4)\r
+    {\r
+      *ret_ptr++ = *prefix_ptr++;\r
+      i++;\r
+    }\r
+    oidret->len = i;\r
+    return 1;\r
+  }\r
+  else\r
+  {\r
+    /* i != ident_len */\r
+    return 0;\r
+  }\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_in.c
new file mode 100644 (file)
index 0000000..4f62bc9
--- /dev/null
@@ -0,0 +1,1453 @@
+/**\r
+ * @file\r
+ * SNMP input message processing (RFC1157).\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/udp.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_msg.h"\r
+#include "lwip/snmp_structs.h"\r
+\r
+#include <string.h>\r
+\r
+/* public (non-static) constants */\r
+/** SNMP v1 == 0 */\r
+const s32_t snmp_version = 0;\r
+/** default SNMP community string */\r
+const char snmp_publiccommunity[7] = "public";\r
+\r
+/* statically allocated buffers for SNMP_CONCURRENT_REQUESTS */\r
+struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS];\r
+/* UDP Protocol Control Block */\r
+struct udp_pcb *snmp1_pcb;\r
+\r
+static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);\r
+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);\r
+static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat);\r
+\r
+\r
+/**\r
+ * Starts SNMP Agent.\r
+ * Allocates UDP pcb and binds it to IP_ADDR_ANY port 161.\r
+ */\r
+void\r
+snmp_init(void)\r
+{\r
+  struct snmp_msg_pstat *msg_ps;\r
+  u8_t i;\r
+\r
+  snmp1_pcb = udp_new();\r
+  if (snmp1_pcb != NULL)\r
+  {\r
+    udp_recv(snmp1_pcb, snmp_recv, (void *)SNMP_IN_PORT);\r
+    udp_bind(snmp1_pcb, IP_ADDR_ANY, SNMP_IN_PORT);\r
+  }\r
+  msg_ps = &msg_input_list[0];\r
+  for (i=0; i<SNMP_CONCURRENT_REQUESTS; i++)\r
+  {\r
+    msg_ps->state = SNMP_MSG_EMPTY;\r
+    msg_ps->error_index = 0;\r
+    msg_ps->error_status = SNMP_ES_NOERROR;\r
+    msg_ps++;\r
+  }\r
+  trap_msg.pcb = snmp1_pcb;\r
+  /* The coldstart trap will only be output\r
+     if our outgoing interface is up & configured  */\r
+  snmp_coldstart_trap();\r
+}\r
+\r
+static void\r
+snmp_error_response(struct snmp_msg_pstat *msg_ps, u8_t error)\r
+{\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->outvb = msg_ps->invb;\r
+  msg_ps->invb.head = NULL;\r
+  msg_ps->invb.tail = NULL;\r
+  msg_ps->invb.count = 0;\r
+  msg_ps->error_status = error;\r
+  msg_ps->error_index = 1 + msg_ps->vb_idx;\r
+  snmp_send_response(msg_ps);\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->state = SNMP_MSG_EMPTY;\r
+}\r
+\r
+static void\r
+snmp_ok_response(struct snmp_msg_pstat *msg_ps)\r
+{\r
+  err_t err_ret;\r
+\r
+  err_ret = snmp_send_response(msg_ps);\r
+  if (err_ret == ERR_MEM)\r
+  {\r
+    /* serious memory problem, can't return tooBig */\r
+  }\r
+  else\r
+  {\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event = %"S32_F"\n",msg_ps->error_status));\r
+  }\r
+  /* free varbinds (if available) */\r
+  snmp_varbind_list_free(&msg_ps->invb);\r
+  snmp_varbind_list_free(&msg_ps->outvb);\r
+  msg_ps->state = SNMP_MSG_EMPTY;\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP GET.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_get_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;\r
+      en->get_value_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_varbind *vb;\r
+\r
+    /* get_value() answer */\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    /* allocate output varbind */\r
+    vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+    LWIP_ASSERT("vb != NULL",vb != NULL);\r
+    if (vb != NULL)\r
+    {\r
+      vb->next = NULL;\r
+      vb->prev = NULL;\r
+\r
+      /* move name from invb to outvb */\r
+      vb->ident = msg_ps->vb_ptr->ident;\r
+      vb->ident_len = msg_ps->vb_ptr->ident_len;\r
+      /* ensure this memory is refereced once only */\r
+      msg_ps->vb_ptr->ident = NULL;\r
+      msg_ps->vb_ptr->ident_len = 0;\r
+\r
+      vb->value_type = msg_ps->ext_object_def.asn_type;\r
+      vb->value_len =  msg_ps->ext_object_def.v_len;\r
+      if (vb->value_len > 0)\r
+      {\r
+        vb->value = mem_malloc(vb->value_len);\r
+        LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+        if (vb->value != NULL)\r
+        {\r
+          en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);\r
+          snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+          /* search again (if vb_idx < msg_ps->invb.count) */\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          msg_ps->vb_idx += 1;\r
+        }\r
+        else\r
+        {\r
+          en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n"));\r
+          msg_ps->vb_ptr->ident = vb->ident;\r
+          msg_ps->vb_ptr->ident_len = vb->ident_len;\r
+          mem_free(vb);\r
+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* vb->value_len == 0, empty value (e.g. empty string) */\r
+        en->get_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);\r
+        vb->value = NULL;\r
+        snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+        /* search again (if vb_idx < msg_ps->invb.count) */\r
+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no outvb space\n"));\r
+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+    }\r
+  }\r
+\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /** test object identifier for .iso.org.dod.internet prefix */\r
+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))\r
+    {\r
+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                             msg_ps->vb_ptr->ident + 4, &np);\r
+      if (mn != NULL)\r
+      {\r
+        if (mn->node_type == MIB_NODE_EX)\r
+        {\r
+          /* external object */\r
+          struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+          /* save en && args in msg_ps!! */\r
+          msg_ps->ext_mib_node = en;\r
+          msg_ps->ext_name_ptr = np;\r
+\r
+          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+        }\r
+        else\r
+        {\r
+          /* internal object */\r
+          struct obj_def object_def;\r
+\r
+          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+          mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+          if (object_def.instance != MIB_OBJECT_NONE)\r
+          {\r
+            mn = mn;\r
+          }\r
+          else\r
+          {\r
+            /* search failed, object id points to unknown object (nosuchname) */\r
+            mn =  NULL;\r
+          }\r
+          if (mn != NULL)\r
+          {\r
+            struct snmp_varbind *vb;\r
+\r
+            msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;\r
+            /* allocate output varbind */\r
+            vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+            LWIP_ASSERT("vb != NULL",vb != NULL);\r
+            if (vb != NULL)\r
+            {\r
+              vb->next = NULL;\r
+              vb->prev = NULL;\r
+\r
+              /* move name from invb to outvb */\r
+              vb->ident = msg_ps->vb_ptr->ident;\r
+              vb->ident_len = msg_ps->vb_ptr->ident_len;\r
+              /* ensure this memory is refereced once only */\r
+              msg_ps->vb_ptr->ident = NULL;\r
+              msg_ps->vb_ptr->ident_len = 0;\r
+\r
+              vb->value_type = object_def.asn_type;\r
+              vb->value_len = object_def.v_len;\r
+              if (vb->value_len > 0)\r
+              {\r
+                vb->value = mem_malloc(vb->value_len);\r
+                LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+                if (vb->value != NULL)\r
+                {\r
+                  mn->get_value(&object_def, vb->value_len, vb->value);\r
+                  snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+                  msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+                  msg_ps->vb_idx += 1;\r
+                }\r
+                else\r
+                {\r
+                  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n"));\r
+                  msg_ps->vb_ptr->ident = vb->ident;\r
+                  msg_ps->vb_ptr->ident_len = vb->ident_len;\r
+                  mem_free(vb);\r
+                  snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+                }\r
+              }\r
+              else\r
+              {\r
+                /* vb->value_len == 0, empty value (e.g. empty string) */\r
+                vb->value = NULL;\r
+                snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+                msg_ps->vb_idx += 1;\r
+              }\r
+            }\r
+            else\r
+            {\r
+              LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate outvb space\n"));\r
+              snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP GETNEXT.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1], &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE;\r
+      en->get_value_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, 1, &msg_ps->ext_oid.id[msg_ps->ext_oid.len - 1]);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_varbind *vb;\r
+\r
+    /* get_value() answer */\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    vb = snmp_varbind_alloc(&msg_ps->ext_oid,\r
+                            msg_ps->ext_object_def.asn_type,\r
+                            msg_ps->ext_object_def.v_len);\r
+    if (vb != NULL)\r
+    {\r
+      en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value);\r
+      snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+      msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+      msg_ps->vb_idx += 1;\r
+    }\r
+    else\r
+    {\r
+      en->get_value_pc(request_id, &msg_ps->ext_object_def);\r
+      LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_getnext_event: couldn't allocate outvb space\n"));\r
+      snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+    }\r
+  }\r
+\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_obj_id oid;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    if (snmp_iso_prefix_expand(msg_ps->vb_ptr->ident_len, msg_ps->vb_ptr->ident, &oid))\r
+    {\r
+      if (msg_ps->vb_ptr->ident_len > 3)\r
+      {\r
+        /* can offset ident_len and ident */\r
+        mn = snmp_expand_tree((struct mib_node*)&internet,\r
+                              msg_ps->vb_ptr->ident_len - 4,\r
+                              msg_ps->vb_ptr->ident + 4, &oid);\r
+      }\r
+      else\r
+      {\r
+        /* can't offset ident_len -4, ident + 4 */\r
+        mn = snmp_expand_tree((struct mib_node*)&internet, 0, NULL, &oid);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_oid = oid;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, 1, &oid.id[oid.len - 1]);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+        struct snmp_varbind *vb;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+        mn->get_object_def(1, &oid.id[oid.len - 1], &object_def);\r
+\r
+        vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len);\r
+        if (vb != NULL)\r
+        {\r
+          msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE;\r
+          mn->get_value(&object_def, object_def.v_len, vb->value);\r
+          snmp_varbind_tail_add(&msg_ps->outvb, vb);\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          msg_ps->vb_idx += 1;\r
+        }\r
+        else\r
+        {\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv couldn't allocate outvb space\n"));\r
+          snmp_error_response(msg_ps,SNMP_ES_TOOBIG);\r
+        }\r
+      }\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+/**\r
+ * Service an internal or external event for SNMP SET.\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ * @param msg_ps points to the assosicated message process state\r
+ */\r
+static void\r
+snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)\r
+{\r
+  LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_set_event: msg_ps->state==%"U16_F"\n",(u16_t)msg_ps->state));\r
+\r
+  if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_TEST;\r
+      en->set_test_q(request_id, &msg_ps->ext_object_def);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* search failed, object id points to unknown object (nosuchname) */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_TEST)\r
+  {\r
+    struct mib_external_node *en;\r
+\r
+    /* set_test() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+\r
+    if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE)\r
+    {\r
+       if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) &&\r
+           (en->set_test_a(request_id,&msg_ps->ext_object_def,\r
+                           msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))\r
+      {\r
+        msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+      else\r
+      {\r
+        en->set_test_pc(request_id,&msg_ps->ext_object_def);\r
+        /* bad value */\r
+        snmp_error_response(msg_ps,SNMP_ES_BADVALUE);\r
+      }\r
+    }\r
+    else\r
+    {\r
+      en->set_test_pc(request_id,&msg_ps->ext_object_def);\r
+      /* object not available for set */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_GET_OBJDEF_S)\r
+  {\r
+    struct mib_external_node *en;\r
+    struct snmp_name_ptr np;\r
+\r
+    /* get_object_def() answer*/\r
+    en = msg_ps->ext_mib_node;\r
+    np = msg_ps->ext_name_ptr;\r
+\r
+    /* translate answer into a known lifeform */\r
+    en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def);\r
+    if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE)\r
+    {\r
+      msg_ps->state = SNMP_MSG_EXTERNAL_SET_VALUE;\r
+      en->set_value_q(request_id, &msg_ps->ext_object_def,\r
+                      msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);\r
+    }\r
+    else\r
+    {\r
+      en->get_object_def_pc(request_id, np.ident_len, np.ident);\r
+      /* set_value failed, object has disappeared for some odd reason?? */\r
+      snmp_error_response(msg_ps,SNMP_ES_GENERROR);\r
+    }\r
+  }\r
+  else if (msg_ps->state == SNMP_MSG_EXTERNAL_SET_VALUE)\r
+  {\r
+    struct mib_external_node *en;\r
+\r
+    /** set_value_a() @todo: use reply value?? */\r
+    en = msg_ps->ext_mib_node;\r
+    en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);\r
+\r
+    /** @todo use set_value_pc() if toobig */\r
+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+    msg_ps->vb_idx += 1;\r
+  }\r
+\r
+  /* test all values before setting */\r
+  while ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /** test object identifier for .iso.org.dod.internet prefix */\r
+    if (snmp_iso_prefix_tst(msg_ps->vb_ptr->ident_len,  msg_ps->vb_ptr->ident))\r
+    {\r
+      mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                             msg_ps->vb_ptr->ident + 4, &np);\r
+      if (mn != NULL)\r
+      {\r
+        if (mn->node_type == MIB_NODE_EX)\r
+        {\r
+          /* external object */\r
+          struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+          msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF;\r
+          /* save en && args in msg_ps!! */\r
+          msg_ps->ext_mib_node = en;\r
+          msg_ps->ext_name_ptr = np;\r
+\r
+          en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+        }\r
+        else\r
+        {\r
+          /* internal object */\r
+          struct obj_def object_def;\r
+\r
+          msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF;\r
+          mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+          if (object_def.instance != MIB_OBJECT_NONE)\r
+          {\r
+            mn = mn;\r
+          }\r
+          else\r
+          {\r
+            /* search failed, object id points to unknown object (nosuchname) */\r
+            mn = NULL;\r
+          }\r
+          if (mn != NULL)\r
+          {\r
+            msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST;\r
+\r
+            if (object_def.access == MIB_OBJECT_READ_WRITE)\r
+            {\r
+              if ((object_def.asn_type == msg_ps->vb_ptr->value_type) &&\r
+                  (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0))\r
+              {\r
+                msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+                msg_ps->vb_idx += 1;\r
+              }\r
+              else\r
+              {\r
+                /* bad value */\r
+                snmp_error_response(msg_ps,SNMP_ES_BADVALUE);\r
+              }\r
+            }\r
+            else\r
+            {\r
+              /* object not available for set */\r
+              snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+            }\r
+          }\r
+        }\r
+      }\r
+    }\r
+    else\r
+    {\r
+      mn = NULL;\r
+    }\r
+    if (mn == NULL)\r
+    {\r
+      /* mn == NULL, noSuchName */\r
+      snmp_error_response(msg_ps,SNMP_ES_NOSUCHNAME);\r
+    }\r
+  }\r
+\r
+  if ((msg_ps->state == SNMP_MSG_SEARCH_OBJ) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    msg_ps->vb_idx = 0;\r
+    msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+  }\r
+\r
+  /* set all values "atomically" (be as "atomic" as possible) */\r
+  while ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&\r
+         (msg_ps->vb_idx < msg_ps->invb.count))\r
+  {\r
+    struct mib_node *mn;\r
+    struct snmp_name_ptr np;\r
+\r
+    if (msg_ps->vb_idx == 0)\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->invb.head;\r
+    }\r
+    else\r
+    {\r
+      msg_ps->vb_ptr = msg_ps->vb_ptr->next;\r
+    }\r
+    /* skip iso prefix test, was done previously while settesting() */\r
+    mn = snmp_search_tree((struct mib_node*)&internet, msg_ps->vb_ptr->ident_len - 4,\r
+                           msg_ps->vb_ptr->ident + 4, &np);\r
+    /* check if object is still available\r
+       (e.g. external hot-plug thingy present?) */\r
+    if (mn != NULL)\r
+    {\r
+      if (mn->node_type == MIB_NODE_EX)\r
+      {\r
+        /* external object */\r
+        struct mib_external_node *en = (struct mib_external_node*)mn;\r
+\r
+        msg_ps->state = SNMP_MSG_EXTERNAL_GET_OBJDEF_S;\r
+        /* save en && args in msg_ps!! */\r
+        msg_ps->ext_mib_node = en;\r
+        msg_ps->ext_name_ptr = np;\r
+\r
+        en->get_object_def_q(en->addr_inf, request_id, np.ident_len, np.ident);\r
+      }\r
+      else\r
+      {\r
+        /* internal object */\r
+        struct obj_def object_def;\r
+\r
+        msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF_S;\r
+        mn->get_object_def(np.ident_len, np.ident, &object_def);\r
+        msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;\r
+        mn->set_value(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value);\r
+        msg_ps->vb_idx += 1;\r
+      }\r
+    }\r
+  }\r
+  if ((msg_ps->state == SNMP_MSG_INTERNAL_SET_VALUE) &&\r
+      (msg_ps->vb_idx == msg_ps->invb.count))\r
+  {\r
+    /* simply echo the input if we can set it\r
+       @todo do we need to return the actual value?\r
+       e.g. if value is silently modified or behaves sticky? */\r
+    msg_ps->outvb = msg_ps->invb;\r
+    msg_ps->invb.head = NULL;\r
+    msg_ps->invb.tail = NULL;\r
+    msg_ps->invb.count = 0;\r
+    snmp_ok_response(msg_ps);\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ * Handle one internal or external event.\r
+ * Called for one async event. (recv external/private answer)\r
+ *\r
+ * @param request_id identifies requests from 0 to (SNMP_CONCURRENT_REQUESTS-1)\r
+ */\r
+void\r
+snmp_msg_event(u8_t request_id)\r
+{\r
+  struct snmp_msg_pstat *msg_ps;\r
+\r
+  if (request_id < SNMP_CONCURRENT_REQUESTS)\r
+  {\r
+    msg_ps = &msg_input_list[request_id];\r
+    if (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ)\r
+    {\r
+      snmp_msg_getnext_event(request_id, msg_ps);\r
+    }\r
+    else if (msg_ps->rt == SNMP_ASN1_PDU_GET_REQ)\r
+    {\r
+      snmp_msg_get_event(request_id, msg_ps);\r
+    }\r
+    else if(msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)\r
+    {\r
+      snmp_msg_set_event(request_id, msg_ps);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/* lwIP UDP receive callback function */\r
+static void\r
+snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port)\r
+{\r
+  struct udp_hdr *udphdr;\r
+\r
+  /* suppress unused argument warning */\r
+  LWIP_UNUSED_ARG(arg);\r
+  /* peek in the UDP header (goto IP payload) */\r
+  if(pbuf_header(p, UDP_HLEN)){\r
+    LWIP_ASSERT("Can't move to UDP header", 0);\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  udphdr = p->payload;\r
+\r
+  /* check if datagram is really directed at us (including broadcast requests) */\r
+  if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT))\r
+  {\r
+    struct snmp_msg_pstat *msg_ps;\r
+    u8_t req_idx;\r
+\r
+    /* traverse input message process list, look for SNMP_MSG_EMPTY */\r
+    msg_ps = &msg_input_list[0];\r
+    req_idx = 0;\r
+    while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY))\r
+    {\r
+      req_idx++;\r
+      msg_ps++;\r
+    }\r
+    if (req_idx != SNMP_CONCURRENT_REQUESTS)\r
+    {\r
+      err_t err_ret;\r
+      u16_t payload_len;\r
+      u16_t payload_ofs;\r
+      u16_t varbind_ofs = 0;\r
+\r
+      /* accepting request */\r
+      snmp_inc_snmpinpkts();\r
+      /* record used 'protocol control block' */\r
+      msg_ps->pcb = pcb;\r
+      /* source address (network order) */\r
+      msg_ps->sip = *addr;\r
+      /* source port (host order (lwIP oddity)) */\r
+      msg_ps->sp = port;\r
+      /* read UDP payload length from UDP header */\r
+      payload_len = ntohs(udphdr->len) - UDP_HLEN;\r
+\r
+      /* adjust to UDP payload */\r
+      payload_ofs = UDP_HLEN;\r
+\r
+      /* check total length, version, community, pdu type */\r
+      err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps);\r
+      if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) ||\r
+           (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) ||\r
+           (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) &&\r
+          ((msg_ps->error_status == SNMP_ES_NOERROR) &&\r
+           (msg_ps->error_index == 0)) )\r
+      {\r
+        /* Only accept requests and requests without error (be robust) */\r
+        err_ret = err_ret;\r
+      }\r
+      else\r
+      {\r
+        /* Reject response and trap headers or error requests as input! */\r
+        err_ret = ERR_ARG;\r
+      }\r
+      if (err_ret == ERR_OK)\r
+      {\r
+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community));\r
+\r
+        /* Builds a list of variable bindings. Copy the varbinds from the pbuf\r
+          chain to glue them when these are divided over two or more pbuf's. */\r
+        err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps);\r
+        if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0))\r
+        {\r
+          /* we've decoded the incoming message, release input msg now */\r
+          pbuf_free(p);\r
+\r
+          msg_ps->error_status = SNMP_ES_NOERROR;\r
+          msg_ps->error_index = 0;\r
+          /* find object for each variable binding */\r
+          msg_ps->state = SNMP_MSG_SEARCH_OBJ;\r
+          /* first variable binding from list to inspect */\r
+          msg_ps->vb_idx = 0;\r
+\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count));\r
+\r
+          /* handle input event and as much objects as possible in one go */\r
+          snmp_msg_event(req_idx);\r
+        }\r
+        else\r
+        {\r
+          /* varbind-list decode failed, or varbind list empty.\r
+             drop request silently, do not return error!\r
+             (errors are only returned for a specific varbind failure) */\r
+          pbuf_free(p);\r
+          LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n"));\r
+        }\r
+      }\r
+      else\r
+      {\r
+        /* header check failed\r
+           drop request silently, do not return error! */\r
+        pbuf_free(p);\r
+        LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n"));\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* exceeding number of concurrent requests */\r
+      pbuf_free(p);\r
+    }\r
+  }\r
+  else\r
+  {\r
+    /* datagram not for us */\r
+    pbuf_free(p);\r
+  }\r
+}\r
+\r
+/**\r
+ * Checks and decodes incoming SNMP message header, logs header errors.\r
+ *\r
+ * @param p points to pbuf chain of SNMP message (UDP payload)\r
+ * @param ofs points to first octet of SNMP message\r
+ * @param pdu_len the length of the UDP payload\r
+ * @param ofs_ret returns the ofset of the variable bindings\r
+ * @param m_stat points to the current message request state return\r
+ * @return\r
+ * - ERR_OK SNMP header is sane and accepted\r
+ * - ERR_ARG SNMP header is either malformed or rejected\r
+ */\r
+static err_t\r
+snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)\r
+{\r
+  err_t derr;\r
+  u16_t len, ofs_base;\r
+  u8_t  len_octets;\r
+  u8_t  type;\r
+  s32_t version;\r
+\r
+  ofs_base = ofs;\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) ||\r
+      (pdu_len != (1 + len_octets + len)) ||\r
+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (version) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &version);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  if (version != 0)\r
+  {\r
+    /* not version 1 */\r
+    snmp_inc_snmpinbadversions();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR)))\r
+  {\r
+    /* can't decode or no octet string (community) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, SNMP_COMMUNITY_STR_LEN, m_stat->community);\r
+  if (derr != ERR_OK)\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* add zero terminator */\r
+  len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN));\r
+  m_stat->community[len] = 0;\r
+  m_stat->com_strlen = len;\r
+  if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0)\r
+  {\r
+    /** @todo: move this if we need to check more names */\r
+    snmp_inc_snmpinbadcommunitynames();\r
+    snmp_authfail_trap();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if (derr != ERR_OK)\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  switch(type)\r
+  {\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_REQ):\r
+      /* GetRequest PDU */\r
+      snmp_inc_snmpingetrequests();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_NEXT_REQ):\r
+      /* GetNextRequest PDU */\r
+      snmp_inc_snmpingetnexts();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP):\r
+      /* GetResponse PDU */\r
+      snmp_inc_snmpingetresponses();\r
+      derr = ERR_ARG;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_SET_REQ):\r
+      /* SetRequest PDU */\r
+      snmp_inc_snmpinsetrequests();\r
+      derr = ERR_OK;\r
+      break;\r
+    case (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP):\r
+      /* Trap PDU */\r
+      snmp_inc_snmpintraps();\r
+      derr = ERR_ARG;\r
+      break;\r
+    default:\r
+      snmp_inc_snmpinasnparseerrs();\r
+      derr = ERR_ARG;\r
+      break;\r
+  }\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* unsupported input PDU for this agent (no parse error) */\r
+    return ERR_ARG;\r
+  }\r
+  m_stat->rt = type & 0x1F;\r
+  ofs += (1 + len_octets);\r
+  if (len != (pdu_len - (ofs - ofs_base)))\r
+  {\r
+    /* decoded PDU length does not equal actual payload length */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (request ID) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->rid);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (error-status) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* must be noError (0) for incoming requests.\r
+     log errors for mib-2 completeness and for debug purposes */\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_status);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  switch (m_stat->error_status)\r
+  {\r
+    case SNMP_ES_TOOBIG:\r
+      snmp_inc_snmpintoobigs();\r
+      break;\r
+    case SNMP_ES_NOSUCHNAME:\r
+      snmp_inc_snmpinnosuchnames();\r
+      break;\r
+    case SNMP_ES_BADVALUE:\r
+      snmp_inc_snmpinbadvalues();\r
+      break;\r
+    case SNMP_ES_READONLY:\r
+      snmp_inc_snmpinreadonlys();\r
+      break;\r
+    case SNMP_ES_GENERROR:\r
+      snmp_inc_snmpingenerrs();\r
+      break;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+  if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG)))\r
+  {\r
+    /* can't decode or no integer (error-index) */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  /* must be 0 for incoming requests.\r
+     decode anyway to catch bad integers (and dirty tricks) */\r
+  derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, &m_stat->error_index);\r
+  if (derr != ERR_OK)\r
+  {\r
+    /* can't decode */\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets + len);\r
+  *ofs_ret = ofs;\r
+  return ERR_OK;\r
+}\r
+\r
+static err_t\r
+snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat)\r
+{\r
+  err_t derr;\r
+  u16_t len, vb_len;\r
+  u8_t  len_octets;\r
+  u8_t type;\r
+\r
+  /* variable binding list */\r
+  snmp_asn1_dec_type(p, ofs, &type);\r
+  derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &vb_len);\r
+  if ((derr != ERR_OK) ||\r
+      (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)))\r
+  {\r
+    snmp_inc_snmpinasnparseerrs();\r
+    return ERR_ARG;\r
+  }\r
+  ofs += (1 + len_octets);\r
+\r
+  /* start with empty list */\r
+  m_stat->invb.count = 0;\r
+  m_stat->invb.head = NULL;\r
+  m_stat->invb.tail = NULL;\r
+\r
+  while (vb_len > 0)\r
+  {\r
+    struct snmp_obj_id oid, oid_value;\r
+    struct snmp_varbind *vb;\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if ((derr != ERR_OK) ||\r
+        (type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||\r
+        (len <= 0) || (len > vb_len))\r
+    {\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets);\r
+    vb_len -= (1 + len_octets);\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if ((derr != ERR_OK) || (type != (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID)))\r
+    {\r
+      /* can't decode object name length */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid);\r
+    if (derr != ERR_OK)\r
+    {\r
+      /* can't decode object name */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets + len);\r
+    vb_len -= (1 + len_octets + len);\r
+\r
+    snmp_asn1_dec_type(p, ofs, &type);\r
+    derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);\r
+    if (derr != ERR_OK)\r
+    {\r
+      /* can't decode object value length */\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+\r
+    switch (type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t));\r
+        if (vb != NULL)\r
+        {\r
+          s32_t *vptr = vb->value;\r
+\r
+          derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t));\r
+        if (vb != NULL)\r
+        {\r
+          u32_t *vptr = vb->value;\r
+\r
+          derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        vb = snmp_varbind_alloc(&oid, type, len);\r
+        if (vb != NULL)\r
+        {\r
+          derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+        vb = snmp_varbind_alloc(&oid, type, 0);\r
+        if (vb != NULL)\r
+        {\r
+          snmp_varbind_tail_add(&m_stat->invb, vb);\r
+          derr = ERR_OK;\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        derr = snmp_asn1_dec_oid(p, ofs + 1 + len_octets, len, &oid_value);\r
+        if (derr == ERR_OK)\r
+        {\r
+          vb = snmp_varbind_alloc(&oid, type, oid_value.len * sizeof(s32_t));\r
+          if (vb != NULL)\r
+          {\r
+            u8_t i = oid_value.len;\r
+            s32_t *vptr = vb->value;\r
+\r
+            while(i > 0)\r
+            {\r
+              i--;\r
+              vptr[i] = oid_value.id[i];\r
+            }\r
+            snmp_varbind_tail_add(&m_stat->invb, vb);\r
+            derr = ERR_OK;\r
+          }\r
+          else\r
+          {\r
+            derr = ERR_ARG;\r
+          }\r
+        }\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+        if (len == 4)\r
+        {\r
+          /* must be exactly 4 octets! */\r
+          vb = snmp_varbind_alloc(&oid, type, 4);\r
+          if (vb != NULL)\r
+          {\r
+            derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value);\r
+            snmp_varbind_tail_add(&m_stat->invb, vb);\r
+          }\r
+          else\r
+          {\r
+            derr = ERR_ARG;\r
+          }\r
+        }\r
+        else\r
+        {\r
+          derr = ERR_ARG;\r
+        }\r
+        break;\r
+      default:\r
+        derr = ERR_ARG;\r
+        break;\r
+    }\r
+    if (derr != ERR_OK)\r
+    {\r
+      snmp_inc_snmpinasnparseerrs();\r
+      /* free varbinds (if available) */\r
+      snmp_varbind_list_free(&m_stat->invb);\r
+      return ERR_ARG;\r
+    }\r
+    ofs += (1 + len_octets + len);\r
+    vb_len -= (1 + len_octets + len);\r
+  }\r
+\r
+  if (m_stat->rt == SNMP_ASN1_PDU_SET_REQ)\r
+  {\r
+    snmp_add_snmpintotalsetvars(m_stat->invb.count);\r
+  }\r
+  else\r
+  {\r
+    snmp_add_snmpintotalreqvars(m_stat->invb.count);\r
+  }\r
+\r
+  *ofs_ret = ofs;\r
+  return ERR_OK;\r
+}\r
+\r
+struct snmp_varbind*\r
+snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len)\r
+{\r
+  struct snmp_varbind *vb;\r
+\r
+  vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind));\r
+  LWIP_ASSERT("vb != NULL",vb != NULL);\r
+  if (vb != NULL)\r
+  {\r
+    u8_t i;\r
+\r
+    vb->next = NULL;\r
+    vb->prev = NULL;\r
+    i = oid->len;\r
+    vb->ident_len = i;\r
+    if (i > 0)\r
+    {\r
+      /* allocate array of s32_t for our object identifier */\r
+      vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i);\r
+      LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL);\r
+      if (vb->ident == NULL)\r
+      {\r
+        mem_free(vb);\r
+        return NULL;\r
+      }\r
+      while(i > 0)\r
+      {\r
+        i--;\r
+        vb->ident[i] = oid->id[i];\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* i == 0, pass zero length object identifier */\r
+      vb->ident = NULL;\r
+    }\r
+    vb->value_type = type;\r
+    vb->value_len = len;\r
+    if (len > 0)\r
+    {\r
+      /* allocate raw bytes for our object value */\r
+      vb->value = mem_malloc(len);\r
+      LWIP_ASSERT("vb->value != NULL",vb->value != NULL);\r
+      if (vb->value == NULL)\r
+      {\r
+        if (vb->ident != NULL)\r
+        {\r
+          mem_free(vb->ident);\r
+        }\r
+        mem_free(vb);\r
+        return NULL;\r
+      }\r
+    }\r
+    else\r
+    {\r
+      /* ASN1_NUL type, or zero length ASN1_OC_STR */\r
+      vb->value = NULL;\r
+    }\r
+  }\r
+  return vb;\r
+}\r
+\r
+void\r
+snmp_varbind_free(struct snmp_varbind *vb)\r
+{\r
+  if (vb->value != NULL )\r
+  {\r
+    mem_free(vb->value);\r
+  }\r
+  if (vb->ident != NULL )\r
+  {\r
+    mem_free(vb->ident);\r
+  }\r
+  mem_free(vb);\r
+}\r
+\r
+void\r
+snmp_varbind_list_free(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind *vb, *prev;\r
+\r
+  vb = root->tail;\r
+  while ( vb != NULL )\r
+  {\r
+    prev = vb->prev;\r
+    snmp_varbind_free(vb);\r
+    vb = prev;\r
+  }\r
+  root->count = 0;\r
+  root->head = NULL;\r
+  root->tail = NULL;\r
+}\r
+\r
+void\r
+snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb)\r
+{\r
+  if (root->count == 0)\r
+  {\r
+    /* add first varbind to list */\r
+    root->head = vb;\r
+    root->tail = vb;\r
+  }\r
+  else\r
+  {\r
+    /* add nth varbind to list tail */\r
+    root->tail->next = vb;\r
+    vb->prev = root->tail;\r
+    root->tail = vb;\r
+  }\r
+  root->count += 1;\r
+}\r
+\r
+struct snmp_varbind*\r
+snmp_varbind_tail_remove(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind* vb;\r
+\r
+  if (root->count > 0)\r
+  {\r
+    /* remove tail varbind */\r
+    vb = root->tail;\r
+    root->tail = vb->prev;\r
+    vb->prev->next = NULL;\r
+    root->count -= 1;\r
+  }\r
+  else\r
+  {\r
+    /* nothing to remove */\r
+    vb = NULL;\r
+  }\r
+  return vb;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c b/Demo/Common/ethernet/lwIP_130/src/core/snmp/msg_out.c
new file mode 100644 (file)
index 0000000..242d309
--- /dev/null
@@ -0,0 +1,683 @@
+/**\r
+ * @file\r
+ * SNMP output message processing (RFC1157).\r
+ *\r
+ * Output responses and traps are build in two passes:\r
+ *\r
+ * Pass 0: iterate over the output message backwards to determine encoding lengths\r
+ * Pass 1: the actual forward encoding of internal form into ASN1\r
+ *\r
+ * The single-pass encoding method described by Comer & Stevens\r
+ * requires extra buffer space and copying for reversal of the packet.\r
+ * The buffer requirement can be prohibitively large for big payloads\r
+ * (>= 484) therefore we use the two encoding passes.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/udp.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_asn1.h"\r
+#include "lwip/snmp_msg.h"\r
+\r
+struct snmp_trap_dst\r
+{\r
+  /* destination IP address in network order */\r
+  struct ip_addr dip;\r
+  /* set to 0 when disabled, >0 when enabled */\r
+  u8_t enable;\r
+};\r
+struct snmp_trap_dst trap_dst[SNMP_TRAP_DESTINATIONS];\r
+\r
+/** TRAP message structure */\r
+struct snmp_msg_trap trap_msg;\r
+\r
+static u16_t snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len);\r
+static u16_t snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len);\r
+static u16_t snmp_varbind_list_sum(struct snmp_varbind_root *root);\r
+\r
+static u16_t snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p);\r
+static u16_t snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p);\r
+static u16_t snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs);\r
+\r
+/**\r
+ * Sets enable switch for this trap destination.\r
+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1\r
+ * @param enable switch if 0 destination is disabled >0 enabled.\r
+ */\r
+void\r
+snmp_trap_dst_enable(u8_t dst_idx, u8_t enable)\r
+{\r
+  if (dst_idx < SNMP_TRAP_DESTINATIONS)\r
+  {\r
+    trap_dst[dst_idx].enable = enable;\r
+  }\r
+}\r
+\r
+/**\r
+ * Sets IPv4 address for this trap destination.\r
+ * @param dst_idx index in 0 .. SNMP_TRAP_DESTINATIONS-1\r
+ * @param dst IPv4 address in host order.\r
+ */\r
+void\r
+snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst)\r
+{\r
+  if (dst_idx < SNMP_TRAP_DESTINATIONS)\r
+  {\r
+    trap_dst[dst_idx].dip.addr = htonl(dst->addr);\r
+  }\r
+}\r
+\r
+/**\r
+ * Sends a 'getresponse' message to the request originator.\r
+ *\r
+ * @param m_stat points to the current message request state source\r
+ * @return ERR_OK when success, ERR_MEM if we're out of memory\r
+ *\r
+ * @note the caller is responsible for filling in outvb in the m_stat\r
+ * and provide error-status and index (except for tooBig errors) ...\r
+ */\r
+err_t\r
+snmp_send_response(struct snmp_msg_pstat *m_stat)\r
+{\r
+  struct snmp_varbind_root emptyvb = {NULL, NULL, 0, 0, 0};\r
+  struct pbuf *p;\r
+  u16_t tot_len;\r
+  err_t err;\r
+\r
+  /* pass 0, calculate length fields */\r
+  tot_len = snmp_varbind_list_sum(&m_stat->outvb);\r
+  tot_len = snmp_resp_header_sum(m_stat, tot_len);\r
+\r
+  /* try allocating pbuf(s) for complete response */\r
+  p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+  if (p == NULL)\r
+  {\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() tooBig\n"));\r
+\r
+    /* can't construct reply, return error-status tooBig */\r
+    m_stat->error_status = SNMP_ES_TOOBIG;\r
+    m_stat->error_index = 0;\r
+    /* pass 0, recalculate lengths, for empty varbind-list */\r
+    tot_len = snmp_varbind_list_sum(&emptyvb);\r
+    tot_len = snmp_resp_header_sum(m_stat, tot_len);\r
+    /* retry allocation once for header and empty varbind-list */\r
+    p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+  }\r
+  if (p != NULL)\r
+  {\r
+    /* first pbuf alloc try or retry alloc success */\r
+    u16_t ofs;\r
+\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() p != NULL\n"));\r
+\r
+    /* pass 1, size error, encode packet ino the pbuf(s) */\r
+    ofs = snmp_resp_header_enc(m_stat, p);\r
+    if (m_stat->error_status == SNMP_ES_TOOBIG)\r
+    {\r
+      snmp_varbind_list_enc(&emptyvb, p, ofs);\r
+    }\r
+    else\r
+    {\r
+      snmp_varbind_list_enc(&m_stat->outvb, p, ofs);\r
+    }\r
+\r
+    switch (m_stat->error_status)\r
+    {\r
+      case SNMP_ES_TOOBIG:\r
+        snmp_inc_snmpouttoobigs();\r
+        break;\r
+      case SNMP_ES_NOSUCHNAME:\r
+        snmp_inc_snmpoutnosuchnames();\r
+        break;\r
+      case SNMP_ES_BADVALUE:\r
+        snmp_inc_snmpoutbadvalues();\r
+        break;\r
+      case SNMP_ES_GENERROR:\r
+        snmp_inc_snmpoutgenerrs();\r
+        break;\r
+    }\r
+    snmp_inc_snmpoutgetresponses();\r
+    snmp_inc_snmpoutpkts();\r
+\r
+    /** @todo do we need separate rx and tx pcbs for threaded case? */\r
+    /** connect to the originating source */\r
+    udp_connect(m_stat->pcb, &m_stat->sip, m_stat->sp);\r
+    err = udp_send(m_stat->pcb, p);\r
+    if (err == ERR_MEM)\r
+    {\r
+      /** @todo release some memory, retry and return tooBig? tooMuchHassle? */\r
+      err = ERR_MEM;\r
+    }\r
+    else\r
+    {\r
+      err = ERR_OK;\r
+    }\r
+    /** disassociate remote address and port with this pcb */\r
+    udp_disconnect(m_stat->pcb);\r
+\r
+    pbuf_free(p);\r
+    LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_snd_response() done\n"));\r
+    return err;\r
+  }\r
+  else\r
+  {\r
+    /* first pbuf alloc try or retry alloc failed\r
+       very low on memory, couldn't return tooBig */\r
+    return ERR_MEM;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+ * Sends an generic or enterprise specific trap message.\r
+ *\r
+ * @param generic_trap is the trap code\r
+ * @param eoid points to enterprise object identifier\r
+ * @param specific_trap used for enterprise traps when generic_trap == 6\r
+ * @return ERR_OK when success, ERR_MEM if we're out of memory\r
+ *\r
+ * @note the caller is responsible for filling in outvb in the trap_msg\r
+ * @note the use of the enterpise identifier field\r
+ * is per RFC1215.\r
+ * Use .iso.org.dod.internet.mgmt.mib-2.snmp for generic traps\r
+ * and .iso.org.dod.internet.private.enterprises.yourenterprise\r
+ * (sysObjectID) for specific traps.\r
+ */\r
+err_t\r
+snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap)\r
+{\r
+  struct snmp_trap_dst *td;\r
+  struct netif *dst_if;\r
+  struct ip_addr dst_ip;\r
+  struct pbuf *p;\r
+  u16_t i,tot_len;\r
+\r
+  for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++)\r
+  {\r
+    if ((td->enable != 0) && (td->dip.addr != 0))\r
+    {\r
+      /* network order trap destination */\r
+      trap_msg.dip.addr = td->dip.addr;\r
+      /* lookup current source address for this dst */\r
+      dst_if = ip_route(&td->dip);\r
+      dst_ip.addr = ntohl(dst_if->ip_addr.addr);\r
+      trap_msg.sip_raw[0] = dst_ip.addr >> 24;\r
+      trap_msg.sip_raw[1] = dst_ip.addr >> 16;\r
+      trap_msg.sip_raw[2] = dst_ip.addr >> 8;\r
+      trap_msg.sip_raw[3] = dst_ip.addr;\r
+      trap_msg.gen_trap = generic_trap;\r
+      trap_msg.spc_trap = specific_trap;\r
+      if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC)\r
+      {\r
+        /* enterprise-Specific trap */\r
+        trap_msg.enterprise = eoid;\r
+      }\r
+      else\r
+      {\r
+        /* generic (MIB-II) trap */\r
+        snmp_get_snmpgrpid_ptr(&trap_msg.enterprise);\r
+      }\r
+      snmp_get_sysuptime(&trap_msg.ts);\r
+\r
+      /* pass 0, calculate length fields */\r
+      tot_len = snmp_varbind_list_sum(&trap_msg.outvb);\r
+      tot_len = snmp_trap_header_sum(&trap_msg, tot_len);\r
+\r
+      /* allocate pbuf(s) */\r
+      p = pbuf_alloc(PBUF_TRANSPORT, tot_len, PBUF_POOL);\r
+      if (p != NULL)\r
+      {\r
+        u16_t ofs;\r
+\r
+        /* pass 1, encode packet ino the pbuf(s) */\r
+        ofs = snmp_trap_header_enc(&trap_msg, p);\r
+        snmp_varbind_list_enc(&trap_msg.outvb, p, ofs);\r
+\r
+        snmp_inc_snmpouttraps();\r
+        snmp_inc_snmpoutpkts();\r
+\r
+        /** connect to the TRAP destination */\r
+        udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT);\r
+        udp_send(trap_msg.pcb, p);\r
+        /** disassociate remote address and port with this pcb */\r
+        udp_disconnect(trap_msg.pcb);\r
+\r
+        pbuf_free(p);\r
+      }\r
+      else\r
+      {\r
+        return ERR_MEM;\r
+      }\r
+    }\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+void\r
+snmp_coldstart_trap(void)\r
+{\r
+  trap_msg.outvb.head = NULL;\r
+  trap_msg.outvb.tail = NULL;\r
+  trap_msg.outvb.count = 0;\r
+  snmp_send_trap(SNMP_GENTRAP_COLDSTART, NULL, 0);\r
+}\r
+\r
+void\r
+snmp_authfail_trap(void)\r
+{\r
+  u8_t enable;\r
+  snmp_get_snmpenableauthentraps(&enable);\r
+  if (enable == 1)\r
+  {\r
+    trap_msg.outvb.head = NULL;\r
+    trap_msg.outvb.tail = NULL;\r
+    trap_msg.outvb.count = 0;\r
+    snmp_send_trap(SNMP_GENTRAP_AUTHFAIL, NULL, 0);\r
+  }\r
+}\r
+\r
+/**\r
+ * Sums response header field lengths from tail to head and\r
+ * returns resp_header_lengths for second encoding pass.\r
+ *\r
+ * @param vb_len varbind-list length\r
+ * @param rhl points to returned header lengths\r
+ * @return the required lenght for encoding the response header\r
+ */\r
+static u16_t\r
+snmp_resp_header_sum(struct snmp_msg_pstat *m_stat, u16_t vb_len)\r
+{\r
+  u16_t tot_len;\r
+  struct snmp_resp_header_lengths *rhl;\r
+\r
+  rhl = &m_stat->rhl;\r
+  tot_len = vb_len;\r
+  snmp_asn1_enc_s32t_cnt(m_stat->error_index, &rhl->erridxlen);\r
+  snmp_asn1_enc_length_cnt(rhl->erridxlen, &rhl->erridxlenlen);\r
+  tot_len += 1 + rhl->erridxlenlen + rhl->erridxlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_stat->error_status, &rhl->errstatlen);\r
+  snmp_asn1_enc_length_cnt(rhl->errstatlen, &rhl->errstatlenlen);\r
+  tot_len += 1 + rhl->errstatlenlen + rhl->errstatlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_stat->rid, &rhl->ridlen);\r
+  snmp_asn1_enc_length_cnt(rhl->ridlen, &rhl->ridlenlen);\r
+  tot_len += 1 + rhl->ridlenlen + rhl->ridlen;\r
+\r
+  rhl->pdulen = tot_len;\r
+  snmp_asn1_enc_length_cnt(rhl->pdulen, &rhl->pdulenlen);\r
+  tot_len += 1 + rhl->pdulenlen;\r
+\r
+  rhl->comlen = m_stat->com_strlen;\r
+  snmp_asn1_enc_length_cnt(rhl->comlen, &rhl->comlenlen);\r
+  tot_len += 1 + rhl->comlenlen + rhl->comlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(snmp_version, &rhl->verlen);\r
+  snmp_asn1_enc_length_cnt(rhl->verlen, &rhl->verlenlen);\r
+  tot_len += 1 + rhl->verlen + rhl->verlenlen;\r
+\r
+  rhl->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(rhl->seqlen, &rhl->seqlenlen);\r
+  tot_len += 1 + rhl->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Sums trap header field lengths from tail to head and\r
+ * returns trap_header_lengths for second encoding pass.\r
+ *\r
+ * @param vb_len varbind-list length\r
+ * @param thl points to returned header lengths\r
+ * @return the required lenght for encoding the trap header\r
+ */\r
+static u16_t\r
+snmp_trap_header_sum(struct snmp_msg_trap *m_trap, u16_t vb_len)\r
+{\r
+  u16_t tot_len;\r
+  struct snmp_trap_header_lengths *thl;\r
+\r
+  thl = &m_trap->thl;\r
+  tot_len = vb_len;\r
+\r
+  snmp_asn1_enc_u32t_cnt(m_trap->ts, &thl->tslen);\r
+  snmp_asn1_enc_length_cnt(thl->tslen, &thl->tslenlen);\r
+  tot_len += 1 + thl->tslen + thl->tslenlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_trap->spc_trap, &thl->strplen);\r
+  snmp_asn1_enc_length_cnt(thl->strplen, &thl->strplenlen);\r
+  tot_len += 1 + thl->strplen + thl->strplenlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(m_trap->gen_trap, &thl->gtrplen);\r
+  snmp_asn1_enc_length_cnt(thl->gtrplen, &thl->gtrplenlen);\r
+  tot_len += 1 + thl->gtrplen + thl->gtrplenlen;\r
+\r
+  thl->aaddrlen = 4;\r
+  snmp_asn1_enc_length_cnt(thl->aaddrlen, &thl->aaddrlenlen);\r
+  tot_len += 1 + thl->aaddrlen + thl->aaddrlenlen;\r
+\r
+  snmp_asn1_enc_oid_cnt(m_trap->enterprise->len, &m_trap->enterprise->id[0], &thl->eidlen);\r
+  snmp_asn1_enc_length_cnt(thl->eidlen, &thl->eidlenlen);\r
+  tot_len += 1 + thl->eidlen + thl->eidlenlen;\r
+\r
+  thl->pdulen = tot_len;\r
+  snmp_asn1_enc_length_cnt(thl->pdulen, &thl->pdulenlen);\r
+  tot_len += 1 + thl->pdulenlen;\r
+\r
+  thl->comlen = sizeof(snmp_publiccommunity) - 1;\r
+  snmp_asn1_enc_length_cnt(thl->comlen, &thl->comlenlen);\r
+  tot_len += 1 + thl->comlenlen + thl->comlen;\r
+\r
+  snmp_asn1_enc_s32t_cnt(snmp_version, &thl->verlen);\r
+  snmp_asn1_enc_length_cnt(thl->verlen, &thl->verlenlen);\r
+  tot_len += 1 + thl->verlen + thl->verlenlen;\r
+\r
+  thl->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(thl->seqlen, &thl->seqlenlen);\r
+  tot_len += 1 + thl->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Sums varbind lengths from tail to head and\r
+ * annotates lengths in varbind for second encoding pass.\r
+ *\r
+ * @param root points to the root of the variable binding list\r
+ * @return the required lenght for encoding the variable bindings\r
+ */\r
+static u16_t\r
+snmp_varbind_list_sum(struct snmp_varbind_root *root)\r
+{\r
+  struct snmp_varbind *vb;\r
+  u32_t *uint_ptr;\r
+  s32_t *sint_ptr;\r
+  u16_t tot_len;\r
+\r
+  tot_len = 0;\r
+  vb = root->tail;\r
+  while ( vb != NULL )\r
+  {\r
+    /* encoded value lenght depends on type */\r
+    switch (vb->value_type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen);\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        uint_ptr = vb->value;\r
+        snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        vb->vlen = vb->value_len;\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen);\r
+        break;\r
+      default:\r
+        /* unsupported type */\r
+        vb->vlen = 0;\r
+        break;\r
+    };\r
+    /* encoding length of value length field */\r
+    snmp_asn1_enc_length_cnt(vb->vlen, &vb->vlenlen);\r
+    snmp_asn1_enc_oid_cnt(vb->ident_len, vb->ident, &vb->olen);\r
+    snmp_asn1_enc_length_cnt(vb->olen, &vb->olenlen);\r
+\r
+    vb->seqlen = 1 + vb->vlenlen + vb->vlen;\r
+    vb->seqlen += 1 + vb->olenlen + vb->olen;\r
+    snmp_asn1_enc_length_cnt(vb->seqlen, &vb->seqlenlen);\r
+\r
+    /* varbind seq */\r
+    tot_len += 1 + vb->seqlenlen + vb->seqlen;\r
+\r
+    vb = vb->prev;\r
+  }\r
+\r
+  /* varbind-list seq */\r
+  root->seqlen = tot_len;\r
+  snmp_asn1_enc_length_cnt(root->seqlen, &root->seqlenlen);\r
+  tot_len += 1 + root->seqlenlen;\r
+\r
+  return tot_len;\r
+}\r
+\r
+/**\r
+ * Encodes response header from head to tail.\r
+ */\r
+static u16_t\r
+snmp_resp_header_enc(struct snmp_msg_pstat *m_stat, struct pbuf *p)\r
+{\r
+  u16_t ofs;\r
+\r
+  ofs = 0;\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.seqlen);\r
+  ofs += m_stat->rhl.seqlenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.verlen);\r
+  ofs += m_stat->rhl.verlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.verlen, snmp_version);\r
+  ofs += m_stat->rhl.verlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.comlen);\r
+  ofs += m_stat->rhl.comlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_stat->rhl.comlen, m_stat->community);\r
+  ofs += m_stat->rhl.comlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_GET_RESP));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.pdulen);\r
+  ofs += m_stat->rhl.pdulenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.ridlen);\r
+  ofs += m_stat->rhl.ridlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.ridlen, m_stat->rid);\r
+  ofs += m_stat->rhl.ridlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.errstatlen);\r
+  ofs += m_stat->rhl.errstatlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.errstatlen, m_stat->error_status);\r
+  ofs += m_stat->rhl.errstatlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_stat->rhl.erridxlen);\r
+  ofs += m_stat->rhl.erridxlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_stat->rhl.erridxlen, m_stat->error_index);\r
+  ofs += m_stat->rhl.erridxlen;\r
+\r
+  return ofs;\r
+}\r
+\r
+/**\r
+ * Encodes trap header from head to tail.\r
+ */\r
+static u16_t\r
+snmp_trap_header_enc(struct snmp_msg_trap *m_trap, struct pbuf *p)\r
+{\r
+  u16_t ofs;\r
+\r
+  ofs = 0;\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.seqlen);\r
+  ofs += m_trap->thl.seqlenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.verlen);\r
+  ofs += m_trap->thl.verlenlen;\r
+  snmp_asn1_enc_s32t(p, ofs, m_trap->thl.verlen, snmp_version);\r
+  ofs += m_trap->thl.verlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.comlen);\r
+  ofs += m_trap->thl.comlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.comlen, (u8_t *)&snmp_publiccommunity[0]);\r
+  ofs += m_trap->thl.comlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_CONTXT | SNMP_ASN1_CONSTR | SNMP_ASN1_PDU_TRAP));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.pdulen);\r
+  ofs += m_trap->thl.pdulenlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.eidlen);\r
+  ofs += m_trap->thl.eidlenlen;\r
+  snmp_asn1_enc_oid(p, ofs, m_trap->enterprise->len, &m_trap->enterprise->id[0]);\r
+  ofs += m_trap->thl.eidlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.aaddrlen);\r
+  ofs += m_trap->thl.aaddrlenlen;\r
+  snmp_asn1_enc_raw(p, ofs, m_trap->thl.aaddrlen, &m_trap->sip_raw[0]);\r
+  ofs += m_trap->thl.aaddrlen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.gtrplen);\r
+  ofs += m_trap->thl.gtrplenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.gtrplen, m_trap->gen_trap);\r
+  ofs += m_trap->thl.gtrplen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.strplen);\r
+  ofs += m_trap->thl.strplenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.strplen, m_trap->spc_trap);\r
+  ofs += m_trap->thl.strplen;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, m_trap->thl.tslen);\r
+  ofs += m_trap->thl.tslenlen;\r
+  snmp_asn1_enc_u32t(p, ofs, m_trap->thl.tslen, m_trap->ts);\r
+  ofs += m_trap->thl.tslen;\r
+\r
+  return ofs;\r
+}\r
+\r
+/**\r
+ * Encodes varbind list from head to tail.\r
+ */\r
+static u16_t\r
+snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs)\r
+{\r
+  struct snmp_varbind *vb;\r
+  s32_t *sint_ptr;\r
+  u32_t *uint_ptr;\r
+  u8_t *raw_ptr;\r
+\r
+  snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+  ofs += 1;\r
+  snmp_asn1_enc_length(p, ofs, root->seqlen);\r
+  ofs += root->seqlenlen;\r
+\r
+  vb = root->head;\r
+  while ( vb != NULL )\r
+  {\r
+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ));\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->seqlen);\r
+    ofs += vb->seqlenlen;\r
+\r
+    snmp_asn1_enc_type(p, ofs, (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID));\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->olen);\r
+    ofs += vb->olenlen;\r
+    snmp_asn1_enc_oid(p, ofs, vb->ident_len, &vb->ident[0]);\r
+    ofs += vb->olen;\r
+\r
+    snmp_asn1_enc_type(p, ofs, vb->value_type);\r
+    ofs += 1;\r
+    snmp_asn1_enc_length(p, ofs, vb->vlen);\r
+    ofs += vb->vlenlen;\r
+\r
+    switch (vb->value_type)\r
+    {\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr);\r
+        break;\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS):\r
+        uint_ptr = vb->value;\r
+        snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR):\r
+      case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE):\r
+        raw_ptr = vb->value;\r
+        snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr);\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL):\r
+        break;\r
+      case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID):\r
+        sint_ptr = vb->value;\r
+        snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr);\r
+        break;\r
+      default:\r
+        /* unsupported type */\r
+        break;\r
+    };\r
+    ofs += vb->vlen;\r
+    vb = vb->next;\r
+  }\r
+  return ofs;\r
+}\r
+\r
+#endif /* LWIP_SNMP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/stats.c b/Demo/Common/ethernet/lwIP_130/src/core/stats.c
new file mode 100644 (file)
index 0000000..76c979f
--- /dev/null
@@ -0,0 +1,142 @@
+/**\r
+ * @file\r
+ * Statistics module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_STATS /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+\r
+#include <string.h>\r
+\r
+struct stats_ lwip_stats;\r
+\r
+#if LWIP_STATS_DISPLAY\r
+void\r
+stats_display_proto(struct stats_proto *proto, char *name)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\n%s\n\t", name));\r
+  LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));\r
+  LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit));\r
+  LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));\r
+  LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));\r
+  LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));\r
+  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", proto->chkerr));\r
+  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", proto->lenerr));\r
+  LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", proto->memerr));\r
+  LWIP_PLATFORM_DIAG(("rterr: %"STAT_COUNTER_F"\n\t", proto->rterr));\r
+  LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", proto->proterr));\r
+  LWIP_PLATFORM_DIAG(("opterr: %"STAT_COUNTER_F"\n\t", proto->opterr));\r
+  LWIP_PLATFORM_DIAG(("err: %"STAT_COUNTER_F"\n\t", proto->err));\r
+  LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));\r
+}\r
+\r
+void\r
+stats_display_igmp(struct stats_igmp *igmp)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));\r
+  LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));\r
+  LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr));\r
+  LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed));\r
+  LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent));\r
+  LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent));\r
+  LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query));\r
+  LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent));\r
+  LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed));\r
+  LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed));\r
+}\r
+\r
+void\r
+stats_display_mem(struct stats_mem *mem, char *name)\r
+{\r
+  LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));\r
+  LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));\r
+  LWIP_PLATFORM_DIAG(("used: %"U32_F"\n\t", (u32_t)mem->used));\r
+  LWIP_PLATFORM_DIAG(("max: %"U32_F"\n\t", (u32_t)mem->max));\r
+  LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));\r
+}\r
+\r
+void\r
+stats_display(void)\r
+{\r
+#if MEMP_STATS\r
+  s16_t i;\r
+  char * memp_names[] = {\r
+#define LWIP_MEMPOOL(name,num,size,desc) desc,\r
+#include "lwip/memp_std.h"\r
+  };\r
+#endif\r
+#if LINK_STATS\r
+  stats_display_proto(&lwip_stats.link, "LINK");\r
+#endif\r
+#if ETHARP_STATS\r
+  stats_display_proto(&lwip_stats.etharp, "ETHARP");\r
+#endif\r
+#if IPFRAG_STATS\r
+  stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");\r
+#endif\r
+#if IP_STATS\r
+  stats_display_proto(&lwip_stats.ip, "IP");\r
+#endif\r
+#if ICMP_STATS\r
+  stats_display_proto(&lwip_stats.icmp, "ICMP");\r
+#endif\r
+#if IGMP_STATS\r
+  stats_display_igmp(&lwip_stats.igmp);\r
+#endif\r
+#if UDP_STATS\r
+  stats_display_proto(&lwip_stats.udp, "UDP");\r
+#endif\r
+#if TCP_STATS\r
+  stats_display_proto(&lwip_stats.tcp, "TCP");\r
+#endif\r
+#if MEM_STATS\r
+  stats_display_mem(&lwip_stats.mem, "HEAP");\r
+#endif\r
+#if MEMP_STATS\r
+  for (i = 0; i < MEMP_MAX; i++) {\r
+    stats_display_mem(&lwip_stats.memp[i], memp_names[i]);\r
+  }\r
+#endif\r
+}\r
+#endif /* LWIP_STATS_DISPLAY */\r
+\r
+#endif /* LWIP_STATS */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/sys.c b/Demo/Common/ethernet/lwIP_130/src/core/sys.c
new file mode 100644 (file)
index 0000000..7f81e50
--- /dev/null
@@ -0,0 +1,344 @@
+/**\r
+ * @file\r
+ * lwIP Operating System abstraction\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/tcpip.h"\r
+\r
+/**\r
+ * Struct used for sys_sem_wait_timeout() to tell wether the time\r
+ * has run out or the semaphore has really become available.\r
+ */\r
+struct sswt_cb\r
+{\r
+  s16_t timeflag;\r
+  sys_sem_t *psem;\r
+};\r
+\r
+/**\r
+ * Wait (forever) for a message to arrive in an mbox.\r
+ * While waiting, timeouts (for this thread) are processed.\r
+ *\r
+ * @param mbox the mbox to fetch the message from\r
+ * @param msg the place to store the message\r
+ */\r
+void\r
+sys_mbox_fetch(sys_mbox_t mbox, void **msg)\r
+{\r
+  u32_t time;\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *tmptimeout;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+\r
+ again:\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  if (!timeouts || !timeouts->next) {\r
+    UNLOCK_TCPIP_CORE();\r
+    time = sys_arch_mbox_fetch(mbox, msg, 0);\r
+    LOCK_TCPIP_CORE();\r
+  } else {\r
+    if (timeouts->next->time > 0) {\r
+      UNLOCK_TCPIP_CORE();\r
+      time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);\r
+      LOCK_TCPIP_CORE();\r
+    } else {\r
+      time = SYS_ARCH_TIMEOUT;\r
+    }\r
+\r
+    if (time == SYS_ARCH_TIMEOUT) {\r
+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message\r
+         could be fetched. We should now call the timeout handler and\r
+         deallocate the memory allocated for the timeout. */\r
+      tmptimeout = timeouts->next;\r
+      timeouts->next = tmptimeout->next;\r
+      h   = tmptimeout->h;\r
+      arg = tmptimeout->arg;\r
+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\r
+      if (h != NULL) {\r
+        LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", (void*)&h, arg));\r
+        h(arg);\r
+      }\r
+\r
+      /* We try again to fetch a message from the mbox. */\r
+      goto again;\r
+    } else {\r
+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout\r
+         occured. The time variable is set to the number of\r
+         milliseconds we waited for the message. */\r
+      if (time < timeouts->next->time) {\r
+        timeouts->next->time -= time;\r
+      } else {\r
+        timeouts->next->time = 0;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Wait (forever) for a semaphore to become available.\r
+ * While waiting, timeouts (for this thread) are processed.\r
+ *\r
+ * @param sem semaphore to wait for\r
+ */\r
+void\r
+sys_sem_wait(sys_sem_t sem)\r
+{\r
+  u32_t time;\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *tmptimeout;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+\r
+ again:\r
+\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  if (!timeouts || !timeouts->next) {\r
+    sys_arch_sem_wait(sem, 0);\r
+  } else {\r
+    if (timeouts->next->time > 0) {\r
+      time = sys_arch_sem_wait(sem, timeouts->next->time);\r
+    } else {\r
+      time = SYS_ARCH_TIMEOUT;\r
+    }\r
+\r
+    if (time == SYS_ARCH_TIMEOUT) {\r
+      /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message\r
+        could be fetched. We should now call the timeout handler and\r
+        deallocate the memory allocated for the timeout. */\r
+      tmptimeout = timeouts->next;\r
+      timeouts->next = tmptimeout->next;\r
+      h = tmptimeout->h;\r
+      arg = tmptimeout->arg;\r
+      memp_free(MEMP_SYS_TIMEOUT, tmptimeout);\r
+      if (h != NULL) {\r
+        LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", (void*)&h, (void *)arg));\r
+        h(arg);\r
+      }\r
+\r
+      /* We try again to fetch a message from the mbox. */\r
+      goto again;\r
+    } else {\r
+      /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout\r
+         occured. The time variable is set to the number of\r
+         milliseconds we waited for the message. */\r
+      if (time < timeouts->next->time) {\r
+        timeouts->next->time -= time;\r
+      } else {\r
+        timeouts->next->time = 0;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Create a one-shot timer (aka timeout). Timeouts are processed in the\r
+ * following cases:\r
+ * - while waiting for a message using sys_mbox_fetch()\r
+ * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()\r
+ * - while sleeping using the inbuilt sys_msleep()\r
+ *\r
+ * @param msecs time in milliseconds after that the timer should expire\r
+ * @param h callback function to call when msecs have elapsed\r
+ * @param arg argument to pass to the callback function\r
+ */\r
+void\r
+sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)\r
+{\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *timeout, *t;\r
+\r
+  timeout = memp_malloc(MEMP_SYS_TIMEOUT);\r
+  if (timeout == NULL) {\r
+    LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);\r
+    return;\r
+  }\r
+  timeout->next = NULL;\r
+  timeout->h = h;\r
+  timeout->arg = arg;\r
+  timeout->time = msecs;\r
+\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",\r
+    (void *)timeout, msecs, (void*)&h, (void *)arg));\r
+\r
+  if (timeouts == NULL) {\r
+    LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);\r
+    return;\r
+  }\r
+\r
+  if (timeouts->next == NULL) {\r
+    timeouts->next = timeout;\r
+    return;\r
+  }\r
+\r
+  if (timeouts->next->time > msecs) {\r
+    timeouts->next->time -= msecs;\r
+    timeout->next = timeouts->next;\r
+    timeouts->next = timeout;\r
+  } else {\r
+    for(t = timeouts->next; t != NULL; t = t->next) {\r
+      timeout->time -= t->time;\r
+      if (t->next == NULL || t->next->time > timeout->time) {\r
+        if (t->next != NULL) {\r
+          t->next->time -= timeout->time;\r
+        }\r
+        timeout->next = t->next;\r
+        t->next = timeout;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Go through timeout list (for this task only) and remove the first matching\r
+ * entry, even though the timeout has not triggered yet.\r
+ *\r
+ * @note This function only works as expected if there is only one timeout\r
+ * calling 'h' in the list of timeouts.\r
+ *\r
+ * @param h callback function that would be called by the timeout\r
+ * @param arg callback argument that would be passed to h\r
+*/\r
+void\r
+sys_untimeout(sys_timeout_handler h, void *arg)\r
+{\r
+  struct sys_timeouts *timeouts;\r
+  struct sys_timeo *prev_t, *t;\r
+\r
+  timeouts = sys_arch_timeouts();\r
+\r
+  if (timeouts == NULL) {\r
+    LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);\r
+    return;\r
+  }\r
+  if (timeouts->next == NULL) {\r
+    return;\r
+  }\r
+\r
+  for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {\r
+    if ((t->h == h) && (t->arg == arg)) {\r
+      /* We have a match */\r
+      /* Unlink from previous in list */\r
+      if (prev_t == NULL)\r
+        timeouts->next = t->next;\r
+      else\r
+        prev_t->next = t->next;\r
+      /* If not the last one, add time of this one back to next */\r
+      if (t->next != NULL)\r
+        t->next->time += t->time;\r
+      memp_free(MEMP_SYS_TIMEOUT, t);\r
+      return;\r
+    }\r
+  }\r
+  return;\r
+}\r
+\r
+/**\r
+ * Timeout handler function for sys_sem_wait_timeout()\r
+ *\r
+ * @param arg struct sswt_cb* used to signal a semaphore and end waiting.\r
+ */\r
+static void\r
+sswt_handler(void *arg)\r
+{\r
+  struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;\r
+\r
+  /* Timeout. Set flag to TRUE and signal semaphore */\r
+  sswt_cb->timeflag = 1;\r
+  sys_sem_signal(*(sswt_cb->psem));\r
+}\r
+\r
+/**\r
+ * Wait for a semaphore with timeout (specified in ms)\r
+ *\r
+ * @param sem semaphore to wait\r
+ * @param timeout timeout in ms (0: wait forever)\r
+ * @return 0 on timeout, 1 otherwise\r
+ */\r
+int\r
+sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)\r
+{\r
+  struct sswt_cb sswt_cb;\r
+\r
+  sswt_cb.psem = &sem;\r
+  sswt_cb.timeflag = 0;\r
+\r
+  /* If timeout is zero, then just wait forever */\r
+  if (timeout > 0) {\r
+    /* Create a timer and pass it the address of our flag */\r
+    sys_timeout(timeout, sswt_handler, &sswt_cb);\r
+  }\r
+  sys_sem_wait(sem);\r
+  /* Was it a timeout? */\r
+  if (sswt_cb.timeflag) {\r
+    /* timeout */\r
+    return 0;\r
+  } else {\r
+    /* Not a timeout. Remove timeout entry */\r
+    sys_untimeout(sswt_handler, &sswt_cb);\r
+    return 1;\r
+  }\r
+}\r
+\r
+/**\r
+ * Sleep for some ms. Timeouts are processed while sleeping.\r
+ *\r
+ * @param ms number of milliseconds to sleep\r
+ */\r
+void\r
+sys_msleep(u32_t ms)\r
+{\r
+  sys_sem_t delaysem = sys_sem_new(0);\r
+\r
+  sys_sem_wait_timeout(delaysem, ms);\r
+\r
+  sys_sem_free(delaysem);\r
+}\r
+\r
+\r
+#endif /* NO_SYS */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/tcp.c b/Demo/Common/ethernet/lwIP_130/src/core/tcp.c
new file mode 100644 (file)
index 0000000..aa2f3c8
--- /dev/null
@@ -0,0 +1,1418 @@
+/**\r
+ * @file\r
+ * Transmission Control Protocol for IP\r
+ *\r
+ * This file contains common functions for the TCP implementation, such as functinos\r
+ * for manipulating the data structures and the TCP timer functions. TCP functions\r
+ * related to input and output is found in tcp_in.c and tcp_out.c respectively.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/tcp.h"\r
+\r
+#include <string.h>\r
+\r
+/* Incremented every coarse grained timer shot (typically every 500 ms). */\r
+u32_t tcp_ticks;\r
+const u8_t tcp_backoff[13] =\r
+    { 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};\r
+ /* Times per slowtmr hits */\r
+const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };\r
+\r
+/* The TCP PCB lists. */\r
+\r
+/** List of all TCP PCBs bound but not yet (connected || listening) */\r
+struct tcp_pcb *tcp_bound_pcbs;\r
+/** List of all TCP PCBs in LISTEN state */\r
+union tcp_listen_pcbs_t tcp_listen_pcbs;\r
+/** List of all TCP PCBs that are in a state in which\r
+ * they accept or send data. */\r
+struct tcp_pcb *tcp_active_pcbs;\r
+/** List of all TCP PCBs in TIME-WAIT state */\r
+struct tcp_pcb *tcp_tw_pcbs;\r
+\r
+struct tcp_pcb *tcp_tmp_pcb;\r
+\r
+static u8_t tcp_timer;\r
+static u16_t tcp_new_port(void);\r
+\r
+/**\r
+ * Called periodically to dispatch TCP timers.\r
+ *\r
+ */\r
+void\r
+tcp_tmr(void)\r
+{\r
+  /* Call tcp_fasttmr() every 250 ms */\r
+  tcp_fasttmr();\r
+\r
+  if (++tcp_timer & 1) {\r
+    /* Call tcp_tmr() every 500 ms, i.e., every other timer\r
+       tcp_tmr() is called. */\r
+    tcp_slowtmr();\r
+  }\r
+}\r
+\r
+/**\r
+ * Closes the connection held by the PCB.\r
+ *\r
+ * Listening pcbs are freed and may not be referenced any more.\r
+ * Connection pcbs are freed if not yet connected and may not be referenced\r
+ * any more. If a connection is established (at least SYN received or in\r
+ * a closing state), the connection is closed, and put in a closing state.\r
+ * The pcb is then automatically freed in tcp_slowtmr(). It is therefore\r
+ * unsafe to reference it.\r
+ *\r
+ * @param pcb the tcp_pcb to close\r
+ * @return ERR_OK if connection has been closed\r
+ *         another err_t if closing failed and pcb is not freed\r
+ */\r
+err_t\r
+tcp_close(struct tcp_pcb *pcb)\r
+{\r
+  err_t err;\r
+\r
+#if TCP_DEBUG\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in "));\r
+  tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+\r
+  switch (pcb->state) {\r
+  case CLOSED:\r
+    /* Closing a pcb in the CLOSED state might seem erroneous,\r
+     * however, it is in this state once allocated and as yet unused\r
+     * and the user needs some way to free it should the need arise.\r
+     * Calling tcp_close() with a pcb that has already been closed, (i.e. twice)\r
+     * or for a pcb that has been used and then entered the CLOSED state\r
+     * is erroneous, but this should never happen as the pcb has in those cases\r
+     * been freed, and so any remaining handles are bogus. */\r
+    err = ERR_OK;\r
+    TCP_RMV(&tcp_bound_pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    pcb = NULL;\r
+    break;\r
+  case LISTEN:\r
+    err = ERR_OK;\r
+    tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB_LISTEN, pcb);\r
+    pcb = NULL;\r
+    break;\r
+  case SYN_SENT:\r
+    err = ERR_OK;\r
+    tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    pcb = NULL;\r
+    snmp_inc_tcpattemptfails();\r
+    break;\r
+  case SYN_RCVD:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpattemptfails();\r
+      pcb->state = FIN_WAIT_1;\r
+    }\r
+    break;\r
+  case ESTABLISHED:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpestabresets();\r
+      pcb->state = FIN_WAIT_1;\r
+    }\r
+    break;\r
+  case CLOSE_WAIT:\r
+    err = tcp_send_ctrl(pcb, TCP_FIN);\r
+    if (err == ERR_OK) {\r
+      snmp_inc_tcpestabresets();\r
+      pcb->state = LAST_ACK;\r
+    }\r
+    break;\r
+  default:\r
+    /* Has already been closed, do nothing. */\r
+    err = ERR_OK;\r
+    pcb = NULL;\r
+    break;\r
+  }\r
+\r
+  if (pcb != NULL && err == ERR_OK) {\r
+    /* To ensure all data has been sent when tcp_close returns, we have\r
+       to make sure tcp_output doesn't fail.\r
+       Since we don't really have to ensure all data has been sent when tcp_close\r
+       returns (unsent data is sent from tcp timer functions, also), we don't care\r
+       for the return value of tcp_output for now. */\r
+    /* @todo: When implementing SO_LINGER, this must be changed somehow:\r
+       If SOF_LINGER is set, the data should be sent when tcp_close returns. */\r
+    tcp_output(pcb);\r
+  }\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Aborts a connection by sending a RST to the remote host and deletes\r
+ * the local protocol control block. This is done when a connection is\r
+ * killed because of shortage of memory.\r
+ *\r
+ * @param pcb the tcp_pcb to abort\r
+ */\r
+void\r
+tcp_abort(struct tcp_pcb *pcb)\r
+{\r
+  u32_t seqno, ackno;\r
+  u16_t remote_port, local_port;\r
+  struct ip_addr remote_ip, local_ip;\r
+#if LWIP_CALLBACK_API\r
+  void (* errf)(void *arg, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+  void *errf_arg;\r
+\r
+\r
+  /* Figure out on which TCP PCB list we are, and remove us. If we\r
+     are in an active state, call the receive function associated with\r
+     the PCB with a NULL argument, and send an RST to the remote end. */\r
+  if (pcb->state == TIME_WAIT) {\r
+    tcp_pcb_remove(&tcp_tw_pcbs, pcb);\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+  } else {\r
+    seqno = pcb->snd_nxt;\r
+    ackno = pcb->rcv_nxt;\r
+    ip_addr_set(&local_ip, &(pcb->local_ip));\r
+    ip_addr_set(&remote_ip, &(pcb->remote_ip));\r
+    local_port = pcb->local_port;\r
+    remote_port = pcb->remote_port;\r
+#if LWIP_CALLBACK_API\r
+    errf = pcb->errf;\r
+#endif /* LWIP_CALLBACK_API */\r
+    errf_arg = pcb->callback_arg;\r
+    tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+    if (pcb->unacked != NULL) {\r
+      tcp_segs_free(pcb->unacked);\r
+    }\r
+    if (pcb->unsent != NULL) {\r
+      tcp_segs_free(pcb->unsent);\r
+    }\r
+#if TCP_QUEUE_OOSEQ\r
+    if (pcb->ooseq != NULL) {\r
+      tcp_segs_free(pcb->ooseq);\r
+    }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+    memp_free(MEMP_TCP_PCB, pcb);\r
+    TCP_EVENT_ERR(errf, errf_arg, ERR_ABRT);\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_abort: sending RST\n"));\r
+    tcp_rst(seqno, ackno, &local_ip, &remote_ip, local_port, remote_port);\r
+  }\r
+}\r
+\r
+/**\r
+ * Binds the connection to a local portnumber and IP address. If the\r
+ * IP address is not given (i.e., ipaddr == NULL), the IP address of\r
+ * the outgoing network interface is used instead.\r
+ *\r
+ * @param pcb the tcp_pcb to bind (no check is done whether this pcb is\r
+ *        already bound!)\r
+ * @param ipaddr the local ip address to bind to (use IP_ADDR_ANY to bind\r
+ *        to any local address\r
+ * @param port the local port to bind to\r
+ * @return ERR_USE if the port is already in use\r
+ *         ERR_OK if bound\r
+ */\r
+err_t\r
+tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct tcp_pcb *cpcb;\r
+\r
+  LWIP_ERROR("tcp_connect: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);\r
+\r
+  if (port == 0) {\r
+    port = tcp_new_port();\r
+  }\r
+  /* Check if the address already is in use. */\r
+  /* Check the listen pcbs. */\r
+  for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs;\r
+      cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_isany(&(cpcb->local_ip)) ||\r
+          ip_addr_isany(ipaddr) ||\r
+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+        return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+  /* Check the connected pcbs. */\r
+  for(cpcb = tcp_active_pcbs;\r
+      cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_isany(&(cpcb->local_ip)) ||\r
+          ip_addr_isany(ipaddr) ||\r
+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+        return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+  /* Check the bound, not yet connected pcbs. */\r
+  for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_isany(&(cpcb->local_ip)) ||\r
+          ip_addr_isany(ipaddr) ||\r
+          ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+        return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+  /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah),\r
+   * we have to check the pcbs in TIME-WAIT state, also: */\r
+  for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) {\r
+    if (cpcb->local_port == port) {\r
+      if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) {\r
+        return ERR_USE;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (!ip_addr_isany(ipaddr)) {\r
+    pcb->local_ip = *ipaddr;\r
+  }\r
+  pcb->local_port = port;\r
+  TCP_REG(&tcp_bound_pcbs, pcb);\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_bind: bind to port %"U16_F"\n", port));\r
+  return ERR_OK;\r
+}\r
+#if LWIP_CALLBACK_API\r
+/**\r
+ * Default accept callback if no accept callback is specified by the user.\r
+ */\r
+static err_t\r
+tcp_accept_null(void *arg, struct tcp_pcb *pcb, err_t err)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+  LWIP_UNUSED_ARG(pcb);\r
+  LWIP_UNUSED_ARG(err);\r
+\r
+  return ERR_ABRT;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+/**\r
+ * Set the state of the connection to be LISTEN, which means that it\r
+ * is able to accept incoming connections. The protocol control block\r
+ * is reallocated in order to consume less memory. Setting the\r
+ * connection to LISTEN is an irreversible process.\r
+ *\r
+ * @param pcb the original tcp_pcb\r
+ * @param backlog the incoming connections queue limit\r
+ * @return tcp_pcb used for listening, consumes less memory.\r
+ *\r
+ * @note The original tcp_pcb is freed. This function therefore has to be\r
+ *       called like this:\r
+ *             tpcb = tcp_listen(tpcb);\r
+ */\r
+struct tcp_pcb *\r
+tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog)\r
+{\r
+  struct tcp_pcb_listen *lpcb;\r
+\r
+  LWIP_UNUSED_ARG(backlog);\r
+  LWIP_ERROR("tcp_listen: pcb already connected", pcb->state == CLOSED, return NULL);\r
+\r
+  /* already listening? */\r
+  if (pcb->state == LISTEN) {\r
+    return pcb;\r
+  }\r
+  lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN);\r
+  if (lpcb == NULL) {\r
+    return NULL;\r
+  }\r
+  lpcb->callback_arg = pcb->callback_arg;\r
+  lpcb->local_port = pcb->local_port;\r
+  lpcb->state = LISTEN;\r
+  lpcb->so_options = pcb->so_options;\r
+  lpcb->so_options |= SOF_ACCEPTCONN;\r
+  lpcb->ttl = pcb->ttl;\r
+  lpcb->tos = pcb->tos;\r
+  ip_addr_set(&lpcb->local_ip, &pcb->local_ip);\r
+  TCP_RMV(&tcp_bound_pcbs, pcb);\r
+  memp_free(MEMP_TCP_PCB, pcb);\r
+#if LWIP_CALLBACK_API\r
+  lpcb->accept = tcp_accept_null;\r
+#endif /* LWIP_CALLBACK_API */\r
+#if TCP_LISTEN_BACKLOG\r
+  lpcb->accepts_pending = 0;\r
+  lpcb->backlog = (backlog ? backlog : 1);\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+  TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb);\r
+  return (struct tcp_pcb *)lpcb;\r
+}\r
+\r
+/**\r
+ * This function should be called by the application when it has\r
+ * processed the data. The purpose is to advertise a larger window\r
+ * when the data has been processed.\r
+ *\r
+ * @param pcb the tcp_pcb for which data is read\r
+ * @param len the amount of bytes that have been read by the application\r
+ */\r
+void\r
+tcp_recved(struct tcp_pcb *pcb, u16_t len)\r
+{\r
+  if ((u32_t)pcb->rcv_wnd + len > TCP_WND) {\r
+    pcb->rcv_wnd = TCP_WND;\r
+    pcb->rcv_ann_wnd = TCP_WND;\r
+  } else {\r
+    pcb->rcv_wnd += len;\r
+    if (pcb->rcv_wnd >= pcb->mss) {\r
+      pcb->rcv_ann_wnd = pcb->rcv_wnd;\r
+    }\r
+  }\r
+\r
+  if (!(pcb->flags & TF_ACK_DELAY) &&\r
+     !(pcb->flags & TF_ACK_NOW)) {\r
+    /*\r
+     * We send an ACK here (if one is not already pending, hence\r
+     * the above tests) as tcp_recved() implies that the application\r
+     * has processed some data, and so we can open the receiver's\r
+     * window to allow more to be transmitted.  This could result in\r
+     * two ACKs being sent for each received packet in some limited cases\r
+     * (where the application is only receiving data, and is slow to\r
+     * process it) but it is necessary to guarantee that the sender can\r
+     * continue to transmit.\r
+     */\r
+    tcp_ack(pcb);\r
+  }\r
+  else if (pcb->flags & TF_ACK_DELAY && pcb->rcv_wnd >= TCP_WND/2) {\r
+    /* If we can send a window update such that there is a full\r
+     * segment available in the window, do so now.  This is sort of\r
+     * nagle-like in its goals, and tries to hit a compromise between\r
+     * sending acks each time the window is updated, and only sending\r
+     * window updates when a timer expires.  The "threshold" used\r
+     * above (currently TCP_WND/2) can be tuned to be more or less\r
+     * aggressive  */\r
+    tcp_ack_now(pcb);\r
+  }\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n",\r
+         len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd));\r
+}\r
+\r
+/**\r
+ * A nastly hack featuring 'goto' statements that allocates a\r
+ * new TCP local port.\r
+ *\r
+ * @return a new (free) local TCP port number\r
+ */\r
+static u16_t\r
+tcp_new_port(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+#ifndef TCP_LOCAL_PORT_RANGE_START\r
+#define TCP_LOCAL_PORT_RANGE_START 4096\r
+#define TCP_LOCAL_PORT_RANGE_END   0x7fff\r
+#endif\r
+  static u16_t port = TCP_LOCAL_PORT_RANGE_START;\r
+\r
+ again:\r
+  if (++port > TCP_LOCAL_PORT_RANGE_END) {\r
+    port = TCP_LOCAL_PORT_RANGE_START;\r
+  }\r
+\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->local_port == port) {\r
+      goto again;\r
+    }\r
+  }\r
+  return port;\r
+}\r
+\r
+/**\r
+ * Connects to another host. The function given as the "connected"\r
+ * argument will be called when the connection has been established.\r
+ *\r
+ * @param pcb the tcp_pcb used to establish the connection\r
+ * @param ipaddr the remote ip address to connect to\r
+ * @param port the remote tcp port to connect to\r
+ * @param connected callback function to call when connected (or on error)\r
+ * @return ERR_VAL if invalid arguments are given\r
+ *         ERR_OK if connect request has been sent\r
+ *         other err_t values if connect request couldn't be sent\r
+ */\r
+err_t\r
+tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port,\r
+      err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err))\r
+{\r
+  u32_t optdata;\r
+  err_t ret;\r
+  u32_t iss;\r
+\r
+  LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN);\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port));\r
+  if (ipaddr != NULL) {\r
+    pcb->remote_ip = *ipaddr;\r
+  } else {\r
+    return ERR_VAL;\r
+  }\r
+  pcb->remote_port = port;\r
+  if (pcb->local_port == 0) {\r
+    pcb->local_port = tcp_new_port();\r
+  }\r
+  iss = tcp_next_iss();\r
+  pcb->rcv_nxt = 0;\r
+  pcb->snd_nxt = iss;\r
+  pcb->lastack = iss - 1;\r
+  pcb->snd_lbb = iss - 1;\r
+  pcb->rcv_wnd = TCP_WND;\r
+  pcb->rcv_ann_wnd = TCP_WND;\r
+  pcb->snd_wnd = TCP_WND;\r
+  /* The send MSS is updated when an MSS option is received. */\r
+  pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;\r
+#if TCP_CALCULATE_EFF_SEND_MSS\r
+  pcb->mss = tcp_eff_send_mss(pcb->mss, ipaddr);\r
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */\r
+  pcb->cwnd = 1;\r
+  pcb->ssthresh = pcb->mss * 10;\r
+  pcb->state = SYN_SENT;\r
+#if LWIP_CALLBACK_API\r
+  pcb->connected = connected;\r
+#endif /* LWIP_CALLBACK_API */\r
+  TCP_RMV(&tcp_bound_pcbs, pcb);\r
+  TCP_REG(&tcp_active_pcbs, pcb);\r
+\r
+  snmp_inc_tcpactiveopens();\r
+\r
+  /* Build an MSS option */\r
+  optdata = TCP_BUILD_MSS_OPTION();\r
+\r
+  ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, (u8_t *)&optdata, 4);\r
+  if (ret == ERR_OK) {\r
+    tcp_output(pcb);\r
+  }\r
+  return ret;\r
+}\r
+\r
+/**\r
+ * Called every 500 ms and implements the retransmission timer and the timer that\r
+ * removes PCBs that have been in TIME-WAIT for enough time. It also increments\r
+ * various timers such as the inactivity timer in each PCB.\r
+ *\r
+ * Automatically called from tcp_tmr().\r
+ */\r
+void\r
+tcp_slowtmr(void)\r
+{\r
+  struct tcp_pcb *pcb, *pcb2, *prev;\r
+  u16_t eff_wnd;\r
+  u8_t pcb_remove;      /* flag if a PCB should be removed */\r
+  err_t err;\r
+\r
+  err = ERR_OK;\r
+\r
+  ++tcp_ticks;\r
+\r
+  /* Steps through all of the active PCBs. */\r
+  prev = NULL;\r
+  pcb = tcp_active_pcbs;\r
+  if (pcb == NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: no active pcbs\n"));\r
+  }\r
+  while (pcb != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: processing active pcb\n"));\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != CLOSED\n", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != LISTEN\n", pcb->state != LISTEN);\r
+    LWIP_ASSERT("tcp_slowtmr: active pcb->state != TIME-WAIT\n", pcb->state != TIME_WAIT);\r
+\r
+    pcb_remove = 0;\r
+\r
+    if (pcb->state == SYN_SENT && pcb->nrtx == TCP_SYNMAXRTX) {\r
+      ++pcb_remove;\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max SYN retries reached\n"));\r
+    }\r
+    else if (pcb->nrtx == TCP_MAXRTX) {\r
+      ++pcb_remove;\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));\r
+    } else {\r
+      if (pcb->persist_backoff > 0) {\r
+        /* If snd_wnd is zero, use persist timer to send 1 byte probes\r
+         * instead of using the standard retransmission mechanism. */\r
+        pcb->persist_cnt++;\r
+        if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {\r
+          pcb->persist_cnt = 0;\r
+          if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {\r
+            pcb->persist_backoff++;\r
+          }\r
+          tcp_zero_window_probe(pcb);\r
+        }\r
+      } else {\r
+        /* Increase the retransmission timer if it is running */\r
+        if(pcb->rtime >= 0)\r
+          ++pcb->rtime;\r
+\r
+        if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {\r
+          /* Time for a retransmission. */\r
+          LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F\r
+                                      " pcb->rto %"S16_F"\n",\r
+                                      pcb->rtime, pcb->rto));\r
+\r
+          /* Double retransmission time-out unless we are trying to\r
+           * connect to somebody (i.e., we are in SYN_SENT). */\r
+          if (pcb->state != SYN_SENT) {\r
+            pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx];\r
+          }\r
+\r
+          /* Reset the retransmission timer. */\r
+          pcb->rtime = 0;\r
+\r
+          /* Reduce congestion window and ssthresh. */\r
+          eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);\r
+          pcb->ssthresh = eff_wnd >> 1;\r
+          if (pcb->ssthresh < pcb->mss) {\r
+            pcb->ssthresh = pcb->mss * 2;\r
+          }\r
+          pcb->cwnd = pcb->mss;\r
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F\r
+                                       " ssthresh %"U16_F"\n",\r
+                                       pcb->cwnd, pcb->ssthresh));\r
+\r
+          /* The following needs to be called AFTER cwnd is set to one\r
+             mss - STJ */\r
+          tcp_rexmit_rto(pcb);\r
+        }\r
+      }\r
+    }\r
+    /* Check if this PCB has stayed too long in FIN-WAIT-2 */\r
+    if (pcb->state == FIN_WAIT_2) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) >\r
+          TCP_FIN_WAIT_TIMEOUT / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in FIN-WAIT-2\n"));\r
+      }\r
+    }\r
+\r
+    /* Check if KEEPALIVE should be sent */\r
+    if((pcb->so_options & SOF_KEEPALIVE) &&\r
+       ((pcb->state == ESTABLISHED) ||\r
+        (pcb->state == CLOSE_WAIT))) {\r
+#if LWIP_TCP_KEEPALIVE\r
+      if((u32_t)(tcp_ticks - pcb->tmr) >\r
+         (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl))\r
+         / TCP_SLOW_INTERVAL)\r
+#else\r
+      if((u32_t)(tcp_ticks - pcb->tmr) >\r
+         (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL)\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+      {\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n",\r
+                                ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                                ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
+\r
+        tcp_abort(pcb);\r
+      }\r
+#if LWIP_TCP_KEEPALIVE\r
+      else if((u32_t)(tcp_ticks - pcb->tmr) >\r
+              (pcb->keep_idle + pcb->keep_cnt_sent * pcb->keep_intvl)\r
+              / TCP_SLOW_INTERVAL)\r
+#else\r
+      else if((u32_t)(tcp_ticks - pcb->tmr) >\r
+              (pcb->keep_idle + pcb->keep_cnt_sent * TCP_KEEPINTVL_DEFAULT)\r
+              / TCP_SLOW_INTERVAL)\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+      {\r
+        tcp_keepalive(pcb);\r
+        pcb->keep_cnt_sent++;\r
+      }\r
+    }\r
+\r
+    /* If this PCB has queued out of sequence data, but has been\r
+       inactive for too long, will drop the data (it will eventually\r
+       be retransmitted). */\r
+#if TCP_QUEUE_OOSEQ\r
+    if (pcb->ooseq != NULL &&\r
+        (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) {\r
+      tcp_segs_free(pcb->ooseq);\r
+      pcb->ooseq = NULL;\r
+      LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: dropping OOSEQ queued data\n"));\r
+    }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+    /* Check if this PCB has stayed too long in SYN-RCVD */\r
+    if (pcb->state == SYN_RCVD) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) >\r
+          TCP_SYN_RCVD_TIMEOUT / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in SYN-RCVD\n"));\r
+      }\r
+    }\r
+\r
+    /* Check if this PCB has stayed too long in LAST-ACK */\r
+    if (pcb->state == LAST_ACK) {\r
+      if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
+        ++pcb_remove;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: removing pcb stuck in LAST-ACK\n"));\r
+      }\r
+    }\r
+\r
+    /* If the PCB should be removed, do it. */\r
+    if (pcb_remove) {\r
+      tcp_pcb_purge(pcb);\r
+      /* Remove PCB from tcp_active_pcbs list. */\r
+      if (prev != NULL) {\r
+        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs);\r
+        prev->next = pcb->next;\r
+      } else {\r
+        /* This PCB was the first. */\r
+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_active_pcbs", tcp_active_pcbs == pcb);\r
+        tcp_active_pcbs = pcb->next;\r
+      }\r
+\r
+      TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_ABRT);\r
+\r
+      pcb2 = pcb->next;\r
+      memp_free(MEMP_TCP_PCB, pcb);\r
+      pcb = pcb2;\r
+    } else {\r
+\r
+      /* We check if we should poll the connection. */\r
+      ++pcb->polltmr;\r
+      if (pcb->polltmr >= pcb->pollinterval) {\r
+        pcb->polltmr = 0;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n"));\r
+        TCP_EVENT_POLL(pcb, err);\r
+        if (err == ERR_OK) {\r
+          tcp_output(pcb);\r
+        }\r
+      }\r
+\r
+      prev = pcb;\r
+      pcb = pcb->next;\r
+    }\r
+  }\r
+\r
+\r
+  /* Steps through all of the TIME-WAIT PCBs. */\r
+  prev = NULL;\r
+  pcb = tcp_tw_pcbs;\r
+  while (pcb != NULL) {\r
+    LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+    pcb_remove = 0;\r
+\r
+    /* Check if this PCB has stayed long enough in TIME-WAIT */\r
+    if ((u32_t)(tcp_ticks - pcb->tmr) > 2 * TCP_MSL / TCP_SLOW_INTERVAL) {\r
+      ++pcb_remove;\r
+    }\r
+\r
+\r
+\r
+    /* If the PCB should be removed, do it. */\r
+    if (pcb_remove) {\r
+      tcp_pcb_purge(pcb);\r
+      /* Remove PCB from tcp_tw_pcbs list. */\r
+      if (prev != NULL) {\r
+        LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs);\r
+        prev->next = pcb->next;\r
+      } else {\r
+        /* This PCB was the first. */\r
+        LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb);\r
+        tcp_tw_pcbs = pcb->next;\r
+      }\r
+      pcb2 = pcb->next;\r
+      memp_free(MEMP_TCP_PCB, pcb);\r
+      pcb = pcb2;\r
+    } else {\r
+      prev = pcb;\r
+      pcb = pcb->next;\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Is called every TCP_FAST_INTERVAL (250 ms) and process data previously\r
+ * "refused" by upper layer (application) and sends delayed ACKs.\r
+ *\r
+ * Automatically called from tcp_tmr().\r
+ */\r
+void\r
+tcp_fasttmr(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    /* If there is data which was previously "refused" by upper layer */\r
+    if (pcb->refused_data != NULL) {\r
+      /* Notify again application with data previously received. */\r
+      err_t err;\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_fasttmr: notify kept packet\n"));\r
+      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);\r
+      if (err == ERR_OK) {\r
+        pcb->refused_data = NULL;\r
+      }\r
+    }\r
+\r
+    /* send delayed ACKs */\r
+    if (pcb->flags & TF_ACK_DELAY) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n"));\r
+      tcp_ack_now(pcb);\r
+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+    }\r
+  }\r
+}\r
+\r
+/**\r
+ * Deallocates a list of TCP segments (tcp_seg structures).\r
+ *\r
+ * @param seg tcp_seg list of TCP segments to free\r
+ * @return the number of pbufs that were deallocated\r
+ */\r
+u8_t\r
+tcp_segs_free(struct tcp_seg *seg)\r
+{\r
+  u8_t count = 0;\r
+  struct tcp_seg *next;\r
+  while (seg != NULL) {\r
+    next = seg->next;\r
+    count += tcp_seg_free(seg);\r
+    seg = next;\r
+  }\r
+  return count;\r
+}\r
+\r
+/**\r
+ * Frees a TCP segment (tcp_seg structure).\r
+ *\r
+ * @param seg single tcp_seg to free\r
+ * @return the number of pbufs that were deallocated\r
+ */\r
+u8_t\r
+tcp_seg_free(struct tcp_seg *seg)\r
+{\r
+  u8_t count = 0;\r
+\r
+  if (seg != NULL) {\r
+    if (seg->p != NULL) {\r
+      count = pbuf_free(seg->p);\r
+#if TCP_DEBUG\r
+      seg->p = NULL;\r
+#endif /* TCP_DEBUG */\r
+    }\r
+    memp_free(MEMP_TCP_SEG, seg);\r
+  }\r
+  return count;\r
+}\r
+\r
+/**\r
+ * Sets the priority of a connection.\r
+ *\r
+ * @param pcb the tcp_pcb to manipulate\r
+ * @param prio new priority\r
+ */\r
+void\r
+tcp_setprio(struct tcp_pcb *pcb, u8_t prio)\r
+{\r
+  pcb->prio = prio;\r
+}\r
+#if TCP_QUEUE_OOSEQ\r
+\r
+/**\r
+ * Returns a copy of the given TCP segment.\r
+ * The pbuf and data are not copied, only the pointers\r
+ *\r
+ * @param seg the old tcp_seg\r
+ * @return a copy of seg\r
+ */\r
+struct tcp_seg *\r
+tcp_seg_copy(struct tcp_seg *seg)\r
+{\r
+  struct tcp_seg *cseg;\r
+\r
+  cseg = memp_malloc(MEMP_TCP_SEG);\r
+  if (cseg == NULL) {\r
+    return NULL;\r
+  }\r
+  SMEMCPY((u8_t *)cseg, (const u8_t *)seg, sizeof(struct tcp_seg));\r
+  pbuf_ref(cseg->p);\r
+  return cseg;\r
+}\r
+#endif\r
+\r
+#if LWIP_CALLBACK_API\r
+/**\r
+ * Default receive callback that is called if the user didn't register\r
+ * a recv callback for the pcb.\r
+ */\r
+static err_t\r
+tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)\r
+{\r
+  arg = arg;\r
+  if (p != NULL) {\r
+    pbuf_free(p);\r
+  } else if (err == ERR_OK) {\r
+    return tcp_close(pcb);\r
+  }\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+/**\r
+ * Kills the oldest active connection that has lower priority than prio.\r
+ *\r
+ * @param prio minimum priority\r
+ */\r
+static void\r
+tcp_kill_prio(u8_t prio)\r
+{\r
+  struct tcp_pcb *pcb, *inactive;\r
+  u32_t inactivity;\r
+  u8_t mprio;\r
+\r
+\r
+  mprio = TCP_PRIO_MAX;\r
+\r
+  /* We kill the oldest active connection that has lower priority than prio. */\r
+  inactivity = 0;\r
+  inactive = NULL;\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if (pcb->prio <= prio &&\r
+       pcb->prio <= mprio &&\r
+       (u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
+      inactivity = tcp_ticks - pcb->tmr;\r
+      inactive = pcb;\r
+      mprio = pcb->prio;\r
+    }\r
+  }\r
+  if (inactive != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n",\r
+           (void *)inactive, inactivity));\r
+    tcp_abort(inactive);\r
+  }\r
+}\r
+\r
+/**\r
+ * Kills the oldest connection that is in TIME_WAIT state.\r
+ * Called from tcp_alloc() if no more connections are available.\r
+ */\r
+static void\r
+tcp_kill_timewait(void)\r
+{\r
+  struct tcp_pcb *pcb, *inactive;\r
+  u32_t inactivity;\r
+\r
+  inactivity = 0;\r
+  inactive = NULL;\r
+  /* Go through the list of TIME_WAIT pcbs and get the oldest pcb. */\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    if ((u32_t)(tcp_ticks - pcb->tmr) >= inactivity) {\r
+      inactivity = tcp_ticks - pcb->tmr;\r
+      inactive = pcb;\r
+    }\r
+  }\r
+  if (inactive != NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n",\r
+           (void *)inactive, inactivity));\r
+    tcp_abort(inactive);\r
+  }\r
+}\r
+\r
+/**\r
+ * Allocate a new tcp_pcb structure.\r
+ *\r
+ * @param prio priority for the new pcb\r
+ * @return a new tcp_pcb that initially is in state CLOSED\r
+ */\r
+struct tcp_pcb *\r
+tcp_alloc(u8_t prio)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  u32_t iss;\r
+\r
+  pcb = memp_malloc(MEMP_TCP_PCB);\r
+  if (pcb == NULL) {\r
+    /* Try killing oldest connection in TIME-WAIT. */\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n"));\r
+    tcp_kill_timewait();\r
+    /* Try to allocate a tcp_pcb again. */\r
+    pcb = memp_malloc(MEMP_TCP_PCB);\r
+    if (pcb == NULL) {\r
+      /* Try killing active connections with lower priority than the new one. */\r
+      tcp_kill_prio(prio);\r
+      /* Try to allocate a tcp_pcb again. */\r
+      pcb = memp_malloc(MEMP_TCP_PCB);\r
+    }\r
+  }\r
+  if (pcb != NULL) {\r
+    memset(pcb, 0, sizeof(struct tcp_pcb));\r
+    pcb->prio = TCP_PRIO_NORMAL;\r
+    pcb->snd_buf = TCP_SND_BUF;\r
+    pcb->snd_queuelen = 0;\r
+    pcb->rcv_wnd = TCP_WND;\r
+    pcb->rcv_ann_wnd = TCP_WND;\r
+    pcb->tos = 0;\r
+    pcb->ttl = TCP_TTL;\r
+    /* The send MSS is updated when an MSS option is received. */\r
+    pcb->mss = (TCP_MSS > 536) ? 536 : TCP_MSS;\r
+    pcb->rto = 3000 / TCP_SLOW_INTERVAL;\r
+    pcb->sa = 0;\r
+    pcb->sv = 3000 / TCP_SLOW_INTERVAL;\r
+    pcb->rtime = -1;\r
+    pcb->cwnd = 1;\r
+    iss = tcp_next_iss();\r
+    pcb->snd_wl2 = iss;\r
+    pcb->snd_nxt = iss;\r
+    pcb->snd_max = iss;\r
+    pcb->lastack = iss;\r
+    pcb->snd_lbb = iss;\r
+    pcb->tmr = tcp_ticks;\r
+\r
+    pcb->polltmr = 0;\r
+\r
+#if LWIP_CALLBACK_API\r
+    pcb->recv = tcp_recv_null;\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+    /* Init KEEPALIVE timer */\r
+    pcb->keep_idle  = TCP_KEEPIDLE_DEFAULT;\r
+\r
+#if LWIP_TCP_KEEPALIVE\r
+    pcb->keep_intvl = TCP_KEEPINTVL_DEFAULT;\r
+    pcb->keep_cnt   = TCP_KEEPCNT_DEFAULT;\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+\r
+    pcb->keep_cnt_sent = 0;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+/**\r
+ * Creates a new TCP protocol control block but doesn't place it on\r
+ * any of the TCP PCB lists.\r
+ * The pcb is not put on any list until binding using tcp_bind().\r
+ *\r
+ * @internal: Maybe there should be a idle TCP PCB list where these\r
+ * PCBs are put on. Port reservation using tcp_bind() is implemented but\r
+ * allocated pcbs that are not bound can't be killed automatically if wanting\r
+ * to allocate a pcb with higher prio (@see tcp_kill_prio())\r
+ *\r
+ * @return a new tcp_pcb that initially is in state CLOSED\r
+ */\r
+struct tcp_pcb *\r
+tcp_new(void)\r
+{\r
+  return tcp_alloc(TCP_PRIO_NORMAL);\r
+}\r
+\r
+/**\r
+ * Used to specify the argument that should be passed callback\r
+ * functions.\r
+ *\r
+ * @param pcb tcp_pcb to set the callback argument\r
+ * @param arg void pointer argument to pass to callback functions\r
+ */\r
+void\r
+tcp_arg(struct tcp_pcb *pcb, void *arg)\r
+{\r
+  pcb->callback_arg = arg;\r
+}\r
+#if LWIP_CALLBACK_API\r
+\r
+/**\r
+ * Used to specify the function that should be called when a TCP\r
+ * connection receives data.\r
+ *\r
+ * @param pcb tcp_pcb to set the recv callback\r
+ * @param recv callback function to call for this pcb when data is received\r
+ */\r
+void\r
+tcp_recv(struct tcp_pcb *pcb,\r
+   err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err))\r
+{\r
+  pcb->recv = recv;\r
+}\r
+\r
+/**\r
+ * Used to specify the function that should be called when TCP data\r
+ * has been successfully delivered to the remote host.\r
+ *\r
+ * @param pcb tcp_pcb to set the sent callback\r
+ * @param sent callback function to call for this pcb when data is successfully sent\r
+ */\r
+void\r
+tcp_sent(struct tcp_pcb *pcb,\r
+   err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len))\r
+{\r
+  pcb->sent = sent;\r
+}\r
+\r
+/**\r
+ * Used to specify the function that should be called when a fatal error\r
+ * has occured on the connection.\r
+ *\r
+ * @param pcb tcp_pcb to set the err callback\r
+ * @param errf callback function to call for this pcb when a fatal error\r
+ *        has occured on the connection\r
+ */\r
+void\r
+tcp_err(struct tcp_pcb *pcb,\r
+   void (* errf)(void *arg, err_t err))\r
+{\r
+  pcb->errf = errf;\r
+}\r
+\r
+/**\r
+ * Used for specifying the function that should be called when a\r
+ * LISTENing connection has been connected to another host.\r
+ *\r
+ * @param pcb tcp_pcb to set the accept callback\r
+ * @param accept callback function to call for this pcb when LISTENing\r
+ *        connection has been connected to another host\r
+ */\r
+void\r
+tcp_accept(struct tcp_pcb *pcb,\r
+     err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err))\r
+{\r
+  ((struct tcp_pcb_listen *)pcb)->accept = accept;\r
+}\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+\r
+/**\r
+ * Used to specify the function that should be called periodically\r
+ * from TCP. The interval is specified in terms of the TCP coarse\r
+ * timer interval, which is called twice a second.\r
+ *\r
+ */\r
+void\r
+tcp_poll(struct tcp_pcb *pcb,\r
+   err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval)\r
+{\r
+#if LWIP_CALLBACK_API\r
+  pcb->poll = poll;\r
+#endif /* LWIP_CALLBACK_API */\r
+  pcb->pollinterval = interval;\r
+}\r
+\r
+/**\r
+ * Purges a TCP PCB. Removes any buffered data and frees the buffer memory\r
+ * (pcb->ooseq, pcb->unsent and pcb->unacked are freed).\r
+ *\r
+ * @param pcb tcp_pcb to purge. The pcb itself is not deallocated!\r
+ */\r
+void\r
+tcp_pcb_purge(struct tcp_pcb *pcb)\r
+{\r
+  if (pcb->state != CLOSED &&\r
+     pcb->state != TIME_WAIT &&\r
+     pcb->state != LISTEN) {\r
+\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge\n"));\r
+\r
+    if (pcb->refused_data != NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->refused_data\n"));\r
+      pbuf_free(pcb->refused_data);\r
+      pcb->refused_data = NULL;\r
+    }\r
+    if (pcb->unsent != NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: not all data sent\n"));\r
+    }\r
+    if (pcb->unacked != NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n"));\r
+    }\r
+#if TCP_QUEUE_OOSEQ /* LW */\r
+    if (pcb->ooseq != NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n"));\r
+    }\r
+\r
+    /* Stop the retransmission timer as it will expect data on unacked\r
+       queue if it fires */\r
+    pcb->rtime = -1;\r
+\r
+    tcp_segs_free(pcb->ooseq);\r
+    pcb->ooseq = NULL;\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+    tcp_segs_free(pcb->unsent);\r
+    tcp_segs_free(pcb->unacked);\r
+    pcb->unacked = pcb->unsent = NULL;\r
+  }\r
+}\r
+\r
+/**\r
+ * Purges the PCB and removes it from a PCB list. Any delayed ACKs are sent first.\r
+ *\r
+ * @param pcblist PCB list to purge.\r
+ * @param pcb tcp_pcb to purge. The pcb itself is also deallocated!\r
+ */\r
+void\r
+tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb)\r
+{\r
+  TCP_RMV(pcblist, pcb);\r
+\r
+  tcp_pcb_purge(pcb);\r
+\r
+  /* if there is an outstanding delayed ACKs, send it */\r
+  if (pcb->state != TIME_WAIT &&\r
+     pcb->state != LISTEN &&\r
+     pcb->flags & TF_ACK_DELAY) {\r
+    pcb->flags |= TF_ACK_NOW;\r
+    tcp_output(pcb);\r
+  }\r
+\r
+  if (pcb->state != LISTEN) {\r
+    LWIP_ASSERT("unsent segments leaking", pcb->unsent == NULL);\r
+    LWIP_ASSERT("unacked segments leaking", pcb->unacked == NULL);\r
+#if TCP_QUEUE_OOSEQ\r
+    LWIP_ASSERT("ooseq segments leaking", pcb->ooseq == NULL);\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+  }\r
+\r
+  pcb->state = CLOSED;\r
+\r
+  LWIP_ASSERT("tcp_pcb_remove: tcp_pcbs_sane()", tcp_pcbs_sane());\r
+}\r
+\r
+/**\r
+ * Calculates a new initial sequence number for new connections.\r
+ *\r
+ * @return u32_t pseudo random sequence number\r
+ */\r
+u32_t\r
+tcp_next_iss(void)\r
+{\r
+  static u32_t iss = 6510;\r
+\r
+  iss += tcp_ticks;       /* XXX */\r
+  return iss;\r
+}\r
+\r
+#if TCP_CALCULATE_EFF_SEND_MSS\r
+/**\r
+ * Calcluates the effective send mss that can be used for a specific IP address\r
+ * by using ip_route to determin the netif used to send to the address and\r
+ * calculating the minimum of TCP_MSS and that netif's mtu (if set).\r
+ */\r
+u16_t\r
+tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr)\r
+{\r
+  u16_t mss_s;\r
+  struct netif *outif;\r
+\r
+  outif = ip_route(addr);\r
+  if ((outif != NULL) && (outif->mtu != 0)) {\r
+    mss_s = outif->mtu - IP_HLEN - TCP_HLEN;\r
+    /* RFC 1122, chap 4.2.2.6:\r
+     * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize\r
+     * but we only send options with SYN and that is never filled with data! */\r
+    sendmss = LWIP_MIN(sendmss, mss_s);\r
+  }\r
+  return sendmss;\r
+}\r
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */\r
+\r
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\r
+/**\r
+ * Print a tcp header for debugging purposes.\r
+ *\r
+ * @param tcphdr pointer to a struct tcp_hdr\r
+ */\r
+void\r
+tcp_debug_print(struct tcp_hdr *tcphdr)\r
+{\r
+  LWIP_DEBUGF(TCP_DEBUG, ("TCP header:\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|    %5"U16_F"      |    %5"U16_F"      | (src port, dest port)\n",\r
+         ntohs(tcphdr->src), ntohs(tcphdr->dest)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (seq no)\n",\r
+          ntohl(tcphdr->seqno)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|           %010"U32_F"          | (ack no)\n",\r
+         ntohl(tcphdr->ackno)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("| %2"U16_F" |   |%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"%"U16_F"|     %5"U16_F"     | (hdrlen, flags (",\r
+       TCPH_HDRLEN(tcphdr),\r
+         TCPH_FLAGS(tcphdr) >> 5 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 4 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 3 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 2 & 1,\r
+         TCPH_FLAGS(tcphdr) >> 1 & 1,\r
+         TCPH_FLAGS(tcphdr) & 1,\r
+         ntohs(tcphdr->wnd)));\r
+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("), win)\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("|    0x%04"X16_F"     |     %5"U16_F"     | (chksum, urgp)\n",\r
+         ntohs(tcphdr->chksum), ntohs(tcphdr->urgp)));\r
+  LWIP_DEBUGF(TCP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+\r
+/**\r
+ * Print a tcp state for debugging purposes.\r
+ *\r
+ * @param s enum tcp_state to print\r
+ */\r
+void\r
+tcp_debug_print_state(enum tcp_state s)\r
+{\r
+  LWIP_DEBUGF(TCP_DEBUG, ("State: "));\r
+  switch (s) {\r
+  case CLOSED:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSED\n"));\r
+    break;\r
+ case LISTEN:\r
+   LWIP_DEBUGF(TCP_DEBUG, ("LISTEN\n"));\r
+   break;\r
+  case SYN_SENT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_SENT\n"));\r
+    break;\r
+  case SYN_RCVD:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN_RCVD\n"));\r
+    break;\r
+  case ESTABLISHED:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ESTABLISHED\n"));\r
+    break;\r
+  case FIN_WAIT_1:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_1\n"));\r
+    break;\r
+  case FIN_WAIT_2:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN_WAIT_2\n"));\r
+    break;\r
+  case CLOSE_WAIT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSE_WAIT\n"));\r
+    break;\r
+  case CLOSING:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CLOSING\n"));\r
+    break;\r
+  case LAST_ACK:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("LAST_ACK\n"));\r
+    break;\r
+  case TIME_WAIT:\r
+    LWIP_DEBUGF(TCP_DEBUG, ("TIME_WAIT\n"));\r
+   break;\r
+  }\r
+}\r
+\r
+/**\r
+ * Print tcp flags for debugging purposes.\r
+ *\r
+ * @param flags tcp flags, all active flags are printed\r
+ */\r
+void\r
+tcp_debug_print_flags(u8_t flags)\r
+{\r
+  if (flags & TCP_FIN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("FIN "));\r
+  }\r
+  if (flags & TCP_SYN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("SYN "));\r
+  }\r
+  if (flags & TCP_RST) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("RST "));\r
+  }\r
+  if (flags & TCP_PSH) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("PSH "));\r
+  }\r
+  if (flags & TCP_ACK) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ACK "));\r
+  }\r
+  if (flags & TCP_URG) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("URG "));\r
+  }\r
+  if (flags & TCP_ECE) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("ECE "));\r
+  }\r
+  if (flags & TCP_CWR) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("CWR "));\r
+  }\r
+}\r
+\r
+/**\r
+ * Print all tcp_pcbs in every list for debugging purposes.\r
+ */\r
+void\r
+tcp_debug_print_pcbs(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  LWIP_DEBUGF(TCP_DEBUG, ("Active PCB states:\n"));\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }\r
+  LWIP_DEBUGF(TCP_DEBUG, ("Listen PCB states:\n"));\r
+  for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }\r
+  LWIP_DEBUGF(TCP_DEBUG, ("TIME-WAIT PCB states:\n"));\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("Local port %"U16_F", foreign port %"U16_F" snd_nxt %"U32_F" rcv_nxt %"U32_F" ",\r
+                       pcb->local_port, pcb->remote_port,\r
+                       pcb->snd_nxt, pcb->rcv_nxt));\r
+    tcp_debug_print_state(pcb->state);\r
+  }\r
+}\r
+\r
+/**\r
+ * Check state consistency of the tcp_pcb lists.\r
+ */\r
+s16_t\r
+tcp_pcbs_sane(void)\r
+{\r
+  struct tcp_pcb *pcb;\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != CLOSED", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != LISTEN", pcb->state != LISTEN);\r
+    LWIP_ASSERT("tcp_pcbs_sane: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);\r
+  }\r
+  for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_pcbs_sane: tw pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+  }\r
+  return 1;\r
+}\r
+#endif /* TCP_DEBUG */\r
+\r
+#endif /* LWIP_TCP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c b/Demo/Common/ethernet/lwIP_130/src/core/tcp_in.c
new file mode 100644 (file)
index 0000000..0f79b54
--- /dev/null
@@ -0,0 +1,1352 @@
+/**\r
+ * @file\r
+ * Transmission Control Protocol, incoming traffic\r
+ *\r
+ * The input processing functions of the TCP layer.\r
+ *\r
+ * These functions are generally called in the order (ip_input() ->)\r
+ * tcp_input() -> * tcp_process() -> tcp_receive() (-> application).\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/tcp.h"\r
+#include "lwip/def.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "arch/perf.h"\r
+\r
+/* These variables are global to all functions involved in the input\r
+   processing of TCP segments. They are set by the tcp_input()\r
+   function. */\r
+static struct tcp_seg inseg;\r
+static struct tcp_hdr *tcphdr;\r
+static struct ip_hdr *iphdr;\r
+static u32_t seqno, ackno;\r
+static u8_t flags;\r
+static u16_t tcplen;\r
+\r
+static u8_t recv_flags;\r
+static struct pbuf *recv_data;\r
+\r
+struct tcp_pcb *tcp_input_pcb;\r
+\r
+/* Forward declarations. */\r
+static err_t tcp_process(struct tcp_pcb *pcb);\r
+static u8_t tcp_receive(struct tcp_pcb *pcb);\r
+static void tcp_parseopt(struct tcp_pcb *pcb);\r
+\r
+static err_t tcp_listen_input(struct tcp_pcb_listen *pcb);\r
+static err_t tcp_timewait_input(struct tcp_pcb *pcb);\r
+\r
+/**\r
+ * The initial input processing of TCP. It verifies the TCP header, demultiplexes\r
+ * the segment between the PCBs and passes it on to tcp_process(), which implements\r
+ * the TCP finite state machine. This function is called by the IP layer (in\r
+ * ip_input()).\r
+ *\r
+ * @param p received TCP segment to process (p->payload pointing to the IP header)\r
+ * @param inp network interface on which this segment was received\r
+ */\r
+void\r
+tcp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct tcp_pcb *pcb, *prev;\r
+  struct tcp_pcb_listen *lpcb;\r
+  u8_t hdrlen;\r
+  err_t err;\r
+\r
+  PERF_START;\r
+\r
+  TCP_STATS_INC(tcp.recv);\r
+  snmp_inc_tcpinsegs();\r
+\r
+  iphdr = p->payload;\r
+  tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4);\r
+\r
+#if TCP_INPUT_DEBUG\r
+  tcp_debug_print(tcphdr);\r
+#endif\r
+\r
+  /* remove header from payload */\r
+  if (pbuf_header(p, -((s16_t)(IPH_HL(iphdr) * 4))) || (p->tot_len < sizeof(struct tcp_hdr))) {\r
+    /* drop short packets */\r
+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet (%"U16_F" bytes) discarded\n", p->tot_len));\r
+    TCP_STATS_INC(tcp.lenerr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  /* Don't even process incoming broadcasts/multicasts. */\r
+  if (ip_addr_isbroadcast(&(iphdr->dest), inp) ||\r
+      ip_addr_ismulticast(&(iphdr->dest))) {\r
+    TCP_STATS_INC(tcp.proterr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+#if CHECKSUM_CHECK_TCP\r
+  /* Verify TCP checksum. */\r
+  if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),\r
+      (struct ip_addr *)&(iphdr->dest),\r
+      IP_PROTO_TCP, p->tot_len) != 0) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n",\r
+        inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest),\r
+      IP_PROTO_TCP, p->tot_len)));\r
+#if TCP_DEBUG\r
+    tcp_debug_print(tcphdr);\r
+#endif /* TCP_DEBUG */\r
+    TCP_STATS_INC(tcp.chkerr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+#endif\r
+\r
+  /* Move the payload pointer in the pbuf so that it points to the\r
+     TCP data instead of the TCP header. */\r
+  hdrlen = TCPH_HDRLEN(tcphdr);\r
+  if(pbuf_header(p, -(hdrlen * 4))){\r
+    /* drop short packets */\r
+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: short packet\n"));\r
+    TCP_STATS_INC(tcp.lenerr);\r
+    TCP_STATS_INC(tcp.drop);\r
+    snmp_inc_tcpinerrs();\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  /* Convert fields in TCP header to host byte order. */\r
+  tcphdr->src = ntohs(tcphdr->src);\r
+  tcphdr->dest = ntohs(tcphdr->dest);\r
+  seqno = tcphdr->seqno = ntohl(tcphdr->seqno);\r
+  ackno = tcphdr->ackno = ntohl(tcphdr->ackno);\r
+  tcphdr->wnd = ntohs(tcphdr->wnd);\r
+\r
+  flags = TCPH_FLAGS(tcphdr) & TCP_FLAGS;\r
+  tcplen = p->tot_len + ((flags & TCP_FIN || flags & TCP_SYN)? 1: 0);\r
+\r
+  /* Demultiplex an incoming segment. First, we check if it is destined\r
+     for an active connection. */\r
+  prev = NULL;\r
+\r
+\r
+  for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) {\r
+    LWIP_ASSERT("tcp_input: active pcb->state != CLOSED", pcb->state != CLOSED);\r
+    LWIP_ASSERT("tcp_input: active pcb->state != TIME-WAIT", pcb->state != TIME_WAIT);\r
+    LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN);\r
+    if (pcb->remote_port == tcphdr->src &&\r
+       pcb->local_port == tcphdr->dest &&\r
+       ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&\r
+       ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {\r
+\r
+      /* Move this PCB to the front of the list so that subsequent\r
+         lookups will be faster (we exploit locality in TCP segment\r
+         arrivals). */\r
+      LWIP_ASSERT("tcp_input: pcb->next != pcb (before cache)", pcb->next != pcb);\r
+      if (prev != NULL) {\r
+        prev->next = pcb->next;\r
+        pcb->next = tcp_active_pcbs;\r
+        tcp_active_pcbs = pcb;\r
+      }\r
+      LWIP_ASSERT("tcp_input: pcb->next != pcb (after cache)", pcb->next != pcb);\r
+      break;\r
+    }\r
+    prev = pcb;\r
+  }\r
+\r
+  if (pcb == NULL) {\r
+    /* If it did not go to an active connection, we check the connections\r
+       in the TIME-WAIT state. */\r
+    for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) {\r
+      LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT);\r
+      if (pcb->remote_port == tcphdr->src &&\r
+         pcb->local_port == tcphdr->dest &&\r
+         ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) &&\r
+         ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) {\r
+        /* We don't really care enough to move this PCB to the front\r
+           of the list since we are not very likely to receive that\r
+           many segments for connections in TIME-WAIT. */\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for TIME_WAITing connection.\n"));\r
+        tcp_timewait_input(pcb);\r
+        pbuf_free(p);\r
+        return;\r
+      }\r
+    }\r
+\r
+  /* Finally, if we still did not get a match, we check all PCBs that\r
+     are LISTENing for incoming connections. */\r
+    prev = NULL;\r
+    for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {\r
+      if ((ip_addr_isany(&(lpcb->local_ip)) ||\r
+        ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) &&\r
+        lpcb->local_port == tcphdr->dest) {\r
+        /* Move this PCB to the front of the list so that subsequent\r
+           lookups will be faster (we exploit locality in TCP segment\r
+           arrivals). */\r
+        if (prev != NULL) {\r
+          ((struct tcp_pcb_listen *)prev)->next = lpcb->next;\r
+                /* our successor is the remainder of the listening list */\r
+          lpcb->next = tcp_listen_pcbs.listen_pcbs;\r
+                /* put this listening pcb at the head of the listening list */\r
+          tcp_listen_pcbs.listen_pcbs = lpcb;\r
+        }\r
+\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n"));\r
+        tcp_listen_input(lpcb);\r
+        pbuf_free(p);\r
+        return;\r
+      }\r
+      prev = (struct tcp_pcb *)lpcb;\r
+    }\r
+  }\r
+\r
+#if TCP_INPUT_DEBUG\r
+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("+-+-+-+-+-+-+-+-+-+-+-+-+-+- tcp_input: flags "));\r
+  tcp_debug_print_flags(TCPH_FLAGS(tcphdr));\r
+  LWIP_DEBUGF(TCP_INPUT_DEBUG, ("-+-+-+-+-+-+-+-+-+-+-+-+-+-+\n"));\r
+#endif /* TCP_INPUT_DEBUG */\r
+\r
+\r
+  if (pcb != NULL) {\r
+    /* The incoming segment belongs to a connection. */\r
+#if TCP_INPUT_DEBUG\r
+#if TCP_DEBUG\r
+    tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* TCP_INPUT_DEBUG */\r
+\r
+    /* Set up a tcp_seg structure. */\r
+    inseg.next = NULL;\r
+    inseg.len = p->tot_len;\r
+    inseg.dataptr = p->payload;\r
+    inseg.p = p;\r
+    inseg.tcphdr = tcphdr;\r
+\r
+    recv_data = NULL;\r
+    recv_flags = 0;\r
+\r
+    /* If there is data which was previously "refused" by upper layer */\r
+    if (pcb->refused_data != NULL) {\r
+      /* Notify again application with data previously received. */\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: notify kept packet\n"));\r
+      TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err);\r
+      if (err == ERR_OK) {\r
+        pcb->refused_data = NULL;\r
+      } else {\r
+        /* drop incoming packets, because pcb is "full" */\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n"));\r
+        TCP_STATS_INC(tcp.drop);\r
+        snmp_inc_tcpinerrs();\r
+        pbuf_free(p);\r
+        return;\r
+      }\r
+    }\r
+\r
+    tcp_input_pcb = pcb;\r
+    err = tcp_process(pcb);\r
+    tcp_input_pcb = NULL;\r
+    /* A return value of ERR_ABRT means that tcp_abort() was called\r
+       and that the pcb has been freed. If so, we don't do anything. */\r
+    if (err != ERR_ABRT) {\r
+      if (recv_flags & TF_RESET) {\r
+        /* TF_RESET means that the connection was reset by the other\r
+           end. We then call the error callback to inform the\r
+           application that the connection is dead before we\r
+           deallocate the PCB. */\r
+        TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST);\r
+        tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+        memp_free(MEMP_TCP_PCB, pcb);\r
+      } else if (recv_flags & TF_CLOSED) {\r
+        /* The connection has been closed and we will deallocate the\r
+           PCB. */\r
+        tcp_pcb_remove(&tcp_active_pcbs, pcb);\r
+        memp_free(MEMP_TCP_PCB, pcb);\r
+      } else {\r
+        err = ERR_OK;\r
+        /* If the application has registered a "sent" function to be\r
+           called when new send buffer space is available, we call it\r
+           now. */\r
+        if (pcb->acked > 0) {\r
+          TCP_EVENT_SENT(pcb, pcb->acked, err);\r
+        }\r
+\r
+        if (recv_data != NULL) {\r
+          if(flags & TCP_PSH) {\r
+            recv_data->flags |= PBUF_FLAG_PUSH;\r
+          }\r
+\r
+          /* Notify application that data has been received. */\r
+          TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err);\r
+\r
+          /* If the upper layer can't receive this data, store it */\r
+          if (err != ERR_OK) {\r
+            pcb->refused_data = recv_data;\r
+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: keep incoming packet, because pcb is \"full\"\n"));\r
+          }\r
+        }\r
+\r
+        /* If a FIN segment was received, we call the callback\r
+           function with a NULL buffer to indicate EOF. */\r
+        if (recv_flags & TF_GOT_FIN) {\r
+          TCP_EVENT_RECV(pcb, NULL, ERR_OK, err);\r
+        }\r
+\r
+        /* If there were no errors, we try to send something out. */\r
+        if (err == ERR_OK) {\r
+          tcp_output(pcb);\r
+        }\r
+      }\r
+    }\r
+\r
+\r
+    /* give up our reference to inseg.p */\r
+    if (inseg.p != NULL)\r
+    {\r
+      pbuf_free(inseg.p);\r
+      inseg.p = NULL;\r
+    }\r
+#if TCP_INPUT_DEBUG\r
+#if TCP_DEBUG\r
+    tcp_debug_print_state(pcb->state);\r
+#endif /* TCP_DEBUG */\r
+#endif /* TCP_INPUT_DEBUG */\r
+\r
+  } else {\r
+\r
+    /* If no matching PCB was found, send a TCP RST (reset) to the\r
+       sender. */\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_input: no PCB match found, resetting.\n"));\r
+    if (!(TCPH_FLAGS(tcphdr) & TCP_RST)) {\r
+      TCP_STATS_INC(tcp.proterr);\r
+      TCP_STATS_INC(tcp.drop);\r
+      tcp_rst(ackno, seqno + tcplen,\r
+        &(iphdr->dest), &(iphdr->src),\r
+        tcphdr->dest, tcphdr->src);\r
+    }\r
+    pbuf_free(p);\r
+  }\r
+\r
+  LWIP_ASSERT("tcp_input: tcp_pcbs_sane()", tcp_pcbs_sane());\r
+  PERF_STOP("tcp_input");\r
+}\r
+\r
+/**\r
+ * Called by tcp_input() when a segment arrives for a listening\r
+ * connection (from tcp_input()).\r
+ *\r
+ * @param pcb the tcp_pcb_listen for which a segment arrived\r
+ * @return ERR_OK if the segment was processed\r
+ *         another err_t on error\r
+ *\r
+ * @note the return value is not (yet?) used in tcp_input()\r
+ * @note the segment which arrived is saved in global variables, therefore only the pcb\r
+ *       involved is passed as a parameter to this function\r
+ */\r
+static err_t\r
+tcp_listen_input(struct tcp_pcb_listen *pcb)\r
+{\r
+  struct tcp_pcb *npcb;\r
+  u32_t optdata;\r
+\r
+  /* In the LISTEN state, we check for incoming SYN segments,\r
+     creates a new PCB, and responds with a SYN|ACK. */\r
+  if (flags & TCP_ACK) {\r
+    /* For incoming segments with the ACK flag set, respond with a\r
+       RST. */\r
+    LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n"));\r
+    tcp_rst(ackno + 1, seqno + tcplen,\r
+      &(iphdr->dest), &(iphdr->src),\r
+      tcphdr->dest, tcphdr->src);\r
+  } else if (flags & TCP_SYN) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest));\r
+#if TCP_LISTEN_BACKLOG\r
+    if (pcb->accepts_pending >= pcb->backlog) {\r
+      return ERR_ABRT;\r
+    }\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+    npcb = tcp_alloc(pcb->prio);\r
+    /* If a new PCB could not be created (probably due to lack of memory),\r
+       we don't do anything, but rely on the sender will retransmit the\r
+       SYN at a time when we have more memory available. */\r
+    if (npcb == NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_listen_input: could not allocate PCB\n"));\r
+      TCP_STATS_INC(tcp.memerr);\r
+      return ERR_MEM;\r
+    }\r
+#if TCP_LISTEN_BACKLOG\r
+    pcb->accepts_pending++;\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+    /* Set up the new PCB. */\r
+    ip_addr_set(&(npcb->local_ip), &(iphdr->dest));\r
+    npcb->local_port = pcb->local_port;\r
+    ip_addr_set(&(npcb->remote_ip), &(iphdr->src));\r
+    npcb->remote_port = tcphdr->src;\r
+    npcb->state = SYN_RCVD;\r
+    npcb->rcv_nxt = seqno + 1;\r
+    npcb->snd_wnd = tcphdr->wnd;\r
+    npcb->ssthresh = npcb->snd_wnd;\r
+    npcb->snd_wl1 = seqno - 1;/* initialise to seqno-1 to force window update */\r
+    npcb->callback_arg = pcb->callback_arg;\r
+#if LWIP_CALLBACK_API\r
+    npcb->accept = pcb->accept;\r
+#endif /* LWIP_CALLBACK_API */\r
+    /* inherit socket options */\r
+    npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER);\r
+    /* Register the new PCB so that we can begin receiving segments\r
+       for it. */\r
+    TCP_REG(&tcp_active_pcbs, npcb);\r
+\r
+    /* Parse any options in the SYN. */\r
+    tcp_parseopt(npcb);\r
+#if TCP_CALCULATE_EFF_SEND_MSS\r
+    npcb->mss = tcp_eff_send_mss(npcb->mss, &(npcb->remote_ip));\r
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */\r
+\r
+    snmp_inc_tcppassiveopens();\r
+\r
+    /* Build an MSS option. */\r
+    optdata = TCP_BUILD_MSS_OPTION();\r
+    /* Send a SYN|ACK together with the MSS option. */\r
+    tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, (u8_t *)&optdata, 4);\r
+    return tcp_output(npcb);\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Called by tcp_input() when a segment arrives for a connection in\r
+ * TIME_WAIT.\r
+ *\r
+ * @param pcb the tcp_pcb for which a segment arrived\r
+ *\r
+ * @note the segment which arrived is saved in global variables, therefore only the pcb\r
+ *       involved is passed as a parameter to this function\r
+ */\r
+static err_t\r
+tcp_timewait_input(struct tcp_pcb *pcb)\r
+{\r
+  if (TCP_SEQ_GT(seqno + tcplen, pcb->rcv_nxt)) {\r
+    pcb->rcv_nxt = seqno + tcplen;\r
+  }\r
+  if (tcplen > 0) {\r
+    tcp_ack_now(pcb);\r
+  }\r
+  return tcp_output(pcb);\r
+}\r
+\r
+/**\r
+ * Implements the TCP state machine. Called by tcp_input. In some\r
+ * states tcp_receive() is called to receive data. The tcp_seg\r
+ * argument will be freed by the caller (tcp_input()) unless the\r
+ * recv_data pointer in the pcb is set.\r
+ *\r
+ * @param pcb the tcp_pcb for which a segment arrived\r
+ *\r
+ * @note the segment which arrived is saved in global variables, therefore only the pcb\r
+ *       involved is passed as a parameter to this function\r
+ */\r
+static err_t\r
+tcp_process(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *rseg;\r
+  u8_t acceptable = 0;\r
+  err_t err;\r
+  u8_t accepted_inseq;\r
+\r
+  err = ERR_OK;\r
+\r
+  /* Process incoming RST segments. */\r
+  if (flags & TCP_RST) {\r
+    /* First, determine if the reset is acceptable. */\r
+    if (pcb->state == SYN_SENT) {\r
+      if (ackno == pcb->snd_nxt) {\r
+        acceptable = 1;\r
+      }\r
+    } else {\r
+      if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,\r
+                          pcb->rcv_nxt+pcb->rcv_ann_wnd)) {\r
+        acceptable = 1;\r
+      }\r
+    }\r
+\r
+    if (acceptable) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: Connection RESET\n"));\r
+      LWIP_ASSERT("tcp_input: pcb->state != CLOSED", pcb->state != CLOSED);\r
+      recv_flags = TF_RESET;\r
+      pcb->flags &= ~TF_ACK_DELAY;\r
+      return ERR_RST;\r
+    } else {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",\r
+       seqno, pcb->rcv_nxt));\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_process: unacceptable reset seqno %"U32_F" rcv_nxt %"U32_F"\n",\r
+       seqno, pcb->rcv_nxt));\r
+      return ERR_OK;\r
+    }\r
+  }\r
+\r
+  /* Update the PCB (in)activity timer. */\r
+  pcb->tmr = tcp_ticks;\r
+  pcb->keep_cnt_sent = 0;\r
+\r
+  /* Do different things depending on the TCP state. */\r
+  switch (pcb->state) {\r
+  case SYN_SENT:\r
+    LWIP_DEBUGF(TCP_INPUT_DEBUG, ("SYN-SENT: ackno %"U32_F" pcb->snd_nxt %"U32_F" unacked %"U32_F"\n", ackno,\r
+     pcb->snd_nxt, ntohl(pcb->unacked->tcphdr->seqno)));\r
+    /* received SYN ACK with expected sequence number? */\r
+    if ((flags & TCP_ACK) && (flags & TCP_SYN)\r
+        && ackno == ntohl(pcb->unacked->tcphdr->seqno) + 1) {\r
+      pcb->snd_buf++;\r
+      pcb->rcv_nxt = seqno + 1;\r
+      pcb->lastack = ackno;\r
+      pcb->snd_wnd = tcphdr->wnd;\r
+      pcb->snd_wl1 = seqno - 1; /* initialise to seqno - 1 to force window update */\r
+      pcb->state = ESTABLISHED;\r
+\r
+      /* Parse any options in the SYNACK before using pcb->mss since that\r
+       * can be changed by the received options! */\r
+      tcp_parseopt(pcb);\r
+#if TCP_CALCULATE_EFF_SEND_MSS\r
+      pcb->mss = tcp_eff_send_mss(pcb->mss, &(pcb->remote_ip));\r
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */\r
+\r
+      /* Set ssthresh again after changing pcb->mss (already set in tcp_connect\r
+       * but for the default value of pcb->mss) */\r
+      pcb->ssthresh = pcb->mss * 10;\r
+\r
+      pcb->cwnd = ((pcb->cwnd == 1) ? (pcb->mss * 2) : pcb->mss);\r
+      LWIP_ASSERT("pcb->snd_queuelen > 0", (pcb->snd_queuelen > 0));\r
+      --pcb->snd_queuelen;\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen));\r
+      rseg = pcb->unacked;\r
+      pcb->unacked = rseg->next;\r
+\r
+      /* If there's nothing left to acknowledge, stop the retransmit\r
+         timer, otherwise reset it to start again */\r
+      if(pcb->unacked == NULL)\r
+        pcb->rtime = -1;\r
+      else {\r
+        pcb->rtime = 0;\r
+        pcb->nrtx = 0;\r
+      }\r
+\r
+      tcp_seg_free(rseg);\r
+\r
+      /* Call the user specified function to call when sucessfully\r
+       * connected. */\r
+      TCP_EVENT_CONNECTED(pcb, ERR_OK, err);\r
+      tcp_ack_now(pcb);\r
+    }\r
+    /* received ACK? possibly a half-open connection */\r
+    else if (flags & TCP_ACK) {\r
+      /* send a RST to bring the other side in a non-synchronized state. */\r
+      tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),\r
+        tcphdr->dest, tcphdr->src);\r
+    }\r
+    break;\r
+  case SYN_RCVD:\r
+    if (flags & TCP_ACK &&\r
+       !(flags & TCP_RST)) {\r
+      /* expected ACK number? */\r
+      if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_nxt)) {\r
+        u16_t old_cwnd;\r
+        pcb->state = ESTABLISHED;\r
+        LWIP_DEBUGF(TCP_DEBUG, ("TCP connection established %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+#if LWIP_CALLBACK_API\r
+        LWIP_ASSERT("pcb->accept != NULL", pcb->accept != NULL);\r
+#endif\r
+        /* Call the accept function. */\r
+        TCP_EVENT_ACCEPT(pcb, ERR_OK, err);\r
+        if (err != ERR_OK) {\r
+          /* If the accept function returns with an error, we abort\r
+           * the connection. */\r
+          tcp_abort(pcb);\r
+          return ERR_ABRT;\r
+        }\r
+        old_cwnd = pcb->cwnd;\r
+        /* If there was any data contained within this ACK,\r
+         * we'd better pass it on to the application as well. */\r
+        accepted_inseq = tcp_receive(pcb);\r
+\r
+        pcb->cwnd = ((old_cwnd == 1) ? (pcb->mss * 2) : pcb->mss);\r
+\r
+        if ((flags & TCP_FIN) && accepted_inseq) {\r
+          tcp_ack_now(pcb);\r
+          pcb->state = CLOSE_WAIT;\r
+        }\r
+      }\r
+      /* incorrect ACK number */\r
+      else {\r
+        /* send RST */\r
+        tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src),\r
+                tcphdr->dest, tcphdr->src);\r
+      }\r
+    }\r
+    break;\r
+  case CLOSE_WAIT:\r
+    /* FALLTHROUGH */\r
+  case ESTABLISHED:\r
+    accepted_inseq = tcp_receive(pcb);\r
+    if ((flags & TCP_FIN) && accepted_inseq) { /* passive close */\r
+      tcp_ack_now(pcb);\r
+      pcb->state = CLOSE_WAIT;\r
+    }\r
+    break;\r
+  case FIN_WAIT_1:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_FIN) {\r
+      if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+        LWIP_DEBUGF(TCP_DEBUG,\r
+          ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+        tcp_ack_now(pcb);\r
+        tcp_pcb_purge(pcb);\r
+        TCP_RMV(&tcp_active_pcbs, pcb);\r
+        pcb->state = TIME_WAIT;\r
+        TCP_REG(&tcp_tw_pcbs, pcb);\r
+      } else {\r
+        tcp_ack_now(pcb);\r
+        pcb->state = CLOSING;\r
+      }\r
+    } else if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      pcb->state = FIN_WAIT_2;\r
+    }\r
+    break;\r
+  case FIN_WAIT_2:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_FIN) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      tcp_ack_now(pcb);\r
+      tcp_pcb_purge(pcb);\r
+      TCP_RMV(&tcp_active_pcbs, pcb);\r
+      pcb->state = TIME_WAIT;\r
+      TCP_REG(&tcp_tw_pcbs, pcb);\r
+    }\r
+    break;\r
+  case CLOSING:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      tcp_ack_now(pcb);\r
+      tcp_pcb_purge(pcb);\r
+      TCP_RMV(&tcp_active_pcbs, pcb);\r
+      pcb->state = TIME_WAIT;\r
+      TCP_REG(&tcp_tw_pcbs, pcb);\r
+    }\r
+    break;\r
+  case LAST_ACK:\r
+    tcp_receive(pcb);\r
+    if (flags & TCP_ACK && ackno == pcb->snd_nxt) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("TCP connection closed %"U16_F" -> %"U16_F".\n", inseg.tcphdr->src, inseg.tcphdr->dest));\r
+      /* bugfix #21699: don't set pcb->state to CLOSED here or we risk leaking segments */\r
+      recv_flags = TF_CLOSED;\r
+    }\r
+    break;\r
+  default:\r
+    break;\r
+  }\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Called by tcp_process. Checks if the given segment is an ACK for outstanding\r
+ * data, and if so frees the memory of the buffered data. Next, is places the\r
+ * segment on any of the receive queues (pcb->recved or pcb->ooseq). If the segment\r
+ * is buffered, the pbuf is referenced by pbuf_ref so that it will not be freed until\r
+ * i it has been removed from the buffer.\r
+ *\r
+ * If the incoming segment constitutes an ACK for a segment that was used for RTT\r
+ * estimation, the RTT is estimated here as well.\r
+ *\r
+ * Called from tcp_process().\r
+ *\r
+ * @return 1 if the incoming segment is the next in sequence, 0 if not\r
+ */\r
+static u8_t\r
+tcp_receive(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *next;\r
+#if TCP_QUEUE_OOSEQ\r
+  struct tcp_seg *prev, *cseg;\r
+#endif\r
+  struct pbuf *p;\r
+  s32_t off;\r
+  s16_t m;\r
+  u32_t right_wnd_edge;\r
+  u16_t new_tot_len;\r
+  u8_t accepted_inseq = 0;\r
+\r
+  if (flags & TCP_ACK) {\r
+    right_wnd_edge = pcb->snd_wnd + pcb->snd_wl1;\r
+\r
+    /* Update window. */\r
+    if (TCP_SEQ_LT(pcb->snd_wl1, seqno) ||\r
+       (pcb->snd_wl1 == seqno && TCP_SEQ_LT(pcb->snd_wl2, ackno)) ||\r
+       (pcb->snd_wl2 == ackno && tcphdr->wnd > pcb->snd_wnd)) {\r
+      pcb->snd_wnd = tcphdr->wnd;\r
+      pcb->snd_wl1 = seqno;\r
+      pcb->snd_wl2 = ackno;\r
+      if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {\r
+          pcb->persist_backoff = 0;\r
+      }\r
+      LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));\r
+#if TCP_WND_DEBUG\r
+    } else {\r
+      if (pcb->snd_wnd != tcphdr->wnd) {\r
+        LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: no window update lastack %"U32_F" snd_max %"U32_F" ackno %"U32_F" wl1 %"U32_F" seqno %"U32_F" wl2 %"U32_F"\n",\r
+                               pcb->lastack, pcb->snd_max, ackno, pcb->snd_wl1, seqno, pcb->snd_wl2));\r
+      }\r
+#endif /* TCP_WND_DEBUG */\r
+    }\r
+\r
+    if (pcb->lastack == ackno) {\r
+      pcb->acked = 0;\r
+\r
+      if (pcb->snd_wl1 + pcb->snd_wnd == right_wnd_edge){\r
+        ++pcb->dupacks;\r
+        if (pcb->dupacks >= 3 && pcb->unacked != NULL) {\r
+          if (!(pcb->flags & TF_INFR)) {\r
+            /* This is fast retransmit. Retransmit the first unacked segment. */\r
+            LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupacks %"U16_F" (%"U32_F"), fast retransmit %"U32_F"\n",\r
+                                       (u16_t)pcb->dupacks, pcb->lastack,\r
+                                       ntohl(pcb->unacked->tcphdr->seqno)));\r
+            tcp_rexmit(pcb);\r
+            /* Set ssthresh to max (FlightSize / 2, 2*SMSS) */\r
+            /*pcb->ssthresh = LWIP_MAX((pcb->snd_max -\r
+                                      pcb->lastack) / 2,\r
+                                      2 * pcb->mss);*/\r
+            /* Set ssthresh to half of the minimum of the current cwnd and the advertised window */\r
+            if (pcb->cwnd > pcb->snd_wnd)\r
+              pcb->ssthresh = pcb->snd_wnd / 2;\r
+            else\r
+              pcb->ssthresh = pcb->cwnd / 2;\r
+\r
+            /* The minimum value for ssthresh should be 2 MSS */\r
+            if (pcb->ssthresh < 2*pcb->mss) {\r
+              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));\r
+              pcb->ssthresh = 2*pcb->mss;\r
+            }\r
+\r
+            pcb->cwnd = pcb->ssthresh + 3 * pcb->mss;\r
+            pcb->flags |= TF_INFR;\r
+          } else {\r
+            /* Inflate the congestion window, but not if it means that\r
+               the value overflows. */\r
+            if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\r
+              pcb->cwnd += pcb->mss;\r
+            }\r
+          }\r
+        }\r
+      } else {\r
+        LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n",\r
+                                   pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge));\r
+      }\r
+    } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){\r
+      /* We come here when the ACK acknowledges new data. */\r
+\r
+      /* Reset the "IN Fast Retransmit" flag, since we are no longer\r
+         in fast retransmit. Also reset the congestion window to the\r
+         slow start threshold. */\r
+      if (pcb->flags & TF_INFR) {\r
+        pcb->flags &= ~TF_INFR;\r
+        pcb->cwnd = pcb->ssthresh;\r
+      }\r
+\r
+      /* Reset the number of retransmissions. */\r
+      pcb->nrtx = 0;\r
+\r
+      /* Reset the retransmission time-out. */\r
+      pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
+\r
+      /* Update the send buffer space. Diff between the two can never exceed 64K? */\r
+      pcb->acked = (u16_t)(ackno - pcb->lastack);\r
+\r
+      pcb->snd_buf += pcb->acked;\r
+\r
+      /* Reset the fast retransmit variables. */\r
+      pcb->dupacks = 0;\r
+      pcb->lastack = ackno;\r
+\r
+      /* Update the congestion control variables (cwnd and\r
+         ssthresh). */\r
+      if (pcb->state >= ESTABLISHED) {\r
+        if (pcb->cwnd < pcb->ssthresh) {\r
+          if ((u16_t)(pcb->cwnd + pcb->mss) > pcb->cwnd) {\r
+            pcb->cwnd += pcb->mss;\r
+          }\r
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: slow start cwnd %"U16_F"\n", pcb->cwnd));\r
+        } else {\r
+          u16_t new_cwnd = (pcb->cwnd + pcb->mss * pcb->mss / pcb->cwnd);\r
+          if (new_cwnd > pcb->cwnd) {\r
+            pcb->cwnd = new_cwnd;\r
+          }\r
+          LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_receive: congestion avoidance cwnd %"U16_F"\n", pcb->cwnd));\r
+        }\r
+      }\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: ACK for %"U32_F", unacked->seqno %"U32_F":%"U32_F"\n",\r
+                                    ackno,\r
+                                    pcb->unacked != NULL?\r
+                                    ntohl(pcb->unacked->tcphdr->seqno): 0,\r
+                                    pcb->unacked != NULL?\r
+                                    ntohl(pcb->unacked->tcphdr->seqno) + TCP_TCPLEN(pcb->unacked): 0));\r
+\r
+      /* Remove segment from the unacknowledged list if the incoming\r
+         ACK acknowlegdes them. */\r
+      while (pcb->unacked != NULL &&\r
+             TCP_SEQ_LEQ(ntohl(pcb->unacked->tcphdr->seqno) +\r
+                         TCP_TCPLEN(pcb->unacked), ackno)) {\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",\r
+                                      ntohl(pcb->unacked->tcphdr->seqno),\r
+                                      ntohl(pcb->unacked->tcphdr->seqno) +\r
+                                      TCP_TCPLEN(pcb->unacked)));\r
+\r
+        next = pcb->unacked;\r
+        pcb->unacked = pcb->unacked->next;\r
+\r
+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));\r
+        LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));\r
+        pcb->snd_queuelen -= pbuf_clen(next->p);\r
+        tcp_seg_free(next);\r
+\r
+        LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unacked)\n", (u16_t)pcb->snd_queuelen));\r
+        if (pcb->snd_queuelen != 0) {\r
+          LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||\r
+                      pcb->unsent != NULL);\r
+        }\r
+      }\r
+\r
+      /* If there's nothing left to acknowledge, stop the retransmit\r
+         timer, otherwise reset it to start again */\r
+      if(pcb->unacked == NULL)\r
+        pcb->rtime = -1;\r
+      else\r
+        pcb->rtime = 0;\r
+\r
+      pcb->polltmr = 0;\r
+    } else {\r
+      /* Fix bug bug #21582: out of sequence ACK, didn't really ack anything */\r
+      pcb->acked = 0;\r
+    }\r
+\r
+    /* We go through the ->unsent list to see if any of the segments\r
+       on the list are acknowledged by the ACK. This may seem\r
+       strange since an "unsent" segment shouldn't be acked. The\r
+       rationale is that lwIP puts all outstanding segments on the\r
+       ->unsent list after a retransmission, so these segments may\r
+       in fact have been sent once. */\r
+    while (pcb->unsent != NULL &&\r
+           /*TCP_SEQ_LEQ(ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), ackno) &&\r
+             TCP_SEQ_LEQ(ackno, pcb->snd_max)*/\r
+           TCP_SEQ_BETWEEN(ackno, ntohl(pcb->unsent->tcphdr->seqno) + TCP_TCPLEN(pcb->unsent), pcb->snd_max)\r
+           ) {\r
+      LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",\r
+                                    ntohl(pcb->unsent->tcphdr->seqno), ntohl(pcb->unsent->tcphdr->seqno) +\r
+                                    TCP_TCPLEN(pcb->unsent)));\r
+\r
+      next = pcb->unsent;\r
+      pcb->unsent = pcb->unsent->next;\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"U16_F" ... ", (u16_t)pcb->snd_queuelen));\r
+      LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));\r
+      pcb->snd_queuelen -= pbuf_clen(next->p);\r
+      tcp_seg_free(next);\r
+      LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"U16_F" (after freeing unsent)\n", (u16_t)pcb->snd_queuelen));\r
+      if (pcb->snd_queuelen != 0) {\r
+        LWIP_ASSERT("tcp_receive: valid queue length",\r
+          pcb->unacked != NULL || pcb->unsent != NULL);\r
+      }\r
+\r
+      if (pcb->unsent != NULL) {\r
+        pcb->snd_nxt = htonl(pcb->unsent->tcphdr->seqno);\r
+      }\r
+    }\r
+    /* End of ACK for new data processing. */\r
+\r
+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: pcb->rttest %"U32_F" rtseq %"U32_F" ackno %"U32_F"\n",\r
+                                pcb->rttest, pcb->rtseq, ackno));\r
+\r
+    /* RTT estimation calculations. This is done by checking if the\r
+       incoming segment acknowledges the segment we use to take a\r
+       round-trip time measurement. */\r
+    if (pcb->rttest && TCP_SEQ_LT(pcb->rtseq, ackno)) {\r
+      /* diff between this shouldn't exceed 32K since this are tcp timer ticks\r
+         and a round-trip shouldn't be that long... */\r
+      m = (s16_t)(tcp_ticks - pcb->rttest);\r
+\r
+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: experienced rtt %"U16_F" ticks (%"U16_F" msec).\n",\r
+                                  m, m * TCP_SLOW_INTERVAL));\r
+\r
+      /* This is taken directly from VJs original code in his paper */\r
+      m = m - (pcb->sa >> 3);\r
+      pcb->sa += m;\r
+      if (m < 0) {\r
+        m = -m;\r
+      }\r
+      m = m - (pcb->sv >> 2);\r
+      pcb->sv += m;\r
+      pcb->rto = (pcb->sa >> 3) + pcb->sv;\r
+\r
+      LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_receive: RTO %"U16_F" (%"U16_F" milliseconds)\n",\r
+                                  pcb->rto, pcb->rto * TCP_SLOW_INTERVAL));\r
+\r
+      pcb->rttest = 0;\r
+    }\r
+  }\r
+\r
+  /* If the incoming segment contains data, we must process it\r
+     further. */\r
+  if (tcplen > 0) {\r
+    /* This code basically does three things:\r
+\r
+    +) If the incoming segment contains data that is the next\r
+    in-sequence data, this data is passed to the application. This\r
+    might involve trimming the first edge of the data. The rcv_nxt\r
+    variable and the advertised window are adjusted.\r
+\r
+    +) If the incoming segment has data that is above the next\r
+    sequence number expected (->rcv_nxt), the segment is placed on\r
+    the ->ooseq queue. This is done by finding the appropriate\r
+    place in the ->ooseq queue (which is ordered by sequence\r
+    number) and trim the segment in both ends if needed. An\r
+    immediate ACK is sent to indicate that we received an\r
+    out-of-sequence segment.\r
+\r
+    +) Finally, we check if the first segment on the ->ooseq queue\r
+    now is in sequence (i.e., if rcv_nxt >= ooseq->seqno). If\r
+    rcv_nxt > ooseq->seqno, we must trim the first edge of the\r
+    segment on ->ooseq before we adjust rcv_nxt. The data in the\r
+    segments that are now on sequence are chained onto the\r
+    incoming segment so that we only need to call the application\r
+    once.\r
+    */\r
+\r
+    /* First, we check if we must trim the first edge. We have to do\r
+       this if the sequence number of the incoming segment is less\r
+       than rcv_nxt, and the sequence number plus the length of the\r
+       segment is larger than rcv_nxt. */\r
+    /*    if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){\r
+          if (TCP_SEQ_LT(pcb->rcv_nxt, seqno + tcplen)) {*/\r
+    if (TCP_SEQ_BETWEEN(pcb->rcv_nxt, seqno + 1, seqno + tcplen - 1)){\r
+      /* Trimming the first edge is done by pushing the payload\r
+         pointer in the pbuf downwards. This is somewhat tricky since\r
+         we do not want to discard the full contents of the pbuf up to\r
+         the new starting point of the data since we have to keep the\r
+         TCP header which is present in the first pbuf in the chain.\r
+\r
+         What is done is really quite a nasty hack: the first pbuf in\r
+         the pbuf chain is pointed to by inseg.p. Since we need to be\r
+         able to deallocate the whole pbuf, we cannot change this\r
+         inseg.p pointer to point to any of the later pbufs in the\r
+         chain. Instead, we point the ->payload pointer in the first\r
+         pbuf to data in one of the later pbufs. We also set the\r
+         inseg.data pointer to point to the right place. This way, the\r
+         ->p pointer will still point to the first pbuf, but the\r
+         ->p->payload pointer will point to data in another pbuf.\r
+\r
+         After we are done with adjusting the pbuf pointers we must\r
+         adjust the ->data pointer in the seg and the segment\r
+         length.*/\r
+\r
+      off = pcb->rcv_nxt - seqno;\r
+      p = inseg.p;\r
+      LWIP_ASSERT("inseg.p != NULL", inseg.p);\r
+      LWIP_ASSERT("insane offset!", (off < 0x7fff));\r
+      if (inseg.p->len < off) {\r
+        LWIP_ASSERT("pbuf too short!", (((s32_t)inseg.p->tot_len) >= off));\r
+        new_tot_len = (u16_t)(inseg.p->tot_len - off);\r
+        while (p->len < off) {\r
+          off -= p->len;\r
+          /* KJM following line changed (with addition of new_tot_len var)\r
+             to fix bug #9076\r
+             inseg.p->tot_len -= p->len; */\r
+          p->tot_len = new_tot_len;\r
+          p->len = 0;\r
+          p = p->next;\r
+        }\r
+        if(pbuf_header(p, (s16_t)-off)) {\r
+          /* Do we need to cope with this failing?  Assert for now */\r
+          LWIP_ASSERT("pbuf_header failed", 0);\r
+        }\r
+      } else {\r
+        if(pbuf_header(inseg.p, (s16_t)-off)) {\r
+          /* Do we need to cope with this failing?  Assert for now */\r
+          LWIP_ASSERT("pbuf_header failed", 0);\r
+        }\r
+      }\r
+      /* KJM following line changed to use p->payload rather than inseg->p->payload\r
+         to fix bug #9076 */\r
+      inseg.dataptr = p->payload;\r
+      inseg.len -= (u16_t)(pcb->rcv_nxt - seqno);\r
+      inseg.tcphdr->seqno = seqno = pcb->rcv_nxt;\r
+    }\r
+    else {\r
+      if (TCP_SEQ_LT(seqno, pcb->rcv_nxt)){\r
+        /* the whole segment is < rcv_nxt */\r
+        /* must be a duplicate of a packet that has already been correctly handled */\r
+\r
+        LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: duplicate seqno %"U32_F"\n", seqno));\r
+        tcp_ack_now(pcb);\r
+      }\r
+    }\r
+\r
+    /* The sequence number must be within the window (above rcv_nxt\r
+       and below rcv_nxt + rcv_wnd) in order to be further\r
+       processed. */\r
+    if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,\r
+                        pcb->rcv_nxt + pcb->rcv_ann_wnd - 1)){\r
+      if (pcb->rcv_nxt == seqno) {\r
+        accepted_inseq = 1;\r
+        /* The incoming segment is the next in sequence. We check if\r
+           we have to trim the end of the segment and update rcv_nxt\r
+           and pass the data to the application. */\r
+#if TCP_QUEUE_OOSEQ\r
+        if (pcb->ooseq != NULL &&\r
+                TCP_SEQ_LEQ(pcb->ooseq->tcphdr->seqno, seqno + inseg.len)) {\r
+          if (pcb->ooseq->len > 0) {\r
+            /* We have to trim the second edge of the incoming\r
+               segment. */\r
+            inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno);\r
+            pbuf_realloc(inseg.p, inseg.len);\r
+          } else {\r
+            /* does the ooseq segment contain only flags that are in inseg also? */\r
+            if ((TCPH_FLAGS(inseg.tcphdr) & (TCP_FIN|TCP_SYN)) ==\r
+                (TCPH_FLAGS(pcb->ooseq->tcphdr) & (TCP_FIN|TCP_SYN))) {\r
+              struct tcp_seg *old_ooseq = pcb->ooseq;\r
+              pcb->ooseq = pcb->ooseq->next;\r
+              memp_free(MEMP_TCP_SEG, old_ooseq);\r
+            }\r
+          }\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+        tcplen = TCP_TCPLEN(&inseg);\r
+\r
+        /* First received FIN will be ACKed +1, on any successive (duplicate)\r
+         * FINs we are already in CLOSE_WAIT and have already done +1.\r
+         */\r
+        if (pcb->state != CLOSE_WAIT) {\r
+          pcb->rcv_nxt += tcplen;\r
+        }\r
+\r
+        /* Update the receiver's (our) window. */\r
+        if (pcb->rcv_wnd < tcplen) {\r
+          pcb->rcv_wnd = 0;\r
+        } else {\r
+          pcb->rcv_wnd -= tcplen;\r
+        }\r
+\r
+        if (pcb->rcv_ann_wnd < tcplen) {\r
+          pcb->rcv_ann_wnd = 0;\r
+        } else {\r
+          pcb->rcv_ann_wnd -= tcplen;\r
+        }\r
+\r
+        /* If there is data in the segment, we make preparations to\r
+           pass this up to the application. The ->recv_data variable\r
+           is used for holding the pbuf that goes to the\r
+           application. The code for reassembling out-of-sequence data\r
+           chains its data on this pbuf as well.\r
+\r
+           If the segment was a FIN, we set the TF_GOT_FIN flag that will\r
+           be used to indicate to the application that the remote side has\r
+           closed its end of the connection. */\r
+        if (inseg.p->tot_len > 0) {\r
+          recv_data = inseg.p;\r
+          /* Since this pbuf now is the responsibility of the\r
+             application, we delete our reference to it so that we won't\r
+             (mistakingly) deallocate it. */\r
+          inseg.p = NULL;\r
+        }\r
+        if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) {\r
+          LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received FIN.\n"));\r
+          recv_flags = TF_GOT_FIN;\r
+        }\r
+\r
+#if TCP_QUEUE_OOSEQ\r
+        /* We now check if we have segments on the ->ooseq queue that\r
+           is now in sequence. */\r
+        while (pcb->ooseq != NULL &&\r
+               pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) {\r
+\r
+          cseg = pcb->ooseq;\r
+          seqno = pcb->ooseq->tcphdr->seqno;\r
+\r
+          pcb->rcv_nxt += TCP_TCPLEN(cseg);\r
+          if (pcb->rcv_wnd < TCP_TCPLEN(cseg)) {\r
+            pcb->rcv_wnd = 0;\r
+          } else {\r
+            pcb->rcv_wnd -= TCP_TCPLEN(cseg);\r
+          }\r
+          if (pcb->rcv_ann_wnd < TCP_TCPLEN(cseg)) {\r
+            pcb->rcv_ann_wnd = 0;\r
+          } else {\r
+            pcb->rcv_ann_wnd -= TCP_TCPLEN(cseg);\r
+          }\r
+\r
+          if (cseg->p->tot_len > 0) {\r
+            /* Chain this pbuf onto the pbuf that we will pass to\r
+               the application. */\r
+            if (recv_data) {\r
+              pbuf_cat(recv_data, cseg->p);\r
+            } else {\r
+              recv_data = cseg->p;\r
+            }\r
+            cseg->p = NULL;\r
+          }\r
+          if (TCPH_FLAGS(cseg->tcphdr) & TCP_FIN) {\r
+            LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: dequeued FIN.\n"));\r
+            recv_flags = TF_GOT_FIN;\r
+            if (pcb->state == ESTABLISHED) { /* force passive close or we can move to active close */\r
+              pcb->state = CLOSE_WAIT;\r
+            }\r
+          }\r
+\r
+\r
+          pcb->ooseq = cseg->next;\r
+          tcp_seg_free(cseg);\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+\r
+        /* Acknowledge the segment(s). */\r
+        tcp_ack(pcb);\r
+\r
+      } else {\r
+        /* We get here if the incoming segment is out-of-sequence. */\r
+        tcp_ack_now(pcb);\r
+#if TCP_QUEUE_OOSEQ\r
+        /* We queue the segment on the ->ooseq queue. */\r
+        if (pcb->ooseq == NULL) {\r
+          pcb->ooseq = tcp_seg_copy(&inseg);\r
+        } else {\r
+          /* If the queue is not empty, we walk through the queue and\r
+             try to find a place where the sequence number of the\r
+             incoming segment is between the sequence numbers of the\r
+             previous and the next segment on the ->ooseq queue. That is\r
+             the place where we put the incoming segment. If needed, we\r
+             trim the second edges of the previous and the incoming\r
+             segment so that it will fit into the sequence.\r
+\r
+             If the incoming segment has the same sequence number as a\r
+             segment on the ->ooseq queue, we discard the segment that\r
+             contains less data. */\r
+\r
+          prev = NULL;\r
+          for(next = pcb->ooseq; next != NULL; next = next->next) {\r
+            if (seqno == next->tcphdr->seqno) {\r
+              /* The sequence number of the incoming segment is the\r
+                 same as the sequence number of the segment on\r
+                 ->ooseq. We check the lengths to see which one to\r
+                 discard. */\r
+              if (inseg.len > next->len) {\r
+                /* The incoming segment is larger than the old\r
+                   segment. We replace the old segment with the new\r
+                   one. */\r
+                cseg = tcp_seg_copy(&inseg);\r
+                if (cseg != NULL) {\r
+                  cseg->next = next->next;\r
+                  if (prev != NULL) {\r
+                    prev->next = cseg;\r
+                  } else {\r
+                    pcb->ooseq = cseg;\r
+                  }\r
+                }\r
+                tcp_seg_free(next);\r
+                if (cseg->next != NULL) {\r
+                  next = cseg->next;\r
+                  if (TCP_SEQ_GT(seqno + cseg->len, next->tcphdr->seqno)) {\r
+                    /* We need to trim the incoming segment. */\r
+                    cseg->len = (u16_t)(next->tcphdr->seqno - seqno);\r
+                    pbuf_realloc(cseg->p, cseg->len);\r
+                  }\r
+                }\r
+                break;\r
+              } else {\r
+                /* Either the lenghts are the same or the incoming\r
+                   segment was smaller than the old one; in either\r
+                   case, we ditch the incoming segment. */\r
+                break;\r
+              }\r
+            } else {\r
+              if (prev == NULL) {\r
+                if (TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {\r
+                  /* The sequence number of the incoming segment is lower\r
+                     than the sequence number of the first segment on the\r
+                     queue. We put the incoming segment first on the\r
+                     queue. */\r
+\r
+                  if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {\r
+                    /* We need to trim the incoming segment. */\r
+                    inseg.len = (u16_t)(next->tcphdr->seqno - seqno);\r
+                    pbuf_realloc(inseg.p, inseg.len);\r
+                  }\r
+                  cseg = tcp_seg_copy(&inseg);\r
+                  if (cseg != NULL) {\r
+                    cseg->next = next;\r
+                    pcb->ooseq = cseg;\r
+                  }\r
+                  break;\r
+                }\r
+              } else\r
+                /*if (TCP_SEQ_LT(prev->tcphdr->seqno, seqno) &&\r
+                  TCP_SEQ_LT(seqno, next->tcphdr->seqno)) {*/\r
+                if(TCP_SEQ_BETWEEN(seqno, prev->tcphdr->seqno+1, next->tcphdr->seqno-1)){\r
+                /* The sequence number of the incoming segment is in\r
+                   between the sequence numbers of the previous and\r
+                   the next segment on ->ooseq. We trim and insert the\r
+                   incoming segment and trim the previous segment, if\r
+                   needed. */\r
+                if (TCP_SEQ_GT(seqno + inseg.len, next->tcphdr->seqno)) {\r
+                  /* We need to trim the incoming segment. */\r
+                  inseg.len = (u16_t)(next->tcphdr->seqno - seqno);\r
+                  pbuf_realloc(inseg.p, inseg.len);\r
+                }\r
+\r
+                cseg = tcp_seg_copy(&inseg);\r
+                if (cseg != NULL) {\r
+                  cseg->next = next;\r
+                  prev->next = cseg;\r
+                  if (TCP_SEQ_GT(prev->tcphdr->seqno + prev->len, seqno)) {\r
+                    /* We need to trim the prev segment. */\r
+                    prev->len = (u16_t)(seqno - prev->tcphdr->seqno);\r
+                    pbuf_realloc(prev->p, prev->len);\r
+                  }\r
+                }\r
+                break;\r
+              }\r
+              /* If the "next" segment is the last segment on the\r
+                 ooseq queue, we add the incoming segment to the end\r
+                 of the list. */\r
+              if (next->next == NULL &&\r
+                  TCP_SEQ_GT(seqno, next->tcphdr->seqno)) {\r
+                next->next = tcp_seg_copy(&inseg);\r
+                if (next->next != NULL) {\r
+                  if (TCP_SEQ_GT(next->tcphdr->seqno + next->len, seqno)) {\r
+                    /* We need to trim the last segment. */\r
+                    next->len = (u16_t)(seqno - next->tcphdr->seqno);\r
+                    pbuf_realloc(next->p, next->len);\r
+                  }\r
+                }\r
+                break;\r
+              }\r
+            }\r
+            prev = next;\r
+          }\r
+        }\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+      }\r
+    } else {\r
+      if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt,\r
+                          pcb->rcv_nxt + pcb->rcv_ann_wnd-1)){\r
+        tcp_ack_now(pcb);\r
+      }\r
+    }\r
+  } else {\r
+    /* Segments with length 0 is taken care of here. Segments that\r
+       fall out of the window are ACKed. */\r
+    /*if (TCP_SEQ_GT(pcb->rcv_nxt, seqno) ||\r
+      TCP_SEQ_GEQ(seqno, pcb->rcv_nxt + pcb->rcv_wnd)) {*/\r
+    if(!TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt + pcb->rcv_wnd-1)){\r
+      tcp_ack_now(pcb);\r
+    }\r
+  }\r
+  return accepted_inseq;\r
+}\r
+\r
+/**\r
+ * Parses the options contained in the incoming segment. (Code taken\r
+ * from uIP with only small changes.)\r
+ *\r
+ * Called from tcp_listen_input() and tcp_process().\r
+ * Currently, only the MSS option is supported!\r
+ *\r
+ * @param pcb the tcp_pcb for which a segment arrived\r
+ */\r
+static void\r
+tcp_parseopt(struct tcp_pcb *pcb)\r
+{\r
+  u8_t c;\r
+  u8_t *opts, opt;\r
+  u16_t mss;\r
+\r
+  opts = (u8_t *)tcphdr + TCP_HLEN;\r
+\r
+  /* Parse the TCP MSS option, if present. */\r
+  if(TCPH_HDRLEN(tcphdr) > 0x5) {\r
+    for(c = 0; c < (TCPH_HDRLEN(tcphdr) - 5) << 2 ;) {\r
+      opt = opts[c];\r
+      if (opt == 0x00) {\r
+        /* End of options. */\r
+        break;\r
+      } else if (opt == 0x01) {\r
+        ++c;\r
+        /* NOP option. */\r
+      } else if (opt == 0x02 &&\r
+        opts[c + 1] == 0x04) {\r
+        /* An MSS option with the right option length. */\r
+        mss = (opts[c + 2] << 8) | opts[c + 3];\r
+        pcb->mss = mss > TCP_MSS? TCP_MSS: mss;\r
+\r
+        /* And we are done processing options. */\r
+        break;\r
+      } else {\r
+        if (opts[c + 1] == 0) {\r
+          /* If the length field is zero, the options are malformed\r
+             and we don't process them further. */\r
+          break;\r
+        }\r
+        /* All other options have a length field, so that we easily\r
+           can skip past them. */\r
+        c += opts[c + 1];\r
+      }\r
+    }\r
+  }\r
+}\r
+\r
+#endif /* LWIP_TCP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c b/Demo/Common/ethernet/lwIP_130/src/core/tcp_out.c
new file mode 100644 (file)
index 0000000..1cf479b
--- /dev/null
@@ -0,0 +1,953 @@
+/**\r
+ * @file\r
+ * Transmission Control Protocol, outgoing traffic\r
+ *\r
+ * The output functions of TCP.\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/tcp.h"\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+\r
+#include <string.h>\r
+\r
+/* Forward declarations.*/\r
+static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb);\r
+\r
+/**\r
+ * Called by tcp_close() to send a segment including flags but not data.\r
+ *\r
+ * @param pcb the tcp_pcb over which to send a segment\r
+ * @param flags the flags to set in the segment header\r
+ * @return ERR_OK if sent, another err_t otherwise\r
+ */\r
+err_t\r
+tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags)\r
+{\r
+  /* no data, no length, flags, copy=1, no optdata, no optdatalen */\r
+  return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, NULL, 0);\r
+}\r
+\r
+/**\r
+ * Write data for sending (but does not send it immediately).\r
+ *\r
+ * It waits in the expectation of more data being sent soon (as\r
+ * it can send them more efficiently by combining them together).\r
+ * To prompt the system to send data now, call tcp_output() after\r
+ * calling tcp_write().\r
+ *\r
+ * @param pcb Protocol control block of the TCP connection to enqueue data for.\r
+ * @param data pointer to the data to send\r
+ * @param len length (in bytes) of the data to send\r
+ * @param apiflags combination of following flags :\r
+ * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack\r
+ * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,\r
+ * @return ERR_OK if enqueued, another err_t on error\r
+ *\r
+ * @see tcp_write()\r
+ */\r
+err_t\r
+tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags)\r
+{\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb,\r
+    data, len, (u16_t)apiflags));\r
+  /* connection is in valid state for data transmission? */\r
+  if (pcb->state == ESTABLISHED ||\r
+     pcb->state == CLOSE_WAIT ||\r
+     pcb->state == SYN_SENT ||\r
+     pcb->state == SYN_RCVD) {\r
+    if (len > 0) {\r
+      return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, NULL, 0);\r
+    }\r
+    return ERR_OK;\r
+  } else {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | 3, ("tcp_write() called in invalid state\n"));\r
+    return ERR_CONN;\r
+  }\r
+}\r
+\r
+/**\r
+ * Enqueue either data or TCP options (but not both) for tranmission\r
+ *\r
+ * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write().\r
+ *\r
+ * @param pcb Protocol control block for the TCP connection to enqueue data for.\r
+ * @param arg Pointer to the data to be enqueued for sending.\r
+ * @param len Data length in bytes\r
+ * @param flags tcp header flags to set in the outgoing segment\r
+ * @param apiflags combination of following flags :\r
+ * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack\r
+ * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent,\r
+ * @param optdata\r
+ * @param optlen\r
+ */\r
+err_t\r
+tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len,\r
+  u8_t flags, u8_t apiflags,\r
+  u8_t *optdata, u8_t optlen)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_seg *seg, *useg, *queue;\r
+  u32_t seqno;\r
+  u16_t left, seglen;\r
+  void *ptr;\r
+  u16_t queuelen;\r
+\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n",\r
+    (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags));\r
+  LWIP_ERROR("tcp_enqueue: len == 0 || optlen == 0 (programmer violates API)",\r
+      ((len == 0) || (optlen == 0)), return ERR_ARG;);\r
+  LWIP_ERROR("tcp_enqueue: arg == NULL || optdata == NULL (programmer violates API)",\r
+      ((arg == NULL) || (optdata == NULL)), return ERR_ARG;);\r
+  /* fail on too much data */\r
+  if (len > pcb->snd_buf) {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf));\r
+    pcb->flags |= TF_NAGLEMEMERR;\r
+    return ERR_MEM;\r
+  }\r
+  left = len;\r
+  ptr = arg;\r
+\r
+  /* seqno will be the sequence number of the first segment enqueued\r
+   * by the call to this function. */\r
+  seqno = pcb->snd_lbb;\r
+\r
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen));\r
+\r
+  /* If total number of pbufs on the unsent/unacked queues exceeds the\r
+   * configured maximum, return an error */\r
+  queuelen = pcb->snd_queuelen;\r
+  /* check for configured max queuelen and possible overflow */\r
+  if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN));\r
+    TCP_STATS_INC(tcp.memerr);\r
+    pcb->flags |= TF_NAGLEMEMERR;\r
+    return ERR_MEM;\r
+  }\r
+  if (queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty",\r
+      pcb->unacked != NULL || pcb->unsent != NULL);\r
+  } else {\r
+    LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty",\r
+      pcb->unacked == NULL && pcb->unsent == NULL);\r
+  }\r
+\r
+  /* First, break up the data into segments and tuck them together in\r
+   * the local "queue" variable. */\r
+  useg = queue = seg = NULL;\r
+  seglen = 0;\r
+  while (queue == NULL || left > 0) {\r
+\r
+    /* The segment length should be the MSS if the data to be enqueued\r
+     * is larger than the MSS. */\r
+    seglen = left > pcb->mss? pcb->mss: left;\r
+\r
+    /* Allocate memory for tcp_seg, and fill in fields. */\r
+    seg = memp_malloc(MEMP_TCP_SEG);\r
+    if (seg == NULL) {\r
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for tcp_seg\n"));\r
+      goto memerr;\r
+    }\r
+    seg->next = NULL;\r
+    seg->p = NULL;\r
+\r
+    /* first segment of to-be-queued data? */\r
+    if (queue == NULL) {\r
+      queue = seg;\r
+    }\r
+    /* subsequent segments of to-be-queued data */\r
+    else {\r
+      /* Attach the segment to the end of the queued segments */\r
+      LWIP_ASSERT("useg != NULL", useg != NULL);\r
+      useg->next = seg;\r
+    }\r
+    /* remember last segment of to-be-queued data for next iteration */\r
+    useg = seg;\r
+\r
+    /* If copy is set, memory should be allocated\r
+     * and data copied into pbuf, otherwise data comes from\r
+     * ROM or other static memory, and need not be copied. If\r
+     * optdata is != NULL, we have options instead of data. */\r
+\r
+    /* options? */\r
+    if (optdata != NULL) {\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) {\r
+        goto memerr;\r
+      }\r
+      LWIP_ASSERT("check that first pbuf can hold optlen",\r
+                  (seg->p->len >= optlen));\r
+      queuelen += pbuf_clen(seg->p);\r
+      seg->dataptr = seg->p->payload;\r
+    }\r
+    /* copy from volatile memory? */\r
+    else if (apiflags & TCP_WRITE_FLAG_COPY) {\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_RAM)) == NULL) {\r
+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen));\r
+        goto memerr;\r
+      }\r
+      LWIP_ASSERT("check that first pbuf can hold the complete seglen",\r
+                  (seg->p->len >= seglen));\r
+      queuelen += pbuf_clen(seg->p);\r
+      if (arg != NULL) {\r
+        MEMCPY(seg->p->payload, ptr, seglen);\r
+      }\r
+      seg->dataptr = seg->p->payload;\r
+    }\r
+    /* do not copy data */\r
+    else {\r
+      /* First, allocate a pbuf for holding the data.\r
+       * since the referenced data is available at least until it is sent out on the\r
+       * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM\r
+       * instead of PBUF_REF here.\r
+       */\r
+      if ((p = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) {\r
+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n"));\r
+        goto memerr;\r
+      }\r
+      ++queuelen;\r
+      /* reference the non-volatile payload data */\r
+      p->payload = ptr;\r
+      seg->dataptr = ptr;\r
+\r
+      /* Second, allocate a pbuf for the headers. */\r
+      if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_RAM)) == NULL) {\r
+        /* If allocation fails, we have to deallocate the data pbuf as\r
+         * well. */\r
+        pbuf_free(p);\r
+        LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: could not allocate memory for header pbuf\n"));\r
+        goto memerr;\r
+      }\r
+      queuelen += pbuf_clen(seg->p);\r
+\r
+      /* Concatenate the headers and data pbufs together. */\r
+      pbuf_cat(seg->p/*header*/, p/*data*/);\r
+      p = NULL;\r
+    }\r
+\r
+    /* Now that there are more segments queued, we check again if the\r
+    length of the queue exceeds the configured maximum or overflows. */\r
+    if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) {\r
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN));\r
+      goto memerr;\r
+    }\r
+\r
+    seg->len = seglen;\r
+\r
+    /* build TCP header */\r
+    if (pbuf_header(seg->p, TCP_HLEN)) {\r
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_enqueue: no room for TCP header in pbuf.\n"));\r
+      TCP_STATS_INC(tcp.err);\r
+      goto memerr;\r
+    }\r
+    seg->tcphdr = seg->p->payload;\r
+    seg->tcphdr->src = htons(pcb->local_port);\r
+    seg->tcphdr->dest = htons(pcb->remote_port);\r
+    seg->tcphdr->seqno = htonl(seqno);\r
+    seg->tcphdr->urgp = 0;\r
+    TCPH_FLAGS_SET(seg->tcphdr, flags);\r
+    /* don't fill in tcphdr->ackno and tcphdr->wnd until later */\r
+\r
+    /* Copy the options into the header, if they are present. */\r
+    if (optdata == NULL) {\r
+      TCPH_HDRLEN_SET(seg->tcphdr, 5);\r
+    }\r
+    else {\r
+      TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4));\r
+      /* Copy options into data portion of segment.\r
+       Options can thus only be sent in non data carrying\r
+       segments such as SYN|ACK. */\r
+      SMEMCPY(seg->dataptr, optdata, optlen);\r
+    }\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n",\r
+      ntohl(seg->tcphdr->seqno),\r
+      ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg),\r
+      (u16_t)flags));\r
+\r
+    left -= seglen;\r
+    seqno += seglen;\r
+    ptr = (void *)((u8_t *)ptr + seglen);\r
+  }\r
+\r
+  /* Now that the data to be enqueued has been broken up into TCP\r
+  segments in the queue variable, we add them to the end of the\r
+  pcb->unsent queue. */\r
+  if (pcb->unsent == NULL) {\r
+    useg = NULL;\r
+  }\r
+  else {\r
+    for (useg = pcb->unsent; useg->next != NULL; useg = useg->next);\r
+  }\r
+  /* { useg is last segment on the unsent queue, NULL if list is empty } */\r
+\r
+  /* If there is room in the last pbuf on the unsent queue,\r
+  chain the first pbuf on the queue together with that. */\r
+  if (useg != NULL &&\r
+    TCP_TCPLEN(useg) != 0 &&\r
+    !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) &&\r
+    !(flags & (TCP_SYN | TCP_FIN)) &&\r
+    /* fit within max seg size */\r
+    useg->len + queue->len <= pcb->mss) {\r
+    /* Remove TCP header from first segment of our to-be-queued list */\r
+    if(pbuf_header(queue->p, -TCP_HLEN)) {\r
+      /* Can we cope with this failing?  Just assert for now */\r
+      LWIP_ASSERT("pbuf_header failed\n", 0);\r
+      TCP_STATS_INC(tcp.err);\r
+      goto memerr;\r
+    }\r
+    pbuf_cat(useg->p, queue->p);\r
+    useg->len += queue->len;\r
+    useg->next = queue->next;\r
+\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len));\r
+    if (seg == queue) {\r
+      seg = NULL;\r
+    }\r
+    memp_free(MEMP_TCP_SEG, queue);\r
+  }\r
+  else {\r
+    /* empty list */\r
+    if (useg == NULL) {\r
+      /* initialize list with this segment */\r
+      pcb->unsent = queue;\r
+    }\r
+    /* enqueue segment */\r
+    else {\r
+      useg->next = queue;\r
+    }\r
+  }\r
+  if ((flags & TCP_SYN) || (flags & TCP_FIN)) {\r
+    ++len;\r
+  }\r
+  if (flags & TCP_FIN) {\r
+    pcb->flags |= TF_FIN;\r
+  }\r
+  pcb->snd_lbb += len;\r
+\r
+  pcb->snd_buf -= len;\r
+\r
+  /* update number of segments on the queues */\r
+  pcb->snd_queuelen = queuelen;\r
+  LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen));\r
+  if (pcb->snd_queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: valid queue length",\r
+      pcb->unacked != NULL || pcb->unsent != NULL);\r
+  }\r
+\r
+  /* Set the PSH flag in the last segment that we enqueued, but only\r
+  if the segment has data (indicated by seglen > 0). */\r
+  if (seg != NULL && seglen > 0 && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) {\r
+    TCPH_SET_FLAG(seg->tcphdr, TCP_PSH);\r
+  }\r
+\r
+  return ERR_OK;\r
+memerr:\r
+  pcb->flags |= TF_NAGLEMEMERR;\r
+  TCP_STATS_INC(tcp.memerr);\r
+\r
+  if (queue != NULL) {\r
+    tcp_segs_free(queue);\r
+  }\r
+  if (pcb->snd_queuelen != 0) {\r
+    LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL ||\r
+      pcb->unsent != NULL);\r
+  }\r
+  LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen));\r
+  return ERR_MEM;\r
+}\r
+\r
+/**\r
+ * Find out what we can send and send it\r
+ *\r
+ * @param pcb Protocol control block for the TCP connection to send data\r
+ * @return ERR_OK if data has been sent or nothing to send\r
+ *         another err_t on error\r
+ */\r
+err_t\r
+tcp_output(struct tcp_pcb *pcb)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+  struct tcp_seg *seg, *useg;\r
+  u32_t wnd;\r
+#if TCP_CWND_DEBUG\r
+  s16_t i = 0;\r
+#endif /* TCP_CWND_DEBUG */\r
+\r
+  /* First, check if we are invoked by the TCP input processing\r
+     code. If so, we do not output anything. Instead, we rely on the\r
+     input processing code to call us when input processing is done\r
+     with. */\r
+  if (tcp_input_pcb == pcb) {\r
+    return ERR_OK;\r
+  }\r
+\r
+  wnd = LWIP_MIN(pcb->snd_wnd, pcb->cwnd);\r
+\r
+  seg = pcb->unsent;\r
+\r
+  /* useg should point to last segment on unacked queue */\r
+  useg = pcb->unacked;\r
+  if (useg != NULL) {\r
+    for (; useg->next != NULL; useg = useg->next);\r
+  }\r
+\r
+  /* If the TF_ACK_NOW flag is set and no data will be sent (either\r
+   * because the ->unsent queue is empty or because the window does\r
+   * not allow it), construct an empty ACK segment and send it.\r
+   *\r
+   * If data is to be sent, we will just piggyback the ACK (see below).\r
+   */\r
+  if (pcb->flags & TF_ACK_NOW &&\r
+     (seg == NULL ||\r
+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > wnd)) {\r
+    p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+    if (p == NULL) {\r
+      LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n"));\r
+      return ERR_BUF;\r
+    }\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt));\r
+    /* remove ACK flags from the PCB, as we send an empty ACK now */\r
+    pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+\r
+    tcphdr = p->payload;\r
+    tcphdr->src = htons(pcb->local_port);\r
+    tcphdr->dest = htons(pcb->remote_port);\r
+    tcphdr->seqno = htonl(pcb->snd_nxt);\r
+    tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+    TCPH_FLAGS_SET(tcphdr, TCP_ACK);\r
+    tcphdr->wnd = htons(pcb->rcv_ann_wnd);\r
+    tcphdr->urgp = 0;\r
+    TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+    tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+    tcphdr->chksum = inet_chksum_pseudo(p, &(pcb->local_ip), &(pcb->remote_ip),\r
+          IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+#if LWIP_NETIF_HWADDRHINT\r
+    {\r
+      struct netif *netif;\r
+      netif = ip_route(&pcb->remote_ip);\r
+      if(netif != NULL){\r
+        netif->addr_hint = &(pcb->addr_hint);\r
+        ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,\r
+                     pcb->tos, IP_PROTO_TCP, netif);\r
+        netif->addr_hint = NULL;\r
+      }\r
+    }\r
+#else /* LWIP_NETIF_HWADDRHINT*/\r
+    ip_output(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
+        IP_PROTO_TCP);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+    pbuf_free(p);\r
+\r
+    return ERR_OK;\r
+  }\r
+\r
+#if TCP_OUTPUT_DEBUG\r
+  if (seg == NULL) {\r
+    LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",\r
+                                   (void*)pcb->unsent));\r
+  }\r
+#endif /* TCP_OUTPUT_DEBUG */\r
+#if TCP_CWND_DEBUG\r
+  if (seg == NULL) {\r
+    LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F\r
+                                 ", cwnd %"U16_F", wnd %"U32_F\r
+                                 ", seg == NULL, ack %"U32_F"\n",\r
+                                 pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));\r
+  } else {\r
+    LWIP_DEBUGF(TCP_CWND_DEBUG,\r
+                ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F\r
+                 ", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",\r
+                 pcb->snd_wnd, pcb->cwnd, wnd,\r
+                 ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,\r
+                 ntohl(seg->tcphdr->seqno), pcb->lastack));\r
+  }\r
+#endif /* TCP_CWND_DEBUG */\r
+  /* data available and window allows it to be sent? */\r
+  while (seg != NULL &&\r
+         ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {\r
+    LWIP_ASSERT("RST not expected here!",\r
+                (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);\r
+    /* Stop sending if the nagle algorithm would prevent it\r
+     * Don't stop:\r
+     * - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or\r
+     * - if FIN was already enqueued for this PCB (SYN is always alone in a segment -\r
+     *   either seg->next != NULL or pcb->unacked == NULL;\r
+     *   RST is no sent using tcp_enqueue/tcp_output.\r
+     */\r
+    if((tcp_do_output_nagle(pcb) == 0) &&\r
+      ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){\r
+      break;\r
+    }\r
+#if TCP_CWND_DEBUG\r
+    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",\r
+                            pcb->snd_wnd, pcb->cwnd, wnd,\r
+                            ntohl(seg->tcphdr->seqno) + seg->len -\r
+                            pcb->lastack,\r
+                            ntohl(seg->tcphdr->seqno), pcb->lastack, i));\r
+    ++i;\r
+#endif /* TCP_CWND_DEBUG */\r
+\r
+    pcb->unsent = seg->next;\r
+\r
+    if (pcb->state != SYN_SENT) {\r
+      TCPH_SET_FLAG(seg->tcphdr, TCP_ACK);\r
+      pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW);\r
+    }\r
+\r
+    tcp_output_segment(seg, pcb);\r
+    pcb->snd_nxt = ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg);\r
+    if (TCP_SEQ_LT(pcb->snd_max, pcb->snd_nxt)) {\r
+      pcb->snd_max = pcb->snd_nxt;\r
+    }\r
+    /* put segment on unacknowledged list if length > 0 */\r
+    if (TCP_TCPLEN(seg) > 0) {\r
+      seg->next = NULL;\r
+      /* unacked list is empty? */\r
+      if (pcb->unacked == NULL) {\r
+        pcb->unacked = seg;\r
+        useg = seg;\r
+      /* unacked list is not empty? */\r
+      } else {\r
+        /* In the case of fast retransmit, the packet should not go to the tail\r
+         * of the unacked queue, but rather at the head. We need to check for\r
+         * this case. -STJ Jul 27, 2004 */\r
+        if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){\r
+          /* add segment to head of unacked list */\r
+          seg->next = pcb->unacked;\r
+          pcb->unacked = seg;\r
+        } else {\r
+          /* add segment to tail of unacked list */\r
+          useg->next = seg;\r
+          useg = useg->next;\r
+        }\r
+      }\r
+    /* do not queue empty segments on the unacked list */\r
+    } else {\r
+      tcp_seg_free(seg);\r
+    }\r
+    seg = pcb->unsent;\r
+  }\r
+\r
+  if (seg != NULL && pcb->persist_backoff == 0 &&\r
+      ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) {\r
+    /* prepare for persist timer */\r
+    pcb->persist_cnt = 0;\r
+    pcb->persist_backoff = 1;\r
+  }\r
+\r
+  pcb->flags &= ~TF_NAGLEMEMERR;\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Called by tcp_output() to actually send a TCP segment over IP.\r
+ *\r
+ * @param seg the tcp_seg to send\r
+ * @param pcb the tcp_pcb for the TCP connection used to send the segment\r
+ */\r
+static void\r
+tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb)\r
+{\r
+  u16_t len;\r
+  struct netif *netif;\r
+\r
+  /** @bug Exclude retransmitted segments from this count. */\r
+  snmp_inc_tcpoutsegs();\r
+\r
+  /* The TCP header has already been constructed, but the ackno and\r
+   wnd fields remain. */\r
+  seg->tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+\r
+  /* advertise our receive window size in this TCP segment */\r
+  seg->tcphdr->wnd = htons(pcb->rcv_ann_wnd);\r
+\r
+  /* If we don't have a local IP address, we get one by\r
+     calling ip_route(). */\r
+  if (ip_addr_isany(&(pcb->local_ip))) {\r
+    netif = ip_route(&(pcb->remote_ip));\r
+    if (netif == NULL) {\r
+      return;\r
+    }\r
+    ip_addr_set(&(pcb->local_ip), &(netif->ip_addr));\r
+  }\r
+\r
+  /* Set retransmission timer running if it is not currently enabled */\r
+  if(pcb->rtime == -1)\r
+    pcb->rtime = 0;\r
+\r
+  if (pcb->rttest == 0) {\r
+    pcb->rttest = tcp_ticks;\r
+    pcb->rtseq = ntohl(seg->tcphdr->seqno);\r
+\r
+    LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_output_segment: rtseq %"U32_F"\n", pcb->rtseq));\r
+  }\r
+  LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output_segment: %"U32_F":%"U32_F"\n",\r
+          htonl(seg->tcphdr->seqno), htonl(seg->tcphdr->seqno) +\r
+          seg->len));\r
+\r
+  len = (u16_t)((u8_t *)seg->tcphdr - (u8_t *)seg->p->payload);\r
+\r
+  seg->p->len -= len;\r
+  seg->p->tot_len -= len;\r
+\r
+  seg->p->payload = seg->tcphdr;\r
+\r
+  seg->tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  seg->tcphdr->chksum = inet_chksum_pseudo(seg->p,\r
+             &(pcb->local_ip),\r
+             &(pcb->remote_ip),\r
+             IP_PROTO_TCP, seg->p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+  {\r
+    struct netif *netif;\r
+    netif = ip_route(&pcb->remote_ip);\r
+    if(netif != NULL){\r
+      netif->addr_hint = &(pcb->addr_hint);\r
+      ip_output_if(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,\r
+                   pcb->tos, IP_PROTO_TCP, netif);\r
+      netif->addr_hint = NULL;\r
+    }\r
+  }\r
+#else /* LWIP_NETIF_HWADDRHINT*/\r
+  ip_output(seg->p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl, pcb->tos,\r
+      IP_PROTO_TCP);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+}\r
+\r
+/**\r
+ * Send a TCP RESET packet (empty segment with RST flag set) either to\r
+ * abort a connection or to show that there is no matching local connection\r
+ * for a received segment.\r
+ *\r
+ * Called by tcp_abort() (to abort a local connection), tcp_input() (if no\r
+ * matching local pcb was found), tcp_listen_input() (if incoming segment\r
+ * has ACK flag set) and tcp_process() (received segment in the wrong state)\r
+ *\r
+ * Since a RST segment is in most cases not sent for an active connection,\r
+ * tcp_rst() has a number of arguments that are taken from a tcp_pcb for\r
+ * most other segment output functions.\r
+ *\r
+ * @param seqno the sequence number to use for the outgoing segment\r
+ * @param ackno the acknowledge number to use for the outgoing segment\r
+ * @param local_ip the local IP address to send the segment from\r
+ * @param remote_ip the remote IP address to send the segment to\r
+ * @param local_port the local TCP port to send the segment from\r
+ * @param remote_port the remote TCP port to send the segment to\r
+ */\r
+void\r
+tcp_rst(u32_t seqno, u32_t ackno,\r
+  struct ip_addr *local_ip, struct ip_addr *remote_ip,\r
+  u16_t local_port, u16_t remote_port)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+  if (p == NULL) {\r
+      LWIP_DEBUGF(TCP_DEBUG, ("tcp_rst: could not allocate memory for pbuf\n"));\r
+      return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",\r
+              (p->len >= sizeof(struct tcp_hdr)));\r
+\r
+  tcphdr = p->payload;\r
+  tcphdr->src = htons(local_port);\r
+  tcphdr->dest = htons(remote_port);\r
+  tcphdr->seqno = htonl(seqno);\r
+  tcphdr->ackno = htonl(ackno);\r
+  TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK);\r
+  tcphdr->wnd = htons(TCP_WND);\r
+  tcphdr->urgp = 0;\r
+  TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+  tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip,\r
+              IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+  snmp_inc_tcpoutrsts();\r
+   /* Send output with hardcoded TTL since we have no access to the pcb */\r
+  ip_output(p, local_ip, remote_ip, TCP_TTL, 0, IP_PROTO_TCP);\r
+  pbuf_free(p);\r
+  LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_rst: seqno %"U32_F" ackno %"U32_F".\n", seqno, ackno));\r
+}\r
+\r
+/**\r
+ * Requeue all unacked segments for retransmission\r
+ *\r
+ * Called by tcp_slowtmr() for slow retransmission.\r
+ *\r
+ * @param pcb the tcp_pcb for which to re-enqueue all unacked segments\r
+ */\r
+void\r
+tcp_rexmit_rto(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *seg;\r
+\r
+  if (pcb->unacked == NULL) {\r
+    return;\r
+  }\r
+\r
+  /* Move all unacked segments to the head of the unsent queue */\r
+  for (seg = pcb->unacked; seg->next != NULL; seg = seg->next);\r
+  /* concatenate unsent queue after unacked queue */\r
+  seg->next = pcb->unsent;\r
+  /* unsent queue is the concatenated queue (of unacked, unsent) */\r
+  pcb->unsent = pcb->unacked;\r
+  /* unacked queue is now empty */\r
+  pcb->unacked = NULL;\r
+\r
+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
+  /* increment number of retransmissions */\r
+  ++pcb->nrtx;\r
+\r
+  /* Don't take any RTT measurements after retransmitting. */\r
+  pcb->rttest = 0;\r
+\r
+  /* Do the actual retransmission */\r
+  tcp_output(pcb);\r
+}\r
+\r
+/**\r
+ * Requeue the first unacked segment for retransmission\r
+ *\r
+ * Called by tcp_receive() for fast retramsmit.\r
+ *\r
+ * @param pcb the tcp_pcb for which to retransmit the first unacked segment\r
+ */\r
+void\r
+tcp_rexmit(struct tcp_pcb *pcb)\r
+{\r
+  struct tcp_seg *seg;\r
+\r
+  if (pcb->unacked == NULL) {\r
+    return;\r
+  }\r
+\r
+  /* Move the first unacked segment to the unsent queue */\r
+  seg = pcb->unacked->next;\r
+  pcb->unacked->next = pcb->unsent;\r
+  pcb->unsent = pcb->unacked;\r
+  pcb->unacked = seg;\r
+\r
+  pcb->snd_nxt = ntohl(pcb->unsent->tcphdr->seqno);\r
+\r
+  ++pcb->nrtx;\r
+\r
+  /* Don't take any rtt measurements after retransmitting. */\r
+  pcb->rttest = 0;\r
+\r
+  /* Do the actual retransmission. */\r
+  snmp_inc_tcpretranssegs();\r
+  tcp_output(pcb);\r
+}\r
+\r
+/**\r
+ * Send keepalive packets to keep a connection active although\r
+ * no data is sent over it.\r
+ *\r
+ * Called by tcp_slowtmr()\r
+ *\r
+ * @param pcb the tcp_pcb for which to send a keepalive packet\r
+ */\r
+void\r
+tcp_keepalive(struct tcp_pcb *pcb)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",\r
+                          ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                          ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F"   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",\r
+                          tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));\r
+\r
+  p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM);\r
+\r
+  if(p == NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG,\r
+                ("tcp_keepalive: could not allocate memory for pbuf\n"));\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",\r
+              (p->len >= sizeof(struct tcp_hdr)));\r
+\r
+  tcphdr = p->payload;\r
+  tcphdr->src = htons(pcb->local_port);\r
+  tcphdr->dest = htons(pcb->remote_port);\r
+  tcphdr->seqno = htonl(pcb->snd_nxt - 1);\r
+  tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+  TCPH_FLAGS_SET(tcphdr, 0);\r
+  tcphdr->wnd = htons(pcb->rcv_ann_wnd);\r
+  tcphdr->urgp = 0;\r
+  TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+  tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,\r
+                                      IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+\r
+  /* Send output to IP */\r
+#if LWIP_NETIF_HWADDRHINT\r
+  {\r
+    struct netif *netif;\r
+    netif = ip_route(&pcb->remote_ip);\r
+    if(netif != NULL){\r
+      netif->addr_hint = &(pcb->addr_hint);\r
+      ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,\r
+                   0, IP_PROTO_TCP, netif);\r
+      netif->addr_hint = NULL;\r
+    }\r
+  }\r
+#else /* LWIP_NETIF_HWADDRHINT*/\r
+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+\r
+  pbuf_free(p);\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: seqno %"U32_F" ackno %"U32_F".\n",\r
+                          pcb->snd_nxt - 1, pcb->rcv_nxt));\r
+}\r
+\r
+\r
+/**\r
+ * Send persist timer zero-window probes to keep a connection active\r
+ * when a window update is lost.\r
+ *\r
+ * Called by tcp_slowtmr()\r
+ *\r
+ * @param pcb the tcp_pcb for which to send a zero-window probe packet\r
+ */\r
+void\r
+tcp_zero_window_probe(struct tcp_pcb *pcb)\r
+{\r
+  struct pbuf *p;\r
+  struct tcp_hdr *tcphdr;\r
+  struct tcp_seg *seg;\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG,\r
+              ("tcp_zero_window_probe: sending ZERO WINDOW probe to %"\r
+               U16_F".%"U16_F".%"U16_F".%"U16_F"\n",\r
+               ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+               ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG,\r
+              ("tcp_zero_window_probe: tcp_ticks %"U32_F\r
+               "   pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",\r
+               tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));\r
+\r
+  seg = pcb->unacked;\r
+\r
+  if(seg == NULL)\r
+    seg = pcb->unsent;\r
+\r
+  if(seg == NULL)\r
+    return;\r
+\r
+  p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);\r
+\r
+  if(p == NULL) {\r
+    LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));\r
+    return;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",\r
+              (p->len >= sizeof(struct tcp_hdr)));\r
+\r
+  tcphdr = p->payload;\r
+  tcphdr->src = htons(pcb->local_port);\r
+  tcphdr->dest = htons(pcb->remote_port);\r
+  tcphdr->seqno = seg->tcphdr->seqno;\r
+  tcphdr->ackno = htonl(pcb->rcv_nxt);\r
+  TCPH_FLAGS_SET(tcphdr, 0);\r
+  tcphdr->wnd = htons(pcb->rcv_ann_wnd);\r
+  tcphdr->urgp = 0;\r
+  TCPH_HDRLEN_SET(tcphdr, 5);\r
+\r
+  /* Copy in one byte from the head of the unacked queue */\r
+  *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;\r
+\r
+  tcphdr->chksum = 0;\r
+#if CHECKSUM_GEN_TCP\r
+  tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,\r
+                                      IP_PROTO_TCP, p->tot_len);\r
+#endif\r
+  TCP_STATS_INC(tcp.xmit);\r
+\r
+  /* Send output to IP */\r
+#if LWIP_NETIF_HWADDRHINT\r
+  {\r
+    struct netif *netif;\r
+    netif = ip_route(&pcb->remote_ip);\r
+    if(netif != NULL){\r
+      netif->addr_hint = &(pcb->addr_hint);\r
+      ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,\r
+                   0, IP_PROTO_TCP, netif);\r
+      netif->addr_hint = NULL;\r
+    }\r
+  }\r
+#else /* LWIP_NETIF_HWADDRHINT*/\r
+  ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+\r
+  pbuf_free(p);\r
+\r
+  LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F\r
+                          " ackno %"U32_F".\n",\r
+                          pcb->snd_nxt - 1, pcb->rcv_nxt));\r
+}\r
+#endif /* LWIP_TCP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/core/udp.c b/Demo/Common/ethernet/lwIP_130/src/core/udp.c
new file mode 100644 (file)
index 0000000..a87656b
--- /dev/null
@@ -0,0 +1,824 @@
+/**\r
+ * @file\r
+ * User Datagram Protocol module\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+/* udp.c\r
+ *\r
+ * The code for the User Datagram Protocol UDP & UDPLite (RFC 3828).\r
+ *\r
+ */\r
+\r
+/* @todo Check the use of '(struct udp_pcb).chksum_len_rx'!\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/udp.h"\r
+#include "lwip/def.h"\r
+#include "lwip/memp.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/inet_chksum.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "arch/perf.h"\r
+#include "lwip/dhcp.h"\r
+\r
+#include <string.h>\r
+\r
+/* The list of UDP PCBs */\r
+/* exported in udp.h (was static) */\r
+struct udp_pcb *udp_pcbs;\r
+\r
+/**\r
+ * Process an incoming UDP datagram.\r
+ *\r
+ * Given an incoming UDP datagram (as a chain of pbufs) this function\r
+ * finds a corresponding UDP PCB and hands over the pbuf to the pcbs\r
+ * recv function. If no pcb is found or the datagram is incorrect, the\r
+ * pbuf is freed.\r
+ *\r
+ * @param p pbuf to be demultiplexed to a UDP PCB.\r
+ * @param inp network interface on which the datagram was received.\r
+ *\r
+ */\r
+void\r
+udp_input(struct pbuf *p, struct netif *inp)\r
+{\r
+  struct udp_hdr *udphdr;\r
+  struct udp_pcb *pcb, *prev;\r
+  struct udp_pcb *uncon_pcb;\r
+  struct ip_hdr *iphdr;\r
+  u16_t src, dest;\r
+  u8_t local_match;\r
+\r
+  PERF_START;\r
+\r
+  UDP_STATS_INC(udp.recv);\r
+\r
+  iphdr = p->payload;\r
+\r
+  /* Check minimum length (IP header + UDP header)\r
+   * and move payload pointer to UDP header */\r
+  if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {\r
+    /* drop short packets */\r
+    LWIP_DEBUGF(UDP_DEBUG,\r
+                ("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));\r
+    UDP_STATS_INC(udp.lenerr);\r
+    UDP_STATS_INC(udp.drop);\r
+    snmp_inc_udpinerrors();\r
+    pbuf_free(p);\r
+    goto end;\r
+  }\r
+\r
+  udphdr = (struct udp_hdr *)p->payload;\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));\r
+\r
+  /* convert src and dest ports to host byte order */\r
+  src = ntohs(udphdr->src);\r
+  dest = ntohs(udphdr->dest);\r
+\r
+  udp_debug_print(udphdr);\r
+\r
+  /* print the UDP source and destination */\r
+  LWIP_DEBUGF(UDP_DEBUG,\r
+              ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "\r
+               "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",\r
+               ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),\r
+               ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),\r
+               ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),\r
+               ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));\r
+\r
+#if LWIP_DHCP\r
+  pcb = NULL;\r
+  /* when LWIP_DHCP is active, packets to DHCP_CLIENT_PORT may only be processed by\r
+     the dhcp module, no other UDP pcb may use the local UDP port DHCP_CLIENT_PORT */\r
+  if (dest == DHCP_CLIENT_PORT) {\r
+    /* all packets for DHCP_CLIENT_PORT not coming from DHCP_SERVER_PORT are dropped! */\r
+    if (src == DHCP_SERVER_PORT) {\r
+      if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {\r
+        /* accept the packe if\r
+           (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!\r
+           - inp->dhcp->pcb->remote == ANY or iphdr->src */\r
+        if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||\r
+           ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {\r
+          pcb = inp->dhcp->pcb;\r
+        }\r
+      }\r
+    }\r
+  } else\r
+#endif /* LWIP_DHCP */\r
+  {\r
+    prev = NULL;\r
+    local_match = 0;\r
+    uncon_pcb = NULL;\r
+    /* Iterate through the UDP pcb list for a matching pcb.\r
+     * 'Perfect match' pcbs (connected to the remote port & ip address) are\r
+     * preferred. If no perfect match is found, the first unconnected pcb that\r
+     * matches the local port and ip address gets the datagram. */\r
+    for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {\r
+      local_match = 0;\r
+      /* print the PCB local and remote address */\r
+      LWIP_DEBUGF(UDP_DEBUG,\r
+                  ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "\r
+                   "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",\r
+                   ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),\r
+                   ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,\r
+                   ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),\r
+                   ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));\r
+\r
+      /* compare PCB local addr+port to UDP destination addr+port */\r
+      if ((pcb->local_port == dest) &&\r
+          (ip_addr_isany(&pcb->local_ip) ||\r
+           ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||\r
+#if LWIP_IGMP\r
+           ip_addr_ismulticast(&(iphdr->dest)) ||\r
+#endif /* LWIP_IGMP */\r
+           ip_addr_isbroadcast(&(iphdr->dest), inp))) {\r
+        local_match = 1;\r
+        if ((uncon_pcb == NULL) &&\r
+            ((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {\r
+          /* the first unconnected matching PCB */\r
+          uncon_pcb = pcb;\r
+        }\r
+      }\r
+      /* compare PCB remote addr+port to UDP source addr+port */\r
+      if ((local_match != 0) &&\r
+          (pcb->remote_port == src) &&\r
+          (ip_addr_isany(&pcb->remote_ip) ||\r
+           ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {\r
+        /* the first fully matching PCB */\r
+        if (prev != NULL) {\r
+          /* move the pcb to the front of udp_pcbs so that is\r
+             found faster next time */\r
+          prev->next = pcb->next;\r
+          pcb->next = udp_pcbs;\r
+          udp_pcbs = pcb;\r
+        } else {\r
+          UDP_STATS_INC(udp.cachehit);\r
+        }\r
+        break;\r
+      }\r
+      prev = pcb;\r
+    }\r
+    /* no fully matching pcb found? then look for an unconnected pcb */\r
+    if (pcb == NULL) {\r
+      pcb = uncon_pcb;\r
+    }\r
+  }\r
+\r
+  /* Check checksum if this is a match or if it was directed at us. */\r
+  if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {\r
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));\r
+#if LWIP_UDPLITE\r
+    if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {\r
+      /* Do the UDP Lite checksum */\r
+#if CHECKSUM_CHECK_UDP\r
+      u16_t chklen = ntohs(udphdr->len);\r
+      if (chklen < sizeof(struct udp_hdr)) {\r
+        if (chklen == 0) {\r
+          /* For UDP-Lite, checksum length of 0 means checksum\r
+             over the complete packet (See RFC 3828 chap. 3.1) */\r
+          chklen = p->tot_len;\r
+        } else {\r
+          /* At least the UDP-Lite header must be covered by the\r
+             checksum! (Again, see RFC 3828 chap. 3.1) */\r
+          UDP_STATS_INC(udp.chkerr);\r
+          UDP_STATS_INC(udp.drop);\r
+          snmp_inc_udpinerrors();\r
+          pbuf_free(p);\r
+          goto end;\r
+        }\r
+      }\r
+      if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),\r
+                             (struct ip_addr *)&(iphdr->dest),\r
+                             IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {\r
+        LWIP_DEBUGF(UDP_DEBUG | 2,\r
+                    ("udp_input: UDP Lite datagram discarded due to failing checksum\n"));\r
+        UDP_STATS_INC(udp.chkerr);\r
+        UDP_STATS_INC(udp.drop);\r
+        snmp_inc_udpinerrors();\r
+        pbuf_free(p);\r
+        goto end;\r
+      }\r
+#endif /* CHECKSUM_CHECK_UDP */\r
+    } else\r
+#endif /* LWIP_UDPLITE */\r
+    {\r
+#if CHECKSUM_CHECK_UDP\r
+      if (udphdr->chksum != 0) {\r
+        if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),\r
+                               (struct ip_addr *)&(iphdr->dest),\r
+                               IP_PROTO_UDP, p->tot_len) != 0) {\r
+          LWIP_DEBUGF(UDP_DEBUG | 2,\r
+                      ("udp_input: UDP datagram discarded due to failing checksum\n"));\r
+          UDP_STATS_INC(udp.chkerr);\r
+          UDP_STATS_INC(udp.drop);\r
+          snmp_inc_udpinerrors();\r
+          pbuf_free(p);\r
+          goto end;\r
+        }\r
+      }\r
+#endif /* CHECKSUM_CHECK_UDP */\r
+    }\r
+    if(pbuf_header(p, -UDP_HLEN)) {\r
+      /* Can we cope with this failing? Just assert for now */\r
+      LWIP_ASSERT("pbuf_header failed\n", 0);\r
+      UDP_STATS_INC(udp.drop);\r
+      snmp_inc_udpinerrors();\r
+      pbuf_free(p);\r
+      goto end;\r
+    }\r
+    if (pcb != NULL) {\r
+      snmp_inc_udpindatagrams();\r
+      /* callback */\r
+      if (pcb->recv != NULL) {\r
+        /* now the recv function is responsible for freeing p */\r
+        pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);\r
+      } else {\r
+        /* no recv function registered? then we have to free the pbuf! */\r
+        pbuf_free(p);\r
+        goto end;\r
+      }\r
+    } else {\r
+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));\r
+\r
+#if LWIP_ICMP\r
+      /* No match was found, send ICMP destination port unreachable unless\r
+         destination address was broadcast/multicast. */\r
+      if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&\r
+          !ip_addr_ismulticast(&iphdr->dest)) {\r
+        /* move payload pointer back to ip header */\r
+        pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);\r
+        LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));\r
+        icmp_dest_unreach(p, ICMP_DUR_PORT);\r
+      }\r
+#endif /* LWIP_ICMP */\r
+      UDP_STATS_INC(udp.proterr);\r
+      UDP_STATS_INC(udp.drop);\r
+      snmp_inc_udpnoports();\r
+      pbuf_free(p);\r
+    }\r
+  } else {\r
+    pbuf_free(p);\r
+  }\r
+end:\r
+  PERF_STOP("udp_input");\r
+}\r
+\r
+/**\r
+ * Send data using UDP.\r
+ *\r
+ * @param pcb UDP PCB used to send the data.\r
+ * @param p chain of pbuf's to be sent.\r
+ *\r
+ * The datagram will be sent to the current remote_ip & remote_port\r
+ * stored in pcb. If the pcb is not bound to a port, it will\r
+ * automatically be bound to a random port.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_MEM. Out of memory.\r
+ * - ERR_RTE. Could not find route to destination address.\r
+ * - More errors could be returned by lower protocol layers.\r
+ *\r
+ * @see udp_disconnect() udp_sendto()\r
+ */\r
+err_t\r
+udp_send(struct udp_pcb *pcb, struct pbuf *p)\r
+{\r
+  /* send to the packet using remote ip and port stored in the pcb */\r
+  return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);\r
+}\r
+\r
+/**\r
+ * Send data to a specified address using UDP.\r
+ *\r
+ * @param pcb UDP PCB used to send the data.\r
+ * @param p chain of pbuf's to be sent.\r
+ * @param dst_ip Destination IP address.\r
+ * @param dst_port Destination UDP port.\r
+ *\r
+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.\r
+ *\r
+ * If the PCB already has a remote address association, it will\r
+ * be restored after the data is sent.\r
+ *\r
+ * @return lwIP error code (@see udp_send for possible error codes)\r
+ *\r
+ * @see udp_disconnect() udp_send()\r
+ */\r
+err_t\r
+udp_sendto(struct udp_pcb *pcb, struct pbuf *p,\r
+  struct ip_addr *dst_ip, u16_t dst_port)\r
+{\r
+  struct netif *netif;\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));\r
+\r
+  /* find the outgoing network interface for this packet */\r
+#if LWIP_IGMP\r
+  netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));\r
+#else\r
+  netif = ip_route(dst_ip);\r
+#endif /* LWIP_IGMP */\r
+\r
+  /* no outgoing network interface could be found? */\r
+  if (netif == NULL) {\r
+    LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));\r
+    UDP_STATS_INC(udp.rterr);\r
+    return ERR_RTE;\r
+  }\r
+  return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);\r
+}\r
+\r
+/**\r
+ * Send data to a specified address using UDP.\r
+ * The netif used for sending can be specified.\r
+ *\r
+ * This function exists mainly for DHCP, to be able to send UDP packets\r
+ * on a netif that is still down.\r
+ *\r
+ * @param pcb UDP PCB used to send the data.\r
+ * @param p chain of pbuf's to be sent.\r
+ * @param dst_ip Destination IP address.\r
+ * @param dst_port Destination UDP port.\r
+ * @param netif the netif used for sending.\r
+ *\r
+ * dst_ip & dst_port are expected to be in the same byte order as in the pcb.\r
+ *\r
+ * @return lwIP error code (@see udp_send for possible error codes)\r
+ *\r
+ * @see udp_disconnect() udp_send()\r
+ */\r
+err_t\r
+udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,\r
+  struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)\r
+{\r
+  struct udp_hdr *udphdr;\r
+  struct ip_addr *src_ip;\r
+  err_t err;\r
+  struct pbuf *q; /* q will be sent down the stack */\r
+\r
+  /* if the PCB is not yet bound to a port, bind it here */\r
+  if (pcb->local_port == 0) {\r
+    LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));\r
+    err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\r
+    if (err != ERR_OK) {\r
+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));\r
+      return err;\r
+    }\r
+  }\r
+\r
+  /* not enough space to add an UDP header to first pbuf in given p chain? */\r
+  if (pbuf_header(p, UDP_HLEN)) {\r
+    /* allocate header in a separate new pbuf */\r
+    q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);\r
+    /* new header pbuf could not be allocated? */\r
+    if (q == NULL) {\r
+      LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));\r
+      return ERR_MEM;\r
+    }\r
+    /* chain header q in front of given pbuf p */\r
+    pbuf_chain(q, p);\r
+    /* first pbuf q points to header pbuf */\r
+    LWIP_DEBUGF(UDP_DEBUG,\r
+                ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));\r
+  } else {\r
+    /* adding space for header within p succeeded */\r
+    /* first pbuf q equals given pbuf */\r
+    q = p;\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header in given pbuf %p\n", (void *)p));\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",\r
+              (q->len >= sizeof(struct udp_hdr)));\r
+  /* q now represents the packet to be sent */\r
+  udphdr = q->payload;\r
+  udphdr->src = htons(pcb->local_port);\r
+  udphdr->dest = htons(dst_port);\r
+  /* in UDP, 0 checksum means 'no checksum' */\r
+  udphdr->chksum = 0x0000;\r
+\r
+  /* PCB local address is IP_ANY_ADDR? */\r
+  if (ip_addr_isany(&pcb->local_ip)) {\r
+    /* use outgoing network interface IP address as source address */\r
+    src_ip = &(netif->ip_addr);\r
+  } else {\r
+    /* check if UDP PCB local IP address is correct\r
+     * this could be an old address if netif->ip_addr has changed */\r
+    if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {\r
+      /* local_ip doesn't match, drop the packet */\r
+      if (q != p) {\r
+        /* free the header pbuf */\r
+        pbuf_free(q);\r
+        q = NULL;\r
+        /* p is still referenced by the caller, and will live on */\r
+      }\r
+      return ERR_VAL;\r
+    }\r
+    /* use UDP PCB local IP address as source address */\r
+    src_ip = &(pcb->local_ip);\r
+  }\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));\r
+\r
+#if LWIP_UDPLITE\r
+  /* UDP Lite protocol? */\r
+  if (pcb->flags & UDP_FLAGS_UDPLITE) {\r
+    u16_t chklen, chklen_hdr;\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE packet length %"U16_F"\n", q->tot_len));\r
+    /* set UDP message length in UDP header */\r
+    chklen_hdr = chklen = pcb->chksum_len_tx;\r
+    if ((chklen < sizeof(struct udp_hdr)) || (chklen > q->tot_len)) {\r
+      if (chklen != 0) {\r
+        LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP LITE pcb->chksum_len is illegal: %"U16_F"\n", chklen));\r
+      }\r
+      /* For UDP-Lite, checksum length of 0 means checksum\r
+         over the complete packet. (See RFC 3828 chap. 3.1)\r
+         At least the UDP-Lite header must be covered by the\r
+         checksum, therefore, if chksum_len has an illegal\r
+         value, we generate the checksum over the complete\r
+         packet to be safe. */\r
+      chklen_hdr = 0;\r
+      chklen = q->tot_len;\r
+    }\r
+    udphdr->len = htons(chklen_hdr);\r
+    /* calculate checksum */\r
+#if CHECKSUM_GEN_UDP\r
+    udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,\r
+                                        IP_PROTO_UDPLITE, q->tot_len, chklen);\r
+    /* chksum zero must become 0xffff, as zero means 'no checksum' */\r
+    if (udphdr->chksum == 0x0000)\r
+      udphdr->chksum = 0xffff;\r
+#endif /* CHECKSUM_CHECK_UDP */\r
+    /* output to IP */\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));\r
+#if LWIP_NETIF_HWADDRHINT\r
+    netif->addr_hint = &(pcb->addr_hint);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);\r
+#if LWIP_NETIF_HWADDRHINT\r
+    netif->addr_hint = NULL;\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+  } else\r
+#endif /* LWIP_UDPLITE */\r
+  {      /* UDP */\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP packet length %"U16_F"\n", q->tot_len));\r
+    udphdr->len = htons(q->tot_len);\r
+    /* calculate checksum */\r
+#if CHECKSUM_GEN_UDP\r
+    if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {\r
+      udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);\r
+      /* chksum zero must become 0xffff, as zero means 'no checksum' */\r
+      if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;\r
+    }\r
+#endif /* CHECKSUM_CHECK_UDP */\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));\r
+    LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));\r
+    /* output to IP */\r
+#if LWIP_NETIF_HWADDRHINT\r
+    netif->addr_hint = &(pcb->addr_hint);\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+    err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);\r
+#if LWIP_NETIF_HWADDRHINT\r
+    netif->addr_hint = NULL;\r
+#endif /* LWIP_NETIF_HWADDRHINT*/\r
+  }\r
+  /* TODO: must this be increased even if error occured? */\r
+  snmp_inc_udpoutdatagrams();\r
+\r
+  /* did we chain a separate header pbuf earlier? */\r
+  if (q != p) {\r
+    /* free the header pbuf */\r
+    pbuf_free(q);\r
+    q = NULL;\r
+    /* p is still referenced by the caller, and will live on */\r
+  }\r
+\r
+  UDP_STATS_INC(udp.xmit);\r
+  return err;\r
+}\r
+\r
+/**\r
+ * Bind an UDP PCB.\r
+ *\r
+ * @param pcb UDP PCB to be bound with a local address ipaddr and port.\r
+ * @param ipaddr local IP address to bind with. Use IP_ADDR_ANY to\r
+ * bind to all local interfaces.\r
+ * @param port local UDP port to bind with. Use 0 to automatically bind\r
+ * to a random port between UDP_LOCAL_PORT_RANGE_START and\r
+ * UDP_LOCAL_PORT_RANGE_END.\r
+ *\r
+ * ipaddr & port are expected to be in the same byte order as in the pcb.\r
+ *\r
+ * @return lwIP error code.\r
+ * - ERR_OK. Successful. No error occured.\r
+ * - ERR_USE. The specified ipaddr and port are already bound to by\r
+ * another UDP PCB.\r
+ *\r
+ * @see udp_disconnect()\r
+ */\r
+err_t\r
+udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct udp_pcb *ipcb;\r
+  u8_t rebind;\r
+\r
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));\r
+  ip_addr_debug_print(UDP_DEBUG, ipaddr);\r
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));\r
+\r
+  rebind = 0;\r
+  /* Check for double bind and rebind of the same pcb */\r
+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\r
+    /* is this UDP PCB already on active list? */\r
+    if (pcb == ipcb) {\r
+      /* pcb may occur at most once in active list */\r
+      LWIP_ASSERT("rebind == 0", rebind == 0);\r
+      /* pcb already in list, just rebind */\r
+      rebind = 1;\r
+    }\r
+\r
+    /* this code does not allow upper layer to share a UDP port for\r
+       listening to broadcast or multicast traffic (See SO_REUSE_ADDR and\r
+       SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR\r
+       combine with implementation of UDP PCB flags. Leon Woestenberg. */\r
+#ifdef LWIP_UDP_TODO\r
+    /* port matches that of PCB in list? */\r
+    else\r
+      if ((ipcb->local_port == port) &&\r
+          /* IP address matches, or one is IP_ADDR_ANY? */\r
+          (ip_addr_isany(&(ipcb->local_ip)) ||\r
+           ip_addr_isany(ipaddr) ||\r
+           ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {\r
+        /* other PCB already binds to this local IP and port */\r
+        LWIP_DEBUGF(UDP_DEBUG,\r
+                    ("udp_bind: local port %"U16_F" already bound by another pcb\n", port));\r
+        return ERR_USE;\r
+      }\r
+#endif\r
+  }\r
+\r
+  ip_addr_set(&pcb->local_ip, ipaddr);\r
+\r
+  /* no port specified? */\r
+  if (port == 0) {\r
+#ifndef UDP_LOCAL_PORT_RANGE_START\r
+#define UDP_LOCAL_PORT_RANGE_START 4096\r
+#define UDP_LOCAL_PORT_RANGE_END   0x7fff\r
+#endif\r
+    port = UDP_LOCAL_PORT_RANGE_START;\r
+    ipcb = udp_pcbs;\r
+    while ((ipcb != NULL) && (port != UDP_LOCAL_PORT_RANGE_END)) {\r
+      if (ipcb->local_port == port) {\r
+        /* port is already used by another udp_pcb */\r
+        port++;\r
+        /* restart scanning all udp pcbs */\r
+        ipcb = udp_pcbs;\r
+      } else\r
+        /* go on with next udp pcb */\r
+        ipcb = ipcb->next;\r
+    }\r
+    if (ipcb != NULL) {\r
+      /* no more ports available in local range */\r
+      LWIP_DEBUGF(UDP_DEBUG, ("udp_bind: out of free UDP ports\n"));\r
+      return ERR_USE;\r
+    }\r
+  }\r
+  pcb->local_port = port;\r
+  snmp_insert_udpidx_tree(pcb);\r
+  /* pcb not active yet? */\r
+  if (rebind == 0) {\r
+    /* place the PCB on the active list if not already there */\r
+    pcb->next = udp_pcbs;\r
+    udp_pcbs = pcb;\r
+  }\r
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\r
+              ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),\r
+               (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));\r
+  return ERR_OK;\r
+}\r
+/**\r
+ * Connect an UDP PCB.\r
+ *\r
+ * This will associate the UDP PCB with the remote address.\r
+ *\r
+ * @param pcb UDP PCB to be connected with remote address ipaddr and port.\r
+ * @param ipaddr remote IP address to connect with.\r
+ * @param port remote UDP port to connect with.\r
+ *\r
+ * @return lwIP error code\r
+ *\r
+ * ipaddr & port are expected to be in the same byte order as in the pcb.\r
+ *\r
+ * The udp pcb is bound to a random local port if not already bound.\r
+ *\r
+ * @see udp_disconnect()\r
+ */\r
+err_t\r
+udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)\r
+{\r
+  struct udp_pcb *ipcb;\r
+\r
+  if (pcb->local_port == 0) {\r
+    err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);\r
+    if (err != ERR_OK)\r
+      return err;\r
+  }\r
+\r
+  ip_addr_set(&pcb->remote_ip, ipaddr);\r
+  pcb->remote_port = port;\r
+  pcb->flags |= UDP_FLAGS_CONNECTED;\r
+/** TODO: this functionality belongs in upper layers */\r
+#ifdef LWIP_UDP_TODO\r
+  /* Nail down local IP for netconn_addr()/getsockname() */\r
+  if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {\r
+    struct netif *netif;\r
+\r
+    if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {\r
+      LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));\r
+      UDP_STATS_INC(udp.rterr);\r
+      return ERR_RTE;\r
+    }\r
+    /** TODO: this will bind the udp pcb locally, to the interface which\r
+        is used to route output packets to the remote address. However, we\r
+        might want to accept incoming packets on any interface! */\r
+    pcb->local_ip = netif->ip_addr;\r
+  } else if (ip_addr_isany(&pcb->remote_ip)) {\r
+    pcb->local_ip.addr = 0;\r
+  }\r
+#endif\r
+  LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,\r
+              ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),\r
+               (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));\r
+\r
+  /* Insert UDP PCB into the list of active UDP PCBs. */\r
+  for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {\r
+    if (pcb == ipcb) {\r
+      /* already on the list, just return */\r
+      return ERR_OK;\r
+    }\r
+  }\r
+  /* PCB not yet on the list, add PCB now */\r
+  pcb->next = udp_pcbs;\r
+  udp_pcbs = pcb;\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Disconnect a UDP PCB\r
+ *\r
+ * @param pcb the udp pcb to disconnect.\r
+ */\r
+void\r
+udp_disconnect(struct udp_pcb *pcb)\r
+{\r
+  /* reset remote address association */\r
+  ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);\r
+  pcb->remote_port = 0;\r
+  /* mark PCB as unconnected */\r
+  pcb->flags &= ~UDP_FLAGS_CONNECTED;\r
+}\r
+\r
+/**\r
+ * Set a receive callback for a UDP PCB\r
+ *\r
+ * This callback will be called when receiving a datagram for the pcb.\r
+ *\r
+ * @param pcb the pcb for wich to set the recv callback\r
+ * @param recv function pointer of the callback function\r
+ * @param recv_arg additional argument to pass to the callback function\r
+ */\r
+void\r
+udp_recv(struct udp_pcb *pcb,\r
+         void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,\r
+                       struct ip_addr *addr, u16_t port),\r
+         void *recv_arg)\r
+{\r
+  /* remember recv() callback and user data */\r
+  pcb->recv = recv;\r
+  pcb->recv_arg = recv_arg;\r
+}\r
+\r
+/**\r
+ * Remove an UDP PCB.\r
+ *\r
+ * @param pcb UDP PCB to be removed. The PCB is removed from the list of\r
+ * UDP PCB's and the data structure is freed from memory.\r
+ *\r
+ * @see udp_new()\r
+ */\r
+void\r
+udp_remove(struct udp_pcb *pcb)\r
+{\r
+  struct udp_pcb *pcb2;\r
+\r
+  snmp_delete_udpidx_tree(pcb);\r
+  /* pcb to be removed is first in list? */\r
+  if (udp_pcbs == pcb) {\r
+    /* make list start at 2nd pcb */\r
+    udp_pcbs = udp_pcbs->next;\r
+    /* pcb not 1st in list */\r
+  } else\r
+    for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {\r
+      /* find pcb in udp_pcbs list */\r
+      if (pcb2->next != NULL && pcb2->next == pcb) {\r
+        /* remove pcb from list */\r
+        pcb2->next = pcb->next;\r
+      }\r
+    }\r
+  memp_free(MEMP_UDP_PCB, pcb);\r
+}\r
+\r
+/**\r
+ * Create a UDP PCB.\r
+ *\r
+ * @return The UDP PCB which was created. NULL if the PCB data structure\r
+ * could not be allocated.\r
+ *\r
+ * @see udp_remove()\r
+ */\r
+struct udp_pcb *\r
+udp_new(void)\r
+{\r
+  struct udp_pcb *pcb;\r
+  pcb = memp_malloc(MEMP_UDP_PCB);\r
+  /* could allocate UDP PCB? */\r
+  if (pcb != NULL) {\r
+    /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0\r
+     * which means checksum is generated over the whole datagram per default\r
+     * (recommended as default by RFC 3828). */\r
+    /* initialize PCB to all zeroes */\r
+    memset(pcb, 0, sizeof(struct udp_pcb));\r
+    pcb->ttl = UDP_TTL;\r
+  }\r
+  return pcb;\r
+}\r
+\r
+#if UDP_DEBUG\r
+/**\r
+ * Print UDP header information for debug purposes.\r
+ *\r
+ * @param udphdr pointer to the udp header in memory.\r
+ */\r
+void\r
+udp_debug_print(struct udp_hdr *udphdr)\r
+{\r
+  LWIP_DEBUGF(UDP_DEBUG, ("UDP header:\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     %5"U16_F"     | (src port, dest port)\n",\r
+                          ntohs(udphdr->src), ntohs(udphdr->dest)));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("|     %5"U16_F"     |     0x%04"X16_F"    | (len, chksum)\n",\r
+                          ntohs(udphdr->len), ntohs(udphdr->chksum)));\r
+  LWIP_DEBUGF(UDP_DEBUG, ("+-------------------------------+\n"));\r
+}\r
+#endif /* UDP_DEBUG */\r
+\r
+#endif /* LWIP_UDP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/autoip.h
new file mode 100644 (file)
index 0000000..78e8475
--- /dev/null
@@ -0,0 +1,105 @@
+/**\r
+ * @file\r
+ *\r
+ * AutoIP Automatic LinkLocal IP Configuration\r
+ */\r
+\r
+/*\r
+ *\r
+ * Copyright (c) 2007 Dominik Spies <kontakt@dspies.de>\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Dominik Spies <kontakt@dspies.de>\r
+ *\r
+ * This is a AutoIP implementation for the lwIP TCP/IP stack. It aims to conform\r
+ * with RFC 3927.\r
+ *\r
+ *\r
+ * Please coordinate changes and requests with Dominik Spies\r
+ * <kontakt@dspies.de>\r
+ */\r
+\r
+#ifndef __LWIP_AUTOIP_H__\r
+#define __LWIP_AUTOIP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_AUTOIP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+#include "netif/etharp.h"\r
+\r
+/* AutoIP Timing */\r
+#define AUTOIP_TMR_INTERVAL      100\r
+#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)\r
+\r
+/* RFC 3927 Constants */\r
+#define PROBE_WAIT               1   /* second   (initial random delay)                 */\r
+#define PROBE_MIN                1   /* second   (minimum delay till repeated probe)    */\r
+#define PROBE_MAX                2   /* seconds  (maximum delay till repeated probe)    */\r
+#define PROBE_NUM                3   /*          (number of probe packets)              */\r
+#define ANNOUNCE_NUM             2   /*          (number of announcement packets)       */\r
+#define ANNOUNCE_INTERVAL        2   /* seconds  (time between announcement packets)    */\r
+#define ANNOUNCE_WAIT            2   /* seconds  (delay before announcing)              */\r
+#define MAX_CONFLICTS            10  /*          (max conflicts before rate limiting)   */\r
+#define RATE_LIMIT_INTERVAL      60  /* seconds  (delay between successive attempts)    */\r
+#define DEFEND_INTERVAL          10  /* seconds  (min. wait between defensive ARPs)     */\r
+\r
+/* AutoIP client states */\r
+#define AUTOIP_STATE_OFF         0\r
+#define AUTOIP_STATE_PROBING     1\r
+#define AUTOIP_STATE_ANNOUNCING  2\r
+#define AUTOIP_STATE_BOUND       3\r
+\r
+struct autoip\r
+{\r
+  struct ip_addr llipaddr;  /* the currently selected, probed, announced or used LL IP-Address */\r
+  u8_t state;               /* current AutoIP state machine state */\r
+  u8_t sent_num;            /* sent number of probes or announces, dependent on state */\r
+  u16_t ttw;                /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */\r
+  u8_t lastconflict;        /* ticks until a conflict can be solved by defending */\r
+  u8_t tried_llipaddr;      /* total number of probed/used Link Local IP-Addresses */\r
+};\r
+\r
+\r
+/** Init srand, has to be called before entering mainloop */\r
+void autoip_init(void);\r
+\r
+/** Start AutoIP client */\r
+err_t autoip_start(struct netif *netif);\r
+\r
+/** Stop AutoIP client */\r
+err_t autoip_stop(struct netif *netif);\r
+\r
+/** Handles every incoming ARP Packet, called by etharp_arp_input */\r
+void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);\r
+\r
+/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */\r
+void autoip_tmr(void);\r
+\r
+#endif /* LWIP_AUTOIP */\r
+\r
+#endif /* __LWIP_AUTOIP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/icmp.h
new file mode 100644 (file)
index 0000000..6b34c88
--- /dev/null
@@ -0,0 +1,121 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ICMP_H__\r
+#define __LWIP_ICMP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define ICMP_ER 0      /* echo reply */\r
+#define ICMP_DUR 3     /* destination unreachable */\r
+#define ICMP_SQ 4      /* source quench */\r
+#define ICMP_RD 5      /* redirect */\r
+#define ICMP_ECHO 8    /* echo */\r
+#define ICMP_TE 11     /* time exceeded */\r
+#define ICMP_PP 12     /* parameter problem */\r
+#define ICMP_TS 13     /* timestamp */\r
+#define ICMP_TSR 14    /* timestamp reply */\r
+#define ICMP_IRQ 15    /* information request */\r
+#define ICMP_IR 16     /* information reply */\r
+\r
+enum icmp_dur_type {\r
+  ICMP_DUR_NET = 0,    /* net unreachable */\r
+  ICMP_DUR_HOST = 1,   /* host unreachable */\r
+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */\r
+  ICMP_DUR_PORT = 3,   /* port unreachable */\r
+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */\r
+  ICMP_DUR_SR = 5      /* source route failed */\r
+};\r
+\r
+enum icmp_te_type {\r
+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */\r
+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */\r
+};\r
+\r
+void icmp_input(struct pbuf *p, struct netif *inp);\r
+\r
+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);\r
+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct icmp_echo_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u16_t id);\r
+  PACK_STRUCT_FIELD(u16_t seqno);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+\r
+PACK_STRUCT_BEGIN\r
+struct icmp_dur_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u32_t unused);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+\r
+PACK_STRUCT_BEGIN\r
+struct icmp_te_hdr {\r
+  PACK_STRUCT_FIELD(u16_t _type_code);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u32_t unused);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)\r
+#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)\r
+\r
+#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))\r
+#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_ICMP */\r
+\r
+#endif /* __LWIP_ICMP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/igmp.h
new file mode 100644 (file)
index 0000000..1b4c457
--- /dev/null
@@ -0,0 +1,162 @@
+/*\r
+ * Copyright (c) 2002 CITEL Technologies Ltd.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. Neither the name of CITEL Technologies Ltd nor the names of its contributors\r
+ *    may be used to endorse or promote products derived from this software\r
+ *    without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY CITEL TECHNOLOGIES AND CONTRIBUTORS ``AS IS''\r
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL CITEL TECHNOLOGIES OR CONTRIBUTORS BE LIABLE\r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS\r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)\r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT\r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY\r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF\r
+ * SUCH DAMAGE.\r
+ *\r
+ * This file is a contribution to the lwIP TCP/IP stack.\r
+ * The Swedish Institute of Computer Science and Adam Dunkels\r
+ * are specifically granted permission to redistribute this\r
+ * source code.\r
+*/\r
+\r
+#ifndef __LWIP_IGMP_H__\r
+#define __LWIP_IGMP_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/pbuf.h"\r
+\r
+#if LWIP_IGMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/*\r
+ * IGMP constants\r
+ */\r
+#define IP_PROTO_IGMP                  2\r
+#define IGMP_TTL                       1\r
+#define IGMP_MINLEN                    8\r
+#define ROUTER_ALERT                   0x9404\r
+#define ROUTER_ALERTLEN                4\r
+\r
+/*\r
+ * IGMP message types, including version number.\r
+ */\r
+#define IGMP_MEMB_QUERY                0x11 /* Membership query         */\r
+#define IGMP_V1_MEMB_REPORT            0x12 /* Ver. 1 membership report */\r
+#define IGMP_V2_MEMB_REPORT            0x16 /* Ver. 2 membership report */\r
+#define IGMP_LEAVE_GROUP               0x17 /* Leave-group message      */\r
+\r
+/* IGMP timer */\r
+#define IGMP_TMR_INTERVAL              100 /* Milliseconds */\r
+#define IGMP_V1_DELAYING_MEMBER_TMR   (1000/IGMP_TMR_INTERVAL)\r
+#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)\r
+\r
+/* MAC Filter Actions */\r
+#define IGMP_DEL_MAC_FILTER            0\r
+#define IGMP_ADD_MAC_FILTER            1\r
+\r
+/* Group  membership states */\r
+#define IGMP_GROUP_NON_MEMBER          0\r
+#define IGMP_GROUP_DELAYING_MEMBER     1\r
+#define IGMP_GROUP_IDLE_MEMBER         2\r
+\r
+/*\r
+ * IGMP packet format.\r
+ */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct igmp_msg {\r
+ PACK_STRUCT_FIELD(u8_t           igmp_msgtype);\r
+ PACK_STRUCT_FIELD(u8_t           igmp_maxresp);\r
+ PACK_STRUCT_FIELD(u16_t          igmp_checksum);\r
+ PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/*\r
+ * now a group structure - there is\r
+ * a list of groups for each interface\r
+ * these should really be linked from the interface, but\r
+ * if we keep them separate we will not affect the lwip original code\r
+ * too much\r
+ *\r
+ * There will be a group for the all systems group address but this\r
+ * will not run the state machine as it is used to kick off reports\r
+ * from all the other groups\r
+ */\r
+\r
+struct igmp_group {\r
+  struct igmp_group *next;\r
+  struct netif      *interface;\r
+  struct ip_addr     group_address;\r
+  u8_t               last_reporter_flag; /* signifies we were the last person to report */\r
+  u8_t               group_state;\r
+  u16_t              timer;\r
+  u8_t               use; /* counter of simultaneous uses */\r
+};\r
+\r
+\r
+/*  Prototypes */\r
+void   igmp_init(void);\r
+\r
+err_t  igmp_start( struct netif *netif);\r
+\r
+err_t  igmp_stop( struct netif *netif);\r
+\r
+void   igmp_report_groups( struct netif *netif);\r
+\r
+struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);\r
+\r
+struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);\r
+\r
+err_t  igmp_remove_group( struct igmp_group *group);\r
+\r
+void   igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);\r
+\r
+err_t  igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);\r
+\r
+err_t  igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);\r
+\r
+void   igmp_tmr(void);\r
+\r
+void   igmp_timeout( struct igmp_group *group);\r
+\r
+void   igmp_start_timer( struct igmp_group *group, u8_t max_time);\r
+\r
+void   igmp_stop_timer( struct igmp_group *group);\r
+\r
+void   igmp_delaying_member( struct igmp_group *group, u8_t maxresp);\r
+\r
+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);\r
+\r
+void   igmp_send( struct igmp_group *group, u8_t type);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_IGMP */\r
+\r
+#endif /* __LWIP_IGMP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet.h
new file mode 100644 (file)
index 0000000..2779a00
--- /dev/null
@@ -0,0 +1,95 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_INET_H__\r
+#define __LWIP_INET_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/ip_addr.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+u32_t inet_addr(const char *cp);\r
+int inet_aton(const char *cp, struct in_addr *addr);\r
+char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */\r
+\r
+#ifdef htons\r
+#undef htons\r
+#endif /* htons */\r
+#ifdef htonl\r
+#undef htonl\r
+#endif /* htonl */\r
+#ifdef ntohs\r
+#undef ntohs\r
+#endif /* ntohs */\r
+#ifdef ntohl\r
+#undef ntohl\r
+#endif /* ntohl */\r
+\r
+#ifndef LWIP_PLATFORM_BYTESWAP\r
+#define LWIP_PLATFORM_BYTESWAP 0\r
+#endif\r
+\r
+#if BYTE_ORDER == BIG_ENDIAN\r
+#define htons(x) (x)\r
+#define ntohs(x) (x)\r
+#define htonl(x) (x)\r
+#define ntohl(x) (x)\r
+#else /* BYTE_ORDER != BIG_ENDIAN */\r
+#ifdef LWIP_PREFIX_BYTEORDER_FUNCS\r
+/* workaround for naming collisions on some platforms */\r
+#define htons lwip_htons\r
+#define ntohs lwip_ntohs\r
+#define htonl lwip_htonl\r
+#define ntohl lwip_ntohl\r
+#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */\r
+#if LWIP_PLATFORM_BYTESWAP\r
+#define htons(x) LWIP_PLATFORM_HTONS(x)\r
+#define ntohs(x) LWIP_PLATFORM_HTONS(x)\r
+#define htonl(x) LWIP_PLATFORM_HTONL(x)\r
+#define ntohl(x) LWIP_PLATFORM_HTONL(x)\r
+#else /* LWIP_PLATFORM_BYTESWAP */\r
+u16_t htons(u16_t x);\r
+u16_t ntohs(u16_t x);\r
+u32_t htonl(u32_t x);\r
+u32_t ntohl(u32_t x);\r
+#endif /* LWIP_PLATFORM_BYTESWAP */\r
+\r
+#endif /* BYTE_ORDER == BIG_ENDIAN */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_INET_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/inet_chksum.h
new file mode 100644 (file)
index 0000000..7a381a0
--- /dev/null
@@ -0,0 +1,58 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_INET_CHKSUM_H__\r
+#define __LWIP_INET_CHKSUM_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+u16_t inet_chksum(void *dataptr, u16_t len);\r
+u16_t inet_chksum_pbuf(struct pbuf *p);\r
+u16_t inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len);\r
+u16_t inet_chksum_pseudo_partial(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u16_t proto_len, u16_t chksum_len);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_INET_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip.h
new file mode 100644 (file)
index 0000000..fa2f149
--- /dev/null
@@ -0,0 +1,173 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_H__\r
+#define __LWIP_IP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define ip_init() /* Compatibility define, not init needed. */\r
+struct netif *ip_route(struct ip_addr *dest);\r
+err_t ip_input(struct pbuf *p, struct netif *inp);\r
+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+    u8_t ttl, u8_t tos, u8_t proto);\r
+err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t ttl, u8_t tos, u8_t proto,\r
+       struct netif *netif);\r
+\r
+#define IP_HLEN 20\r
+\r
+#define IP_PROTO_ICMP    1\r
+#define IP_PROTO_UDP     17\r
+#define IP_PROTO_UDPLITE 136\r
+#define IP_PROTO_TCP     6\r
+\r
+/* This is passed as the destination address to ip_output_if (not\r
+   to ip_output), meaning that an IP header already is constructed\r
+   in the pbuf. This is used when TCP retransmits. */\r
+#ifdef IP_HDRINCL\r
+#undef IP_HDRINCL\r
+#endif /* IP_HDRINCL */\r
+#define IP_HDRINCL  NULL\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+#define IP_PCB_ADDRHINT ;u8_t addr_hint\r
+#else\r
+#define IP_PCB_ADDRHINT\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+\r
+/* This is the common part of all PCB types. It needs to be at the\r
+   beginning of a PCB type definition. It is located here so that\r
+   changes to this common part are made in one location instead of\r
+   having to change all PCB structs. */\r
+#define IP_PCB \\r
+  /* ip addresses in network byte order */ \\r
+  struct ip_addr local_ip; \\r
+  struct ip_addr remote_ip; \\r
+   /* Socket options */  \\r
+  u16_t so_options;      \\r
+   /* Type Of Service */ \\r
+  u8_t tos;              \\r
+  /* Time To Live */     \\r
+  u8_t ttl               \\r
+  /* link layer address resolution hint */ \\r
+  IP_PCB_ADDRHINT\r
+\r
+struct ip_pcb {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+};\r
+\r
+/*\r
+ * Option flags per-socket. These are the same like SO_XXX.\r
+ */\r
+#define SOF_DEBUG       (u16_t)0x0001U    /* turn on debugging info recording */\r
+#define SOF_ACCEPTCONN  (u16_t)0x0002U    /* socket has had listen() */\r
+#define SOF_REUSEADDR   (u16_t)0x0004U    /* allow local address reuse */\r
+#define SOF_KEEPALIVE   (u16_t)0x0008U    /* keep connections alive */\r
+#define SOF_DONTROUTE   (u16_t)0x0010U    /* just use interface addresses */\r
+#define SOF_BROADCAST   (u16_t)0x0020U    /* permit sending of broadcast msgs */\r
+#define SOF_USELOOPBACK (u16_t)0x0040U    /* bypass hardware when possible */\r
+#define SOF_LINGER      (u16_t)0x0080U    /* linger on close if data present */\r
+#define SOF_OOBINLINE   (u16_t)0x0100U    /* leave received OOB data in line */\r
+#define SOF_REUSEPORT   (u16_t)0x0200U    /* allow local address & port reuse */\r
+\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_hdr {\r
+  /* version / header length / type of service */\r
+  PACK_STRUCT_FIELD(u16_t _v_hl_tos);\r
+  /* total length */\r
+  PACK_STRUCT_FIELD(u16_t _len);\r
+  /* identification */\r
+  PACK_STRUCT_FIELD(u16_t _id);\r
+  /* fragment offset field */\r
+  PACK_STRUCT_FIELD(u16_t _offset);\r
+#define IP_RF 0x8000        /* reserved fragment flag */\r
+#define IP_DF 0x4000        /* dont fragment flag */\r
+#define IP_MF 0x2000        /* more fragments flag */\r
+#define IP_OFFMASK 0x1fff   /* mask for fragmenting bits */\r
+  /* time to live / protocol*/\r
+  PACK_STRUCT_FIELD(u16_t _ttl_proto);\r
+  /* checksum */\r
+  PACK_STRUCT_FIELD(u16_t _chksum);\r
+  /* source and destination IP addresses */\r
+  PACK_STRUCT_FIELD(struct ip_addr src);\r
+  PACK_STRUCT_FIELD(struct ip_addr dest);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define IPH_V(hdr)  (ntohs((hdr)->_v_hl_tos) >> 12)\r
+#define IPH_HL(hdr) ((ntohs((hdr)->_v_hl_tos) >> 8) & 0x0f)\r
+#define IPH_TOS(hdr) (ntohs((hdr)->_v_hl_tos) & 0xff)\r
+#define IPH_LEN(hdr) ((hdr)->_len)\r
+#define IPH_ID(hdr) ((hdr)->_id)\r
+#define IPH_OFFSET(hdr) ((hdr)->_offset)\r
+#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)\r
+#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)\r
+#define IPH_CHKSUM(hdr) ((hdr)->_chksum)\r
+\r
+#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))\r
+#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)\r
+#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)\r
+#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)\r
+#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))\r
+#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))\r
+#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)\r
+\r
+#if IP_DEBUG\r
+void ip_debug_print(struct pbuf *p);\r
+#else\r
+#define ip_debug_print(p)\r
+#endif /* IP_DEBUG */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_IP_H__ */\r
+\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_addr.h
new file mode 100644 (file)
index 0000000..6b53968
--- /dev/null
@@ -0,0 +1,170 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_ADDR_H__\r
+#define __LWIP_IP_ADDR_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_addr {\r
+  PACK_STRUCT_FIELD(u32_t addr);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/*\r
+ * struct ipaddr2 is used in the definition of the ARP packet format in\r
+ * order to support compilers that don't have structure packing.\r
+ */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_addr2 {\r
+  PACK_STRUCT_FIELD(u16_t addrw[2]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/* For compatibility with BSD code */\r
+struct in_addr {\r
+  u32_t s_addr;\r
+};\r
+\r
+struct netif;\r
+\r
+extern const struct ip_addr ip_addr_any;\r
+extern const struct ip_addr ip_addr_broadcast;\r
+\r
+/** IP_ADDR_ can be used as a fixed IP address\r
+ *  for the wildcard and the broadcast address\r
+ */\r
+#define IP_ADDR_ANY         ((struct ip_addr *)&ip_addr_any)\r
+#define IP_ADDR_BROADCAST   ((struct ip_addr *)&ip_addr_broadcast)\r
+\r
+#define INADDR_NONE         ((u32_t)0xffffffffUL)  /* 255.255.255.255 */\r
+#define INADDR_LOOPBACK     ((u32_t)0x7f000001UL)  /* 127.0.0.1 */\r
+\r
+/* Definitions of the bits in an Internet address integer.\r
+\r
+   On subnets, host and network parts are found according to\r
+   the subnet mask, not these masks.  */\r
+\r
+#define IN_CLASSA(a)        ((((u32_t)(a)) & 0x80000000UL) == 0)\r
+#define IN_CLASSA_NET       0xff000000\r
+#define IN_CLASSA_NSHIFT    24\r
+#define IN_CLASSA_HOST      (0xffffffff & ~IN_CLASSA_NET)\r
+#define IN_CLASSA_MAX       128\r
+\r
+#define IN_CLASSB(a)        ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)\r
+#define IN_CLASSB_NET       0xffff0000\r
+#define IN_CLASSB_NSHIFT    16\r
+#define IN_CLASSB_HOST      (0xffffffff & ~IN_CLASSB_NET)\r
+#define IN_CLASSB_MAX       65536\r
+\r
+#define IN_CLASSC(a)        ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)\r
+#define IN_CLASSC_NET       0xffffff00\r
+#define IN_CLASSC_NSHIFT    8\r
+#define IN_CLASSC_HOST      (0xffffffff & ~IN_CLASSC_NET)\r
+\r
+#define IN_CLASSD(a)        (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)\r
+#define IN_CLASSD_NET       0xf0000000          /* These ones aren't really */\r
+#define IN_CLASSD_NSHIFT    28                  /*   net and host fields, but */\r
+#define IN_CLASSD_HOST      0x0fffffff          /*   routing needn't know. */\r
+#define IN_MULTICAST(a)     IN_CLASSD(a)\r
+\r
+#define IN_EXPERIMENTAL(a)  (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)\r
+#define IN_BADCLASS(a)      (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)\r
+\r
+#define IN_LOOPBACKNET      127                 /* official! */\r
+\r
+#define IP4_ADDR(ipaddr, a,b,c,d) \\r
+        (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \\r
+                               ((u32_t)((b) & 0xff) << 16) | \\r
+                               ((u32_t)((c) & 0xff) << 8) | \\r
+                                (u32_t)((d) & 0xff))\r
+\r
+#define ip_addr_set(dest, src) (dest)->addr = \\r
+                               ((src) == NULL? 0:\\r
+                               (src)->addr)\r
+/**\r
+ * Determine if two address are on the same network.\r
+ *\r
+ * @arg addr1 IP address 1\r
+ * @arg addr2 IP address 2\r
+ * @arg mask network identifier mask\r
+ * @return !0 if the network identifiers of both address match\r
+ */\r
+#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \\r
+                                              (mask)->addr) == \\r
+                                             ((addr2)->addr & \\r
+                                              (mask)->addr))\r
+#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)\r
+\r
+#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)\r
+\r
+u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);\r
+\r
+#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))\r
+\r
+#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))\r
+\r
+#define ip_addr_debug_print(debug, ipaddr) \\r
+        LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \\r
+                ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \\r
+                ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))\r
+\r
+/* These are cast to u16_t, with the intent that they are often arguments\r
+ * to printf using the U16_F format from cc.h. */\r
+#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)\r
+#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)\r
+#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)\r
+#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_IP_ADDR_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv4/lwip/ip_frag.h
new file mode 100644 (file)
index 0000000..a025ca1
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Jani Monoses <jani@iv.ro>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_IP_FRAG_H__\r
+#define __LWIP_IP_FRAG_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/err.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/ip.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if IP_REASSEMBLY\r
+/* The IP reassembly timer interval in milliseconds. */\r
+#define IP_TMR_INTERVAL 1000\r
+\r
+/* IP reassembly helper struct.\r
+ * This is exported because memp needs to know the size.\r
+ */\r
+struct ip_reassdata {\r
+  struct ip_reassdata *next;\r
+  struct pbuf *p;\r
+  struct ip_hdr iphdr;\r
+  u16_t datagram_len;\r
+  u8_t flags;\r
+  u8_t timer;\r
+};\r
+\r
+void ip_reass_init(void);\r
+void ip_reass_tmr(void);\r
+struct pbuf * ip_reass(struct pbuf *p);\r
+#endif /* IP_REASSEMBLY */\r
+\r
+#if IP_FRAG\r
+err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);\r
+#endif /* IP_FRAG */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_IP_FRAG_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/icmp.h
new file mode 100644 (file)
index 0000000..cbdf07a
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ICMP_H__\r
+#define __LWIP_ICMP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/netif.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define ICMP6_DUR  1\r
+#define ICMP6_TE   3\r
+#define ICMP6_ECHO 128    /* echo */\r
+#define ICMP6_ER   129      /* echo reply */\r
+\r
+\r
+enum icmp_dur_type {\r
+  ICMP_DUR_NET = 0,    /* net unreachable */\r
+  ICMP_DUR_HOST = 1,   /* host unreachable */\r
+  ICMP_DUR_PROTO = 2,  /* protocol unreachable */\r
+  ICMP_DUR_PORT = 3,   /* port unreachable */\r
+  ICMP_DUR_FRAG = 4,   /* fragmentation needed and DF set */\r
+  ICMP_DUR_SR = 5      /* source route failed */\r
+};\r
+\r
+enum icmp_te_type {\r
+  ICMP_TE_TTL = 0,     /* time to live exceeded in transit */\r
+  ICMP_TE_FRAG = 1     /* fragment reassembly time exceeded */\r
+};\r
+\r
+void icmp_input(struct pbuf *p, struct netif *inp);\r
+\r
+void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);\r
+void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);\r
+\r
+struct icmp_echo_hdr {\r
+  u8_t type;\r
+  u8_t icode;\r
+  u16_t chksum;\r
+  u16_t id;\r
+  u16_t seqno;\r
+};\r
+\r
+struct icmp_dur_hdr {\r
+  u8_t type;\r
+  u8_t icode;\r
+  u16_t chksum;\r
+  u32_t unused;\r
+};\r
+\r
+struct icmp_te_hdr {\r
+  u8_t type;\r
+  u8_t icode;\r
+  u16_t chksum;\r
+  u32_t unused;\r
+};\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_ICMP */\r
+\r
+#endif /* __LWIP_ICMP_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/inet.h
new file mode 100644 (file)
index 0000000..216ebd7
--- /dev/null
@@ -0,0 +1,68 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_INET_H__\r
+#define __LWIP_INET_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+u16_t inet_chksum(void *data, u16_t len);\r
+u16_t inet_chksum_pbuf(struct pbuf *p);\r
+u16_t inet_chksum_pseudo(struct pbuf *p,\r
+       struct ip_addr *src, struct ip_addr *dest,\r
+       u8_t proto, u32_t proto_len);\r
+\r
+u32_t inet_addr(const char *cp);\r
+s8_t inet_aton(const char *cp, struct in_addr *addr);\r
+\r
+#ifndef _MACHINE_ENDIAN_H_\r
+#ifndef _NETINET_IN_H\r
+#ifndef _LINUX_BYTEORDER_GENERIC_H\r
+u16_t htons(u16_t n);\r
+u16_t ntohs(u16_t n);\r
+u32_t htonl(u32_t n);\r
+u32_t ntohl(u32_t n);\r
+#endif /* _LINUX_BYTEORDER_GENERIC_H */\r
+#endif /* _NETINET_IN_H */\r
+#endif /* _MACHINE_ENDIAN_H_ */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_INET_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip.h
new file mode 100644 (file)
index 0000000..e73bf4b
--- /dev/null
@@ -0,0 +1,127 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_H__\r
+#define __LWIP_IP_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define IP_HLEN 40\r
+\r
+#define IP_PROTO_ICMP    58\r
+#define IP_PROTO_UDP     17\r
+#define IP_PROTO_UDPLITE 136\r
+#define IP_PROTO_TCP     6\r
+\r
+/* This is passed as the destination address to ip_output_if (not\r
+   to ip_output), meaning that an IP header already is constructed\r
+   in the pbuf. This is used when TCP retransmits. */\r
+#ifdef IP_HDRINCL\r
+#undef IP_HDRINCL\r
+#endif /* IP_HDRINCL */\r
+#define IP_HDRINCL  NULL\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+#define IP_PCB_ADDRHINT ;u8_t addr_hint\r
+#else\r
+#define IP_PCB_ADDRHINT\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+\r
+/* This is the common part of all PCB types. It needs to be at the\r
+   beginning of a PCB type definition. It is located here so that\r
+   changes to this common part are made in one location instead of\r
+   having to change all PCB structs. */\r
+#define IP_PCB struct ip_addr local_ip; \\r
+  struct ip_addr remote_ip; \\r
+   /* Socket options */  \\r
+  u16_t so_options;      \\r
+   /* Type Of Service */ \\r
+  u8_t tos;              \\r
+  /* Time To Live */     \\r
+  u8_t ttl;              \\r
+  /* link layer address resolution hint */ \\r
+  IP_PCB_ADDRHINT\r
+\r
+\r
+/* The IPv6 header. */\r
+struct ip_hdr {\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+  u8_t tclass1:4, v:4;\r
+  u8_t flow1:4, tclass2:4;  \r
+#else\r
+  u8_t v:4, tclass1:4;\r
+  u8_t tclass2:8, flow1:4;\r
+#endif\r
+  u16_t flow2;\r
+  u16_t len;                /* payload length */\r
+  u8_t nexthdr;             /* next header */\r
+  u8_t hoplim;              /* hop limit (TTL) */\r
+  struct ip_addr src, dest;          /* source and destination IP addresses */\r
+};\r
+\r
+#define IPH_PROTO(hdr) (iphdr->nexthdr)\r
+\r
+void ip_init(void);\r
+\r
+#include "lwip/netif.h"\r
+\r
+struct netif *ip_route(struct ip_addr *dest);\r
+\r
+void ip_input(struct pbuf *p, struct netif *inp);\r
+\r
+/* source and destination addresses in network byte order, please */\r
+err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+         u8_t ttl, u8_t proto);\r
+\r
+err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,\r
+      u8_t ttl, u8_t proto,\r
+      struct netif *netif);\r
+\r
+#if IP_DEBUG\r
+void ip_debug_print(struct pbuf *p);\r
+#endif /* IP_DEBUG */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_IP_H__ */\r
+\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h b/Demo/Common/ethernet/lwIP_130/src/include/ipv6/lwip/ip_addr.h
new file mode 100644 (file)
index 0000000..85971c9
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_IP_ADDR_H__\r
+#define __LWIP_IP_ADDR_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define IP_ADDR_ANY 0\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+ struct ip_addr {\r
+  PACK_STRUCT_FIELD(u32_t addr[4]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/*\r
+ * struct ipaddr2 is used in the definition of the ARP packet format in\r
+ * order to support compilers that don't have structure packing.\r
+ */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ip_addr2 {\r
+  PACK_STRUCT_FIELD(u16_t addrw[2]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \\r
+                                               (ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \\r
+                                               (ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \\r
+                                               (ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)\r
+\r
+u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,\r
+        struct ip_addr *mask);\r
+u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);\r
+void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);\r
+u8_t ip_addr_isany(struct ip_addr *addr);\r
+\r
+#define ip_addr_debug_print(debug, ipaddr) \\r
+        LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \\r
+         (ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \\r
+         ntohl(ipaddr->addr[0]) & 0xffff, \\r
+         (ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \\r
+         ntohl(ipaddr->addr[1]) & 0xffff, \\r
+         (ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \\r
+         ntohl(ipaddr->addr[2]) & 0xffff, \\r
+         (ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \\r
+         ntohl(ipaddr->addr[3]) & 0xffff));\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_IP_ADDR_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/api.h
new file mode 100644 (file)
index 0000000..c26dada
--- /dev/null
@@ -0,0 +1,217 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_API_H__\r
+#define __LWIP_API_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/netbuf.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* Throughout this file, IP addresses and port numbers are expected to be in\r
+ * the same byte order as in the corresponding pcb.\r
+ */\r
+\r
+/* Flags for netconn_write */\r
+#define NETCONN_NOFLAG 0x00\r
+#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */\r
+#define NETCONN_COPY   0x01\r
+#define NETCONN_MORE   0x02\r
+\r
+/* Helpers to process several netconn_types by the same code */\r
+#define NETCONNTYPE_GROUP(t)    (t&0xF0)\r
+#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)\r
+\r
+enum netconn_type {\r
+  NETCONN_INVALID    = 0,\r
+  /* NETCONN_TCP Group */\r
+  NETCONN_TCP        = 0x10,\r
+  /* NETCONN_UDP Group */\r
+  NETCONN_UDP        = 0x20,\r
+  NETCONN_UDPLITE    = 0x21,\r
+  NETCONN_UDPNOCHKSUM= 0x22,\r
+  /* NETCONN_RAW Group */\r
+  NETCONN_RAW        = 0x40\r
+};\r
+\r
+enum netconn_state {\r
+  NETCONN_NONE,\r
+  NETCONN_WRITE,\r
+  NETCONN_LISTEN,\r
+  NETCONN_CONNECT,\r
+  NETCONN_CLOSE\r
+};\r
+\r
+enum netconn_evt {\r
+  NETCONN_EVT_RCVPLUS,\r
+  NETCONN_EVT_RCVMINUS,\r
+  NETCONN_EVT_SENDPLUS,\r
+  NETCONN_EVT_SENDMINUS\r
+};\r
+\r
+#if LWIP_IGMP\r
+enum netconn_igmp {\r
+  NETCONN_JOIN,\r
+  NETCONN_LEAVE\r
+};\r
+#endif /* LWIP_IGMP */\r
+\r
+/* forward-declare some structs to avoid to include their headers */\r
+struct ip_pcb;\r
+struct tcp_pcb;\r
+struct udp_pcb;\r
+struct raw_pcb;\r
+struct netconn;\r
+\r
+/** A callback prototype to inform about events for a netconn */\r
+typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);\r
+\r
+/** A netconn descriptor */\r
+struct netconn {\r
+  /** type of the netconn (TCP, UDP or RAW) */\r
+  enum netconn_type type;\r
+  /** current state of the netconn */\r
+  enum netconn_state state;\r
+  /** the lwIP internal protocol control block */\r
+  union {\r
+    struct ip_pcb  *ip;\r
+    struct tcp_pcb *tcp;\r
+    struct udp_pcb *udp;\r
+    struct raw_pcb *raw;\r
+  } pcb;\r
+  /** the last error this netconn had */\r
+  err_t err;\r
+  /** sem that is used to synchroneously execute functions in the core context */\r
+  sys_sem_t op_completed;\r
+  /** mbox where received packets are stored until they are fetched\r
+      by the netconn application thread (can grow quite big) */\r
+  sys_mbox_t recvmbox;\r
+  /** mbox where new connections are stored until processed\r
+      by the application thread */\r
+  sys_mbox_t acceptmbox;\r
+  /** only used for socket layer */\r
+  int socket;\r
+#if LWIP_SO_RCVTIMEO\r
+  /** timeout to wait for new data to be received\r
+      (or connections to arrive for listening netconns) */\r
+  int recv_timeout;\r
+#endif /* LWIP_SO_RCVTIMEO */\r
+#if LWIP_SO_RCVBUF\r
+  /** maximum amount of bytes queued in recvmbox */\r
+  int recv_bufsize;\r
+#endif /* LWIP_SO_RCVBUF */\r
+  u16_t recv_avail;\r
+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,\r
+      this temporarily stores the message. */\r
+  struct api_msg_msg *write_msg;\r
+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,\r
+      this temporarily stores how much is already sent. */\r
+  int write_offset;\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+  /** TCP: when data passed to netconn_write doesn't fit into the send buffer,\r
+      this temporarily stores whether to wake up the original application task\r
+      if data couldn't be sent in the first try. */\r
+  u8_t write_delayed;\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+  /** A callback function that is informed about events for this netconn */\r
+  netconn_callback callback;\r
+};\r
+\r
+/* Register an Network connection event */\r
+#define API_EVENT(c,e,l) if (c->callback) {         \\r
+                           (*c->callback)(c, e, l); \\r
+                         }\r
+\r
+/* Network connection functions: */\r
+#define netconn_new(t)                  netconn_new_with_proto_and_callback(t, 0, NULL)\r
+#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)\r
+struct\r
+netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,\r
+                                   netconn_callback callback);\r
+err_t             netconn_delete  (struct netconn *conn);\r
+enum netconn_type netconn_type    (struct netconn *conn);\r
+\r
+err_t             netconn_getaddr (struct netconn *conn,\r
+                                   struct ip_addr *addr,\r
+                                   u16_t *port,\r
+                                   u8_t local);\r
+#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)\r
+#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)\r
+\r
+err_t             netconn_bind    (struct netconn *conn,\r
+                                   struct ip_addr *addr,\r
+                                   u16_t port);\r
+err_t             netconn_connect (struct netconn *conn,\r
+                                   struct ip_addr *addr,\r
+                                   u16_t port);\r
+err_t             netconn_disconnect (struct netconn *conn);\r
+err_t             netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);\r
+#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)\r
+struct netconn *  netconn_accept  (struct netconn *conn);\r
+struct netbuf *   netconn_recv    (struct netconn *conn);\r
+err_t             netconn_sendto  (struct netconn *conn,\r
+                                   struct netbuf *buf, struct ip_addr *addr, u16_t port);\r
+err_t             netconn_send    (struct netconn *conn,\r
+                                   struct netbuf *buf);\r
+err_t             netconn_write   (struct netconn *conn,\r
+                                   const void *dataptr, int size,\r
+                                   u8_t apiflags);\r
+err_t             netconn_close   (struct netconn *conn);\r
+\r
+#if LWIP_IGMP\r
+err_t             netconn_join_leave_group (struct netconn *conn,\r
+                                            struct ip_addr *multiaddr,\r
+                                            struct ip_addr *interface,\r
+                                            enum netconn_igmp join_or_leave);\r
+#endif /* LWIP_IGMP */\r
+#if LWIP_DNS\r
+err_t             netconn_gethostbyname(const char *name, struct ip_addr *addr);\r
+#endif /* LWIP_DNS */\r
+\r
+#define netconn_err(conn)          ((conn)->err)\r
+#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_NETCONN */\r
+\r
+#endif /* __LWIP_API_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/api_msg.h
new file mode 100644 (file)
index 0000000..7635f9d
--- /dev/null
@@ -0,0 +1,160 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_API_MSG_H__\r
+#define __LWIP_API_MSG_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/err.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/igmp.h"\r
+#include "lwip/api.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* IP addresses and port numbers are expected to be in\r
+ * the same byte order as in the corresponding pcb.\r
+ */\r
+/** This struct includes everything that is necessary to execute a function\r
+    for a netconn in another thread context (mainly used to process netconns\r
+    in the tcpip_thread context to be thread safe). */\r
+struct api_msg_msg {\r
+  /** The netconn which to process - always needed: it includes the semaphore\r
+      which is used to block the application thread until the function finished. */\r
+  struct netconn *conn;\r
+  /** Depending on the executed function, one of these union members is used */\r
+  union {\r
+    /** used for do_send */\r
+    struct netbuf *b;\r
+    /** used for do_newconn */\r
+    struct {\r
+      u8_t proto;\r
+    } n;\r
+    /** used for do_bind and do_connect */\r
+    struct {\r
+      struct ip_addr *ipaddr;\r
+      u16_t port;\r
+    } bc;\r
+    /** used for do_getaddr */\r
+    struct {\r
+      struct ip_addr *ipaddr;\r
+      u16_t *port;\r
+      u8_t local;\r
+    } ad;\r
+    /** used for do_write */\r
+    struct {\r
+      const void *dataptr;\r
+      int len;\r
+      u8_t apiflags;\r
+    } w;\r
+    /** used ofr do_recv */\r
+    struct {\r
+      u16_t len;\r
+    } r;\r
+#if LWIP_IGMP\r
+    /** used for do_join_leave_group */\r
+    struct {\r
+      struct ip_addr *multiaddr;\r
+      struct ip_addr *interface;\r
+      enum netconn_igmp join_or_leave;\r
+    } jl;\r
+#endif /* LWIP_IGMP */\r
+#if TCP_LISTEN_BACKLOG\r
+    struct {\r
+      u8_t backlog;\r
+    } lb;\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+  } msg;\r
+};\r
+\r
+/** This struct contains a function to execute in another thread context and\r
+    a struct api_msg_msg that serves as an argument for this function.\r
+    This is passed to tcpip_apimsg to execute functions in tcpip_thread context. */\r
+struct api_msg {\r
+  /** function to execute in tcpip_thread context */\r
+  void (* function)(struct api_msg_msg *msg);\r
+  /** arguments for this function */\r
+  struct api_msg_msg msg;\r
+};\r
+\r
+#if LWIP_DNS\r
+/** As do_gethostbyname requires more arguments but doesn't require a netconn,\r
+    it has its own struct (to avoid struct api_msg getting bigger than necessary).\r
+    do_gethostbyname must be called using tcpip_callback instead of tcpip_apimsg\r
+    (see netconn_gethostbyname). */\r
+struct dns_api_msg {\r
+  /** Hostname to query or dotted IP address string */\r
+  const char *name;\r
+  /** Rhe resolved address is stored here */\r
+  struct ip_addr *addr;\r
+  /** This semaphore is posted when the name is resolved, the application thread\r
+      should wait on it. */\r
+  sys_sem_t sem;\r
+  /** Errors are given back here */\r
+  err_t *err;\r
+};\r
+#endif /* LWIP_DNS */\r
+\r
+void do_newconn         ( struct api_msg_msg *msg);\r
+void do_delconn         ( struct api_msg_msg *msg);\r
+void do_bind            ( struct api_msg_msg *msg);\r
+void do_connect         ( struct api_msg_msg *msg);\r
+void do_disconnect      ( struct api_msg_msg *msg);\r
+void do_listen          ( struct api_msg_msg *msg);\r
+void do_send            ( struct api_msg_msg *msg);\r
+void do_recv            ( struct api_msg_msg *msg);\r
+void do_write           ( struct api_msg_msg *msg);\r
+void do_getaddr         ( struct api_msg_msg *msg);\r
+void do_close           ( struct api_msg_msg *msg);\r
+#if LWIP_IGMP\r
+void do_join_leave_group( struct api_msg_msg *msg);\r
+#endif /* LWIP_IGMP */\r
+\r
+#if LWIP_DNS\r
+void do_gethostbyname(void *arg);\r
+#endif /* LWIP_DNS */\r
+\r
+struct netconn* netconn_alloc(enum netconn_type t, netconn_callback callback);\r
+void netconn_free(struct netconn *conn);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_NETCONN */\r
+\r
+#endif /* __LWIP_API_MSG_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/arch.h
new file mode 100644 (file)
index 0000000..7ecca8b
--- /dev/null
@@ -0,0 +1,228 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ARCH_H__\r
+#define __LWIP_ARCH_H__\r
+\r
+#ifndef LITTLE_ENDIAN\r
+#define LITTLE_ENDIAN 1234\r
+#endif\r
+\r
+#ifndef BIG_ENDIAN\r
+#define BIG_ENDIAN 4321\r
+#endif\r
+\r
+#include "arch/cc.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifndef PACK_STRUCT_BEGIN\r
+#define PACK_STRUCT_BEGIN\r
+#endif /* PACK_STRUCT_BEGIN */\r
+\r
+#ifndef PACK_STRUCT_END\r
+#define PACK_STRUCT_END\r
+#endif /* PACK_STRUCT_END */\r
+\r
+#ifndef PACK_STRUCT_FIELD\r
+#define PACK_STRUCT_FIELD(x) x\r
+#endif /* PACK_STRUCT_FIELD */\r
+\r
+\r
+#ifndef LWIP_UNUSED_ARG\r
+#define LWIP_UNUSED_ARG(x) (void)x\r
+#endif /* LWIP_UNUSED_ARG */\r
+\r
+\r
+#ifdef LWIP_PROVIDE_ERRNO\r
+\r
+#define  EPERM     1  /* Operation not permitted */\r
+#define  ENOENT     2  /* No such file or directory */\r
+#define  ESRCH     3  /* No such process */\r
+#define  EINTR     4  /* Interrupted system call */\r
+#define  EIO     5  /* I/O error */\r
+#define  ENXIO     6  /* No such device or address */\r
+#define  E2BIG     7  /* Arg list too long */\r
+#define  ENOEXEC     8  /* Exec format error */\r
+#define  EBADF     9  /* Bad file number */\r
+#define  ECHILD    10  /* No child processes */\r
+#define  EAGAIN    11  /* Try again */\r
+#define  ENOMEM    12  /* Out of memory */\r
+#define  EACCES    13  /* Permission denied */\r
+#define  EFAULT    14  /* Bad address */\r
+#define  ENOTBLK    15  /* Block device required */\r
+#define  EBUSY    16  /* Device or resource busy */\r
+#define  EEXIST    17  /* File exists */\r
+#define  EXDEV    18  /* Cross-device link */\r
+#define  ENODEV    19  /* No such device */\r
+#define  ENOTDIR    20  /* Not a directory */\r
+#define  EISDIR    21  /* Is a directory */\r
+#define  EINVAL    22  /* Invalid argument */\r
+#define  ENFILE    23  /* File table overflow */\r
+#define  EMFILE    24  /* Too many open files */\r
+#define  ENOTTY    25  /* Not a typewriter */\r
+#define  ETXTBSY    26  /* Text file busy */\r
+#define  EFBIG    27  /* File too large */\r
+#define  ENOSPC    28  /* No space left on device */\r
+#define  ESPIPE    29  /* Illegal seek */\r
+#define  EROFS    30  /* Read-only file system */\r
+#define  EMLINK    31  /* Too many links */\r
+#define  EPIPE    32  /* Broken pipe */\r
+#define  EDOM    33  /* Math argument out of domain of func */\r
+#define  ERANGE    34  /* Math result not representable */\r
+#define  EDEADLK    35  /* Resource deadlock would occur */\r
+#define  ENAMETOOLONG  36  /* File name too long */\r
+#define  ENOLCK    37  /* No record locks available */\r
+#define  ENOSYS    38  /* Function not implemented */\r
+#define  ENOTEMPTY  39  /* Directory not empty */\r
+#define  ELOOP    40  /* Too many symbolic links encountered */\r
+#define  EWOULDBLOCK  EAGAIN  /* Operation would block */\r
+#define  ENOMSG    42  /* No message of desired type */\r
+#define  EIDRM    43  /* Identifier removed */\r
+#define  ECHRNG    44  /* Channel number out of range */\r
+#define  EL2NSYNC  45  /* Level 2 not synchronized */\r
+#define  EL3HLT    46  /* Level 3 halted */\r
+#define  EL3RST    47  /* Level 3 reset */\r
+#define  ELNRNG    48  /* Link number out of range */\r
+#define  EUNATCH    49  /* Protocol driver not attached */\r
+#define  ENOCSI    50  /* No CSI structure available */\r
+#define  EL2HLT    51  /* Level 2 halted */\r
+#define  EBADE    52  /* Invalid exchange */\r
+#define  EBADR    53  /* Invalid request descriptor */\r
+#define  EXFULL    54  /* Exchange full */\r
+#define  ENOANO    55  /* No anode */\r
+#define  EBADRQC    56  /* Invalid request code */\r
+#define  EBADSLT    57  /* Invalid slot */\r
+\r
+#define  EDEADLOCK  EDEADLK\r
+\r
+#define  EBFONT    59  /* Bad font file format */\r
+#define  ENOSTR    60  /* Device not a stream */\r
+#define  ENODATA    61  /* No data available */\r
+#define  ETIME    62  /* Timer expired */\r
+#define  ENOSR    63  /* Out of streams resources */\r
+#define  ENONET    64  /* Machine is not on the network */\r
+#define  ENOPKG    65  /* Package not installed */\r
+#define  EREMOTE    66  /* Object is remote */\r
+#define  ENOLINK    67  /* Link has been severed */\r
+#define  EADV    68  /* Advertise error */\r
+#define  ESRMNT    69  /* Srmount error */\r
+#define  ECOMM    70  /* Communication error on send */\r
+#define  EPROTO    71  /* Protocol error */\r
+#define  EMULTIHOP  72  /* Multihop attempted */\r
+#define  EDOTDOT    73  /* RFS specific error */\r
+#define  EBADMSG    74  /* Not a data message */\r
+#define  EOVERFLOW  75  /* Value too large for defined data type */\r
+#define  ENOTUNIQ  76  /* Name not unique on network */\r
+#define  EBADFD    77  /* File descriptor in bad state */\r
+#define  EREMCHG    78  /* Remote address changed */\r
+#define  ELIBACC    79  /* Can not access a needed shared library */\r
+#define  ELIBBAD    80  /* Accessing a corrupted shared library */\r
+#define  ELIBSCN    81  /* .lib section in a.out corrupted */\r
+#define  ELIBMAX    82  /* Attempting to link in too many shared libraries */\r
+#define  ELIBEXEC  83  /* Cannot exec a shared library directly */\r
+#define  EILSEQ    84  /* Illegal byte sequence */\r
+#define  ERESTART  85  /* Interrupted system call should be restarted */\r
+#define  ESTRPIPE  86  /* Streams pipe error */\r
+#define  EUSERS    87  /* Too many users */\r
+#define  ENOTSOCK  88  /* Socket operation on non-socket */\r
+#define  EDESTADDRREQ  89  /* Destination address required */\r
+#define  EMSGSIZE  90  /* Message too long */\r
+#define  EPROTOTYPE  91  /* Protocol wrong type for socket */\r
+#define  ENOPROTOOPT  92  /* Protocol not available */\r
+#define  EPROTONOSUPPORT  93  /* Protocol not supported */\r
+#define  ESOCKTNOSUPPORT  94  /* Socket type not supported */\r
+#define  EOPNOTSUPP  95  /* Operation not supported on transport endpoint */\r
+#define  EPFNOSUPPORT  96  /* Protocol family not supported */\r
+#define  EAFNOSUPPORT  97  /* Address family not supported by protocol */\r
+#define  EADDRINUSE  98  /* Address already in use */\r
+#define  EADDRNOTAVAIL  99  /* Cannot assign requested address */\r
+#define  ENETDOWN  100  /* Network is down */\r
+#define  ENETUNREACH  101  /* Network is unreachable */\r
+#define  ENETRESET  102  /* Network dropped connection because of reset */\r
+#define  ECONNABORTED  103  /* Software caused connection abort */\r
+#define  ECONNRESET  104  /* Connection reset by peer */\r
+#define  ENOBUFS    105  /* No buffer space available */\r
+#define  EISCONN    106  /* Transport endpoint is already connected */\r
+#define  ENOTCONN  107  /* Transport endpoint is not connected */\r
+#define  ESHUTDOWN  108  /* Cannot send after transport endpoint shutdown */\r
+#define  ETOOMANYREFS  109  /* Too many references: cannot splice */\r
+#define  ETIMEDOUT  110  /* Connection timed out */\r
+#define  ECONNREFUSED  111  /* Connection refused */\r
+#define  EHOSTDOWN  112  /* Host is down */\r
+#define  EHOSTUNREACH  113  /* No route to host */\r
+#define  EALREADY  114  /* Operation already in progress */\r
+#define  EINPROGRESS  115  /* Operation now in progress */\r
+#define  ESTALE    116  /* Stale NFS file handle */\r
+#define  EUCLEAN    117  /* Structure needs cleaning */\r
+#define  ENOTNAM    118  /* Not a XENIX named type file */\r
+#define  ENAVAIL    119  /* No XENIX semaphores available */\r
+#define  EISNAM    120  /* Is a named type file */\r
+#define  EREMOTEIO  121  /* Remote I/O error */\r
+#define  EDQUOT    122  /* Quota exceeded */\r
+\r
+#define  ENOMEDIUM  123  /* No medium found */\r
+#define  EMEDIUMTYPE  124  /* Wrong medium type */\r
+\r
+\r
+#define ENSROK    0 /* DNS server returned answer with no data */\r
+#define ENSRNODATA  160 /* DNS server returned answer with no data */\r
+#define ENSRFORMERR 161 /* DNS server claims query was misformatted */\r
+#define ENSRSERVFAIL 162  /* DNS server returned general failure */\r
+#define ENSRNOTFOUND 163  /* Domain name not found */\r
+#define ENSRNOTIMP  164 /* DNS server does not implement requested operation */\r
+#define ENSRREFUSED 165 /* DNS server refused query */\r
+#define ENSRBADQUERY 166  /* Misformatted DNS query */\r
+#define ENSRBADNAME 167 /* Misformatted domain name */\r
+#define ENSRBADFAMILY 168 /* Unsupported address family */\r
+#define ENSRBADRESP 169 /* Misformatted DNS reply */\r
+#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */\r
+#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */\r
+#define ENSROF    172 /* End of file */\r
+#define ENSRFILE  173 /* Error reading file */\r
+#define ENSRNOMEM 174 /* Out of memory */\r
+#define ENSRDESTRUCTION 175 /* Application terminated lookup */\r
+#define ENSRQUERYDOMAINTOOLONG  176 /* Domain name is too long */\r
+#define ENSRCNAMELOOP 177 /* Domain name is too long */\r
+\r
+#ifndef errno\r
+extern int errno;\r
+#endif\r
+\r
+#endif /* LWIP_PROVIDE_ERRNO */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_ARCH_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/debug.h
new file mode 100644 (file)
index 0000000..1e468f6
--- /dev/null
@@ -0,0 +1,95 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_DEBUG_H__\r
+#define __LWIP_DEBUG_H__\r
+\r
+#include "lwip/arch.h"\r
+\r
+/** lower two bits indicate debug level\r
+ * - 0 off\r
+ * - 1 warning\r
+ * - 2 serious\r
+ * - 3 severe\r
+ */\r
+#define LWIP_DBG_LEVEL_OFF     0x00\r
+#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */\r
+#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */\r
+#define LWIP_DBG_LEVEL_SEVERE  0x03\r
+#define LWIP_DBG_MASK_LEVEL    0x03\r
+\r
+/** flag for LWIP_DEBUGF to enable that debug message */\r
+#define LWIP_DBG_ON            0x80U\r
+/** flag for LWIP_DEBUGF to disable that debug message */\r
+#define LWIP_DBG_OFF           0x00U\r
+\r
+/** flag for LWIP_DEBUGF indicating a tracing message (to follow program flow) */\r
+#define LWIP_DBG_TRACE         0x40U\r
+/** flag for LWIP_DEBUGF indicating a state debug message (to follow module states) */\r
+#define LWIP_DBG_STATE         0x20U\r
+/** flag for LWIP_DEBUGF indicating newly added code, not thoroughly tested yet */\r
+#define LWIP_DBG_FRESH         0x10U\r
+/** flag for LWIP_DEBUGF to halt after printing this debug message */\r
+#define LWIP_DBG_HALT          0x08U\r
+\r
+#ifndef LWIP_NOASSERT\r
+#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)\r
+#else  /* LWIP_NOASSERT */\r
+#define LWIP_ASSERT(x,y)\r
+#endif /* LWIP_NOASSERT */\r
+\r
+/** print "m" message only if "e" is true, and execute "h" expression */\r
+#ifndef LWIP_ERROR\r
+#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0)\r
+#endif /* LWIP_ERROR */\r
+\r
+#ifdef LWIP_DEBUG\r
+/** print debug message only if debug message type is enabled...\r
+ *  AND is of correct type AND is at least LWIP_DBG_LEVEL\r
+ */\r
+#define LWIP_DEBUGF(debug,x) do { \\r
+                               if ( \\r
+                                   ((debug) & LWIP_DBG_ON) && \\r
+                                   ((debug) & LWIP_DBG_TYPES_ON) && \\r
+                                   ((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \\r
+                                 LWIP_PLATFORM_DIAG(x); \\r
+                                 if ((debug) & LWIP_DBG_HALT) { \\r
+                                   while(1); \\r
+                                 } \\r
+                               } \\r
+                             } while(0)\r
+\r
+#else  /* LWIP_DEBUG */\r
+#define LWIP_DEBUGF(debug,x)\r
+#endif /* LWIP_DEBUG */\r
+\r
+#endif /* __LWIP_DEBUG_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/def.h
new file mode 100644 (file)
index 0000000..f64c120
--- /dev/null
@@ -0,0 +1,47 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_DEF_H__\r
+#define __LWIP_DEF_H__\r
+\r
+/* this might define NULL already */\r
+#include "lwip/arch.h"\r
+\r
+#define LWIP_MAX(x , y)  (((x) > (y)) ? (x) : (y))\r
+#define LWIP_MIN(x , y)  (((x) < (y)) ? (x) : (y))\r
+\r
+#ifndef NULL\r
+#define NULL ((void *)0)\r
+#endif\r
+\r
+\r
+#endif /* __LWIP_DEF_H__ */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/dhcp.h
new file mode 100644 (file)
index 0000000..3795d6e
--- /dev/null
@@ -0,0 +1,246 @@
+/** @file\r
+ */\r
+\r
+#ifndef __LWIP_DHCP_H__\r
+#define __LWIP_DHCP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_DHCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/** period (in seconds) of the application calling dhcp_coarse_tmr() */\r
+#define DHCP_COARSE_TIMER_SECS 60\r
+/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */\r
+#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000)\r
+/** period (in milliseconds) of the application calling dhcp_fine_tmr() */\r
+#define DHCP_FINE_TIMER_MSECS 500\r
+\r
+struct dhcp\r
+{\r
+  /** current DHCP state machine state */\r
+  u8_t state;\r
+  /** retries of current request */\r
+  u8_t tries;\r
+  /** transaction identifier of last sent request */\r
+  u32_t xid;\r
+  /** our connection to the DHCP server */\r
+  struct udp_pcb *pcb;\r
+  /** (first) pbuf of incoming msg */\r
+  struct pbuf *p;\r
+  /** incoming msg */\r
+  struct dhcp_msg *msg_in;\r
+  /** incoming msg options */\r
+  struct dhcp_msg *options_in;\r
+  /** ingoing msg options length */\r
+  u16_t options_in_len;\r
+\r
+  struct pbuf *p_out; /* pbuf of outcoming msg */\r
+  struct dhcp_msg *msg_out; /* outgoing msg */\r
+  u16_t options_out_len; /* outgoing msg options length */\r
+  u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */\r
+  u16_t t1_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */\r
+  u16_t t2_timeout;  /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */\r
+  struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */\r
+  struct ip_addr offered_ip_addr;\r
+  struct ip_addr offered_sn_mask;\r
+  struct ip_addr offered_gw_addr;\r
+  struct ip_addr offered_bc_addr;\r
+#define DHCP_MAX_DNS 2\r
+  u32_t dns_count; /* actual number of DNS servers obtained */\r
+  struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */\r
+\r
+  u32_t offered_t0_lease; /* lease period (in seconds) */\r
+  u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */\r
+  u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period)  */\r
+#if LWIP_DHCP_AUTOIP_COOP\r
+  u8_t autoip_coop_state;\r
+#endif\r
+/** Patch #1308\r
+ *  TODO: See dhcp.c "TODO"s\r
+ */\r
+#if 0\r
+  struct ip_addr offered_si_addr;\r
+  u8_t *boot_file_name;\r
+#endif\r
+};\r
+\r
+/* MUST be compiled with "pack structs" or equivalent! */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** minimum set of fields of any DHCP message */\r
+struct dhcp_msg\r
+{\r
+  PACK_STRUCT_FIELD(u8_t op);\r
+  PACK_STRUCT_FIELD(u8_t htype);\r
+  PACK_STRUCT_FIELD(u8_t hlen);\r
+  PACK_STRUCT_FIELD(u8_t hops);\r
+  PACK_STRUCT_FIELD(u32_t xid);\r
+  PACK_STRUCT_FIELD(u16_t secs);\r
+  PACK_STRUCT_FIELD(u16_t flags);\r
+  PACK_STRUCT_FIELD(struct ip_addr ciaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr yiaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr siaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr giaddr);\r
+#define DHCP_CHADDR_LEN 16U\r
+  PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);\r
+#define DHCP_SNAME_LEN 64U\r
+  PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);\r
+#define DHCP_FILE_LEN 128U\r
+  PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);\r
+  PACK_STRUCT_FIELD(u32_t cookie);\r
+#define DHCP_MIN_OPTIONS_LEN 68U\r
+/** make sure user does not configure this too small */\r
+#if ((defined(DHCP_OPTIONS_LEN)) && (DHCP_OPTIONS_LEN < DHCP_MIN_OPTIONS_LEN))\r
+#  undef DHCP_OPTIONS_LEN\r
+#endif\r
+/** allow this to be configured in lwipopts.h, but not too small */\r
+#if (!defined(DHCP_OPTIONS_LEN))\r
+/** set this to be sufficient for your options in outgoing DHCP msgs */\r
+#  define DHCP_OPTIONS_LEN DHCP_MIN_OPTIONS_LEN\r
+#endif\r
+  PACK_STRUCT_FIELD(u8_t options[DHCP_OPTIONS_LEN]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/** start DHCP configuration */\r
+err_t dhcp_start(struct netif *netif);\r
+/** enforce early lease renewal (not needed normally)*/\r
+err_t dhcp_renew(struct netif *netif);\r
+/** release the DHCP lease, usually called before dhcp_stop()*/\r
+err_t dhcp_release(struct netif *netif);\r
+/** stop DHCP configuration */\r
+void dhcp_stop(struct netif *netif);\r
+/** inform server of our manual IP address */\r
+void dhcp_inform(struct netif *netif);\r
+\r
+/** if enabled, check whether the offered IP address is not in use, using ARP */\r
+#if DHCP_DOES_ARP_CHECK\r
+void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);\r
+#endif\r
+\r
+/** to be called every minute */\r
+void dhcp_coarse_tmr(void);\r
+/** to be called every half second */\r
+void dhcp_fine_tmr(void);\r
+\r
+/** DHCP message item offsets and length */\r
+#define DHCP_MSG_OFS (UDP_DATA_OFS)\r
+  #define DHCP_OP_OFS (DHCP_MSG_OFS + 0)\r
+  #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)\r
+  #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)\r
+  #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)\r
+  #define DHCP_XID_OFS (DHCP_MSG_OFS + 4)\r
+  #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)\r
+  #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)\r
+  #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)\r
+  #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)\r
+  #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)\r
+  #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)\r
+  #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)\r
+  #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)\r
+  #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)\r
+#define DHCP_MSG_LEN 236\r
+\r
+#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)\r
+#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)\r
+\r
+#define DHCP_CLIENT_PORT 68\r
+#define DHCP_SERVER_PORT 67\r
+\r
+/** DHCP client states */\r
+#define DHCP_REQUESTING 1\r
+#define DHCP_INIT 2\r
+#define DHCP_REBOOTING 3\r
+#define DHCP_REBINDING 4\r
+#define DHCP_RENEWING 5\r
+#define DHCP_SELECTING 6\r
+#define DHCP_INFORMING 7\r
+#define DHCP_CHECKING 8\r
+#define DHCP_PERMANENT 9\r
+#define DHCP_BOUND 10\r
+/** not yet implemented #define DHCP_RELEASING 11 */\r
+#define DHCP_BACKING_OFF 12\r
+#define DHCP_OFF 13\r
+\r
+/** AUTOIP cooperatation flags */\r
+#define DHCP_AUTOIP_COOP_STATE_OFF 0\r
+#define DHCP_AUTOIP_COOP_STATE_ON 1\r
+\r
+#define DHCP_BOOTREQUEST 1\r
+#define DHCP_BOOTREPLY 2\r
+\r
+#define DHCP_DISCOVER 1\r
+#define DHCP_OFFER 2\r
+#define DHCP_REQUEST 3\r
+#define DHCP_DECLINE 4\r
+#define DHCP_ACK 5\r
+#define DHCP_NAK 6\r
+#define DHCP_RELEASE 7\r
+#define DHCP_INFORM 8\r
+\r
+#define DHCP_HTYPE_ETH 1\r
+\r
+#define DHCP_HLEN_ETH 6\r
+\r
+#define DHCP_BROADCAST_FLAG 15\r
+#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)\r
+\r
+/** BootP options */\r
+#define DHCP_OPTION_PAD 0\r
+#define DHCP_OPTION_SUBNET_MASK 1 /* RFC 2132 3.3 */\r
+#define DHCP_OPTION_ROUTER 3\r
+#define DHCP_OPTION_DNS_SERVER 6\r
+#define DHCP_OPTION_HOSTNAME 12\r
+#define DHCP_OPTION_IP_TTL 23\r
+#define DHCP_OPTION_MTU 26\r
+#define DHCP_OPTION_BROADCAST 28\r
+#define DHCP_OPTION_TCP_TTL 37\r
+#define DHCP_OPTION_END 255\r
+\r
+/** DHCP options */\r
+#define DHCP_OPTION_REQUESTED_IP 50 /* RFC 2132 9.1, requested IP address */\r
+#define DHCP_OPTION_LEASE_TIME 51 /* RFC 2132 9.2, time in seconds, in 4 bytes */\r
+#define DHCP_OPTION_OVERLOAD 52 /* RFC2132 9.3, use file and/or sname field for options */\r
+\r
+#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */\r
+#define DHCP_OPTION_MESSAGE_TYPE_LEN 1\r
+\r
+\r
+#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */\r
+#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */\r
+\r
+#define DHCP_OPTION_MAX_MSG_SIZE 57 /* RFC 2132 9.10, message size accepted >= 576 */\r
+#define DHCP_OPTION_MAX_MSG_SIZE_LEN 2\r
+\r
+#define DHCP_OPTION_T1 58 /* T1 renewal time */\r
+#define DHCP_OPTION_T2 59 /* T2 rebinding time */\r
+#define DHCP_OPTION_US 60\r
+#define DHCP_OPTION_CLIENT_ID 61\r
+#define DHCP_OPTION_TFTP_SERVERNAME 66\r
+#define DHCP_OPTION_BOOTFILE 67\r
+\r
+/** possible combinations of overloading the file and sname fields with options */\r
+#define DHCP_OVERLOAD_NONE 0\r
+#define DHCP_OVERLOAD_FILE 1\r
+#define DHCP_OVERLOAD_SNAME  2\r
+#define DHCP_OVERLOAD_SNAME_FILE 3\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_DHCP */\r
+\r
+#endif /*__LWIP_DHCP_H__*/\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/dns.h
new file mode 100644 (file)
index 0000000..851fe58
--- /dev/null
@@ -0,0 +1,92 @@
+/**\r
+ * lwip DNS resolver header file.\r
+\r
+ * Author: Jim Pettinato\r
+ *   April 2007\r
+\r
+ * ported from uIP resolv.c Copyright (c) 2002-2003, Adam Dunkels.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote\r
+ *    products derived from this software without specific prior\r
+ *    written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS\r
+ * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\r
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE\r
+ * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,\r
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#ifndef __LWIP_DNS_H__\r
+#define __LWIP_DNS_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */\r
+\r
+/** DNS timer period */\r
+#define DNS_TMR_INTERVAL          1000\r
+\r
+/** DNS field TYPE used for "Resource Records" */\r
+#define DNS_RRTYPE_A              1     /* a host address */\r
+#define DNS_RRTYPE_NS             2     /* an authoritative name server */\r
+#define DNS_RRTYPE_MD             3     /* a mail destination (Obsolete - use MX) */\r
+#define DNS_RRTYPE_MF             4     /* a mail forwarder (Obsolete - use MX) */\r
+#define DNS_RRTYPE_CNAME          5     /* the canonical name for an alias */\r
+#define DNS_RRTYPE_SOA            6     /* marks the start of a zone of authority */\r
+#define DNS_RRTYPE_MB             7     /* a mailbox domain name (EXPERIMENTAL) */\r
+#define DNS_RRTYPE_MG             8     /* a mail group member (EXPERIMENTAL) */\r
+#define DNS_RRTYPE_MR             9     /* a mail rename domain name (EXPERIMENTAL) */\r
+#define DNS_RRTYPE_NULL           10    /* a null RR (EXPERIMENTAL) */\r
+#define DNS_RRTYPE_WKS            11    /* a well known service description */\r
+#define DNS_RRTYPE_PTR            12    /* a domain name pointer */\r
+#define DNS_RRTYPE_HINFO          13    /* host information */\r
+#define DNS_RRTYPE_MINFO          14    /* mailbox or mail list information */\r
+#define DNS_RRTYPE_MX             15    /* mail exchange */\r
+#define DNS_RRTYPE_TXT            16    /* text strings */\r
+\r
+/** DNS field CLASS used for "Resource Records" */\r
+#define DNS_RRCLASS_IN            1     /* the Internet */\r
+#define DNS_RRCLASS_CS            2     /* the CSNET class (Obsolete - used only for examples in some obsolete RFCs) */\r
+#define DNS_RRCLASS_CH            3     /* the CHAOS class */\r
+#define DNS_RRCLASS_HS            4     /* Hesiod [Dyer 87] */\r
+#define DNS_RRCLASS_FLUSH         0x800 /* Flush bit */\r
+\r
+/** Callback which is invoked when a hostname is found.\r
+ * A function of this type must be implemented by the application using the DNS resolver.\r
+ * @param name pointer to the name that was looked up.\r
+ * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,\r
+ *        or NULL if the name could not be found (or on any other error).\r
+ * @param callback_arg a user-specified callback argument passed to dns_gethostbyname\r
+*/\r
+typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);\r
+\r
+\r
+void           dns_init(void);\r
+\r
+void           dns_tmr(void);\r
+\r
+void           dns_setserver(u8_t numdns, struct ip_addr *dnsserver);\r
+\r
+struct ip_addr dns_getserver(u8_t numdns);\r
+\r
+err_t          dns_gethostbyname(const char *hostname, struct ip_addr *addr,\r
+                                 dns_found_callback found, void *callback_arg);\r
+\r
+#endif /* LWIP_DNS */\r
+\r
+#endif /* __LWIP_DNS_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/err.h
new file mode 100644 (file)
index 0000000..1685fa9
--- /dev/null
@@ -0,0 +1,81 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_ERR_H__\r
+#define __LWIP_ERR_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+typedef s8_t err_t;\r
+\r
+/* Definitions for error constants. */\r
+\r
+#define ERR_OK          0    /* No error, everything OK. */\r
+#define ERR_MEM        -1    /* Out of memory error.     */\r
+#define ERR_BUF        -2    /* Buffer error.            */\r
+#define ERR_RTE        -3    /* Routing problem.         */\r
+\r
+#define ERR_IS_FATAL(e) ((e) < ERR_RTE)\r
+\r
+#define ERR_ABRT       -4    /* Connection aborted.      */\r
+#define ERR_RST        -5    /* Connection reset.        */\r
+#define ERR_CLSD       -6    /* Connection closed.       */\r
+#define ERR_CONN       -7    /* Not connected.           */\r
+\r
+#define ERR_VAL        -8    /* Illegal value.           */\r
+\r
+#define ERR_ARG        -9    /* Illegal argument.        */\r
+\r
+#define ERR_USE        -10   /* Address in use.          */\r
+\r
+#define ERR_IF         -11   /* Low-level netif error    */\r
+#define ERR_ISCONN     -12   /* Already connected.       */\r
+\r
+#define ERR_TIMEOUT    -13   /* Timeout.                 */\r
+\r
+#define ERR_INPROGRESS -14   /* Operation in progress    */\r
+\r
+\r
+#ifdef LWIP_DEBUG\r
+extern const char *lwip_strerr(err_t err);\r
+#else\r
+#define lwip_strerr(x) ""\r
+#endif /* LWIP_DEBUG */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_ERR_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/init.h
new file mode 100644 (file)
index 0000000..7fe5799
--- /dev/null
@@ -0,0 +1,48 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_INIT_H__\r
+#define __LWIP_INIT_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* Modules initialization */\r
+void lwip_init(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_INIT_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/mem.h
new file mode 100644 (file)
index 0000000..21c48f8
--- /dev/null
@@ -0,0 +1,103 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_MEM_H__\r
+#define __LWIP_MEM_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if MEM_LIBC_MALLOC\r
+\r
+#include <stddef.h> /* for size_t */\r
+\r
+typedef size_t mem_size_t;\r
+\r
+/* aliases for C library malloc() */\r
+#define mem_init()\r
+/* in case C library malloc() needs extra protection,\r
+ * allow these defines to be overridden.\r
+ */\r
+#ifndef mem_free\r
+#define mem_free(x) free(x)\r
+#endif\r
+#ifndef mem_malloc\r
+#define mem_malloc(x) malloc(x)\r
+#endif\r
+#ifndef mem_calloc\r
+#define mem_calloc(x, y) calloc(x, y)\r
+#endif\r
+#ifndef mem_realloc\r
+#define mem_realloc(x, size) (x)\r
+#endif\r
+#else /* MEM_LIBC_MALLOC */\r
+\r
+/* MEM_SIZE would have to be aligned, but using 64000 here instead of\r
+ * 65535 leaves some room for alignment...\r
+ */\r
+#if MEM_SIZE > 64000l\r
+typedef u32_t mem_size_t;\r
+#else\r
+typedef u16_t mem_size_t;\r
+#endif /* MEM_SIZE > 64000 */\r
+\r
+#if MEM_USE_POOLS\r
+/** mem_init is not used when using pools instead of a heap */\r
+#define mem_init()\r
+/** mem_realloc is not used when using pools instead of a heap:\r
+    we can't free part of a pool element and don't want to copy the rest */\r
+#define mem_realloc(mem, size) (mem)\r
+#else /* MEM_USE_POOLS */\r
+/* lwIP alternative malloc */\r
+void  mem_init(void);\r
+void *mem_realloc(void *mem, mem_size_t size);\r
+#endif /* MEM_USE_POOLS */\r
+void *mem_malloc(mem_size_t size);\r
+void *mem_calloc(mem_size_t count, mem_size_t size);\r
+void  mem_free(void *mem);\r
+#endif /* MEM_LIBC_MALLOC */\r
+\r
+#ifndef LWIP_MEM_ALIGN_SIZE\r
+#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))\r
+#endif\r
+\r
+#ifndef LWIP_MEM_ALIGN\r
+#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_MEM_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp.h
new file mode 100644 (file)
index 0000000..18f8831
--- /dev/null
@@ -0,0 +1,94 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_MEMP_H__\r
+#define __LWIP_MEMP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */\r
+typedef enum {\r
+#define LWIP_MEMPOOL(name,num,size,desc)  MEMP_##name,\r
+#include "lwip/memp_std.h"\r
+  MEMP_MAX\r
+} memp_t;\r
+\r
+#if MEM_USE_POOLS\r
+/* Use a helper type to get the start and end of the user "memory pools" for mem_malloc */\r
+typedef enum {\r
+    /* Get the first (via:\r
+       MEMP_POOL_HELPER_START = ((u8_t) 1*MEMP_POOL_A + 0*MEMP_POOL_B + 0*MEMP_POOL_C + 0)*/\r
+    MEMP_POOL_HELPER_FIRST = ((u8_t)\r
+#define LWIP_MEMPOOL(name,num,size,desc)\r
+#define LWIP_MALLOC_MEMPOOL_START 1\r
+#define LWIP_MALLOC_MEMPOOL(num, size) * MEMP_POOL_##size + 0\r
+#define LWIP_MALLOC_MEMPOOL_END\r
+#include "lwip/memp_std.h"\r
+    ) ,\r
+    /* Get the last (via:\r
+       MEMP_POOL_HELPER_END = ((u8_t) 0 + MEMP_POOL_A*0 + MEMP_POOL_B*0 + MEMP_POOL_C*1) */\r
+    MEMP_POOL_HELPER_LAST = ((u8_t)\r
+#define LWIP_MEMPOOL(name,num,size,desc)\r
+#define LWIP_MALLOC_MEMPOOL_START\r
+#define LWIP_MALLOC_MEMPOOL(num, size) 0 + MEMP_POOL_##size *\r
+#define LWIP_MALLOC_MEMPOOL_END 1\r
+#include "lwip/memp_std.h"\r
+    )\r
+} memp_pool_helper_t;\r
+\r
+/* The actual start and stop values are here (cast them over)\r
+   We use this helper type and these defines so we can avoid using const memp_t values */\r
+#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)\r
+#define MEMP_POOL_LAST   ((memp_t) MEMP_POOL_HELPER_LAST)\r
+\r
+extern const u16_t memp_sizes[MEMP_MAX];\r
+#endif /* MEM_USE_POOLS */\r
+\r
+void  memp_init(void);\r
+\r
+#if MEMP_OVERFLOW_CHECK\r
+void *memp_malloc_fn(memp_t type, const char* file, const int line);\r
+#define memp_malloc(t) memp_malloc_fn((t), __FILE__, __LINE__)\r
+#else\r
+void *memp_malloc(memp_t type);\r
+#endif\r
+void  memp_free(memp_t type, void *mem);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_MEMP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/memp_std.h
new file mode 100644 (file)
index 0000000..ac51813
--- /dev/null
@@ -0,0 +1,101 @@
+/*\r
+ * SETUP: Make sure we define everything we will need.\r
+ *\r
+ * We have create three types of pools:\r
+ *   1) MEMPOOL - standard pools\r
+ *   2) MALLOC_MEMPOOL - to be used by mem_malloc in mem.c\r
+ *   3) PBUF_MEMPOOL - a mempool of pbuf's, so include space for the pbuf struct\r
+ *\r
+ * If the include'r doesn't require any special treatment of each of the types\r
+ * above, then will declare #2 & #3 to be just standard mempools.\r
+ */\r
+#ifndef LWIP_MALLOC_MEMPOOL\r
+/* This treats "malloc pools" just like any other pool */\r
+#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)\r
+#define LWIP_MALLOC_MEMPOOL_START\r
+#define LWIP_MALLOC_MEMPOOL_END\r
+#endif /* LWIP_MALLOC_MEMPOOL */\r
+\r
+#ifndef LWIP_PBUF_MEMPOOL\r
+/* This treats "pbuf pools" just like any other pool.\r
+ * Allocates buffers for a pbuf struct AND a payload size */\r
+#define LWIP_PBUF_MEMPOOL(name, num, payload, desc) LWIP_MEMPOOL(name, num, (MEMP_ALIGN_SIZE(sizeof(struct pbuf)) + MEMP_ALIGN_SIZE(payload)), desc)\r
+#endif /* LWIP_PBUF_MEMPOOL */\r
+\r
+\r
+/*\r
+ * A list of internal pools used by LWIP.\r
+ *\r
+ * LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_description)\r
+ *     creates a pool name MEMP_pool_name. description is used in stats.c\r
+ */\r
+#if LWIP_RAW\r
+LWIP_MEMPOOL(RAW_PCB,        MEMP_NUM_RAW_PCB,         sizeof(struct raw_pcb),        "RAW_PCB")\r
+#endif /* LWIP_RAW */\r
+\r
+#if LWIP_UDP\r
+LWIP_MEMPOOL(UDP_PCB,        MEMP_NUM_UDP_PCB,         sizeof(struct udp_pcb),        "UDP_PCB")\r
+#endif /* LWIP_UDP */\r
+\r
+#if LWIP_TCP\r
+LWIP_MEMPOOL(TCP_PCB,        MEMP_NUM_TCP_PCB,         sizeof(struct tcp_pcb),        "TCP_PCB")\r
+LWIP_MEMPOOL(TCP_PCB_LISTEN, MEMP_NUM_TCP_PCB_LISTEN,  sizeof(struct tcp_pcb_listen), "TCP_PCB_LISTEN")\r
+LWIP_MEMPOOL(TCP_SEG,        MEMP_NUM_TCP_SEG,         sizeof(struct tcp_seg),        "TCP_SEG")\r
+#endif /* LWIP_TCP */\r
+\r
+#if IP_REASSEMBLY\r
+LWIP_MEMPOOL(REASSDATA,      MEMP_NUM_REASSDATA,       sizeof(struct ip_reassdata),   "REASSDATA")\r
+#endif /* IP_REASSEMBLY */\r
+\r
+#if LWIP_NETCONN\r
+LWIP_MEMPOOL(NETBUF,         MEMP_NUM_NETBUF,          sizeof(struct netbuf),         "NETBUF")\r
+LWIP_MEMPOOL(NETCONN,        MEMP_NUM_NETCONN,         sizeof(struct netconn),        "NETCONN")\r
+#endif /* LWIP_NETCONN */\r
+\r
+#if NO_SYS==0\r
+LWIP_MEMPOOL(TCPIP_MSG_API,  MEMP_NUM_TCPIP_MSG_API,   sizeof(struct tcpip_msg),      "TCPIP_MSG_API")\r
+LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg),      "TCPIP_MSG_INPKT")\r
+#endif /* NO_SYS==0 */\r
+\r
+#if ARP_QUEUEING\r
+LWIP_MEMPOOL(ARP_QUEUE,      MEMP_NUM_ARP_QUEUE,       sizeof(struct etharp_q_entry), "ARP_QUEUE")\r
+#endif /* ARP_QUEUEING */\r
+\r
+#if LWIP_IGMP\r
+LWIP_MEMPOOL(IGMP_GROUP,     MEMP_NUM_IGMP_GROUP,      sizeof(struct igmp_group),     "IGMP_GROUP")\r
+#endif /* LWIP_IGMP */\r
+\r
+#if NO_SYS==0\r
+LWIP_MEMPOOL(SYS_TIMEOUT,    MEMP_NUM_SYS_TIMEOUT,     sizeof(struct sys_timeo),      "SYS_TIMEOUT")\r
+#endif /* NO_SYS==0 */\r
+\r
+\r
+/*\r
+ * A list of pools of pbuf's used by LWIP.\r
+ *\r
+ * LWIP_PBUF_MEMPOOL(pool_name, number_elements, pbuf_payload_size, pool_description)\r
+ *     creates a pool name MEMP_pool_name. description is used in stats.c\r
+ *     This allocates enough space for the pbuf struct and a payload.\r
+ *     (Example: pbuf_payload_size=0 allocates only size for the struct)\r
+ */\r
+LWIP_PBUF_MEMPOOL(PBUF,      MEMP_NUM_PBUF,            0,                             "PBUF_REF/ROM")\r
+LWIP_PBUF_MEMPOOL(PBUF_POOL, PBUF_POOL_SIZE,           PBUF_POOL_BUFSIZE,             "PBUF_POOL")\r
+\r
+\r
+/*\r
+ * Allow for user-defined pools; this must be explicitly set in lwipopts.h\r
+ * since the default is to NOT look for lwippools.h\r
+ */\r
+#if MEMP_USE_CUSTOM_POOLS\r
+#include "lwippools.h"\r
+#endif /* MEMP_USE_CUSTOM_POOLS */\r
+\r
+/*\r
+ * REQUIRED CLEANUP: Clear up so we don't get "multiply defined" error later\r
+ * (#undef is ignored for something that is not defined)\r
+ */\r
+#undef LWIP_MEMPOOL\r
+#undef LWIP_MALLOC_MEMPOOL\r
+#undef LWIP_MALLOC_MEMPOOL_START\r
+#undef LWIP_MALLOC_MEMPOOL_END\r
+#undef LWIP_PBUF_MEMPOOL\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/netbuf.h
new file mode 100644 (file)
index 0000000..131f8a3
--- /dev/null
@@ -0,0 +1,76 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_NETBUF_H__\r
+#define __LWIP_NETBUF_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/pbuf.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+struct netbuf {\r
+  struct pbuf *p, *ptr;\r
+  struct ip_addr *addr;\r
+  u16_t port;\r
+};\r
+\r
+/* Network buffer functions: */\r
+struct netbuf *   netbuf_new      (void);\r
+void              netbuf_delete   (struct netbuf *buf);\r
+void *            netbuf_alloc    (struct netbuf *buf, u16_t size);\r
+void              netbuf_free     (struct netbuf *buf);\r
+err_t             netbuf_ref      (struct netbuf *buf,\r
+           const void *dataptr, u16_t size);\r
+void              netbuf_chain    (struct netbuf *head,\r
+           struct netbuf *tail);\r
+\r
+u16_t             netbuf_len      (struct netbuf *buf);\r
+err_t             netbuf_data     (struct netbuf *buf,\r
+           void **dataptr, u16_t *len);\r
+s8_t              netbuf_next     (struct netbuf *buf);\r
+void              netbuf_first    (struct netbuf *buf);\r
+\r
+\r
+#define netbuf_copy_partial(buf, dataptr, len, offset) \\r
+  pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))\r
+#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)\r
+#define netbuf_len(buf)              ((buf)->p->tot_len)\r
+#define netbuf_fromaddr(buf)         ((buf)->addr)\r
+#define netbuf_fromport(buf)         ((buf)->port)\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_NETBUF_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/netdb.h
new file mode 100644 (file)
index 0000000..f344b31
--- /dev/null
@@ -0,0 +1,109 @@
+/*\r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Simon Goldschmidt\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_DNS && LWIP_SOCKET\r
+\r
+#include "lwip/sockets.h"\r
+\r
+/* some rarely used options */\r
+#ifndef LWIP_DNS_API_DECLARE_H_ERRNO\r
+#define LWIP_DNS_API_DECLARE_H_ERRNO 1\r
+#endif\r
+\r
+#ifndef LWIP_DNS_API_DEFINE_ERRORS\r
+#define LWIP_DNS_API_DEFINE_ERRORS 1\r
+#endif\r
+\r
+#ifndef LWIP_DNS_API_DECLARE_STRUCTS\r
+#define LWIP_DNS_API_DECLARE_STRUCTS 1\r
+#endif\r
+\r
+#if LWIP_DNS_API_DEFINE_ERRORS\r
+/** Errors used by the DNS API functions, h_errno can be one of them */\r
+#define EAI_NONAME      200\r
+#define EAI_SERVICE     201\r
+#define EAI_FAIL        202\r
+#define EAI_MEMORY      203\r
+\r
+#define HOST_NOT_FOUND  210\r
+#define NO_DATA         211\r
+#define NO_RECOVERY     212\r
+#define TRY_AGAIN       213\r
+#endif /* LWIP_DNS_API_DEFINE_ERRORS */\r
+\r
+#if LWIP_DNS_API_DECLARE_STRUCTS\r
+struct hostent {\r
+    char  *h_name;      /* Official name of the host. */\r
+    char **h_aliases;   /* A pointer to an array of pointers to alternative host names,\r
+                           terminated by a null pointer. */\r
+    int    h_addrtype;  /* Address type. */\r
+    int    h_length;    /* The length, in bytes, of the address. */\r
+    char **h_addr_list; /* A pointer to an array of pointers to network addresses (in\r
+                           network byte order) for the host, terminated by a null pointer. */\r
+#define h_addr h_addr_list[0] /* for backward compatibility */\r
+};\r
+\r
+struct addrinfo {\r
+    int               ai_flags;      /* Input flags. */\r
+    int               ai_family;     /* Address family of socket. */\r
+    int               ai_socktype;   /* Socket type. */\r
+    int               ai_protocol;   /* Protocol of socket. */\r
+    socklen_t         ai_addrlen;    /* Length of socket address. */\r
+    struct sockaddr  *ai_addr;       /* Socket address of socket. */\r
+    char             *ai_canonname;  /* Canonical name of service location. */\r
+    struct addrinfo  *ai_next;       /* Pointer to next in list. */\r
+};\r
+#endif /* LWIP_DNS_API_DECLARE_STRUCTS */\r
+\r
+#if LWIP_DNS_API_DECLARE_H_ERRNO\r
+/* application accessable error code set by the DNS API functions */\r
+extern int h_errno;\r
+#endif /* LWIP_DNS_API_DECLARE_H_ERRNO*/\r
+\r
+struct hostent *lwip_gethostbyname(const char *name);\r
+int lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf,\r
+                size_t buflen, struct hostent **result, int *h_errnop);\r
+void lwip_freeaddrinfo(struct addrinfo *ai);\r
+int lwip_getaddrinfo(const char *nodename,\r
+       const char *servname,\r
+       const struct addrinfo *hints,\r
+       struct addrinfo **res);\r
+\r
+#if LWIP_COMPAT_SOCKETS\r
+#define gethostbyname(name) lwip_gethostbyname(name)\r
+#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \\r
+       lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)\r
+#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)\r
+#define getaddrinfo(nodname, servname, hints, res) \\r
+       lwip_getaddrinfo(nodname, servname, hints, res)\r
+#endif /* LWIP_COMPAT_SOCKETS */\r
+\r
+#endif /* LWIP_DNS && LWIP_SOCKET */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/netif.h
new file mode 100644 (file)
index 0000000..d8a59ae
--- /dev/null
@@ -0,0 +1,245 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_NETIF_H__\r
+#define __LWIP_NETIF_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/err.h"\r
+\r
+#include "lwip/ip_addr.h"\r
+\r
+#include "lwip/inet.h"\r
+#include "lwip/pbuf.h"\r
+#if LWIP_DHCP\r
+struct dhcp;\r
+#endif\r
+#if LWIP_AUTOIP\r
+struct autoip;\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* Throughout this file, IP addresses are expected to be in\r
+ * the same byte order as in IP_PCB. */\r
+\r
+/** must be the maximum of all used hardware address lengths\r
+    across all types of interfaces in use */\r
+#define NETIF_MAX_HWADDR_LEN 6U\r
+\r
+/** TODO: define the use (where, when, whom) of netif flags */\r
+\r
+/** whether the network interface is 'up'. this is\r
+ * a software flag used to control whether this network\r
+ * interface is enabled and processes traffic.\r
+ */\r
+#define NETIF_FLAG_UP           0x01U\r
+/** if set, the netif has broadcast capability */\r
+#define NETIF_FLAG_BROADCAST    0x02U\r
+/** if set, the netif is one end of a point-to-point connection */\r
+#define NETIF_FLAG_POINTTOPOINT 0x04U\r
+/** if set, the interface is configured using DHCP */\r
+#define NETIF_FLAG_DHCP         0x08U\r
+/** if set, the interface has an active link\r
+ *  (set by the network interface driver) */\r
+#define NETIF_FLAG_LINK_UP      0x10U\r
+/** if set, the netif is an device using ARP */\r
+#define NETIF_FLAG_ETHARP       0x20U\r
+/** if set, the netif has IGMP capability */\r
+#define NETIF_FLAG_IGMP         0x40U\r
+\r
+/** Generic data structure used for all lwIP network interfaces.\r
+ *  The following fields should be filled in by the initialization\r
+ *  function for the device driver: hwaddr_len, hwaddr[], mtu, flags */\r
+\r
+struct netif {\r
+  /** pointer to next in linked list */\r
+  struct netif *next;\r
+\r
+  /** IP address configuration in network byte order */\r
+  struct ip_addr ip_addr;\r
+  struct ip_addr netmask;\r
+  struct ip_addr gw;\r
+\r
+  /** This function is called by the network device driver\r
+   *  to pass a packet up the TCP/IP stack. */\r
+  err_t (* input)(struct pbuf *p, struct netif *inp);\r
+  /** This function is called by the IP module when it wants\r
+   *  to send a packet on the interface. This function typically\r
+   *  first resolves the hardware address, then sends the packet. */\r
+  err_t (* output)(struct netif *netif, struct pbuf *p,\r
+       struct ip_addr *ipaddr);\r
+  /** This function is called by the ARP module when it wants\r
+   *  to send a packet on the interface. This function outputs\r
+   *  the pbuf as-is on the link medium. */\r
+  err_t (* linkoutput)(struct netif *netif, struct pbuf *p);\r
+#if LWIP_NETIF_STATUS_CALLBACK\r
+  /** This function is called when the netif state is set to up or down\r
+   */\r
+  void (* status_callback)(struct netif *netif);\r
+#endif /* LWIP_NETIF_STATUS_CALLBACK */\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+  /** This function is called when the netif link is set to up or down\r
+   */\r
+  void (* link_callback)(struct netif *netif);\r
+#endif /* LWIP_NETIF_LINK_CALLBACK */\r
+  /** This field can be set by the device driver and could point\r
+   *  to state information for the device. */\r
+  void *state;\r
+#if LWIP_DHCP\r
+  /** the DHCP client state information for this netif */\r
+  struct dhcp *dhcp;\r
+#endif /* LWIP_DHCP */\r
+#if LWIP_AUTOIP\r
+  /** the AutoIP client state information for this netif */\r
+  struct autoip *autoip;\r
+#endif\r
+#if LWIP_NETIF_HOSTNAME\r
+  /* the hostname for this netif, NULL is a valid value */\r
+  char*  hostname;\r
+#endif /* LWIP_NETIF_HOSTNAME */\r
+  /** number of bytes used in hwaddr */\r
+  u8_t hwaddr_len;\r
+  /** link level hardware address of this interface */\r
+  u8_t hwaddr[NETIF_MAX_HWADDR_LEN];\r
+  /** maximum transfer unit (in bytes) */\r
+  u16_t mtu;\r
+  /** flags (see NETIF_FLAG_ above) */\r
+  u8_t flags;\r
+  /** descriptive abbreviation */\r
+  char name[2];\r
+  /** number of this interface */\r
+  u8_t num;\r
+#if LWIP_SNMP\r
+  /** link type (from "snmp_ifType" enum from snmp.h) */\r
+  u8_t link_type;\r
+  /** (estimate) link speed */\r
+  u32_t link_speed;\r
+  /** timestamp at last change made (up/down) */\r
+  u32_t ts;\r
+  /** counters */\r
+  u32_t ifinoctets;\r
+  u32_t ifinucastpkts;\r
+  u32_t ifinnucastpkts;\r
+  u32_t ifindiscards;\r
+  u32_t ifoutoctets;\r
+  u32_t ifoutucastpkts;\r
+  u32_t ifoutnucastpkts;\r
+  u32_t ifoutdiscards;\r
+#endif /* LWIP_SNMP */\r
+#if LWIP_IGMP\r
+  /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/\r
+  err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);\r
+#endif /* LWIP_IGMP */\r
+#if LWIP_NETIF_HWADDRHINT\r
+  u8_t *addr_hint;\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+};\r
+\r
+#if LWIP_SNMP\r
+#define NETIF_INIT_SNMP(netif, type, speed) \\r
+  /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \\r
+  netif->link_type = type;    \\r
+  /* your link speed here (units: bits per second) */  \\r
+  netif->link_speed = speed;  \\r
+  netif->ts = 0;              \\r
+  netif->ifinoctets = 0;      \\r
+  netif->ifinucastpkts = 0;   \\r
+  netif->ifinnucastpkts = 0;  \\r
+  netif->ifindiscards = 0;    \\r
+  netif->ifoutoctets = 0;     \\r
+  netif->ifoutucastpkts = 0;  \\r
+  netif->ifoutnucastpkts = 0; \\r
+  netif->ifoutdiscards = 0\r
+#else /* LWIP_SNMP */\r
+#define NETIF_INIT_SNMP(netif, type, speed)\r
+#endif /* LWIP_SNMP */\r
+\r
+\r
+/** The list of network interfaces. */\r
+extern struct netif *netif_list;\r
+/** The default network interface. */\r
+extern struct netif *netif_default;\r
+\r
+#define netif_init() /* Compatibility define, not init needed. */\r
+\r
+struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+      struct ip_addr *gw,\r
+      void *state,\r
+      err_t (* init)(struct netif *netif),\r
+      err_t (* input)(struct pbuf *p, struct netif *netif));\r
+\r
+void\r
+netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,\r
+    struct ip_addr *gw);\r
+void netif_remove(struct netif * netif);\r
+\r
+/* Returns a network interface given its name. The name is of the form\r
+   "et0", where the first two letters are the "name" field in the\r
+   netif structure, and the digit is in the num field in the same\r
+   structure. */\r
+struct netif *netif_find(char *name);\r
+\r
+void netif_set_default(struct netif *netif);\r
+\r
+void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);\r
+void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);\r
+void netif_set_gw(struct netif *netif, struct ip_addr *gw);\r
+\r
+void netif_set_up(struct netif *netif);\r
+void netif_set_down(struct netif *netif);\r
+u8_t netif_is_up(struct netif *netif);\r
+\r
+#if LWIP_NETIF_STATUS_CALLBACK\r
+/*\r
+ * Set callback to be called when interface is brought up/down\r
+ */\r
+void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));\r
+#endif /* LWIP_NETIF_STATUS_CALLBACK */\r
+\r
+#if LWIP_NETIF_LINK_CALLBACK\r
+void netif_set_link_up(struct netif *netif);\r
+void netif_set_link_down(struct netif *netif);\r
+u8_t netif_is_link_up(struct netif *netif);\r
+/*\r
+ * Set callback to be called when link is brought up/down\r
+ */\r
+void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));\r
+#endif /* LWIP_NETIF_LINK_CALLBACK */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_NETIF_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/netifapi.h
new file mode 100644 (file)
index 0000000..88f8d31
--- /dev/null
@@ -0,0 +1,100 @@
+/*\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_NETIFAPI_H__\r
+#define __LWIP_NETIFAPI_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_NETIF_API /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/dhcp.h"\r
+#include "lwip/autoip.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+struct netifapi_msg_msg {\r
+#if !LWIP_TCPIP_CORE_LOCKING\r
+  sys_sem_t sem;\r
+#endif /* !LWIP_TCPIP_CORE_LOCKING */\r
+  err_t err;\r
+  struct netif *netif;\r
+  union {\r
+    struct {\r
+      struct ip_addr *ipaddr;\r
+      struct ip_addr *netmask;\r
+      struct ip_addr *gw;\r
+      void *state;\r
+      err_t (* init) (struct netif *netif);\r
+      err_t (* input)(struct pbuf *p, struct netif *netif);\r
+    } add;\r
+    struct {\r
+      void  (* voidfunc)(struct netif *netif);\r
+      err_t (* errtfunc)(struct netif *netif);\r
+    } common;\r
+  } msg;\r
+};\r
+\r
+struct netifapi_msg {\r
+  void (* function)(struct netifapi_msg_msg *msg);\r
+  struct netifapi_msg_msg msg;\r
+};\r
+\r
+\r
+/* API for application */\r
+err_t netifapi_netif_add       ( struct netif *netif,\r
+                                 struct ip_addr *ipaddr,\r
+                                 struct ip_addr *netmask,\r
+                                 struct ip_addr *gw,\r
+                                 void *state,\r
+                                 err_t (* init)(struct netif *netif),\r
+                                 err_t (* input)(struct pbuf *p, struct netif *netif) );\r
+\r
+err_t netifapi_netif_common    ( struct netif *netif,\r
+                                 void  (* voidfunc)(struct netif *netif),\r
+                                 err_t (* errtfunc)(struct netif *netif) );\r
+\r
+#define netifapi_netif_remove(n)      netifapi_netif_common(n, netif_remove, NULL)\r
+#define netifapi_netif_set_up(n)      netifapi_netif_common(n, netif_set_up, NULL)\r
+#define netifapi_netif_set_down(n)    netifapi_netif_common(n, netif_set_down, NULL)\r
+#define netifapi_netif_set_default(n) netifapi_netif_common(n, netif_set_default, NULL)\r
+#define netifapi_dhcp_start(n)        netifapi_netif_common(n, NULL, dhcp_start)\r
+#define netifapi_dhcp_stop(n)         netifapi_netif_common(n, dhcp_stop, NULL)\r
+#define netifapi_autoip_start(n)      netifapi_netif_common(n, NULL, autoip_start)\r
+#define netifapi_autoip_stop(n)       netifapi_netif_common(n, NULL, autoip_stop)\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_NETIF_API */\r
+\r
+#endif /* __LWIP_NETIFAPI_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/opt.h
new file mode 100644 (file)
index 0000000..98058b4
--- /dev/null
@@ -0,0 +1,1654 @@
+/**\r
+ * @file\r
+ *\r
+ * lwIP Options Configuration\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_OPT_H__\r
+#define __LWIP_OPT_H__\r
+\r
+/*\r
+ * Include user defined options first. Anything not defined in these files\r
+ * will be set to standard values. Override anything you dont like!\r
+ */\r
+#include "lwipopts.h"\r
+#include "lwip/debug.h"\r
+\r
+/*\r
+   -----------------------------------------------\r
+   ---------- Platform specific locking ----------\r
+   -----------------------------------------------\r
+*/\r
+\r
+/**\r
+ * SYS_LIGHTWEIGHT_PROT==1: if you want inter-task protection for certain\r
+ * critical regions during buffer allocation, deallocation and memory\r
+ * allocation and deallocation.\r
+ */\r
+#ifndef SYS_LIGHTWEIGHT_PROT\r
+#define SYS_LIGHTWEIGHT_PROT            0\r
+#endif\r
+\r
+/**\r
+ * NO_SYS==1: Provides VERY minimal functionality. Otherwise,\r
+ * use lwIP facilities.\r
+ */\r
+#ifndef NO_SYS\r
+#define NO_SYS                          0\r
+#endif\r
+\r
+/**\r
+ * MEMCPY: override this if you have a faster implementation at hand than the\r
+ * one included in your C library\r
+ */\r
+#ifndef MEMCPY\r
+#define MEMCPY(dst,src,len)             memcpy(dst,src,len)\r
+#endif\r
+\r
+/**\r
+ * SMEMCPY: override this with care! Some compilers (e.g. gcc) can inline a\r
+ * call to memcpy() if the length is known at compile time and is small.\r
+ */\r
+#ifndef SMEMCPY\r
+#define SMEMCPY(dst,src,len)            memcpy(dst,src,len)\r
+#endif\r
+\r
+/*\r
+   ------------------------------------\r
+   ---------- Memory options ----------\r
+   ------------------------------------\r
+*/\r
+/**\r
+ * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library\r
+ * instead of the lwip internal allocator. Can save code size if you\r
+ * already use it.\r
+ */\r
+#ifndef MEM_LIBC_MALLOC\r
+#define MEM_LIBC_MALLOC                 0\r
+#endif\r
+\r
+/**\r
+ * MEM_ALIGNMENT: should be set to the alignment of the CPU\r
+ *    4 byte alignment -> #define MEM_ALIGNMENT 4\r
+ *    2 byte alignment -> #define MEM_ALIGNMENT 2\r
+ */\r
+#ifndef MEM_ALIGNMENT\r
+#define MEM_ALIGNMENT                   1\r
+#endif\r
+\r
+/**\r
+ * MEM_SIZE: the size of the heap memory. If the application will send\r
+ * a lot of data that needs to be copied, this should be set high.\r
+ */\r
+#ifndef MEM_SIZE\r
+#define MEM_SIZE                        1600\r
+#endif\r
+\r
+/**\r
+ * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable\r
+ * amount of bytes before and after each memp element in every pool and fills\r
+ * it with a prominent default value.\r
+ *    MEMP_OVERFLOW_CHECK == 0 no checking\r
+ *    MEMP_OVERFLOW_CHECK == 1 checks each element when it is freed\r
+ *    MEMP_OVERFLOW_CHECK >= 2 checks each element in every pool every time\r
+ *      memp_malloc() or memp_free() is called (useful but slow!)\r
+ */\r
+#ifndef MEMP_OVERFLOW_CHECK\r
+#define MEMP_OVERFLOW_CHECK             0\r
+#endif\r
+\r
+/**\r
+ * MEMP_SANITY_CHECK==1: run a sanity check after each memp_free() to make\r
+ * sure that there are no cycles in the linked lists.\r
+ */\r
+#ifndef MEMP_SANITY_CHECK\r
+#define MEMP_SANITY_CHECK               0\r
+#endif\r
+\r
+/**\r
+ * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set\r
+ * of memory pools of various sizes. When mem_malloc is called, an element of\r
+ * the smallest pool that can provide the lenght needed is returned.\r
+ */\r
+#ifndef MEM_USE_POOLS\r
+#define MEM_USE_POOLS                   0\r
+#endif\r
+\r
+/**\r
+ * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h\r
+ * that defines additional pools beyond the "standard" ones required\r
+ * by lwIP. If you set this to 1, you must have lwippools.h in your\r
+ * inlude path somewhere.\r
+ */\r
+#ifndef MEMP_USE_CUSTOM_POOLS\r
+#define MEMP_USE_CUSTOM_POOLS           0\r
+#endif\r
+\r
+\r
+/*\r
+   ------------------------------------------------\r
+   ---------- Internal Memory Pool Sizes ----------\r
+   ------------------------------------------------\r
+*/\r
+/**\r
+ * MEMP_NUM_PBUF: the number of memp struct pbufs (used for PBUF_ROM and PBUF_REF).\r
+ * If the application sends a lot of data out of ROM (or other static memory),\r
+ * this should be set high.\r
+ */\r
+#ifndef MEMP_NUM_PBUF\r
+#define MEMP_NUM_PBUF                   16\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_RAW_PCB: Number of raw connection PCBs\r
+ * (requires the LWIP_RAW option)\r
+ */\r
+#ifndef MEMP_NUM_RAW_PCB\r
+#define MEMP_NUM_RAW_PCB                4\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One\r
+ * per active UDP "connection".\r
+ * (requires the LWIP_UDP option)\r
+ */\r
+#ifndef MEMP_NUM_UDP_PCB\r
+#define MEMP_NUM_UDP_PCB                4\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_TCP_PCB: the number of simulatenously active TCP connections.\r
+ * (requires the LWIP_TCP option)\r
+ */\r
+#ifndef MEMP_NUM_TCP_PCB\r
+#define MEMP_NUM_TCP_PCB                5\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections.\r
+ * (requires the LWIP_TCP option)\r
+ */\r
+#ifndef MEMP_NUM_TCP_PCB_LISTEN\r
+#define MEMP_NUM_TCP_PCB_LISTEN         8\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments.\r
+ * (requires the LWIP_TCP option)\r
+ */\r
+#ifndef MEMP_NUM_TCP_SEG\r
+#define MEMP_NUM_TCP_SEG                16\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for\r
+ * reassembly (whole packets, not fragments!)\r
+ */\r
+#ifndef MEMP_NUM_REASSDATA\r
+#define MEMP_NUM_REASSDATA              5\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing\r
+ * packets (pbufs) that are waiting for an ARP request (to resolve\r
+ * their destination address) to finish.\r
+ * (requires the ARP_QUEUEING option)\r
+ */\r
+#ifndef MEMP_NUM_ARP_QUEUE\r
+#define MEMP_NUM_ARP_QUEUE              30\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_IGMP_GROUP: The number of multicast groups whose network interfaces\r
+ * can be members et the same time (one per netif - allsystems group -, plus one\r
+ * per netif membership).\r
+ * (requires the LWIP_IGMP option)\r
+ */\r
+#ifndef MEMP_NUM_IGMP_GROUP\r
+#define MEMP_NUM_IGMP_GROUP             8\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_SYS_TIMEOUT: the number of simulateously active timeouts.\r
+ * (requires NO_SYS==0)\r
+ */\r
+#ifndef MEMP_NUM_SYS_TIMEOUT\r
+#define MEMP_NUM_SYS_TIMEOUT            3\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_NETBUF: the number of struct netbufs.\r
+ * (only needed if you use the sequential API, like api_lib.c)\r
+ */\r
+#ifndef MEMP_NUM_NETBUF\r
+#define MEMP_NUM_NETBUF                 2\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_NETCONN: the number of struct netconns.\r
+ * (only needed if you use the sequential API, like api_lib.c)\r
+ */\r
+#ifndef MEMP_NUM_NETCONN\r
+#define MEMP_NUM_NETCONN                4\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_TCPIP_MSG_API: the number of struct tcpip_msg, which are used\r
+ * for callback/timeout API communication.\r
+ * (only needed if you use tcpip.c)\r
+ */\r
+#ifndef MEMP_NUM_TCPIP_MSG_API\r
+#define MEMP_NUM_TCPIP_MSG_API          8\r
+#endif\r
+\r
+/**\r
+ * MEMP_NUM_TCPIP_MSG_INPKT: the number of struct tcpip_msg, which are used\r
+ * for incoming packets.\r
+ * (only needed if you use tcpip.c)\r
+ */\r
+#ifndef MEMP_NUM_TCPIP_MSG_INPKT\r
+#define MEMP_NUM_TCPIP_MSG_INPKT        8\r
+#endif\r
+\r
+/**\r
+ * PBUF_POOL_SIZE: the number of buffers in the pbuf pool.\r
+ */\r
+#ifndef PBUF_POOL_SIZE\r
+#define PBUF_POOL_SIZE                  16\r
+#endif\r
+\r
+/*\r
+   ---------------------------------\r
+   ---------- ARP options ----------\r
+   ---------------------------------\r
+*/\r
+/**\r
+ * LWIP_ARP==1: Enable ARP functionality.\r
+ */\r
+#ifndef LWIP_ARP\r
+#define LWIP_ARP                        1\r
+#endif\r
+\r
+/**\r
+ * ARP_TABLE_SIZE: Number of active MAC-IP address pairs cached.\r
+ */\r
+#ifndef ARP_TABLE_SIZE\r
+#define ARP_TABLE_SIZE                  10\r
+#endif\r
+\r
+/**\r
+ * ARP_QUEUEING==1: Outgoing packets are queued during hardware address\r
+ * resolution.\r
+ */\r
+#ifndef ARP_QUEUEING\r
+#define ARP_QUEUEING                    1\r
+#endif\r
+\r
+/**\r
+ * ETHARP_TRUST_IP_MAC==1: Incoming IP packets cause the ARP table to be\r
+ * updated with the source MAC and IP addresses supplied in the packet.\r
+ * You may want to disable this if you do not trust LAN peers to have the\r
+ * correct addresses, or as a limited approach to attempt to handle\r
+ * spoofing. If disabled, lwIP will need to make a new ARP request if\r
+ * the peer is not already in the ARP table, adding a little latency.\r
+ */\r
+#ifndef ETHARP_TRUST_IP_MAC\r
+#define ETHARP_TRUST_IP_MAC             1\r
+#endif\r
+\r
+/*\r
+   --------------------------------\r
+   ---------- IP options ----------\r
+   --------------------------------\r
+*/\r
+/**\r
+ * IP_FORWARD==1: Enables the ability to forward IP packets across network\r
+ * interfaces. If you are going to run lwIP on a device with only one network\r
+ * interface, define this to 0.\r
+ */\r
+#ifndef IP_FORWARD\r
+#define IP_FORWARD                      0\r
+#endif\r
+\r
+/**\r
+ * IP_OPTIONS_ALLOWED: Defines the behavior for IP options.\r
+ *      IP_OPTIONS_ALLOWED==0: All packets with IP options are dropped.\r
+ *      IP_OPTIONS_ALLOWED==1: IP options are allowed (but not parsed).\r
+ */\r
+#ifndef IP_OPTIONS_ALLOWED\r
+#define IP_OPTIONS_ALLOWED              1\r
+#endif\r
+\r
+/**\r
+ * IP_REASSEMBLY==1: Reassemble incoming fragmented IP packets. Note that\r
+ * this option does not affect outgoing packet sizes, which can be controlled\r
+ * via IP_FRAG.\r
+ */\r
+#ifndef IP_REASSEMBLY\r
+#define IP_REASSEMBLY                   1\r
+#endif\r
+\r
+/**\r
+ * IP_FRAG==1: Fragment outgoing IP packets if their size exceeds MTU. Note\r
+ * that this option does not affect incoming packet sizes, which can be\r
+ * controlled via IP_REASSEMBLY.\r
+ */\r
+#ifndef IP_FRAG\r
+#define IP_FRAG                         1\r
+#endif\r
+\r
+/**\r
+ * IP_REASS_MAXAGE: Maximum time (in multiples of IP_TMR_INTERVAL - so seconds, normally)\r
+ * a fragmented IP packet waits for all fragments to arrive. If not all fragments arrived\r
+ * in this time, the whole packet is discarded.\r
+ */\r
+#ifndef IP_REASS_MAXAGE\r
+#define IP_REASS_MAXAGE                 3\r
+#endif\r
+\r
+/**\r
+ * IP_REASS_MAX_PBUFS: Total maximum amount of pbufs waiting to be reassembled.\r
+ * Since the received pbufs are enqueued, be sure to configure\r
+ * PBUF_POOL_SIZE > IP_REASS_MAX_PBUFS so that the stack is still able to receive\r
+ * packets even if the maximum amount of fragments is enqueued for reassembly!\r
+ */\r
+#ifndef IP_REASS_MAX_PBUFS\r
+#define IP_REASS_MAX_PBUFS              10\r
+#endif\r
+\r
+/**\r
+ * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP\r
+ * fragmentation. Otherwise pbufs are allocated and reference the original\r
+ * packet data to be fragmented.\r
+ */\r
+#ifndef IP_FRAG_USES_STATIC_BUF\r
+#define IP_FRAG_USES_STATIC_BUF         1\r
+#endif\r
+\r
+/**\r
+ * IP_FRAG_MAX_MTU: Assumed max MTU on any interface for IP frag buffer\r
+ * (requires IP_FRAG_USES_STATIC_BUF==1)\r
+ */\r
+#if IP_FRAG_USES_STATIC_BUF && !defined(IP_FRAG_MAX_MTU)\r
+#define IP_FRAG_MAX_MTU                 1500\r
+#endif\r
+\r
+/**\r
+ * IP_DEFAULT_TTL: Default value for Time-To-Live used by transport layers.\r
+ */\r
+#ifndef IP_DEFAULT_TTL\r
+#define IP_DEFAULT_TTL                  255\r
+#endif\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- ICMP options ----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * LWIP_ICMP==1: Enable ICMP module inside the IP stack.\r
+ * Be careful, disable that make your product non-compliant to RFC1122\r
+ */\r
+#ifndef LWIP_ICMP\r
+#define LWIP_ICMP                       1\r
+#endif\r
+\r
+/**\r
+ * ICMP_TTL: Default value for Time-To-Live used by ICMP packets.\r
+ */\r
+#ifndef ICMP_TTL\r
+#define ICMP_TTL                       (IP_DEFAULT_TTL)\r
+#endif\r
+\r
+/*\r
+   ---------------------------------\r
+   ---------- RAW options ----------\r
+   ---------------------------------\r
+*/\r
+/**\r
+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\r
+ */\r
+#ifndef LWIP_RAW\r
+#define LWIP_RAW                        1\r
+#endif\r
+\r
+/**\r
+ * LWIP_RAW==1: Enable application layer to hook into the IP layer itself.\r
+ */\r
+#ifndef RAW_TTL\r
+#define RAW_TTL                        (IP_DEFAULT_TTL)\r
+#endif\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- DHCP options ----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * LWIP_DHCP==1: Enable DHCP module.\r
+ */\r
+#ifndef LWIP_DHCP\r
+#define LWIP_DHCP                       0\r
+#endif\r
+\r
+/**\r
+ * DHCP_DOES_ARP_CHECK==1: Do an ARP check on the offered address.\r
+ */\r
+#ifndef DHCP_DOES_ARP_CHECK\r
+#define DHCP_DOES_ARP_CHECK             ((LWIP_DHCP) && (LWIP_ARP))\r
+#endif\r
+\r
+/*\r
+   ------------------------------------\r
+   ---------- AUTOIP options ----------\r
+   ------------------------------------\r
+*/\r
+/**\r
+ * LWIP_AUTOIP==1: Enable AUTOIP module.\r
+ */\r
+#ifndef LWIP_AUTOIP\r
+#define LWIP_AUTOIP                     0\r
+#endif\r
+\r
+/**\r
+ * LWIP_DHCP_AUTOIP_COOP==1: Allow DHCP and AUTOIP to be both enabled on\r
+ * the same interface at the same time.\r
+ */\r
+#ifndef LWIP_DHCP_AUTOIP_COOP\r
+#define LWIP_DHCP_AUTOIP_COOP           0\r
+#endif\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- SNMP options ----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * LWIP_SNMP==1: Turn on SNMP module. UDP must be available for SNMP\r
+ * transport.\r
+ */\r
+#ifndef LWIP_SNMP\r
+#define LWIP_SNMP                       0\r
+#endif\r
+\r
+/**\r
+ * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will\r
+ * allow. At least one request buffer is required.\r
+ */\r
+#ifndef SNMP_CONCURRENT_REQUESTS\r
+#define SNMP_CONCURRENT_REQUESTS        1\r
+#endif\r
+\r
+/**\r
+ * SNMP_TRAP_DESTINATIONS: Number of trap destinations. At least one trap\r
+ * destination is required\r
+ */\r
+#ifndef SNMP_TRAP_DESTINATIONS\r
+#define SNMP_TRAP_DESTINATIONS          1\r
+#endif\r
+\r
+/**\r
+ * SNMP_PRIVATE_MIB:\r
+ */\r
+#ifndef SNMP_PRIVATE_MIB\r
+#define SNMP_PRIVATE_MIB                0\r
+#endif\r
+\r
+/**\r
+ * Only allow SNMP write actions that are 'safe' (e.g. disabeling netifs is not\r
+ * a safe action and disabled when SNMP_SAFE_REQUESTS = 1).\r
+ * Unsafe requests are disabled by default!\r
+ */\r
+#ifndef SNMP_SAFE_REQUESTS\r
+#define SNMP_SAFE_REQUESTS              1\r
+#endif\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- IGMP options ----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * LWIP_IGMP==1: Turn on IGMP module.\r
+ */\r
+#ifndef LWIP_IGMP\r
+#define LWIP_IGMP                       0\r
+#endif\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- DNS options -----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * LWIP_DNS==1: Turn on DNS module. UDP must be available for DNS\r
+ * transport.\r
+ */\r
+#ifndef LWIP_DNS\r
+#define LWIP_DNS                        0\r
+#endif\r
+\r
+/** DNS maximum number of entries to maintain locally. */\r
+#ifndef DNS_TABLE_SIZE\r
+#define DNS_TABLE_SIZE                  4\r
+#endif\r
+\r
+/** DNS maximum host name length supported in the name table. */\r
+#ifndef DNS_MAX_NAME_LENGTH\r
+#define DNS_MAX_NAME_LENGTH             256\r
+#endif\r
+\r
+/** The maximum of DNS servers */\r
+#ifndef DNS_MAX_SERVERS\r
+#define DNS_MAX_SERVERS                 2\r
+#endif\r
+\r
+/** DNS do a name checking between the query and the response. */\r
+#ifndef DNS_DOES_NAME_CHECK\r
+#define DNS_DOES_NAME_CHECK             1\r
+#endif\r
+\r
+/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if\r
+    DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2.\r
+    The buffer will be of size DNS_MSG_SIZE */\r
+#ifndef DNS_USES_STATIC_BUF\r
+#define DNS_USES_STATIC_BUF             1\r
+#endif\r
+\r
+/** DNS message max. size. Default value is RFC compliant. */\r
+#ifndef DNS_MSG_SIZE\r
+#define DNS_MSG_SIZE                    512\r
+#endif\r
+\r
+/*\r
+   ---------------------------------\r
+   ---------- UDP options ----------\r
+   ---------------------------------\r
+*/\r
+/**\r
+ * LWIP_UDP==1: Turn on UDP.\r
+ */\r
+#ifndef LWIP_UDP\r
+#define LWIP_UDP                        1\r
+#endif\r
+\r
+/**\r
+ * LWIP_UDPLITE==1: Turn on UDP-Lite. (Requires LWIP_UDP)\r
+ */\r
+#ifndef LWIP_UDPLITE\r
+#define LWIP_UDPLITE                    0\r
+#endif\r
+\r
+/**\r
+ * UDP_TTL: Default Time-To-Live value.\r
+ */\r
+#ifndef UDP_TTL\r
+#define UDP_TTL                         (IP_DEFAULT_TTL)\r
+#endif\r
+\r
+/*\r
+   ---------------------------------\r
+   ---------- TCP options ----------\r
+   ---------------------------------\r
+*/\r
+/**\r
+ * LWIP_TCP==1: Turn on TCP.\r
+ */\r
+#ifndef LWIP_TCP\r
+#define LWIP_TCP                        1\r
+#endif\r
+\r
+/**\r
+ * TCP_TTL: Default Time-To-Live value.\r
+ */\r
+#ifndef TCP_TTL\r
+#define TCP_TTL                         (IP_DEFAULT_TTL)\r
+#endif\r
+\r
+/**\r
+ * TCP_WND: The size of a TCP window.\r
+ */\r
+#ifndef TCP_WND\r
+#define TCP_WND                         2048\r
+#endif\r
+\r
+/**\r
+ * TCP_MAXRTX: Maximum number of retransmissions of data segments.\r
+ */\r
+#ifndef TCP_MAXRTX\r
+#define TCP_MAXRTX                      12\r
+#endif\r
+\r
+/**\r
+ * TCP_SYNMAXRTX: Maximum number of retransmissions of SYN segments.\r
+ */\r
+#ifndef TCP_SYNMAXRTX\r
+#define TCP_SYNMAXRTX                   6\r
+#endif\r
+\r
+/**\r
+ * TCP_QUEUE_OOSEQ==1: TCP will queue segments that arrive out of order.\r
+ * Define to 0 if your device is low on memory.\r
+ */\r
+#ifndef TCP_QUEUE_OOSEQ\r
+#define TCP_QUEUE_OOSEQ                 1\r
+#endif\r
+\r
+/**\r
+ * TCP_MSS: TCP Maximum segment size. (default is 128, a *very*\r
+ * conservative default.)\r
+ * For the receive side, this MSS is advertised to the remote side\r
+ * when opening a connection. For the transmit size, this MSS sets\r
+ * an upper limit on the MSS advertised by the remote host.\r
+ */\r
+#ifndef TCP_MSS\r
+#define TCP_MSS                         128\r
+#endif\r
+\r
+/**\r
+ * TCP_CALCULATE_EFF_SEND_MSS: "The maximum size of a segment that TCP really\r
+ * sends, the 'effective send MSS,' MUST be the smaller of the send MSS (which\r
+ * reflects the available reassembly buffer size at the remote host) and the\r
+ * largest size permitted by the IP layer" (RFC 1122)\r
+ * Setting this to 1 enables code that checks TCP_MSS against the MTU of the\r
+ * netif used for a connection and limits the MSS if it would be too big otherwise.\r
+ */\r
+#ifndef TCP_CALCULATE_EFF_SEND_MSS\r
+#define TCP_CALCULATE_EFF_SEND_MSS      1\r
+#endif\r
+\r
+\r
+/**\r
+ * TCP_SND_BUF: TCP sender buffer space (bytes).\r
+ */\r
+#ifndef TCP_SND_BUF\r
+#define TCP_SND_BUF                     256\r
+#endif\r
+\r
+/**\r
+ * TCP_SND_QUEUELEN: TCP sender buffer space (pbufs). This must be at least\r
+ * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work.\r
+ */\r
+#ifndef TCP_SND_QUEUELEN\r
+#define TCP_SND_QUEUELEN                (4 * (TCP_SND_BUF/TCP_MSS))\r
+#endif\r
+\r
+/**\r
+ * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal\r
+ * to TCP_SND_BUF. It is the amount of space which must be available in the\r
+ * TCP snd_buf for select to return writable.\r
+ */\r
+#ifndef TCP_SNDLOWAT\r
+#define TCP_SNDLOWAT                    (TCP_SND_BUF/2)\r
+#endif\r
+\r
+/**\r
+ * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb.\r
+ */\r
+#ifndef TCP_LISTEN_BACKLOG\r
+#define TCP_LISTEN_BACKLOG              0\r
+#endif\r
+\r
+/**\r
+ * The maximum allowed backlog for TCP listen netconns.\r
+ * This backlog is used unless another is explicitly specified.\r
+ * 0xff is the maximum (u8_t).\r
+ */\r
+#ifndef TCP_DEFAULT_LISTEN_BACKLOG\r
+#define TCP_DEFAULT_LISTEN_BACKLOG      0xff\r
+#endif\r
+\r
+/**\r
+ * LWIP_EVENT_API and LWIP_CALLBACK_API: Only one of these should be set to 1.\r
+ *     LWIP_EVENT_API==1: The user defines lwip_tcp_event() to receive all\r
+ *         events (accept, sent, etc) that happen in the system.\r
+ *     LWIP_CALLBACK_API==1: The PCB callback function is called directly\r
+ *         for the event.\r
+ */\r
+#ifndef LWIP_EVENT_API\r
+#define LWIP_EVENT_API                  0\r
+#define LWIP_CALLBACK_API               1\r
+#else\r
+#define LWIP_EVENT_API                  1\r
+#define LWIP_CALLBACK_API               0\r
+#endif\r
+\r
+\r
+/*\r
+   ----------------------------------\r
+   ---------- Pbuf options ----------\r
+   ----------------------------------\r
+*/\r
+/**\r
+ * PBUF_LINK_HLEN: the number of bytes that should be allocated for a\r
+ * link level header. The default is 14, the standard value for\r
+ * Ethernet.\r
+ */\r
+#ifndef PBUF_LINK_HLEN\r
+#define PBUF_LINK_HLEN                  14\r
+#endif\r
+\r
+/**\r
+ * PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. The default is\r
+ * designed to accomodate single full size TCP frame in one pbuf, including\r
+ * TCP_MSS, IP header, and link header.\r
+ */\r
+#ifndef PBUF_POOL_BUFSIZE\r
+#define PBUF_POOL_BUFSIZE               LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_HLEN)\r
+#endif\r
+\r
+/*\r
+   ------------------------------------------------\r
+   ---------- Network Interfaces options ----------\r
+   ------------------------------------------------\r
+*/\r
+/**\r
+ * LWIP_NETIF_HOSTNAME==1: use DHCP_OPTION_HOSTNAME with netif's hostname\r
+ * field.\r
+ */\r
+#ifndef LWIP_NETIF_HOSTNAME\r
+#define LWIP_NETIF_HOSTNAME             0\r
+#endif\r
+\r
+/**\r
+ * LWIP_NETIF_API==1: Support netif api (in netifapi.c)\r
+ */\r
+#ifndef LWIP_NETIF_API\r
+#define LWIP_NETIF_API                  0\r
+#endif\r
+\r
+/**\r
+ * LWIP_NETIF_STATUS_CALLBACK==1: Support a callback function whenever an interface\r
+ * changes its up/down status (i.e., due to DHCP IP acquistion)\r
+ */\r
+#ifndef LWIP_NETIF_STATUS_CALLBACK\r
+#define LWIP_NETIF_STATUS_CALLBACK      0\r
+#endif\r
+\r
+/**\r
+ * LWIP_NETIF_LINK_CALLBACK==1: Support a callback function from an interface\r
+ * whenever the link changes (i.e., link down)\r
+ */\r
+#ifndef LWIP_NETIF_LINK_CALLBACK\r
+#define LWIP_NETIF_LINK_CALLBACK        0\r
+#endif\r
+\r
+/**\r
+ * LWIP_NETIF_HWADDRHINT==1: Cache link-layer-address hints (e.g. table\r
+ * indices) in struct netif. TCP and UDP can make use of this to prevent\r
+ * scanning the ARP table for every sent packet. While this is faster for big\r
+ * ARP tables or many concurrent connections, it might be counterproductive\r
+ * if you have a tiny ARP table or if there never are concurrent connections.\r
+ */\r
+#ifndef LWIP_NETIF_HWADDRHINT\r
+#define LWIP_NETIF_HWADDRHINT           0\r
+#endif\r
+\r
+/*\r
+   ------------------------------------\r
+   ---------- LOOPIF options ----------\r
+   ------------------------------------\r
+*/\r
+/**\r
+ * LWIP_HAVE_LOOPIF==1: Support loop interface (127.0.0.1) and loopif.c\r
+ */\r
+#ifndef LWIP_HAVE_LOOPIF\r
+#define LWIP_HAVE_LOOPIF                0\r
+#endif\r
+\r
+/**\r
+ * LWIP_LOOPIF_MULTITHREADING: Indicates whether threading is enabled in\r
+ * the system, as LOOPIF must change how it behaves depending on this setting.\r
+ * Setting this is needed to avoid reentering non-reentrant functions like\r
+ * tcp_input().\r
+ *    LWIP_LOOPIF_MULTITHREADING==1: Indicates that the user is using a\r
+ *       multithreaded environment like tcpip.c. In this case, netif->input()\r
+ *       is called directly.\r
+ *    LWIP_LOOPIF_MULTITHREADING==0: Indicates a polling (or NO_SYS) setup.\r
+ *       The packets are put on a list and loopif_poll() must be called in\r
+ *       the main application loop.\r
+ */\r
+#ifndef LWIP_LOOPIF_MULTITHREADING\r
+#define LWIP_LOOPIF_MULTITHREADING      1\r
+#endif\r
+\r
+/*\r
+   ------------------------------------\r
+   ---------- Thread options ----------\r
+   ------------------------------------\r
+*/\r
+/**\r
+ * TCPIP_THREAD_NAME: The name assigned to the main tcpip thread.\r
+ */\r
+#ifndef TCPIP_THREAD_NAME\r
+#define TCPIP_THREAD_NAME              "tcpip_thread"\r
+#endif\r
+\r
+/**\r
+ * TCPIP_THREAD_STACKSIZE: The stack size used by the main tcpip thread.\r
+ * The stack size value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef TCPIP_THREAD_STACKSIZE\r
+#define TCPIP_THREAD_STACKSIZE          0\r
+#endif\r
+\r
+/**\r
+ * TCPIP_THREAD_PRIO: The priority assigned to the main tcpip thread.\r
+ * The priority value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef TCPIP_THREAD_PRIO\r
+#define TCPIP_THREAD_PRIO               1\r
+#endif\r
+\r
+/**\r
+ * TCPIP_MBOX_SIZE: The mailbox size for the tcpip thread messages\r
+ * The queue size value itself is platform-dependent, but is passed to\r
+ * sys_mbox_new() when tcpip_init is called.\r
+ */\r
+#ifndef TCPIP_MBOX_SIZE\r
+#define TCPIP_MBOX_SIZE                 0\r
+#endif\r
+\r
+/**\r
+ * SLIPIF_THREAD_NAME: The name assigned to the slipif_loop thread.\r
+ */\r
+#ifndef SLIPIF_THREAD_NAME\r
+#define SLIPIF_THREAD_NAME             "slipif_loop"\r
+#endif\r
+\r
+/**\r
+ * SLIP_THREAD_STACKSIZE: The stack size used by the slipif_loop thread.\r
+ * The stack size value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef SLIPIF_THREAD_STACKSIZE\r
+#define SLIPIF_THREAD_STACKSIZE         0\r
+#endif\r
+\r
+/**\r
+ * SLIPIF_THREAD_PRIO: The priority assigned to the slipif_loop thread.\r
+ * The priority value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef SLIPIF_THREAD_PRIO\r
+#define SLIPIF_THREAD_PRIO              1\r
+#endif\r
+\r
+/**\r
+ * PPP_THREAD_NAME: The name assigned to the pppMain thread.\r
+ */\r
+#ifndef PPP_THREAD_NAME\r
+#define PPP_THREAD_NAME                "pppMain"\r
+#endif\r
+\r
+/**\r
+ * PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread.\r
+ * The stack size value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef PPP_THREAD_STACKSIZE\r
+#define PPP_THREAD_STACKSIZE            0\r
+#endif\r
+\r
+/**\r
+ * PPP_THREAD_PRIO: The priority assigned to the pppMain thread.\r
+ * The priority value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef PPP_THREAD_PRIO\r
+#define PPP_THREAD_PRIO                 1\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_THREAD_NAME: The name assigned to any other lwIP thread.\r
+ */\r
+#ifndef DEFAULT_THREAD_NAME\r
+#define DEFAULT_THREAD_NAME            "lwIP"\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_THREAD_STACKSIZE: The stack size used by any other lwIP thread.\r
+ * The stack size value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef DEFAULT_THREAD_STACKSIZE\r
+#define DEFAULT_THREAD_STACKSIZE        0\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_THREAD_PRIO: The priority assigned to any other lwIP thread.\r
+ * The priority value itself is platform-dependent, but is passed to\r
+ * sys_thread_new() when the thread is created.\r
+ */\r
+#ifndef DEFAULT_THREAD_PRIO\r
+#define DEFAULT_THREAD_PRIO             1\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_RAW_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\r
+ * NETCONN_RAW. The queue size value itself is platform-dependent, but is passed\r
+ * to sys_mbox_new() when the recvmbox is created.\r
+ */\r
+#ifndef DEFAULT_RAW_RECVMBOX_SIZE\r
+#define DEFAULT_RAW_RECVMBOX_SIZE       0\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_UDP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\r
+ * NETCONN_UDP. The queue size value itself is platform-dependent, but is passed\r
+ * to sys_mbox_new() when the recvmbox is created.\r
+ */\r
+#ifndef DEFAULT_UDP_RECVMBOX_SIZE\r
+#define DEFAULT_UDP_RECVMBOX_SIZE       0\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_TCP_RECVMBOX_SIZE: The mailbox size for the incoming packets on a\r
+ * NETCONN_TCP. The queue size value itself is platform-dependent, but is passed\r
+ * to sys_mbox_new() when the recvmbox is created.\r
+ */\r
+#ifndef DEFAULT_TCP_RECVMBOX_SIZE\r
+#define DEFAULT_TCP_RECVMBOX_SIZE       0\r
+#endif\r
+\r
+/**\r
+ * DEFAULT_ACCEPTMBOX_SIZE: The mailbox size for the incoming connections.\r
+ * The queue size value itself is platform-dependent, but is passed to\r
+ * sys_mbox_new() when the acceptmbox is created.\r
+ */\r
+#ifndef DEFAULT_ACCEPTMBOX_SIZE\r
+#define DEFAULT_ACCEPTMBOX_SIZE         0\r
+#endif\r
+\r
+/*\r
+   ----------------------------------------------\r
+   ---------- Sequential layer options ----------\r
+   ----------------------------------------------\r
+*/\r
+/**\r
+ * LWIP_TCPIP_CORE_LOCKING: (EXPERIMENTAL!)\r
+ * Don't use it if you're not an active lwIP project member\r
+ */\r
+#ifndef LWIP_TCPIP_CORE_LOCKING\r
+#define LWIP_TCPIP_CORE_LOCKING         0\r
+#endif\r
+\r
+/**\r
+ * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c)\r
+ */\r
+#ifndef LWIP_NETCONN\r
+#define LWIP_NETCONN                    1\r
+#endif\r
+\r
+/*\r
+   ------------------------------------\r
+   ---------- Socket options ----------\r
+   ------------------------------------\r
+*/\r
+/**\r
+ * LWIP_SOCKET==1: Enable Socket API (require to use sockets.c)\r
+ */\r
+#ifndef LWIP_SOCKET\r
+#define LWIP_SOCKET                     1\r
+#endif\r
+\r
+/**\r
+ * LWIP_COMPAT_SOCKETS==1: Enable BSD-style sockets functions names.\r
+ * (only used if you use sockets.c)\r
+ */\r
+#ifndef LWIP_COMPAT_SOCKETS\r
+#define LWIP_COMPAT_SOCKETS             1\r
+#endif\r
+\r
+/**\r
+ * LWIP_POSIX_SOCKETS_IO_NAMES==1: Enable POSIX-style sockets functions names.\r
+ * Disable this option if you use a POSIX operating system that uses the same\r
+ * names (read, write & close). (only used if you use sockets.c)\r
+ */\r
+#ifndef LWIP_POSIX_SOCKETS_IO_NAMES\r
+#define LWIP_POSIX_SOCKETS_IO_NAMES     1\r
+#endif\r
+\r
+/**\r
+ * LWIP_TCP_KEEPALIVE==1: Enable TCP_KEEPIDLE, TCP_KEEPINTVL and TCP_KEEPCNT\r
+ * options processing. Note that TCP_KEEPIDLE and TCP_KEEPINTVL have to be set\r
+ * in seconds. (does not require sockets.c, and will affect tcp.c)\r
+ */\r
+#ifndef LWIP_TCP_KEEPALIVE\r
+#define LWIP_TCP_KEEPALIVE              0\r
+#endif\r
+\r
+/**\r
+ * LWIP_SO_RCVTIMEO==1: Enable SO_RCVTIMEO processing.\r
+ */\r
+#ifndef LWIP_SO_RCVTIMEO\r
+#define LWIP_SO_RCVTIMEO                0\r
+#endif\r
+\r
+/**\r
+ * LWIP_SO_RCVBUF==1: Enable SO_RCVBUF processing.\r
+ */\r
+#ifndef LWIP_SO_RCVBUF\r
+#define LWIP_SO_RCVBUF                  0\r
+#endif\r
+\r
+/**\r
+ * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE!\r
+ */\r
+#ifndef SO_REUSE\r
+#define SO_REUSE                        0\r
+#endif\r
+\r
+/*\r
+   ----------------------------------------\r
+   ---------- Statistics options ----------\r
+   ----------------------------------------\r
+*/\r
+/**\r
+ * LWIP_STATS==1: Enable statistics collection in lwip_stats.\r
+ */\r
+#ifndef LWIP_STATS\r
+#define LWIP_STATS                      1\r
+#endif\r
+\r
+#if LWIP_STATS\r
+\r
+/**\r
+ * LWIP_STATS_DISPLAY==1: Compile in the statistics output functions.\r
+ */\r
+#ifndef LWIP_STATS_DISPLAY\r
+#define LWIP_STATS_DISPLAY              0\r
+#endif\r
+\r
+/**\r
+ * LINK_STATS==1: Enable link stats.\r
+ */\r
+#ifndef LINK_STATS\r
+#define LINK_STATS                      1\r
+#endif\r
+\r
+/**\r
+ * ETHARP_STATS==1: Enable etharp stats.\r
+ */\r
+#ifndef ETHARP_STATS\r
+#define ETHARP_STATS                    (LWIP_ARP)\r
+#endif\r
+\r
+/**\r
+ * IP_STATS==1: Enable IP stats.\r
+ */\r
+#ifndef IP_STATS\r
+#define IP_STATS                        1\r
+#endif\r
+\r
+/**\r
+ * IPFRAG_STATS==1: Enable IP fragmentation stats. Default is\r
+ * on if using either frag or reass.\r
+ */\r
+#ifndef IPFRAG_STATS\r
+#define IPFRAG_STATS                    (IP_REASSEMBLY || IP_FRAG)\r
+#endif\r
+\r
+/**\r
+ * ICMP_STATS==1: Enable ICMP stats.\r
+ */\r
+#ifndef ICMP_STATS\r
+#define ICMP_STATS                      1\r
+#endif\r
+\r
+/**\r
+ * IGMP_STATS==1: Enable IGMP stats.\r
+ */\r
+#ifndef IGMP_STATS\r
+#define IGMP_STATS                      (LWIP_IGMP)\r
+#endif\r
+\r
+/**\r
+ * UDP_STATS==1: Enable UDP stats. Default is on if\r
+ * UDP enabled, otherwise off.\r
+ */\r
+#ifndef UDP_STATS\r
+#define UDP_STATS                       (LWIP_UDP)\r
+#endif\r
+\r
+/**\r
+ * TCP_STATS==1: Enable TCP stats. Default is on if TCP\r
+ * enabled, otherwise off.\r
+ */\r
+#ifndef TCP_STATS\r
+#define TCP_STATS                       (LWIP_TCP)\r
+#endif\r
+\r
+/**\r
+ * MEM_STATS==1: Enable mem.c stats.\r
+ */\r
+#ifndef MEM_STATS\r
+#define MEM_STATS                       1\r
+#endif\r
+\r
+/**\r
+ * MEMP_STATS==1: Enable memp.c pool stats.\r
+ */\r
+#ifndef MEMP_STATS\r
+#define MEMP_STATS                      1\r
+#endif\r
+\r
+/**\r
+ * SYS_STATS==1: Enable system stats (sem and mbox counts, etc).\r
+ */\r
+#ifndef SYS_STATS\r
+#define SYS_STATS                       1\r
+#endif\r
+\r
+#else\r
+\r
+#define LINK_STATS                      0\r
+#define IP_STATS                        0\r
+#define IPFRAG_STATS                    0\r
+#define ICMP_STATS                      0\r
+#define IGMP_STATS                      0\r
+#define UDP_STATS                       0\r
+#define TCP_STATS                       0\r
+#define MEM_STATS                       0\r
+#define MEMP_STATS                      0\r
+#define SYS_STATS                       0\r
+#define LWIP_STATS_DISPLAY              0\r
+\r
+#endif /* LWIP_STATS */\r
+\r
+/*\r
+   ---------------------------------\r
+   ---------- PPP options ----------\r
+   ---------------------------------\r
+*/\r
+/**\r
+ * PPP_SUPPORT==1: Enable PPP.\r
+ */\r
+#ifndef PPP_SUPPORT\r
+#define PPP_SUPPORT                     0\r
+#endif\r
+\r
+/**\r
+ * PPPOE_SUPPORT==1: Enable PPP Over Ethernet\r
+ */\r
+#ifndef PPPOE_SUPPORT\r
+#define PPPOE_SUPPORT                   0\r
+#endif\r
+\r
+/**\r
+ * PPPOS_SUPPORT==1: Enable PPP Over Serial\r
+ */\r
+#ifndef PPPOS_SUPPORT\r
+#define PPPOS_SUPPORT                   PPP_SUPPORT\r
+#endif\r
+\r
+#if PPP_SUPPORT\r
+\r
+/**\r
+ * NUM_PPP: Max PPP sessions.\r
+ */\r
+#ifndef NUM_PPP\r
+#define NUM_PPP                         1\r
+#endif\r
+\r
+/**\r
+ * PAP_SUPPORT==1: Support PAP.\r
+ */\r
+#ifndef PAP_SUPPORT\r
+#define PAP_SUPPORT                     0\r
+#endif\r
+\r
+/**\r
+ * CHAP_SUPPORT==1: Support CHAP.\r
+ */\r
+#ifndef CHAP_SUPPORT\r
+#define CHAP_SUPPORT                    0\r
+#endif\r
+\r
+/**\r
+ * MSCHAP_SUPPORT==1: Support MSCHAP. CURRENTLY NOT SUPPORTED! DO NOT SET!\r
+ */\r
+#ifndef MSCHAP_SUPPORT\r
+#define MSCHAP_SUPPORT                  0\r
+#endif\r
+\r
+/**\r
+ * CBCP_SUPPORT==1: Support CBCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\r
+ */\r
+#ifndef CBCP_SUPPORT\r
+#define CBCP_SUPPORT                    0\r
+#endif\r
+\r
+/**\r
+ * CCP_SUPPORT==1: Support CCP. CURRENTLY NOT SUPPORTED! DO NOT SET!\r
+ */\r
+#ifndef CCP_SUPPORT\r
+#define CCP_SUPPORT                     0\r
+#endif\r
+\r
+/**\r
+ * VJ_SUPPORT==1: Support VJ header compression.\r
+ */\r
+#ifndef VJ_SUPPORT\r
+#define VJ_SUPPORT                      0\r
+#endif\r
+\r
+/**\r
+ * MD5_SUPPORT==1: Support MD5 (see also CHAP).\r
+ */\r
+#ifndef MD5_SUPPORT\r
+#define MD5_SUPPORT                     0\r
+#endif\r
+\r
+/*\r
+ * Timeouts\r
+ */\r
+#ifndef FSM_DEFTIMEOUT\r
+#define FSM_DEFTIMEOUT                  6       /* Timeout time in seconds */\r
+#endif\r
+\r
+#ifndef FSM_DEFMAXTERMREQS\r
+#define FSM_DEFMAXTERMREQS              2       /* Maximum Terminate-Request transmissions */\r
+#endif\r
+\r
+#ifndef FSM_DEFMAXCONFREQS\r
+#define FSM_DEFMAXCONFREQS              10      /* Maximum Configure-Request transmissions */\r
+#endif\r
+\r
+#ifndef FSM_DEFMAXNAKLOOPS\r
+#define FSM_DEFMAXNAKLOOPS              5       /* Maximum number of nak loops */\r
+#endif\r
+\r
+#ifndef UPAP_DEFTIMEOUT\r
+#define UPAP_DEFTIMEOUT                 6       /* Timeout (seconds) for retransmitting req */\r
+#endif\r
+\r
+#ifndef UPAP_DEFREQTIME\r
+#define UPAP_DEFREQTIME                 30      /* Time to wait for auth-req from peer */\r
+#endif\r
+\r
+#ifndef CHAP_DEFTIMEOUT\r
+#define CHAP_DEFTIMEOUT                 6       /* Timeout time in seconds */\r
+#endif\r
+\r
+#ifndef CHAP_DEFTRANSMITS\r
+#define CHAP_DEFTRANSMITS               10      /* max # times to send challenge */\r
+#endif\r
+\r
+/* Interval in seconds between keepalive echo requests, 0 to disable. */\r
+#ifndef LCP_ECHOINTERVAL\r
+#define LCP_ECHOINTERVAL                0\r
+#endif\r
+\r
+/* Number of unanswered echo requests before failure. */\r
+#ifndef LCP_MAXECHOFAILS\r
+#define LCP_MAXECHOFAILS                3\r
+#endif\r
+\r
+/* Max Xmit idle time (in jiffies) before resend flag char. */\r
+#ifndef PPP_MAXIDLEFLAG\r
+#define PPP_MAXIDLEFLAG                 100\r
+#endif\r
+\r
+/*\r
+ * Packet sizes\r
+ *\r
+ * Note - lcp shouldn't be allowed to negotiate stuff outside these\r
+ *    limits.  See lcp.h in the pppd directory.\r
+ * (XXX - these constants should simply be shared by lcp.c instead\r
+ *    of living in lcp.h)\r
+ */\r
+#define PPP_MTU                         1500     /* Default MTU (size of Info field) */\r
+#ifndef PPP_MAXMTU\r
+/* #define PPP_MAXMTU  65535 - (PPP_HDRLEN + PPP_FCSLEN) */\r
+#define PPP_MAXMTU                      1500 /* Largest MTU we allow */\r
+#endif\r
+#define PPP_MINMTU                      64\r
+#define PPP_MRU                         1500     /* default MRU = max length of info field */\r
+#define PPP_MAXMRU                      1500     /* Largest MRU we allow */\r
+#ifndef PPP_DEFMRU\r
+#define PPP_DEFMRU                      296             /* Try for this */\r
+#endif\r
+#define PPP_MINMRU                      128             /* No MRUs below this */\r
+\r
+\r
+#define MAXNAMELEN                      256     /* max length of hostname or name for auth */\r
+#define MAXSECRETLEN                    256     /* max length of password or secret */\r
+\r
+#endif /* PPP_SUPPORT */\r
+\r
+/*\r
+   --------------------------------------\r
+   ---------- Checksum options ----------\r
+   --------------------------------------\r
+*/\r
+/**\r
+ * CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.\r
+ */\r
+#ifndef CHECKSUM_GEN_IP\r
+#define CHECKSUM_GEN_IP                 1\r
+#endif\r
+\r
+/**\r
+ * CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.\r
+ */\r
+#ifndef CHECKSUM_GEN_UDP\r
+#define CHECKSUM_GEN_UDP                1\r
+#endif\r
+\r
+/**\r
+ * CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.\r
+ */\r
+#ifndef CHECKSUM_GEN_TCP\r
+#define CHECKSUM_GEN_TCP                1\r
+#endif\r
+\r
+/**\r
+ * CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.\r
+ */\r
+#ifndef CHECKSUM_CHECK_IP\r
+#define CHECKSUM_CHECK_IP               1\r
+#endif\r
+\r
+/**\r
+ * CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.\r
+ */\r
+#ifndef CHECKSUM_CHECK_UDP\r
+#define CHECKSUM_CHECK_UDP              1\r
+#endif\r
+\r
+/**\r
+ * CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.\r
+ */\r
+#ifndef CHECKSUM_CHECK_TCP\r
+#define CHECKSUM_CHECK_TCP              1\r
+#endif\r
+\r
+/*\r
+   ---------------------------------------\r
+   ---------- Debugging options ----------\r
+   ---------------------------------------\r
+*/\r
+/**\r
+ * LWIP_DBG_MIN_LEVEL: After masking, the value of the debug is\r
+ * compared against this value. If it is smaller, then debugging\r
+ * messages are written.\r
+ */\r
+#ifndef LWIP_DBG_MIN_LEVEL\r
+#define LWIP_DBG_MIN_LEVEL              LWIP_DBG_LEVEL_OFF\r
+#endif\r
+\r
+/**\r
+ * LWIP_DBG_TYPES_ON: A mask that can be used to globally enable/disable\r
+ * debug messages of certain types.\r
+ */\r
+#ifndef LWIP_DBG_TYPES_ON\r
+#define LWIP_DBG_TYPES_ON               LWIP_DBG_ON\r
+#endif\r
+\r
+/**\r
+ * ETHARP_DEBUG: Enable debugging in etharp.c.\r
+ */\r
+#ifndef ETHARP_DEBUG\r
+#define ETHARP_DEBUG                    LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * NETIF_DEBUG: Enable debugging in netif.c.\r
+ */\r
+#ifndef NETIF_DEBUG\r
+#define NETIF_DEBUG                     LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * PBUF_DEBUG: Enable debugging in pbuf.c.\r
+ */\r
+#ifndef PBUF_DEBUG\r
+#define PBUF_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * API_LIB_DEBUG: Enable debugging in api_lib.c.\r
+ */\r
+#ifndef API_LIB_DEBUG\r
+#define API_LIB_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * API_MSG_DEBUG: Enable debugging in api_msg.c.\r
+ */\r
+#ifndef API_MSG_DEBUG\r
+#define API_MSG_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * SOCKETS_DEBUG: Enable debugging in sockets.c.\r
+ */\r
+#ifndef SOCKETS_DEBUG\r
+#define SOCKETS_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * ICMP_DEBUG: Enable debugging in icmp.c.\r
+ */\r
+#ifndef ICMP_DEBUG\r
+#define ICMP_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * IGMP_DEBUG: Enable debugging in igmp.c.\r
+ */\r
+#ifndef IGMP_DEBUG\r
+#define IGMP_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * INET_DEBUG: Enable debugging in inet.c.\r
+ */\r
+#ifndef INET_DEBUG\r
+#define INET_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * IP_DEBUG: Enable debugging for IP.\r
+ */\r
+#ifndef IP_DEBUG\r
+#define IP_DEBUG                        LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * IP_REASS_DEBUG: Enable debugging in ip_frag.c for both frag & reass.\r
+ */\r
+#ifndef IP_REASS_DEBUG\r
+#define IP_REASS_DEBUG                  LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * RAW_DEBUG: Enable debugging in raw.c.\r
+ */\r
+#ifndef RAW_DEBUG\r
+#define RAW_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * MEM_DEBUG: Enable debugging in mem.c.\r
+ */\r
+#ifndef MEM_DEBUG\r
+#define MEM_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * MEMP_DEBUG: Enable debugging in memp.c.\r
+ */\r
+#ifndef MEMP_DEBUG\r
+#define MEMP_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * SYS_DEBUG: Enable debugging in sys.c.\r
+ */\r
+#ifndef SYS_DEBUG\r
+#define SYS_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_DEBUG: Enable debugging for TCP.\r
+ */\r
+#ifndef TCP_DEBUG\r
+#define TCP_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_INPUT_DEBUG: Enable debugging in tcp_in.c for incoming debug.\r
+ */\r
+#ifndef TCP_INPUT_DEBUG\r
+#define TCP_INPUT_DEBUG                 LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_FR_DEBUG: Enable debugging in tcp_in.c for fast retransmit.\r
+ */\r
+#ifndef TCP_FR_DEBUG\r
+#define TCP_FR_DEBUG                    LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_RTO_DEBUG: Enable debugging in TCP for retransmit\r
+ * timeout.\r
+ */\r
+#ifndef TCP_RTO_DEBUG\r
+#define TCP_RTO_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_CWND_DEBUG: Enable debugging for TCP congestion window.\r
+ */\r
+#ifndef TCP_CWND_DEBUG\r
+#define TCP_CWND_DEBUG                  LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_WND_DEBUG: Enable debugging in tcp_in.c for window updating.\r
+ */\r
+#ifndef TCP_WND_DEBUG\r
+#define TCP_WND_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_OUTPUT_DEBUG: Enable debugging in tcp_out.c output functions.\r
+ */\r
+#ifndef TCP_OUTPUT_DEBUG\r
+#define TCP_OUTPUT_DEBUG                LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_RST_DEBUG: Enable debugging for TCP with the RST message.\r
+ */\r
+#ifndef TCP_RST_DEBUG\r
+#define TCP_RST_DEBUG                   LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCP_QLEN_DEBUG: Enable debugging for TCP queue lengths.\r
+ */\r
+#ifndef TCP_QLEN_DEBUG\r
+#define TCP_QLEN_DEBUG                  LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * UDP_DEBUG: Enable debugging in UDP.\r
+ */\r
+#ifndef UDP_DEBUG\r
+#define UDP_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * TCPIP_DEBUG: Enable debugging in tcpip.c.\r
+ */\r
+#ifndef TCPIP_DEBUG\r
+#define TCPIP_DEBUG                     LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * PPP_DEBUG: Enable debugging for PPP.\r
+ */\r
+#ifndef PPP_DEBUG\r
+#define PPP_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * SLIP_DEBUG: Enable debugging in slipif.c.\r
+ */\r
+#ifndef SLIP_DEBUG\r
+#define SLIP_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * DHCP_DEBUG: Enable debugging in dhcp.c.\r
+ */\r
+#ifndef DHCP_DEBUG\r
+#define DHCP_DEBUG                      LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * AUTOIP_DEBUG: Enable debugging in autoip.c.\r
+ */\r
+#ifndef AUTOIP_DEBUG\r
+#define AUTOIP_DEBUG                    LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * SNMP_MSG_DEBUG: Enable debugging for SNMP messages.\r
+ */\r
+#ifndef SNMP_MSG_DEBUG\r
+#define SNMP_MSG_DEBUG                  LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * SNMP_MIB_DEBUG: Enable debugging for SNMP MIBs.\r
+ */\r
+#ifndef SNMP_MIB_DEBUG\r
+#define SNMP_MIB_DEBUG                  LWIP_DBG_OFF\r
+#endif\r
+\r
+/**\r
+ * DNS_DEBUG: Enable debugging for DNS.\r
+ */\r
+#ifndef DNS_DEBUG\r
+#define DNS_DEBUG                       LWIP_DBG_OFF\r
+#endif\r
+\r
+#endif /* __LWIP_OPT_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/pbuf.h
new file mode 100644 (file)
index 0000000..d02ab45
--- /dev/null
@@ -0,0 +1,118 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __LWIP_PBUF_H__\r
+#define __LWIP_PBUF_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define PBUF_TRANSPORT_HLEN 20\r
+#define PBUF_IP_HLEN        20\r
+\r
+typedef enum {\r
+  PBUF_TRANSPORT,\r
+  PBUF_IP,\r
+  PBUF_LINK,\r
+  PBUF_RAW\r
+} pbuf_layer;\r
+\r
+typedef enum {\r
+  PBUF_RAM, /* pbuf data is stored in RAM */\r
+  PBUF_ROM, /* pbuf data is stored in ROM */\r
+  PBUF_REF, /* pbuf comes from the pbuf pool */\r
+  PBUF_POOL /* pbuf payload refers to RAM */\r
+} pbuf_type;\r
+\r
+\r
+/** indicates this packet's data should be immediately passed to the application */\r
+#define PBUF_FLAG_PUSH 0x01U\r
+\r
+struct pbuf {\r
+  /** next pbuf in singly linked pbuf chain */\r
+  struct pbuf *next;\r
+\r
+  /** pointer to the actual data in the buffer */\r
+  void *payload;\r
+\r
+  /**\r
+   * total length of this buffer and all next buffers in chain\r
+   * belonging to the same packet.\r
+   *\r
+   * For non-queue packet chains this is the invariant:\r
+   * p->tot_len == p->len + (p->next? p->next->tot_len: 0)\r
+   */\r
+  u16_t tot_len;\r
+\r
+  /** length of this buffer */\r
+  u16_t len;\r
+\r
+  /** pbuf_type as u8_t instead of enum to save space */\r
+  u8_t /*pbuf_type*/ type;\r
+\r
+  /** misc flags */\r
+  u8_t flags;\r
+\r
+  /**\r
+   * the reference count always equals the number of pointers\r
+   * that refer to this pbuf. This can be pointers from an application,\r
+   * the stack itself, or pbuf->next pointers from a chain.\r
+   */\r
+  u16_t ref;\r
+\r
+};\r
+\r
+/* Initializes the pbuf module. This call is empty for now, but may not be in future. */\r
+#define pbuf_init()\r
+\r
+struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);\r
+void pbuf_realloc(struct pbuf *p, u16_t size);\r
+u8_t pbuf_header(struct pbuf *p, s16_t header_size);\r
+void pbuf_ref(struct pbuf *p);\r
+void pbuf_ref_chain(struct pbuf *p);\r
+u8_t pbuf_free(struct pbuf *p);\r
+u8_t pbuf_clen(struct pbuf *p);\r
+void pbuf_cat(struct pbuf *head, struct pbuf *tail);\r
+void pbuf_chain(struct pbuf *head, struct pbuf *tail);\r
+struct pbuf *pbuf_dechain(struct pbuf *p);\r
+err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);\r
+u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_PBUF_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/raw.h
new file mode 100644 (file)
index 0000000..8681ce2
--- /dev/null
@@ -0,0 +1,97 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_RAW_H__\r
+#define __LWIP_RAW_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/ip_addr.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+struct raw_pcb {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+\r
+  struct raw_pcb *next;\r
+\r
+  u8_t protocol;\r
+\r
+  /* receive callback function\r
+   * @param arg user supplied argument (raw_pcb.recv_arg)\r
+   * @param pcb the raw_pcb which received data\r
+   * @param p the packet buffer that was received\r
+   * @param addr the remote IP address from which the packet was received\r
+   * @return 1 if the packet was 'eaten' (aka. deleted),\r
+   *         0 if the packet lives on\r
+   * If returning 1, the callback is responsible for freeing the pbuf\r
+   * if it's not used any more.\r
+   */\r
+  u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr);\r
+  /* user-supplied argument for the recv callback */\r
+  void *recv_arg;\r
+};\r
+\r
+/* The following functions is the application layer interface to the\r
+   RAW code. */\r
+struct raw_pcb * raw_new        (u8_t proto);\r
+void             raw_remove     (struct raw_pcb *pcb);\r
+err_t            raw_bind       (struct raw_pcb *pcb, struct ip_addr *ipaddr);\r
+err_t            raw_connect    (struct raw_pcb *pcb, struct ip_addr *ipaddr);\r
+\r
+void             raw_recv       (struct raw_pcb *pcb,\r
+                                 u8_t (* recv)(void *arg, struct raw_pcb *pcb,\r
+                                              struct pbuf *p,\r
+                                              struct ip_addr *addr),\r
+                                 void *recv_arg);\r
+err_t            raw_sendto     (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);\r
+err_t            raw_send       (struct raw_pcb *pcb, struct pbuf *p);\r
+\r
+/* The following functions are the lower layer interface to RAW. */\r
+u8_t             raw_input      (struct pbuf *p, struct netif *inp);\r
+#define raw_init() /* Compatibility define, not init needed. */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_RAW */\r
+\r
+#endif /* __LWIP_RAW_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/sio.h
new file mode 100644 (file)
index 0000000..79cf292
--- /dev/null
@@ -0,0 +1,71 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ */\r
+\r
+/*\r
+ * This is the interface to the platform specific serial IO module\r
+ * It needs to be implemented by those platforms which need SLIP or PPP\r
+ */\r
+\r
+#include "lwip/arch.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifndef __sio_fd_t_defined\r
+typedef void * sio_fd_t;\r
+#endif\r
+\r
+#ifndef sio_open\r
+sio_fd_t sio_open(u8_t);\r
+#endif\r
+\r
+#ifndef sio_send\r
+void sio_send(u8_t, sio_fd_t);\r
+#endif\r
+\r
+#ifndef sio_recv\r
+u8_t sio_recv(sio_fd_t);\r
+#endif\r
+\r
+#ifndef sio_read\r
+u32_t sio_read(sio_fd_t, u8_t *, u32_t);\r
+#endif\r
+\r
+#ifndef sio_write\r
+u32_t sio_write(sio_fd_t, u8_t *, u32_t);\r
+#endif\r
+\r
+#ifndef sio_read_abort\r
+void sio_read_abort(sio_fd_t);\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp.h
new file mode 100644 (file)
index 0000000..d775d3e
--- /dev/null
@@ -0,0 +1,364 @@
+/*\r
+ * Copyright (c) 2001, 2002 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2001, 2002 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ *\r
+ */\r
+#ifndef __LWIP_SNMP_H__\r
+#define __LWIP_SNMP_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/udp.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/**\r
+ * @see RFC1213, "MIB-II, 6. Definitions"\r
+ */\r
+enum snmp_ifType {\r
+  snmp_ifType_other=1,                /* none of the following */\r
+  snmp_ifType_regular1822,\r
+  snmp_ifType_hdh1822,\r
+  snmp_ifType_ddn_x25,\r
+  snmp_ifType_rfc877_x25,\r
+  snmp_ifType_ethernet_csmacd,\r
+  snmp_ifType_iso88023_csmacd,\r
+  snmp_ifType_iso88024_tokenBus,\r
+  snmp_ifType_iso88025_tokenRing,\r
+  snmp_ifType_iso88026_man,\r
+  snmp_ifType_starLan,\r
+  snmp_ifType_proteon_10Mbit,\r
+  snmp_ifType_proteon_80Mbit,\r
+  snmp_ifType_hyperchannel,\r
+  snmp_ifType_fddi,\r
+  snmp_ifType_lapb,\r
+  snmp_ifType_sdlc,\r
+  snmp_ifType_ds1,                    /* T-1 */\r
+  snmp_ifType_e1,                     /* european equiv. of T-1 */\r
+  snmp_ifType_basicISDN,\r
+  snmp_ifType_primaryISDN,            /* proprietary serial */\r
+  snmp_ifType_propPointToPointSerial,\r
+  snmp_ifType_ppp,\r
+  snmp_ifType_softwareLoopback,\r
+  snmp_ifType_eon,                    /* CLNP over IP [11] */\r
+  snmp_ifType_ethernet_3Mbit,\r
+  snmp_ifType_nsip,                   /* XNS over IP */\r
+  snmp_ifType_slip,                   /* generic SLIP */\r
+  snmp_ifType_ultra,                  /* ULTRA technologies */\r
+  snmp_ifType_ds3,                    /* T-3 */\r
+  snmp_ifType_sip,                    /* SMDS */\r
+  snmp_ifType_frame_relay\r
+};\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+/** SNMP "sysuptime" Interval */\r
+#define SNMP_SYSUPTIME_INTERVAL 10\r
+\r
+/** fixed maximum length for object identifier type */\r
+#define LWIP_SNMP_OBJ_ID_LEN 32\r
+\r
+/** internal object identifier representation */\r
+struct snmp_obj_id\r
+{\r
+  u8_t len;\r
+  s32_t id[LWIP_SNMP_OBJ_ID_LEN];\r
+};\r
+\r
+/* system */\r
+void snmp_set_sysdesr(u8_t* str, u8_t* len);\r
+void snmp_set_sysobjid(struct snmp_obj_id *oid);\r
+void snmp_get_sysobjid_ptr(struct snmp_obj_id **oid);\r
+void snmp_inc_sysuptime(void);\r
+void snmp_add_sysuptime(u32_t value);\r
+void snmp_get_sysuptime(u32_t *value);\r
+void snmp_set_syscontact(u8_t *ocstr, u8_t *ocstrlen);\r
+void snmp_set_sysname(u8_t *ocstr, u8_t *ocstrlen);\r
+void snmp_set_syslocation(u8_t *ocstr, u8_t *ocstrlen);\r
+\r
+/* network interface */\r
+void snmp_add_ifinoctets(struct netif *ni, u32_t value);\r
+void snmp_inc_ifinucastpkts(struct netif *ni);\r
+void snmp_inc_ifinnucastpkts(struct netif *ni);\r
+void snmp_inc_ifindiscards(struct netif *ni);\r
+void snmp_add_ifoutoctets(struct netif *ni, u32_t value);\r
+void snmp_inc_ifoutucastpkts(struct netif *ni);\r
+void snmp_inc_ifoutnucastpkts(struct netif *ni);\r
+void snmp_inc_ifoutdiscards(struct netif *ni);\r
+void snmp_inc_iflist(void);\r
+void snmp_dec_iflist(void);\r
+\r
+/* ARP (for atTable and ipNetToMediaTable) */\r
+void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);\r
+void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);\r
+\r
+/* IP */\r
+void snmp_inc_ipinreceives(void);\r
+void snmp_inc_ipinhdrerrors(void);\r
+void snmp_inc_ipinaddrerrors(void);\r
+void snmp_inc_ipforwdatagrams(void);\r
+void snmp_inc_ipinunknownprotos(void);\r
+void snmp_inc_ipindiscards(void);\r
+void snmp_inc_ipindelivers(void);\r
+void snmp_inc_ipoutrequests(void);\r
+void snmp_inc_ipoutdiscards(void);\r
+void snmp_inc_ipoutnoroutes(void);\r
+void snmp_inc_ipreasmreqds(void);\r
+void snmp_inc_ipreasmoks(void);\r
+void snmp_inc_ipreasmfails(void);\r
+void snmp_inc_ipfragoks(void);\r
+void snmp_inc_ipfragfails(void);\r
+void snmp_inc_ipfragcreates(void);\r
+void snmp_inc_iproutingdiscards(void);\r
+void snmp_insert_ipaddridx_tree(struct netif *ni);\r
+void snmp_delete_ipaddridx_tree(struct netif *ni);\r
+void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni);\r
+void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni);\r
+\r
+/* ICMP */\r
+void snmp_inc_icmpinmsgs(void);\r
+void snmp_inc_icmpinerrors(void);\r
+void snmp_inc_icmpindestunreachs(void);\r
+void snmp_inc_icmpintimeexcds(void);\r
+void snmp_inc_icmpinparmprobs(void);\r
+void snmp_inc_icmpinsrcquenchs(void);\r
+void snmp_inc_icmpinredirects(void);\r
+void snmp_inc_icmpinechos(void);\r
+void snmp_inc_icmpinechoreps(void);\r
+void snmp_inc_icmpintimestamps(void);\r
+void snmp_inc_icmpintimestampreps(void);\r
+void snmp_inc_icmpinaddrmasks(void);\r
+void snmp_inc_icmpinaddrmaskreps(void);\r
+void snmp_inc_icmpoutmsgs(void);\r
+void snmp_inc_icmpouterrors(void);\r
+void snmp_inc_icmpoutdestunreachs(void);\r
+void snmp_inc_icmpouttimeexcds(void);\r
+void snmp_inc_icmpoutparmprobs(void);\r
+void snmp_inc_icmpoutsrcquenchs(void);\r
+void snmp_inc_icmpoutredirects(void);\r
+void snmp_inc_icmpoutechos(void);\r
+void snmp_inc_icmpoutechoreps(void);\r
+void snmp_inc_icmpouttimestamps(void);\r
+void snmp_inc_icmpouttimestampreps(void);\r
+void snmp_inc_icmpoutaddrmasks(void);\r
+void snmp_inc_icmpoutaddrmaskreps(void);\r
+\r
+/* TCP */\r
+void snmp_inc_tcpactiveopens(void);\r
+void snmp_inc_tcppassiveopens(void);\r
+void snmp_inc_tcpattemptfails(void);\r
+void snmp_inc_tcpestabresets(void);\r
+void snmp_inc_tcpinsegs(void);\r
+void snmp_inc_tcpoutsegs(void);\r
+void snmp_inc_tcpretranssegs(void);\r
+void snmp_inc_tcpinerrs(void);\r
+void snmp_inc_tcpoutrsts(void);\r
+\r
+/* UDP */\r
+void snmp_inc_udpindatagrams(void);\r
+void snmp_inc_udpnoports(void);\r
+void snmp_inc_udpinerrors(void);\r
+void snmp_inc_udpoutdatagrams(void);\r
+void snmp_insert_udpidx_tree(struct udp_pcb *pcb);\r
+void snmp_delete_udpidx_tree(struct udp_pcb *pcb);\r
+\r
+/* SNMP */\r
+void snmp_inc_snmpinpkts(void);\r
+void snmp_inc_snmpoutpkts(void);\r
+void snmp_inc_snmpinbadversions(void);\r
+void snmp_inc_snmpinbadcommunitynames(void);\r
+void snmp_inc_snmpinbadcommunityuses(void);\r
+void snmp_inc_snmpinasnparseerrs(void);\r
+void snmp_inc_snmpintoobigs(void);\r
+void snmp_inc_snmpinnosuchnames(void);\r
+void snmp_inc_snmpinbadvalues(void);\r
+void snmp_inc_snmpinreadonlys(void);\r
+void snmp_inc_snmpingenerrs(void);\r
+void snmp_add_snmpintotalreqvars(u8_t value);\r
+void snmp_add_snmpintotalsetvars(u8_t value);\r
+void snmp_inc_snmpingetrequests(void);\r
+void snmp_inc_snmpingetnexts(void);\r
+void snmp_inc_snmpinsetrequests(void);\r
+void snmp_inc_snmpingetresponses(void);\r
+void snmp_inc_snmpintraps(void);\r
+void snmp_inc_snmpouttoobigs(void);\r
+void snmp_inc_snmpoutnosuchnames(void);\r
+void snmp_inc_snmpoutbadvalues(void);\r
+void snmp_inc_snmpoutgenerrs(void);\r
+void snmp_inc_snmpoutgetrequests(void);\r
+void snmp_inc_snmpoutgetnexts(void);\r
+void snmp_inc_snmpoutsetrequests(void);\r
+void snmp_inc_snmpoutgetresponses(void);\r
+void snmp_inc_snmpouttraps(void);\r
+void snmp_get_snmpgrpid_ptr(struct snmp_obj_id **oid);\r
+void snmp_set_snmpenableauthentraps(u8_t *value);\r
+void snmp_get_snmpenableauthentraps(u8_t *value);\r
+\r
+/* LWIP_SNMP support not available */\r
+/* define everything to be empty */\r
+#else\r
+\r
+/* system */\r
+#define snmp_set_sysdesr(str, len)\r
+#define snmp_set_sysobjid(oid);\r
+#define snmp_get_sysobjid_ptr(oid)\r
+#define snmp_inc_sysuptime()\r
+#define snmp_add_sysuptime(value)\r
+#define snmp_get_sysuptime(value)\r
+#define snmp_set_syscontact(ocstr, ocstrlen);\r
+#define snmp_set_sysname(ocstr, ocstrlen);\r
+#define snmp_set_syslocation(ocstr, ocstrlen);\r
+\r
+/* network interface */\r
+#define snmp_add_ifinoctets(ni,value)\r
+#define snmp_inc_ifinucastpkts(ni)\r
+#define snmp_inc_ifinnucastpkts(ni)\r
+#define snmp_inc_ifindiscards(ni)\r
+#define snmp_add_ifoutoctets(ni,value)\r
+#define snmp_inc_ifoutucastpkts(ni)\r
+#define snmp_inc_ifoutnucastpkts(ni)\r
+#define snmp_inc_ifoutdiscards(ni)\r
+#define snmp_inc_iflist()\r
+#define snmp_dec_iflist()\r
+\r
+/* ARP */\r
+#define snmp_insert_arpidx_tree(ni,ip)\r
+#define snmp_delete_arpidx_tree(ni,ip)\r
+\r
+/* IP */\r
+#define snmp_inc_ipinreceives()\r
+#define snmp_inc_ipinhdrerrors()\r
+#define snmp_inc_ipinaddrerrors()\r
+#define snmp_inc_ipforwdatagrams()\r
+#define snmp_inc_ipinunknownprotos()\r
+#define snmp_inc_ipindiscards()\r
+#define snmp_inc_ipindelivers()\r
+#define snmp_inc_ipoutrequests()\r
+#define snmp_inc_ipoutdiscards()\r
+#define snmp_inc_ipoutnoroutes()\r
+#define snmp_inc_ipreasmreqds()\r
+#define snmp_inc_ipreasmoks()\r
+#define snmp_inc_ipreasmfails()\r
+#define snmp_inc_ipfragoks()\r
+#define snmp_inc_ipfragfails()\r
+#define snmp_inc_ipfragcreates()\r
+#define snmp_inc_iproutingdiscards()\r
+#define snmp_insert_ipaddridx_tree(ni)\r
+#define snmp_delete_ipaddridx_tree(ni)\r
+#define snmp_insert_iprteidx_tree(dflt, ni)\r
+#define snmp_delete_iprteidx_tree(dflt, ni)\r
+\r
+/* ICMP */\r
+#define snmp_inc_icmpinmsgs()\r
+#define snmp_inc_icmpinerrors()\r
+#define snmp_inc_icmpindestunreachs()\r
+#define snmp_inc_icmpintimeexcds()\r
+#define snmp_inc_icmpinparmprobs()\r
+#define snmp_inc_icmpinsrcquenchs()\r
+#define snmp_inc_icmpinredirects()\r
+#define snmp_inc_icmpinechos()\r
+#define snmp_inc_icmpinechoreps()\r
+#define snmp_inc_icmpintimestamps()\r
+#define snmp_inc_icmpintimestampreps()\r
+#define snmp_inc_icmpinaddrmasks()\r
+#define snmp_inc_icmpinaddrmaskreps()\r
+#define snmp_inc_icmpoutmsgs()\r
+#define snmp_inc_icmpouterrors()\r
+#define snmp_inc_icmpoutdestunreachs()\r
+#define snmp_inc_icmpouttimeexcds()\r
+#define snmp_inc_icmpoutparmprobs()\r
+#define snmp_inc_icmpoutsrcquenchs()\r
+#define snmp_inc_icmpoutredirects()\r
+#define snmp_inc_icmpoutechos()\r
+#define snmp_inc_icmpoutechoreps()\r
+#define snmp_inc_icmpouttimestamps()\r
+#define snmp_inc_icmpouttimestampreps()\r
+#define snmp_inc_icmpoutaddrmasks()\r
+#define snmp_inc_icmpoutaddrmaskreps()\r
+/* TCP */\r
+#define snmp_inc_tcpactiveopens()\r
+#define snmp_inc_tcppassiveopens()\r
+#define snmp_inc_tcpattemptfails()\r
+#define snmp_inc_tcpestabresets()\r
+#define snmp_inc_tcpinsegs()\r
+#define snmp_inc_tcpoutsegs()\r
+#define snmp_inc_tcpretranssegs()\r
+#define snmp_inc_tcpinerrs()\r
+#define snmp_inc_tcpoutrsts()\r
+\r
+/* UDP */\r
+#define snmp_inc_udpindatagrams()\r
+#define snmp_inc_udpnoports()\r
+#define snmp_inc_udpinerrors()\r
+#define snmp_inc_udpoutdatagrams()\r
+#define snmp_insert_udpidx_tree(pcb)\r
+#define snmp_delete_udpidx_tree(pcb)\r
+\r
+/* SNMP */\r
+#define snmp_inc_snmpinpkts()\r
+#define snmp_inc_snmpoutpkts()\r
+#define snmp_inc_snmpinbadversions()\r
+#define snmp_inc_snmpinbadcommunitynames()\r
+#define snmp_inc_snmpinbadcommunityuses()\r
+#define snmp_inc_snmpinasnparseerrs()\r
+#define snmp_inc_snmpintoobigs()\r
+#define snmp_inc_snmpinnosuchnames()\r
+#define snmp_inc_snmpinbadvalues()\r
+#define snmp_inc_snmpinreadonlys()\r
+#define snmp_inc_snmpingenerrs()\r
+#define snmp_add_snmpintotalreqvars(value)\r
+#define snmp_add_snmpintotalsetvars(value)\r
+#define snmp_inc_snmpingetrequests()\r
+#define snmp_inc_snmpingetnexts()\r
+#define snmp_inc_snmpinsetrequests()\r
+#define snmp_inc_snmpingetresponses()\r
+#define snmp_inc_snmpintraps()\r
+#define snmp_inc_snmpouttoobigs()\r
+#define snmp_inc_snmpoutnosuchnames()\r
+#define snmp_inc_snmpoutbadvalues()\r
+#define snmp_inc_snmpoutgenerrs()\r
+#define snmp_inc_snmpoutgetrequests()\r
+#define snmp_inc_snmpoutgetnexts()\r
+#define snmp_inc_snmpoutsetrequests()\r
+#define snmp_inc_snmpoutgetresponses()\r
+#define snmp_inc_snmpouttraps()\r
+#define snmp_get_snmpgrpid_ptr(oid)\r
+#define snmp_set_snmpenableauthentraps(value)\r
+#define snmp_get_snmpenableauthentraps(value)\r
+\r
+#endif /* LWIP_SNMP */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_SNMP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_asn1.h
new file mode 100644 (file)
index 0000000..fd1c4ec
--- /dev/null
@@ -0,0 +1,97 @@
+/**\r
+ * @file\r
+ * Abstract Syntax Notation One (ISO 8824, 8825) codec.\r
+ */\r
\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_ASN1_H__\r
+#define __LWIP_SNMP_ASN1_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/err.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/snmp.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define SNMP_ASN1_UNIV   (!0x80 | !0x40)\r
+#define SNMP_ASN1_APPLIC (!0x80 |  0x40)\r
+#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)\r
+\r
+#define SNMP_ASN1_CONSTR (0x20)\r
+#define SNMP_ASN1_PRIMIT (!0x20)\r
+\r
+/* universal tags */\r
+#define SNMP_ASN1_INTEG  2\r
+#define SNMP_ASN1_OC_STR 4\r
+#define SNMP_ASN1_NUL    5\r
+#define SNMP_ASN1_OBJ_ID 6\r
+#define SNMP_ASN1_SEQ    16\r
+\r
+/* application specific (SNMP) tags */\r
+#define SNMP_ASN1_IPADDR 0    /* octet string size(4) */\r
+#define SNMP_ASN1_COUNTER 1   /* u32_t */\r
+#define SNMP_ASN1_GAUGE 2     /* u32_t */\r
+#define SNMP_ASN1_TIMETICKS 3 /* u32_t */\r
+#define SNMP_ASN1_OPAQUE 4    /* octet string */\r
+\r
+/* context specific (SNMP) tags */\r
+#define SNMP_ASN1_PDU_GET_REQ 0\r
+#define SNMP_ASN1_PDU_GET_NEXT_REQ 1\r
+#define SNMP_ASN1_PDU_GET_RESP 2\r
+#define SNMP_ASN1_PDU_SET_REQ 3\r
+#define SNMP_ASN1_PDU_TRAP 4\r
+\r
+err_t snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type);\r
+err_t snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length);\r
+err_t snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value);\r
+err_t snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value);\r
+err_t snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid);\r
+err_t snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw);\r
+\r
+void snmp_asn1_enc_length_cnt(u16_t length, u8_t *octets_needed);\r
+void snmp_asn1_enc_u32t_cnt(u32_t value, u16_t *octets_needed);\r
+void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);\r
+void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);\r
+err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);\r
+err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);\r
+err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);\r
+err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);\r
+err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);\r
+err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_SNMP_ASN1_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_msg.h
new file mode 100644 (file)
index 0000000..017be6a
--- /dev/null
@@ -0,0 +1,307 @@
+/**\r
+ * @file\r
+ * SNMP Agent message handling structures.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_MSG_H__\r
+#define __LWIP_SNMP_MSG_H__\r
+\r
+#include "lwip/opt.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/snmp_structs.h"\r
+\r
+#if SNMP_PRIVATE_MIB\r
+#include "private_mib.h"\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* The listen port of the SNMP agent. Clients have to make their requests to\r
+   this port. Most standard clients won't work if you change this! */\r
+#ifndef SNMP_IN_PORT\r
+#define SNMP_IN_PORT 161\r
+#endif\r
+/* The remote port the SNMP agent sends traps to. Most standard trap sinks won't\r
+   work if you change this! */\r
+#ifndef SNMP_TRAP_PORT\r
+#define SNMP_TRAP_PORT 162\r
+#endif\r
+\r
+#define SNMP_ES_NOERROR 0\r
+#define SNMP_ES_TOOBIG 1\r
+#define SNMP_ES_NOSUCHNAME 2\r
+#define SNMP_ES_BADVALUE 3\r
+#define SNMP_ES_READONLY 4\r
+#define SNMP_ES_GENERROR 5\r
+\r
+#define SNMP_GENTRAP_COLDSTART 0\r
+#define SNMP_GENTRAP_WARMSTART 1\r
+#define SNMP_GENTRAP_AUTHFAIL 4\r
+#define SNMP_GENTRAP_ENTERPRISESPC 6\r
+\r
+struct snmp_varbind\r
+{\r
+  /* next pointer, NULL for last in list */\r
+  struct snmp_varbind *next;\r
+  /* previous pointer, NULL for first in list */\r
+  struct snmp_varbind *prev;\r
+\r
+  /* object identifier length (in s32_t) */\r
+  u8_t ident_len;\r
+  /* object identifier array */\r
+  s32_t *ident;\r
+\r
+  /* object value ASN1 type */\r
+  u8_t value_type;\r
+  /* object value length (in u8_t) */\r
+  u8_t value_len;\r
+  /* object value */\r
+  void *value;\r
+\r
+  /* encoding varbind seq length length */\r
+  u8_t seqlenlen;\r
+  /* encoding object identifier length length */\r
+  u8_t olenlen;\r
+  /* encoding object value length length */\r
+  u8_t vlenlen;\r
+  /* encoding varbind seq length */\r
+  u16_t seqlen;\r
+  /* encoding object identifier length */\r
+  u16_t olen;\r
+  /* encoding object value length */\r
+  u16_t vlen;\r
+};\r
+\r
+struct snmp_varbind_root\r
+{\r
+  struct snmp_varbind *head;\r
+  struct snmp_varbind *tail;\r
+  /* number of variable bindings in list */\r
+  u8_t count;\r
+  /* encoding varbind-list seq length length */\r
+  u8_t seqlenlen;\r
+  /* encoding varbind-list seq length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/** output response message header length fields */\r
+struct snmp_resp_header_lengths\r
+{\r
+  /* encoding error-index length length */\r
+  u8_t erridxlenlen;\r
+  /* encoding error-status length length */\r
+  u8_t errstatlenlen;\r
+  /* encoding request id length length */\r
+  u8_t ridlenlen;\r
+  /* encoding pdu length length */\r
+  u8_t pdulenlen;\r
+  /* encoding community length length */\r
+  u8_t comlenlen;\r
+  /* encoding version length length */\r
+  u8_t verlenlen;\r
+  /* encoding sequence length length */\r
+  u8_t seqlenlen;\r
+\r
+  /* encoding error-index length */\r
+  u16_t erridxlen;\r
+  /* encoding error-status length */\r
+  u16_t errstatlen;\r
+  /* encoding request id length */\r
+  u16_t ridlen;\r
+  /* encoding pdu length */\r
+  u16_t pdulen;\r
+  /* encoding community length */\r
+  u16_t comlen;\r
+  /* encoding version length */\r
+  u16_t verlen;\r
+  /* encoding sequence length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/** output response message header length fields */\r
+struct snmp_trap_header_lengths\r
+{\r
+  /* encoding timestamp length length */\r
+  u8_t tslenlen;\r
+  /* encoding specific-trap length length */\r
+  u8_t strplenlen;\r
+  /* encoding generic-trap length length */\r
+  u8_t gtrplenlen;\r
+  /* encoding agent-addr length length */\r
+  u8_t aaddrlenlen;\r
+  /* encoding enterprise-id length length */\r
+  u8_t eidlenlen;\r
+  /* encoding pdu length length */\r
+  u8_t pdulenlen;\r
+  /* encoding community length length */\r
+  u8_t comlenlen;\r
+  /* encoding version length length */\r
+  u8_t verlenlen;\r
+  /* encoding sequence length length */\r
+  u8_t seqlenlen;\r
+\r
+  /* encoding timestamp length */\r
+  u16_t tslen;\r
+  /* encoding specific-trap length */\r
+  u16_t strplen;\r
+  /* encoding generic-trap length */\r
+  u16_t gtrplen;\r
+  /* encoding agent-addr length */\r
+  u16_t aaddrlen;\r
+  /* encoding enterprise-id length */\r
+  u16_t eidlen;\r
+  /* encoding pdu length */\r
+  u16_t pdulen;\r
+  /* encoding community length */\r
+  u16_t comlen;\r
+  /* encoding version length */\r
+  u16_t verlen;\r
+  /* encoding sequence length */\r
+  u16_t seqlen;\r
+};\r
+\r
+/* Accepting new SNMP messages. */\r
+#define SNMP_MSG_EMPTY                 0\r
+/* Search for matching object for variable binding. */\r
+#define SNMP_MSG_SEARCH_OBJ            1\r
+/* Perform SNMP operation on in-memory object.\r
+   Pass-through states, for symmetry only. */\r
+#define SNMP_MSG_INTERNAL_GET_OBJDEF   2\r
+#define SNMP_MSG_INTERNAL_GET_VALUE    3\r
+#define SNMP_MSG_INTERNAL_SET_TEST     4\r
+#define SNMP_MSG_INTERNAL_GET_OBJDEF_S 5\r
+#define SNMP_MSG_INTERNAL_SET_VALUE    6\r
+/* Perform SNMP operation on object located externally.\r
+   In theory this could be used for building a proxy agent.\r
+   Practical use is for an enterprise spc. app. gateway. */\r
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF   7\r
+#define SNMP_MSG_EXTERNAL_GET_VALUE    8\r
+#define SNMP_MSG_EXTERNAL_SET_TEST     9\r
+#define SNMP_MSG_EXTERNAL_GET_OBJDEF_S 10\r
+#define SNMP_MSG_EXTERNAL_SET_VALUE    11\r
+\r
+#define SNMP_COMMUNITY_STR_LEN 64\r
+struct snmp_msg_pstat\r
+{\r
+  /* lwIP local port (161) binding */\r
+  struct udp_pcb *pcb;\r
+  /* source IP address */\r
+  struct ip_addr sip;\r
+  /* source UDP port */\r
+  u16_t sp;\r
+  /* request type */\r
+  u8_t rt;\r
+  /* request ID */\r
+  s32_t rid;\r
+  /* error status */\r
+  s32_t error_status;\r
+  /* error index */\r
+  s32_t error_index;\r
+  /* community name (zero terminated) */\r
+  u8_t community[SNMP_COMMUNITY_STR_LEN + 1];\r
+  /* community string length (exclusive zero term) */\r
+  u8_t com_strlen;\r
+  /* one out of MSG_EMPTY, MSG_DEMUX, MSG_INTERNAL, MSG_EXTERNAL_x */\r
+  u8_t state;\r
+  /* saved arguments for MSG_EXTERNAL_x */\r
+  struct mib_external_node *ext_mib_node;\r
+  struct snmp_name_ptr ext_name_ptr;\r
+  struct obj_def ext_object_def;\r
+  struct snmp_obj_id ext_oid;\r
+  /* index into input variable binding list */\r
+  u8_t vb_idx;\r
+  /* ptr into input variable binding list */\r
+  struct snmp_varbind *vb_ptr;\r
+  /* list of variable bindings from input */\r
+  struct snmp_varbind_root invb;\r
+  /* list of variable bindings to output */\r
+  struct snmp_varbind_root outvb;\r
+  /* output response lengths used in ASN encoding */\r
+  struct snmp_resp_header_lengths rhl;\r
+};\r
+\r
+struct snmp_msg_trap\r
+{\r
+  /* lwIP local port (161) binding */\r
+  struct udp_pcb *pcb;\r
+  /* destination IP address in network order */\r
+  struct ip_addr dip;\r
+\r
+  /* source enterprise ID (sysObjectID) */\r
+  struct snmp_obj_id *enterprise;\r
+  /* source IP address, raw network order format */\r
+  u8_t sip_raw[4];\r
+  /* generic trap code */\r
+  u32_t gen_trap;\r
+  /* specific trap code */\r
+  u32_t spc_trap;\r
+  /* timestamp */\r
+  u32_t ts;\r
+  /* list of variable bindings to output */\r
+  struct snmp_varbind_root outvb;\r
+  /* output trap lengths used in ASN encoding */\r
+  struct snmp_trap_header_lengths thl;\r
+};\r
+\r
+/** Agent Version constant, 0 = v1 oddity */\r
+extern const s32_t snmp_version;\r
+/** Agent default "public" community string */\r
+extern const char snmp_publiccommunity[7];\r
+\r
+extern struct snmp_msg_trap trap_msg;\r
+\r
+/** Agent setup, start listening to port 161. */\r
+void snmp_init(void);\r
+void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);\r
+void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);\r
+\r
+/** Varbind-list functions. */\r
+struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);\r
+void snmp_varbind_free(struct snmp_varbind *vb);\r
+void snmp_varbind_list_free(struct snmp_varbind_root *root);\r
+void snmp_varbind_tail_add(struct snmp_varbind_root *root, struct snmp_varbind *vb);\r
+struct snmp_varbind* snmp_varbind_tail_remove(struct snmp_varbind_root *root);\r
+\r
+/** Handle an internal (recv) or external (private response) event. */\r
+void snmp_msg_event(u8_t request_id);\r
+err_t snmp_send_response(struct snmp_msg_pstat *m_stat);\r
+err_t snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap);\r
+void snmp_coldstart_trap(void);\r
+void snmp_authfail_trap(void);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_SNMP_MSG_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/snmp_structs.h
new file mode 100644 (file)
index 0000000..2c86a98
--- /dev/null
@@ -0,0 +1,262 @@
+/**\r
+ * @file\r
+ * Generic MIB tree structures.\r
+ *\r
+ * @todo namespace prefixes\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2006 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * Author: Christiaan Simons <christiaan.simons@axon.tv>\r
+ */\r
+\r
+#ifndef __LWIP_SNMP_STRUCTS_H__\r
+#define __LWIP_SNMP_STRUCTS_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/snmp.h"\r
+\r
+#if SNMP_PRIVATE_MIB\r
+#include "private_mib.h"\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* MIB object instance */\r
+#define MIB_OBJECT_NONE 0 \r
+#define MIB_OBJECT_SCALAR 1\r
+#define MIB_OBJECT_TAB 2\r
+\r
+/* MIB object access */\r
+#define MIB_OBJECT_READ_ONLY 0\r
+#define MIB_OBJECT_READ_WRITE 1\r
+#define MIB_OBJECT_WRITE_ONLY 2\r
+#define MIB_OBJECT_NOT_ACCESSIBLE 3\r
+\r
+/** object definition returned by (get_object_def)() */\r
+struct obj_def\r
+{\r
+  /* MIB_OBJECT_NONE (0), MIB_OBJECT_SCALAR (1), MIB_OBJECT_TAB (2) */\r
+  u8_t instance;\r
+  /* 0 read-only, 1 read-write, 2 write-only, 3 not-accessible */\r
+  u8_t access;\r
+  /* ASN type for this object */\r
+  u8_t asn_type;\r
+  /* value length (host length) */\r
+  u16_t v_len;\r
+  /* length of instance part of supplied object identifier */\r
+  u8_t  id_inst_len;\r
+  /* instance part of supplied object identifier */\r
+  s32_t *id_inst_ptr;\r
+};\r
+\r
+struct snmp_name_ptr\r
+{\r
+  u8_t ident_len;\r
+  s32_t *ident;\r
+};\r
+\r
+/** MIB const scalar (.0) node */\r
+#define MIB_NODE_SC 0x01\r
+/** MIB const array node */\r
+#define MIB_NODE_AR 0x02\r
+/** MIB array node (mem_malloced from RAM) */\r
+#define MIB_NODE_RA 0x03\r
+/** MIB list root node (mem_malloced from RAM) */\r
+#define MIB_NODE_LR 0x04\r
+/** MIB node for external objects */\r
+#define MIB_NODE_EX 0x05\r
+\r
+/** node "base class" layout, the mandatory fields for a node  */\r
+struct mib_node\r
+{\r
+  /** returns struct obj_def for the given object identifier */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  /** returns object value for the given object identifier,\r
+     @note the caller must allocate at least len bytes for the value */\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  /** tests length and/or range BEFORE setting */\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  /** sets object value, only to be called when set_test()  */\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);  \r
+  /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */\r
+  const u8_t node_type;\r
+  /* array or max list length */\r
+  const u16_t maxlength;\r
+};\r
+\r
+/** derived node for scalars .0 index */\r
+typedef struct mib_node mib_scalar_node;\r
+\r
+/** derived node, points to a fixed size const array\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_array_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (* const get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  const u8_t node_type;\r
+  const u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  const s32_t *objid;\r
+  struct mib_node* const *nptr;\r
+};\r
+\r
+/** derived node, points to a fixed size mem_malloced array\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_ram_array_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  s32_t *objid;\r
+  struct mib_node **nptr;\r
+};\r
+\r
+struct mib_list_node\r
+{\r
+  struct mib_list_node *prev;  \r
+  struct mib_list_node *next;\r
+  s32_t objid;\r
+  struct mib_node *nptr;\r
+};\r
+\r
+/** derived node, points to a doubly linked list\r
+    of sub-identifiers plus a 'child' pointer */\r
+struct mib_list_rootnode\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  struct mib_list_node *head;\r
+  struct mib_list_node *tail;\r
+  /* counts list nodes in list  */\r
+  u16_t count;\r
+};\r
+\r
+/** derived node, has access functions for mib object in external memory or device\r
+    using 'tree_level' and 'idx', with a range 0 .. (level_length() - 1) */\r
+struct mib_external_node\r
+{\r
+  /* inherited "base class" members */\r
+  void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value)(struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value)(struct obj_def *od, u16_t len, void *value);\r
+\r
+  u8_t node_type;\r
+  u16_t maxlength;\r
+\r
+  /* aditional struct members */\r
+  /** points to an extenal (in memory) record of some sort of addressing\r
+      information, passed to and interpreted by the funtions below */\r
+  void* addr_inf;\r
+  /** tree levels under this node */\r
+  u8_t tree_levels;\r
+  /** number of objects at this level */\r
+  u16_t (*level_length)(void* addr_inf, u8_t level);\r
+  /** compares object sub identifier with external id\r
+      return zero when equal, nonzero when unequal */\r
+  s32_t (*ident_cmp)(void* addr_inf, u8_t level, u16_t idx, s32_t sub_id);\r
+  void (*get_objid)(void* addr_inf, u8_t level, u16_t idx, s32_t *sub_id);\r
+\r
+  /** async Questions */\r
+  void (*get_object_def_q)(void* addr_inf, u8_t rid, u8_t ident_len, s32_t *ident);\r
+  void (*get_value_q)(u8_t rid, struct obj_def *od);\r
+  void (*set_test_q)(u8_t rid, struct obj_def *od);\r
+  void (*set_value_q)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  /** async Answers */\r
+  void (*get_object_def_a)(u8_t rid, u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+  void (*get_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  u8_t (*set_test_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  void (*set_value_a)(u8_t rid, struct obj_def *od, u16_t len, void *value);\r
+  /** async Panic Close (agent returns error reply, \r
+      e.g. used for external transaction cleanup) */\r
+  void (*get_object_def_pc)(u8_t rid, u8_t ident_len, s32_t *ident);\r
+  void (*get_value_pc)(u8_t rid, struct obj_def *od);\r
+  void (*set_test_pc)(u8_t rid, struct obj_def *od);\r
+  void (*set_value_pc)(u8_t rid, struct obj_def *od);\r
+};\r
+\r
+/** export MIB tree from mib2.c */\r
+extern const struct mib_array_node internet;\r
+\r
+/** dummy function pointers for non-leaf MIB nodes from mib2.c */\r
+void noleafs_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od);\r
+void noleafs_get_value(struct obj_def *od, u16_t len, void *value);\r
+u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);\r
+void noleafs_set_value(struct obj_def *od, u16_t len, void *value);\r
+\r
+void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);\r
+void snmp_iptooid(struct ip_addr *ip, s32_t *ident);\r
+void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);\r
+void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);\r
+\r
+struct mib_list_node* snmp_mib_ln_alloc(s32_t id);\r
+void snmp_mib_ln_free(struct mib_list_node *ln);\r
+struct mib_list_rootnode* snmp_mib_lrn_alloc(void);\r
+void snmp_mib_lrn_free(struct mib_list_rootnode *lrn);\r
+\r
+s8_t snmp_mib_node_insert(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **insn);\r
+s8_t snmp_mib_node_find(struct mib_list_rootnode *rn, s32_t objid, struct mib_list_node **fn);\r
+struct mib_list_rootnode *snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n);\r
+\r
+struct mib_node* snmp_search_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_name_ptr *np);\r
+struct mib_node* snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\r
+u8_t snmp_iso_prefix_tst(u8_t ident_len, s32_t *ident);\r
+u8_t snmp_iso_prefix_expand(u8_t ident_len, s32_t *ident, struct snmp_obj_id *oidret);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_SNMP */\r
+\r
+#endif /* __LWIP_SNMP_STRUCTS_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/sockets.h
new file mode 100644 (file)
index 0000000..aa3e65c
--- /dev/null
@@ -0,0 +1,337 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+\r
+#ifndef __LWIP_SOCKETS_H__\r
+#define __LWIP_SOCKETS_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/inet.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+/* members are in network byte order */\r
+struct sockaddr_in {\r
+  u8_t sin_len;\r
+  u8_t sin_family;\r
+  u16_t sin_port;\r
+  struct in_addr sin_addr;\r
+  char sin_zero[8];\r
+};\r
+\r
+struct sockaddr {\r
+  u8_t sa_len;\r
+  u8_t sa_family;\r
+  char sa_data[14];\r
+};\r
+\r
+#ifndef socklen_t\r
+#  define socklen_t u32_t\r
+#endif\r
+\r
+/* Socket protocol types (TCP/UDP/RAW) */\r
+#define SOCK_STREAM     1\r
+#define SOCK_DGRAM      2\r
+#define SOCK_RAW        3\r
+\r
+/*\r
+ * Option flags per-socket. These must match the SOF_ flags in ip.h!\r
+ */\r
+#define  SO_DEBUG       0x0001 /* Unimplemented: turn on debugging info recording */\r
+#define  SO_ACCEPTCONN  0x0002 /* socket has had listen() */\r
+#define  SO_REUSEADDR   0x0004 /* Unimplemented: allow local address reuse */\r
+#define  SO_KEEPALIVE   0x0008 /* keep connections alive */\r
+#define  SO_DONTROUTE   0x0010 /* Unimplemented: just use interface addresses */\r
+#define  SO_BROADCAST   0x0020 /* Unimplemented: permit sending of broadcast msgs */\r
+#define  SO_USELOOPBACK 0x0040 /* Unimplemented: bypass hardware when possible */\r
+#define  SO_LINGER      0x0080 /* linger on close if data present */\r
+#define  SO_OOBINLINE   0x0100 /* Unimplemented: leave received OOB data in line */\r
+#define  SO_REUSEPORT   0x0200 /* Unimplemented: allow local address & port reuse */\r
+\r
+#define SO_DONTLINGER   ((int)(~SO_LINGER))\r
+\r
+/*\r
+ * Additional options, not kept in so_options.\r
+ */\r
+#define SO_SNDBUF    0x1001    /* Unimplemented: send buffer size */\r
+#define SO_RCVBUF    0x1002    /* receive buffer size */\r
+#define SO_SNDLOWAT  0x1003    /* Unimplemented: send low-water mark */\r
+#define SO_RCVLOWAT  0x1004    /* Unimplemented: receive low-water mark */\r
+#define SO_SNDTIMEO  0x1005    /* Unimplemented: send timeout */\r
+#define SO_RCVTIMEO  0x1006    /* receive timeout */\r
+#define SO_ERROR     0x1007    /* get error status and clear */\r
+#define SO_TYPE      0x1008    /* get socket type */\r
+#define SO_CONTIMEO  0x1009    /* Unimplemented: connect timeout */\r
+#define SO_NO_CHECK  0x100a    /* don't create UDP checksum */\r
+\r
+\r
+/*\r
+ * Structure used for manipulating linger option.\r
+ */\r
+struct linger {\r
+       int l_onoff;                /* option on/off */\r
+       int l_linger;               /* linger time */\r
+};\r
+\r
+/*\r
+ * Level number for (get/set)sockopt() to apply to socket itself.\r
+ */\r
+#define  SOL_SOCKET  0xfff    /* options for socket level */\r
+\r
+\r
+#define AF_UNSPEC       0\r
+#define AF_INET         2\r
+#define PF_INET         AF_INET\r
+#define PF_UNSPEC       AF_UNSPEC\r
+\r
+#define IPPROTO_IP      0\r
+#define IPPROTO_TCP     6\r
+#define IPPROTO_UDP     17\r
+#define IPPROTO_UDPLITE 136\r
+\r
+#define INADDR_ANY       0\r
+#define INADDR_BROADCAST 0xffffffff\r
+\r
+/* Flags we can use with send and recv. */\r
+#define MSG_PEEK       0x01    /* Peeks at an incoming message */\r
+#define MSG_WAITALL    0x02    /* Unimplemented: Requests that the function block until the full amount of data requested can be returned */\r
+#define MSG_OOB        0x04    /* Unimplemented: Requests out-of-band data. The significance and semantics of out-of-band data are protocol-specific */\r
+#define MSG_DONTWAIT   0x08    /* Nonblocking i/o for this operation only */\r
+#define MSG_MORE       0x10    /* Sender will send more */\r
+\r
+\r
+/*\r
+ * Options for level IPPROTO_IP\r
+ */\r
+#define IP_TOS             1\r
+#define IP_TTL             2\r
+\r
+#if LWIP_TCP\r
+/*\r
+ * Options for level IPPROTO_TCP\r
+ */\r
+#define TCP_NODELAY    0x01    /* don't delay send to coalesce packets */\r
+#define TCP_KEEPALIVE  0x02    /* send KEEPALIVE probes when idle for pcb->keep_idle milliseconds */\r
+#define TCP_KEEPIDLE   0x03    /* set pcb->keep_idle  - Same as TCP_KEEPALIVE, but use seconds for get/setsockopt */\r
+#define TCP_KEEPINTVL  0x04    /* set pcb->keep_intvl - Use seconds for get/setsockopt */\r
+#define TCP_KEEPCNT    0x05    /* set pcb->keep_cnt   - Use number of probes sent for get/setsockopt */\r
+#endif /* LWIP_TCP */\r
+\r
+#if LWIP_UDP && LWIP_UDPLITE\r
+/*\r
+ * Options for level IPPROTO_UDPLITE\r
+ */\r
+#define UDPLITE_SEND_CSCOV 0x01 /* sender checksum coverage */\r
+#define UDPLITE_RECV_CSCOV 0x02 /* minimal receiver checksum coverage */\r
+#endif /* LWIP_UDP && LWIP_UDPLITE*/\r
+\r
+\r
+#if LWIP_IGMP\r
+/*\r
+ * Options and types for UDP multicast traffic handling\r
+ */\r
+#define IP_ADD_MEMBERSHIP  3\r
+#define IP_DROP_MEMBERSHIP 4\r
+#define IP_MULTICAST_TTL   5\r
+#define IP_MULTICAST_IF    6\r
+#define IP_MULTICAST_LOOP  7\r
+\r
+typedef struct ip_mreq {\r
+    struct in_addr imr_multiaddr; /* IP multicast address of group */\r
+    struct in_addr imr_interface; /* local IP address of interface */\r
+} ip_mreq;\r
+#endif /* LWIP_IGMP */\r
+\r
+/* Unimplemented for now... */\r
+#define IPTOS_TOS_MASK          0x1E\r
+#define IPTOS_TOS(tos)          ((tos) & IPTOS_TOS_MASK)\r
+#define IPTOS_LOWDELAY          0x10\r
+#define IPTOS_THROUGHPUT        0x08\r
+#define IPTOS_RELIABILITY       0x04\r
+#define IPTOS_LOWCOST           0x02\r
+#define IPTOS_MINCOST           IPTOS_LOWCOST\r
+\r
+/*\r
+ * Definitions for IP precedence (also in ip_tos) (Unimplemented)\r
+ */\r
+#define IPTOS_PREC_MASK                 0xe0\r
+#define IPTOS_PREC(tos)                ((tos) & IPTOS_PREC_MASK)\r
+#define IPTOS_PREC_NETCONTROL           0xe0\r
+#define IPTOS_PREC_INTERNETCONTROL      0xc0\r
+#define IPTOS_PREC_CRITIC_ECP           0xa0\r
+#define IPTOS_PREC_FLASHOVERRIDE        0x80\r
+#define IPTOS_PREC_FLASH                0x60\r
+#define IPTOS_PREC_IMMEDIATE            0x40\r
+#define IPTOS_PREC_PRIORITY             0x20\r
+#define IPTOS_PREC_ROUTINE              0x00\r
+\r
+\r
+/*\r
+ * Commands for ioctlsocket(),  taken from the BSD file fcntl.h.\r
+ * lwip_ioctl only supports FIONREAD and FIONBIO, for now\r
+ *\r
+ * Ioctl's have the command encoded in the lower word,\r
+ * and the size of any in or out parameters in the upper\r
+ * word.  The high 2 bits of the upper word are used\r
+ * to encode the in/out status of the parameter; for now\r
+ * we restrict parameters to at most 128 bytes.\r
+ */\r
+#if !defined(FIONREAD) || !defined(FIONBIO)\r
+#define IOCPARM_MASK    0x7fU           /* parameters must be < 128 bytes */\r
+#define IOC_VOID        0x20000000UL    /* no parameters */\r
+#define IOC_OUT         0x40000000UL    /* copy out parameters */\r
+#define IOC_IN          0x80000000UL    /* copy in parameters */\r
+#define IOC_INOUT       (IOC_IN|IOC_OUT)\r
+                                        /* 0x20000000 distinguishes new &\r
+                                           old ioctl's */\r
+#define _IO(x,y)        (IOC_VOID|((x)<<8)|(y))\r
+\r
+#define _IOR(x,y,t)     (IOC_OUT|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\r
+\r
+#define _IOW(x,y,t)     (IOC_IN|(((long)sizeof(t)&IOCPARM_MASK)<<16)|((x)<<8)|(y))\r
+#endif /* !defined(FIONREAD) || !defined(FIONBIO) */\r
+\r
+#ifndef FIONREAD\r
+#define FIONREAD    _IOR('f', 127, unsigned long) /* get # bytes to read */\r
+#endif\r
+#ifndef FIONBIO\r
+#define FIONBIO     _IOW('f', 126, unsigned long) /* set/clear non-blocking i/o */\r
+#endif\r
+\r
+/* Socket I/O Controls: unimplemented */\r
+#ifndef SIOCSHIWAT\r
+#define SIOCSHIWAT  _IOW('s',  0, unsigned long)  /* set high watermark */\r
+#define SIOCGHIWAT  _IOR('s',  1, unsigned long)  /* get high watermark */\r
+#define SIOCSLOWAT  _IOW('s',  2, unsigned long)  /* set low watermark */\r
+#define SIOCGLOWAT  _IOR('s',  3, unsigned long)  /* get low watermark */\r
+#define SIOCATMARK  _IOR('s',  7, unsigned long)  /* at oob mark? */\r
+#endif\r
+\r
+/* Socket flags: */\r
+#ifndef O_NONBLOCK\r
+#define O_NONBLOCK    04000U\r
+#endif\r
+\r
+/* FD_SET used for lwip_select */\r
+#ifndef FD_SET\r
+  #undef  FD_SETSIZE\r
+  /* Make FD_SETSIZE match NUM_SOCKETS in socket.c */\r
+  #define FD_SETSIZE    MEMP_NUM_NETCONN\r
+  #define FD_SET(n, p)  ((p)->fd_bits[(n)/8] |=  (1 << ((n) & 7)))\r
+  #define FD_CLR(n, p)  ((p)->fd_bits[(n)/8] &= ~(1 << ((n) & 7)))\r
+  #define FD_ISSET(n,p) ((p)->fd_bits[(n)/8] &   (1 << ((n) & 7)))\r
+  #define FD_ZERO(p)    memset((void*)(p),0,sizeof(*(p)))\r
+\r
+  typedef struct fd_set {\r
+          unsigned char fd_bits [(FD_SETSIZE+7)/8];\r
+        } fd_set;\r
+\r
+#endif /* FD_SET */\r
+\r
+/** LWIP_TIMEVAL_PRIVATE: if you want to use the struct timeval provided\r
+ * by your system, set this to 0 and include <sys/time.h> in cc.h */\r
+#ifndef LWIP_TIMEVAL_PRIVATE\r
+#define LWIP_TIMEVAL_PRIVATE 1\r
+#endif\r
+\r
+#if LWIP_TIMEVAL_PRIVATE\r
+struct timeval {\r
+  long    tv_sec;         /* seconds */\r
+  long    tv_usec;        /* and microseconds */\r
+};\r
+#endif /* LWIP_TIMEVAL_PRIVATE */\r
+\r
+void lwip_socket_init(void);\r
+\r
+int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen);\r
+int lwip_bind(int s, struct sockaddr *name, socklen_t namelen);\r
+int lwip_shutdown(int s, int how);\r
+int lwip_getpeername (int s, struct sockaddr *name, socklen_t *namelen);\r
+int lwip_getsockname (int s, struct sockaddr *name, socklen_t *namelen);\r
+int lwip_getsockopt (int s, int level, int optname, void *optval, socklen_t *optlen);\r
+int lwip_setsockopt (int s, int level, int optname, const void *optval, socklen_t optlen);\r
+int lwip_close(int s);\r
+int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen);\r
+int lwip_listen(int s, int backlog);\r
+int lwip_recv(int s, void *mem, int len, unsigned int flags);\r
+int lwip_read(int s, void *mem, int len);\r
+int lwip_recvfrom(int s, void *mem, int len, unsigned int flags,\r
+      struct sockaddr *from, socklen_t *fromlen);\r
+int lwip_send(int s, const void *dataptr, int size, unsigned int flags);\r
+int lwip_sendto(int s, const void *dataptr, int size, unsigned int flags,\r
+    struct sockaddr *to, socklen_t tolen);\r
+int lwip_socket(int domain, int type, int protocol);\r
+int lwip_write(int s, const void *dataptr, int size);\r
+int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset,\r
+                struct timeval *timeout);\r
+int lwip_ioctl(int s, long cmd, void *argp);\r
+\r
+#if LWIP_COMPAT_SOCKETS\r
+#define accept(a,b,c)         lwip_accept(a,b,c)\r
+#define bind(a,b,c)           lwip_bind(a,b,c)\r
+#define shutdown(a,b)         lwip_shutdown(a,b)\r
+#define closesocket(s)        lwip_close(s)\r
+#define connect(a,b,c)        lwip_connect(a,b,c)\r
+#define getsockname(a,b,c)    lwip_getsockname(a,b,c)\r
+#define getpeername(a,b,c)    lwip_getpeername(a,b,c)\r
+#define setsockopt(a,b,c,d,e) lwip_setsockopt(a,b,c,d,e)\r
+#define getsockopt(a,b,c,d,e) lwip_getsockopt(a,b,c,d,e)\r
+#define listen(a,b)           lwip_listen(a,b)\r
+#define recv(a,b,c,d)         lwip_recv(a,b,c,d)\r
+#define recvfrom(a,b,c,d,e,f) lwip_recvfrom(a,b,c,d,e,f)\r
+#define send(a,b,c,d)         lwip_send(a,b,c,d)\r
+#define sendto(a,b,c,d,e,f)   lwip_sendto(a,b,c,d,e,f)\r
+#define socket(a,b,c)         lwip_socket(a,b,c)\r
+#define select(a,b,c,d,e)     lwip_select(a,b,c,d,e)\r
+#define ioctlsocket(a,b,c)    lwip_ioctl(a,b,c)\r
+\r
+#if LWIP_POSIX_SOCKETS_IO_NAMES\r
+#define read(a,b,c)           lwip_read(a,b,c)\r
+#define write(a,b,c)          lwip_write(a,b,c)\r
+#define close(s)              lwip_close(s)\r
+#endif /* LWIP_POSIX_SOCKETS_IO_NAMES */\r
+\r
+#endif /* LWIP_COMPAT_SOCKETS */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_SOCKET */\r
+\r
+#endif /* __LWIP_SOCKETS_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/stats.h
new file mode 100644 (file)
index 0000000..aebf490
--- /dev/null
@@ -0,0 +1,209 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_STATS_H__\r
+#define __LWIP_STATS_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#include "lwip/mem.h"\r
+#include "lwip/memp.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if LWIP_STATS\r
+\r
+#ifndef LWIP_STATS_LARGE\r
+#define LWIP_STATS_LARGE 0\r
+#endif\r
+\r
+#if LWIP_STATS_LARGE\r
+#define STAT_COUNTER     u32_t\r
+#define STAT_COUNTER_F   U32_F\r
+#else\r
+#define STAT_COUNTER     u16_t\r
+#define STAT_COUNTER_F   U16_F\r
+#endif\r
+\r
+struct stats_proto {\r
+  STAT_COUNTER xmit;             /* Transmitted packets. */\r
+  STAT_COUNTER rexmit;           /* Retransmitted packets. */\r
+  STAT_COUNTER recv;             /* Received packets. */\r
+  STAT_COUNTER fw;               /* Forwarded packets. */\r
+  STAT_COUNTER drop;             /* Dropped packets. */\r
+  STAT_COUNTER chkerr;           /* Checksum error. */\r
+  STAT_COUNTER lenerr;           /* Invalid length error. */\r
+  STAT_COUNTER memerr;           /* Out of memory error. */\r
+  STAT_COUNTER rterr;            /* Routing error. */\r
+  STAT_COUNTER proterr;          /* Protocol error. */\r
+  STAT_COUNTER opterr;           /* Error in options. */\r
+  STAT_COUNTER err;              /* Misc error. */\r
+  STAT_COUNTER cachehit;\r
+};\r
+\r
+struct stats_igmp {\r
+  STAT_COUNTER lenerr;           /* Invalid length error. */\r
+  STAT_COUNTER chkerr;           /* Checksum error. */\r
+  STAT_COUNTER v1_rxed;          /* */\r
+  STAT_COUNTER join_sent;        /* */\r
+  STAT_COUNTER leave_sent;       /* */\r
+  STAT_COUNTER unicast_query;    /* */\r
+  STAT_COUNTER report_sent;      /* */\r
+  STAT_COUNTER report_rxed;      /* */\r
+  STAT_COUNTER group_query_rxed; /* */\r
+};\r
+\r
+struct stats_mem {\r
+  mem_size_t avail;\r
+  mem_size_t used;\r
+  mem_size_t max;\r
+  mem_size_t err;\r
+};\r
+\r
+struct stats_syselem {\r
+  STAT_COUNTER used;\r
+  STAT_COUNTER max;\r
+  STAT_COUNTER err;\r
+};\r
+\r
+struct stats_sys {\r
+  struct stats_syselem sem;\r
+  struct stats_syselem mbox;\r
+};\r
+\r
+struct stats_ {\r
+#if LINK_STATS\r
+  struct stats_proto link;\r
+#endif\r
+#if ETHARP_STATS\r
+  struct stats_proto etharp;\r
+#endif\r
+#if IPFRAG_STATS\r
+  struct stats_proto ip_frag;\r
+#endif\r
+#if IP_STATS\r
+  struct stats_proto ip;\r
+#endif\r
+#if ICMP_STATS\r
+  struct stats_proto icmp;\r
+#endif\r
+#if IGMP_STATS\r
+  struct stats_igmp igmp;\r
+#endif\r
+#if UDP_STATS\r
+  struct stats_proto udp;\r
+#endif\r
+#if TCP_STATS\r
+  struct stats_proto tcp;\r
+#endif\r
+#if MEM_STATS\r
+  struct stats_mem mem;\r
+#endif\r
+#if MEMP_STATS\r
+  struct stats_mem memp[MEMP_MAX];\r
+#endif\r
+#if SYS_STATS\r
+  struct stats_sys sys;\r
+#endif\r
+};\r
+\r
+extern struct stats_ lwip_stats;\r
+\r
+#define stats_init() /* Compatibility define, not init needed. */\r
+\r
+#define STATS_INC(x) ++lwip_stats.x\r
+#else\r
+#define stats_init()\r
+#define STATS_INC(x)\r
+#endif /* LWIP_STATS */\r
+\r
+#if TCP_STATS\r
+#define TCP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define TCP_STATS_INC(x)\r
+#endif\r
+\r
+#if UDP_STATS\r
+#define UDP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define UDP_STATS_INC(x)\r
+#endif\r
+\r
+#if ICMP_STATS\r
+#define ICMP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define ICMP_STATS_INC(x)\r
+#endif\r
+\r
+#if IGMP_STATS\r
+#define IGMP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define IGMP_STATS_INC(x)\r
+#endif\r
+\r
+#if IP_STATS\r
+#define IP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define IP_STATS_INC(x)\r
+#endif\r
+\r
+#if IPFRAG_STATS\r
+#define IPFRAG_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define IPFRAG_STATS_INC(x)\r
+#endif\r
+\r
+#if ETHARP_STATS\r
+#define ETHARP_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define ETHARP_STATS_INC(x)\r
+#endif\r
+\r
+#if LINK_STATS\r
+#define LINK_STATS_INC(x) STATS_INC(x)\r
+#else\r
+#define LINK_STATS_INC(x)\r
+#endif\r
+\r
+/* Display of statistics */\r
+#if LWIP_STATS_DISPLAY\r
+void stats_display(void);\r
+#else\r
+#define stats_display()\r
+#endif /* LWIP_STATS_DISPLAY */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_STATS_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/sys.h
new file mode 100644 (file)
index 0000000..f713f1e
--- /dev/null
@@ -0,0 +1,246 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_SYS_H__\r
+#define __LWIP_SYS_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if NO_SYS\r
+\r
+/* For a totally minimal and standalone system, we provide null\r
+   definitions of the sys_ functions. */\r
+typedef u8_t sys_sem_t;\r
+typedef u8_t sys_mbox_t;\r
+typedef u8_t sys_prot_t;\r
+struct sys_timeo {u8_t dummy;};\r
+\r
+#define sys_init()\r
+#define sys_timeout(m,h,a)\r
+#define sys_untimeout(m,a)\r
+#define sys_sem_new(c) c\r
+#define sys_sem_signal(s)\r
+#define sys_sem_wait(s)\r
+#define sys_sem_wait_timeout(s,t)\r
+#define sys_arch_sem_wait(s,t)\r
+#define sys_sem_free(s)\r
+#define sys_mbox_new(s) 0\r
+#define sys_mbox_fetch(m,d)\r
+#define sys_mbox_tryfetch(m,d)\r
+#define sys_mbox_post(m,d)\r
+#define sys_mbox_trypost(m,d)\r
+#define sys_mbox_free(m)\r
+\r
+#define sys_thread_new(n,t,a,s,p)\r
+\r
+#else /* NO_SYS */\r
+\r
+/** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */\r
+#define SYS_ARCH_TIMEOUT 0xffffffffUL\r
+\r
+/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate.\r
+ * For now we use the same magic value, but we allow this to change in future.\r
+ */\r
+#define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT\r
+\r
+#include "lwip/err.h"\r
+#include "arch/sys_arch.h"\r
+\r
+typedef void (* sys_timeout_handler)(void *arg);\r
+\r
+struct sys_timeo {\r
+  struct sys_timeo *next;\r
+  u32_t time;\r
+  sys_timeout_handler h;\r
+  void *arg;\r
+};\r
+\r
+struct sys_timeouts {\r
+  struct sys_timeo *next;\r
+};\r
+\r
+/* sys_init() must be called before anthing else. */\r
+void sys_init(void);\r
+\r
+/*\r
+ * sys_timeout():\r
+ *\r
+ * Schedule a timeout a specified amount of milliseconds in the\r
+ * future. When the timeout occurs, the specified timeout handler will\r
+ * be called. The handler will be passed the "arg" argument when\r
+ * called.\r
+ *\r
+ */\r
+void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg);\r
+void sys_untimeout(sys_timeout_handler h, void *arg);\r
+struct sys_timeouts *sys_arch_timeouts(void);\r
+\r
+/* Semaphore functions. */\r
+sys_sem_t sys_sem_new(u8_t count);\r
+void sys_sem_signal(sys_sem_t sem);\r
+u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout);\r
+void sys_sem_free(sys_sem_t sem);\r
+void sys_sem_wait(sys_sem_t sem);\r
+int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout);\r
+\r
+/* Time functions. */\r
+#ifndef sys_msleep\r
+void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */\r
+#endif\r
+#ifndef sys_jiffies\r
+u32_t sys_jiffies(void); /* since power up. */\r
+#endif\r
+\r
+/* Mailbox functions. */\r
+sys_mbox_t sys_mbox_new(int size);\r
+void sys_mbox_post(sys_mbox_t mbox, void *msg);\r
+err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg);\r
+u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout);\r
+#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */\r
+u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg);\r
+#endif\r
+/* For now, we map straight to sys_arch implementation. */\r
+#define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg)\r
+void sys_mbox_free(sys_mbox_t mbox);\r
+void sys_mbox_fetch(sys_mbox_t mbox, void **msg);\r
+\r
+/* Thread functions. */\r
+sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio);\r
+\r
+/* The following functions are used only in Unix code, and\r
+   can be omitted when porting the stack. */\r
+/* Returns the current time in microseconds. */\r
+unsigned long sys_now(void);\r
+\r
+#endif /* NO_SYS */\r
+\r
+/* Critical Region Protection */\r
+/* These functions must be implemented in the sys_arch.c file.\r
+   In some implementations they can provide a more light-weight protection\r
+   mechanism than using semaphores. Otherwise semaphores can be used for\r
+   implementation */\r
+#ifndef SYS_ARCH_PROTECT\r
+/** SYS_LIGHTWEIGHT_PROT\r
+ * define SYS_LIGHTWEIGHT_PROT in lwipopts.h if you want inter-task protection\r
+ * for certain critical regions during buffer allocation, deallocation and memory\r
+ * allocation and deallocation.\r
+ */\r
+#if SYS_LIGHTWEIGHT_PROT\r
+\r
+/** SYS_ARCH_DECL_PROTECT\r
+ * declare a protection variable. This macro will default to defining a variable of\r
+ * type sys_prot_t. If a particular port needs a different implementation, then\r
+ * this macro may be defined in sys_arch.h.\r
+ */\r
+#define SYS_ARCH_DECL_PROTECT(lev) sys_prot_t lev\r
+/** SYS_ARCH_PROTECT\r
+ * Perform a "fast" protect. This could be implemented by\r
+ * disabling interrupts for an embedded system or by using a semaphore or\r
+ * mutex. The implementation should allow calling SYS_ARCH_PROTECT when\r
+ * already protected. The old protection level is returned in the variable\r
+ * "lev". This macro will default to calling the sys_arch_protect() function\r
+ * which should be implemented in sys_arch.c. If a particular port needs a\r
+ * different implementation, then this macro may be defined in sys_arch.h\r
+ */\r
+#define SYS_ARCH_PROTECT(lev) lev = sys_arch_protect()\r
+/** SYS_ARCH_UNPROTECT\r
+ * Perform a "fast" set of the protection level to "lev". This could be\r
+ * implemented by setting the interrupt level to "lev" within the MACRO or by\r
+ * using a semaphore or mutex.  This macro will default to calling the\r
+ * sys_arch_unprotect() function which should be implemented in\r
+ * sys_arch.c. If a particular port needs a different implementation, then\r
+ * this macro may be defined in sys_arch.h\r
+ */\r
+#define SYS_ARCH_UNPROTECT(lev) sys_arch_unprotect(lev)\r
+sys_prot_t sys_arch_protect(void);\r
+void sys_arch_unprotect(sys_prot_t pval);\r
+\r
+#else\r
+\r
+#define SYS_ARCH_DECL_PROTECT(lev)\r
+#define SYS_ARCH_PROTECT(lev)\r
+#define SYS_ARCH_UNPROTECT(lev)\r
+\r
+#endif /* SYS_LIGHTWEIGHT_PROT */\r
+\r
+#endif /* SYS_ARCH_PROTECT */\r
+\r
+/*\r
+ * Macros to set/get and increase/decrease variables in a thread-safe way.\r
+ * Use these for accessing variable that are used from more than one thread.\r
+ */\r
+\r
+#ifndef SYS_ARCH_INC\r
+#define SYS_ARCH_INC(var, val) do { \\r
+                                SYS_ARCH_DECL_PROTECT(old_level); \\r
+                                SYS_ARCH_PROTECT(old_level); \\r
+                                var += val; \\r
+                                SYS_ARCH_UNPROTECT(old_level); \\r
+                              } while(0)\r
+#endif /* SYS_ARCH_INC */\r
+\r
+#ifndef SYS_ARCH_DEC\r
+#define SYS_ARCH_DEC(var, val) do { \\r
+                                SYS_ARCH_DECL_PROTECT(old_level); \\r
+                                SYS_ARCH_PROTECT(old_level); \\r
+                                var -= val; \\r
+                                SYS_ARCH_UNPROTECT(old_level); \\r
+                              } while(0)\r
+#endif /* SYS_ARCH_DEC */\r
+\r
+#ifndef SYS_ARCH_GET\r
+#define SYS_ARCH_GET(var, ret) do { \\r
+                                SYS_ARCH_DECL_PROTECT(old_level); \\r
+                                SYS_ARCH_PROTECT(old_level); \\r
+                                ret = var; \\r
+                                SYS_ARCH_UNPROTECT(old_level); \\r
+                              } while(0)\r
+#endif /* SYS_ARCH_GET */\r
+\r
+#ifndef SYS_ARCH_SET\r
+#define SYS_ARCH_SET(var, val) do { \\r
+                                SYS_ARCH_DECL_PROTECT(old_level); \\r
+                                SYS_ARCH_PROTECT(old_level); \\r
+                                var = val; \\r
+                                SYS_ARCH_UNPROTECT(old_level); \\r
+                              } while(0)\r
+#endif /* SYS_ARCH_SET */\r
+\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __LWIP_SYS_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcp.h
new file mode 100644 (file)
index 0000000..efef3df
--- /dev/null
@@ -0,0 +1,641 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_TCP_H__\r
+#define __LWIP_TCP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/icmp.h"\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+struct tcp_pcb;\r
+\r
+/* Functions for interfacing with TCP: */\r
+\r
+/* Lower layer interface to TCP: */\r
+#define tcp_init() /* Compatibility define, not init needed. */\r
+void             tcp_tmr     (void);  /* Must be called every\r
+                                         TCP_TMR_INTERVAL\r
+                                         ms. (Typically 250 ms). */\r
+/* Application program's interface: */\r
+struct tcp_pcb * tcp_new     (void);\r
+struct tcp_pcb * tcp_alloc   (u8_t prio);\r
+\r
+void             tcp_arg     (struct tcp_pcb *pcb, void *arg);\r
+void             tcp_accept  (struct tcp_pcb *pcb,\r
+                              err_t (* accept)(void *arg, struct tcp_pcb *newpcb,\r
+                 err_t err));\r
+void             tcp_recv    (struct tcp_pcb *pcb,\r
+                              err_t (* recv)(void *arg, struct tcp_pcb *tpcb,\r
+                              struct pbuf *p, err_t err));\r
+void             tcp_sent    (struct tcp_pcb *pcb,\r
+                              err_t (* sent)(void *arg, struct tcp_pcb *tpcb,\r
+                              u16_t len));\r
+void             tcp_poll    (struct tcp_pcb *pcb,\r
+                              err_t (* poll)(void *arg, struct tcp_pcb *tpcb),\r
+                              u8_t interval);\r
+void             tcp_err     (struct tcp_pcb *pcb,\r
+                              void (* err)(void *arg, err_t err));\r
+\r
+#define          tcp_mss(pcb)      ((pcb)->mss)\r
+#define          tcp_sndbuf(pcb)   ((pcb)->snd_buf)\r
+\r
+#if TCP_LISTEN_BACKLOG\r
+#define          tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--)\r
+#else  /* TCP_LISTEN_BACKLOG */\r
+#define          tcp_accepted(pcb)\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+\r
+void             tcp_recved  (struct tcp_pcb *pcb, u16_t len);\r
+err_t            tcp_bind    (struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+                              u16_t port);\r
+err_t            tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr,\r
+                              u16_t port, err_t (* connected)(void *arg,\r
+                              struct tcp_pcb *tpcb,\r
+                              err_t err));\r
+\r
+struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog);\r
+#define          tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG)\r
+\r
+void             tcp_abort   (struct tcp_pcb *pcb);\r
+err_t            tcp_close   (struct tcp_pcb *pcb);\r
+\r
+/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */\r
+#define TCP_WRITE_FLAG_COPY 0x01\r
+#define TCP_WRITE_FLAG_MORE 0x02\r
+\r
+err_t            tcp_write   (struct tcp_pcb *pcb, const void *dataptr, u16_t len,\r
+                              u8_t apiflags);\r
+\r
+void             tcp_setprio (struct tcp_pcb *pcb, u8_t prio);\r
+\r
+#define TCP_PRIO_MIN    1\r
+#define TCP_PRIO_NORMAL 64\r
+#define TCP_PRIO_MAX    127\r
+\r
+/* It is also possible to call these two functions at the right\r
+   intervals (instead of calling tcp_tmr()). */\r
+void             tcp_slowtmr (void);\r
+void             tcp_fasttmr (void);\r
+\r
+\r
+/* Only used by IP to pass a TCP segment to TCP: */\r
+void             tcp_input   (struct pbuf *p, struct netif *inp);\r
+/* Used within the TCP code only: */\r
+err_t            tcp_output  (struct tcp_pcb *pcb);\r
+void             tcp_rexmit  (struct tcp_pcb *pcb);\r
+void             tcp_rexmit_rto  (struct tcp_pcb *pcb);\r
+\r
+/**\r
+ * This is the Nagle algorithm: inhibit the sending of new TCP\r
+ * segments when new outgoing data arrives from the user if any\r
+ * previously transmitted data on the connection remains\r
+ * unacknowledged.\r
+ */\r
+#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \\r
+                            ((tpcb)->flags & TF_NODELAY) || \\r
+                            (((tpcb)->unsent != NULL) && ((tpcb)->unsent->next != NULL))) ? \\r
+                                1 : 0)\r
+#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK)\r
+\r
+\r
+/** This returns a TCP header option for MSS in an u32_t */\r
+#define TCP_BUILD_MSS_OPTION()  htonl(((u32_t)2 << 24) | \\r
+                                ((u32_t)4 << 16) | \\r
+                                (((u32_t)TCP_MSS / 256) << 8) | \\r
+                                (TCP_MSS & 255))\r
+\r
+#define TCP_SEQ_LT(a,b)     ((s32_t)((a)-(b)) < 0)\r
+#define TCP_SEQ_LEQ(a,b)    ((s32_t)((a)-(b)) <= 0)\r
+#define TCP_SEQ_GT(a,b)     ((s32_t)((a)-(b)) > 0)\r
+#define TCP_SEQ_GEQ(a,b)    ((s32_t)((a)-(b)) >= 0)\r
+/* is b<=a<=c? */\r
+#if 0 /* see bug #10548 */\r
+#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b))\r
+#endif\r
+#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c))\r
+#define TCP_FIN 0x01U\r
+#define TCP_SYN 0x02U\r
+#define TCP_RST 0x04U\r
+#define TCP_PSH 0x08U\r
+#define TCP_ACK 0x10U\r
+#define TCP_URG 0x20U\r
+#define TCP_ECE 0x40U\r
+#define TCP_CWR 0x80U\r
+\r
+#define TCP_FLAGS 0x3fU\r
+\r
+/* Length of the TCP header, excluding options. */\r
+#define TCP_HLEN 20\r
+\r
+#ifndef TCP_TMR_INTERVAL\r
+#define TCP_TMR_INTERVAL       250  /* The TCP timer interval in milliseconds. */\r
+#endif /* TCP_TMR_INTERVAL */\r
+\r
+#ifndef TCP_FAST_INTERVAL\r
+#define TCP_FAST_INTERVAL      TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */\r
+#endif /* TCP_FAST_INTERVAL */\r
+\r
+#ifndef TCP_SLOW_INTERVAL\r
+#define TCP_SLOW_INTERVAL      (2*TCP_TMR_INTERVAL)  /* the coarse grained timeout in milliseconds */\r
+#endif /* TCP_SLOW_INTERVAL */\r
+\r
+#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */\r
+#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */\r
+\r
+#define TCP_OOSEQ_TIMEOUT        6U /* x RTO */\r
+\r
+#ifndef TCP_MSL\r
+#define TCP_MSL 60000U /* The maximum segment lifetime in milliseconds */\r
+#endif\r
+\r
+/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */\r
+#ifndef  TCP_KEEPIDLE_DEFAULT\r
+#define  TCP_KEEPIDLE_DEFAULT     7200000UL /* Default KEEPALIVE timer in milliseconds */\r
+#endif\r
+\r
+#ifndef  TCP_KEEPINTVL_DEFAULT\r
+#define  TCP_KEEPINTVL_DEFAULT    75000UL   /* Default Time between KEEPALIVE probes in milliseconds */\r
+#endif\r
+\r
+#ifndef  TCP_KEEPCNT_DEFAULT\r
+#define  TCP_KEEPCNT_DEFAULT      9U        /* Default Counter for KEEPALIVE probes */\r
+#endif\r
+\r
+#define  TCP_MAXIDLE              TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT  /* Maximum KEEPALIVE probe time */\r
+\r
+/* Fields are (of course) in network byte order.\r
+ * Some fields are converted to host byte order in tcp_input().\r
+ */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct tcp_hdr {\r
+  PACK_STRUCT_FIELD(u16_t src);\r
+  PACK_STRUCT_FIELD(u16_t dest);\r
+  PACK_STRUCT_FIELD(u32_t seqno);\r
+  PACK_STRUCT_FIELD(u32_t ackno);\r
+  PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags);\r
+  PACK_STRUCT_FIELD(u16_t wnd);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+  PACK_STRUCT_FIELD(u16_t urgp);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8)\r
+#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12)\r
+#define TCPH_FLAGS(phdr)  (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS)\r
+\r
+#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr))\r
+#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr))\r
+#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons((ntohs((phdr)->_hdrlen_rsvd_flags) & ~TCP_FLAGS) | (flags))\r
+#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (flags))\r
+#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) )\r
+\r
+#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & TCP_FIN || \\r
+          TCPH_FLAGS((seg)->tcphdr) & TCP_SYN)? 1: 0))\r
+\r
+enum tcp_state {\r
+  CLOSED      = 0,\r
+  LISTEN      = 1,\r
+  SYN_SENT    = 2,\r
+  SYN_RCVD    = 3,\r
+  ESTABLISHED = 4,\r
+  FIN_WAIT_1  = 5,\r
+  FIN_WAIT_2  = 6,\r
+  CLOSE_WAIT  = 7,\r
+  CLOSING     = 8,\r
+  LAST_ACK    = 9,\r
+  TIME_WAIT   = 10\r
+};\r
+\r
+/** Flags used on input processing, not on pcb->flags\r
+*/\r
+#define TF_RESET     (u8_t)0x08U   /* Connection was reset. */\r
+#define TF_CLOSED    (u8_t)0x10U   /* Connection was sucessfully closed. */\r
+#define TF_GOT_FIN   (u8_t)0x20U   /* Connection was closed by the remote end. */\r
+\r
+/**\r
+ * members common to struct tcp_pcb and struct tcp_listen_pcb\r
+ */\r
+#define TCP_PCB_COMMON(type) \\r
+  type *next; /* for the linked list */ \\r
+  enum tcp_state state; /* TCP state */ \\r
+  u8_t prio; \\r
+  void *callback_arg; \\r
+  /* ports are in host byte order */ \\r
+  u16_t local_port\r
+\r
+/* the TCP protocol control block */\r
+struct tcp_pcb {\r
+/** common PCB members */\r
+  IP_PCB;\r
+/** protocol specific PCB members */\r
+  TCP_PCB_COMMON(struct tcp_pcb);\r
+\r
+  /* ports are in host byte order */\r
+  u16_t remote_port;\r
+\r
+  u8_t flags;\r
+#define TF_ACK_DELAY   (u8_t)0x01U   /* Delayed ACK. */\r
+#define TF_ACK_NOW     (u8_t)0x02U   /* Immediate ACK. */\r
+#define TF_INFR        (u8_t)0x04U   /* In fast recovery. */\r
+#define TF_FIN         (u8_t)0x20U   /* Connection was closed locally (FIN segment enqueued). */\r
+#define TF_NODELAY     (u8_t)0x40U   /* Disable Nagle algorithm */\r
+#define TF_NAGLEMEMERR (u8_t)0x80U /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */\r
+\r
+  /* the rest of the fields are in host byte order\r
+     as we have to do some math with them */\r
+  /* receiver variables */\r
+  u32_t rcv_nxt;   /* next seqno expected */\r
+  u16_t rcv_wnd;   /* receiver window */\r
+  u16_t rcv_ann_wnd; /* announced receive window */\r
+\r
+  /* Timers */\r
+  u32_t tmr;\r
+  u8_t polltmr, pollinterval;\r
+\r
+  /* Retransmission timer. */\r
+  s16_t rtime;\r
+\r
+  u16_t mss;   /* maximum segment size */\r
+\r
+  /* RTT (round trip time) estimation variables */\r
+  u32_t rttest; /* RTT estimate in 500ms ticks */\r
+  u32_t rtseq;  /* sequence number being timed */\r
+  s16_t sa, sv; /* @todo document this */\r
+\r
+  s16_t rto;    /* retransmission time-out */\r
+  u8_t nrtx;    /* number of retransmissions */\r
+\r
+  /* fast retransmit/recovery */\r
+  u32_t lastack; /* Highest acknowledged seqno. */\r
+  u8_t dupacks;\r
+\r
+  /* congestion avoidance/control variables */\r
+  u16_t cwnd;\r
+  u16_t ssthresh;\r
+\r
+  /* sender variables */\r
+  u32_t snd_nxt,   /* next seqno to be sent */\r
+    snd_max;       /* Highest seqno sent. */\r
+  u16_t snd_wnd;   /* sender window */\r
+  u32_t snd_wl1, snd_wl2, /* Sequence and acknowledgement numbers of last\r
+                             window update. */\r
+    snd_lbb;       /* Sequence number of next byte to be buffered. */\r
+\r
+  u16_t acked;\r
+\r
+  u16_t snd_buf;   /* Available buffer space for sending (in bytes). */\r
+#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3)\r
+  u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */\r
+\r
+\r
+  /* These are ordered by sequence number: */\r
+  struct tcp_seg *unsent;   /* Unsent (queued) segments. */\r
+  struct tcp_seg *unacked;  /* Sent but unacknowledged segments. */\r
+#if TCP_QUEUE_OOSEQ\r
+  struct tcp_seg *ooseq;    /* Received out of sequence segments. */\r
+#endif /* TCP_QUEUE_OOSEQ */\r
+\r
+  struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */\r
+\r
+#if LWIP_CALLBACK_API\r
+  /* Function to be called when more send buffer space is available.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb the tcp_pcb which has send buffer space available\r
+   * @param space the amount of bytes available\r
+   * @return ERR_OK: try to send some data by calling tcp_output\r
+   */\r
+  err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space);\r
+\r
+  /* Function to be called when (in-sequence) data has arrived.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb the tcp_pcb for which data has arrived\r
+   * @param p the packet buffer which arrived\r
+   * @param err an error argument (TODO: that is current always ERR_OK?)\r
+   * @return ERR_OK: try to send some data by calling tcp_output\r
+   */\r
+  err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err);\r
+\r
+  /* Function to be called when a connection has been set up.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb the tcp_pcb that now is connected\r
+   * @param err an error argument (TODO: that is current always ERR_OK?)\r
+   * @return value is currently ignored\r
+   */\r
+  err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err);\r
+\r
+  /* Function to call when a listener has been connected.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb a new tcp_pcb that now is connected\r
+   * @param err an error argument (TODO: that is current always ERR_OK?)\r
+   * @return ERR_OK: accept the new connection,\r
+   *                 any other err_t abortsthe new connection\r
+   */\r
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);\r
+\r
+  /* Function which is called periodically.\r
+   * The period can be adjusted in multiples of the TCP slow timer interval\r
+   * by changing tcp_pcb.polltmr.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb the tcp_pcb to poll for\r
+   * @return ERR_OK: try to send some data by calling tcp_output\r
+   */\r
+  err_t (* poll)(void *arg, struct tcp_pcb *pcb);\r
+\r
+  /* Function to be called whenever a fatal error occurs.\r
+   * There is no pcb parameter since most of the times, the pcb is\r
+   * already deallocated (or there is no pcb) when this function is called.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param err an indication why the error callback is called:\r
+   *            ERR_ABRT: aborted through tcp_abort or by a TCP timer\r
+   *            ERR_RST: the connection was reset by the remote host\r
+   */\r
+  void (* errf)(void *arg, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+\r
+  /* idle time before KEEPALIVE is sent */\r
+  u32_t keep_idle;\r
+#if LWIP_TCP_KEEPALIVE\r
+  u32_t keep_intvl;\r
+  u32_t keep_cnt;\r
+#endif /* LWIP_TCP_KEEPALIVE */\r
+\r
+  /* Persist timer counter */\r
+  u32_t persist_cnt;\r
+  /* Persist timer back-off */\r
+  u8_t persist_backoff;\r
+\r
+  /* KEEPALIVE counter */\r
+  u8_t keep_cnt_sent;\r
+};\r
+\r
+struct tcp_pcb_listen {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+/* Protocol specific PCB members */\r
+  TCP_PCB_COMMON(struct tcp_pcb_listen);\r
+\r
+#if LWIP_CALLBACK_API\r
+  /* Function to call when a listener has been connected.\r
+   * @param arg user-supplied argument (tcp_pcb.callback_arg)\r
+   * @param pcb a new tcp_pcb that now is connected\r
+   * @param err an error argument (TODO: that is current always ERR_OK?)\r
+   * @return ERR_OK: accept the new connection,\r
+   *                 any other err_t abortsthe new connection\r
+   */\r
+  err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err);\r
+#endif /* LWIP_CALLBACK_API */\r
+#if TCP_LISTEN_BACKLOG\r
+  u8_t backlog;\r
+  u8_t accepts_pending;\r
+#endif /* TCP_LISTEN_BACKLOG */\r
+};\r
+\r
+#if LWIP_EVENT_API\r
+\r
+enum lwip_event {\r
+  LWIP_EVENT_ACCEPT,\r
+  LWIP_EVENT_SENT,\r
+  LWIP_EVENT_RECV,\r
+  LWIP_EVENT_CONNECTED,\r
+  LWIP_EVENT_POLL,\r
+  LWIP_EVENT_ERR\r
+};\r
+\r
+err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb,\r
+         enum lwip_event,\r
+         struct pbuf *p,\r
+         u16_t size,\r
+         err_t err);\r
+\r
+#define TCP_EVENT_ACCEPT(pcb,err,ret)    ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_ACCEPT, NULL, 0, err)\r
+#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                   LWIP_EVENT_SENT, NULL, space, ERR_OK)\r
+#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_RECV, (p), 0, (err))\r
+#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_CONNECTED, NULL, 0, (err))\r
+#define TCP_EVENT_POLL(pcb,ret)       ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\\r
+                LWIP_EVENT_POLL, NULL, 0, ERR_OK)\r
+#define TCP_EVENT_ERR(errf,arg,err)  lwip_tcp_event((arg), NULL, \\r
+                LWIP_EVENT_ERR, NULL, 0, (err))\r
+#else /* LWIP_EVENT_API */\r
+#define TCP_EVENT_ACCEPT(pcb,err,ret)     \\r
+                        if((pcb)->accept != NULL) \\r
+                        (ret = (pcb)->accept((pcb)->callback_arg,(pcb),(err)))\r
+#define TCP_EVENT_SENT(pcb,space,ret) \\r
+                        if((pcb)->sent != NULL) \\r
+                        (ret = (pcb)->sent((pcb)->callback_arg,(pcb),(space)))\r
+#define TCP_EVENT_RECV(pcb,p,err,ret) \\r
+                        if((pcb)->recv != NULL) \\r
+                        { ret = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); } else { \\r
+                          ret = ERR_OK; \\r
+                          if (p) pbuf_free(p); }\r
+#define TCP_EVENT_CONNECTED(pcb,err,ret) \\r
+                        if((pcb)->connected != NULL) \\r
+                        (ret = (pcb)->connected((pcb)->callback_arg,(pcb),(err)))\r
+#define TCP_EVENT_POLL(pcb,ret) \\r
+                        if((pcb)->poll != NULL) \\r
+                        (ret = (pcb)->poll((pcb)->callback_arg,(pcb)))\r
+#define TCP_EVENT_ERR(errf,arg,err) \\r
+                        if((errf) != NULL) \\r
+                        (errf)((arg),(err))\r
+#endif /* LWIP_EVENT_API */\r
+\r
+/* This structure represents a TCP segment on the unsent and unacked queues */\r
+struct tcp_seg {\r
+  struct tcp_seg *next;    /* used when putting segements on a queue */\r
+  struct pbuf *p;          /* buffer containing data + TCP header */\r
+  void *dataptr;           /* pointer to the TCP data in the pbuf */\r
+  u16_t len;               /* the TCP length of this segment */\r
+  struct tcp_hdr *tcphdr;  /* the TCP header */\r
+};\r
+\r
+/* Internal functions and global variables: */\r
+struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb);\r
+void tcp_pcb_purge(struct tcp_pcb *pcb);\r
+void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb);\r
+\r
+u8_t tcp_segs_free(struct tcp_seg *seg);\r
+u8_t tcp_seg_free(struct tcp_seg *seg);\r
+struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg);\r
+\r
+#define tcp_ack(pcb)     if((pcb)->flags & TF_ACK_DELAY) { \\r
+                            (pcb)->flags &= ~TF_ACK_DELAY; \\r
+                            (pcb)->flags |= TF_ACK_NOW; \\r
+                            tcp_output(pcb); \\r
+                         } else { \\r
+                            (pcb)->flags |= TF_ACK_DELAY; \\r
+                         }\r
+\r
+#define tcp_ack_now(pcb) (pcb)->flags |= TF_ACK_NOW; \\r
+                         tcp_output(pcb)\r
+\r
+err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags);\r
+err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len,\r
+    u8_t flags, u8_t apiflags,\r
+                u8_t *optdata, u8_t optlen);\r
+\r
+void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg);\r
+\r
+void tcp_rst(u32_t seqno, u32_t ackno,\r
+       struct ip_addr *local_ip, struct ip_addr *remote_ip,\r
+       u16_t local_port, u16_t remote_port);\r
+\r
+u32_t tcp_next_iss(void);\r
+\r
+void tcp_keepalive(struct tcp_pcb *pcb);\r
+void tcp_zero_window_probe(struct tcp_pcb *pcb);\r
+\r
+#if TCP_CALCULATE_EFF_SEND_MSS\r
+u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);\r
+#endif /* TCP_CALCULATE_EFF_SEND_MSS */\r
+\r
+extern struct tcp_pcb *tcp_input_pcb;\r
+extern u32_t tcp_ticks;\r
+\r
+#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG\r
+void tcp_debug_print(struct tcp_hdr *tcphdr);\r
+void tcp_debug_print_flags(u8_t flags);\r
+void tcp_debug_print_state(enum tcp_state s);\r
+void tcp_debug_print_pcbs(void);\r
+s16_t tcp_pcbs_sane(void);\r
+#else\r
+#  define tcp_debug_print(tcphdr)\r
+#  define tcp_debug_print_flags(flags)\r
+#  define tcp_debug_print_state(s)\r
+#  define tcp_debug_print_pcbs()\r
+#  define tcp_pcbs_sane() 1\r
+#endif /* TCP_DEBUG */\r
+\r
+#if NO_SYS\r
+#define tcp_timer_needed()\r
+#else\r
+void tcp_timer_needed(void);\r
+#endif\r
+\r
+/* The TCP PCB lists. */\r
+union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */\r
+  struct tcp_pcb_listen *listen_pcbs;\r
+  struct tcp_pcb *pcbs;\r
+};\r
+extern union tcp_listen_pcbs_t tcp_listen_pcbs;\r
+extern struct tcp_pcb *tcp_active_pcbs;  /* List of all TCP PCBs that are in a\r
+              state in which they accept or send\r
+              data. */\r
+extern struct tcp_pcb *tcp_tw_pcbs;      /* List of all TCP PCBs in TIME-WAIT. */\r
+\r
+extern struct tcp_pcb *tcp_tmp_pcb;      /* Only used for temporary storage. */\r
+\r
+/* Axioms about the above lists:\r
+   1) Every TCP PCB that is not CLOSED is in one of the lists.\r
+   2) A PCB is only in one of the lists.\r
+   3) All PCBs in the tcp_listen_pcbs list is in LISTEN state.\r
+   4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state.\r
+*/\r
+\r
+/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB\r
+   with a PCB list or removes a PCB from a list, respectively. */\r
+#if 0\r
+#define TCP_REG(pcbs, npcb) do {\\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \\r
+                            for(tcp_tmp_pcb = *pcbs; \\r
+          tcp_tmp_pcb != NULL; \\r
+        tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                                LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \\r
+                            } \\r
+                            LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \\r
+                            npcb->next = *pcbs; \\r
+                            LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \\r
+                            *(pcbs) = npcb; \\r
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \\r
+              tcp_timer_needed(); \\r
+                            } while(0)\r
+#define TCP_RMV(pcbs, npcb) do { \\r
+                            LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \\r
+                            if(*pcbs == npcb) { \\r
+                               *pcbs = (*pcbs)->next; \\r
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \\r
+                                  tcp_tmp_pcb->next = npcb->next; \\r
+                                  break; \\r
+                               } \\r
+                            } \\r
+                            npcb->next = NULL; \\r
+                            LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \\r
+                            LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \\r
+                            } while(0)\r
+\r
+#else /* LWIP_DEBUG */\r
+#define TCP_REG(pcbs, npcb) do { \\r
+                            npcb->next = *pcbs; \\r
+                            *(pcbs) = npcb; \\r
+              tcp_timer_needed(); \\r
+                            } while(0)\r
+#define TCP_RMV(pcbs, npcb) do { \\r
+                            if(*(pcbs) == npcb) { \\r
+                               (*(pcbs)) = (*pcbs)->next; \\r
+                            } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \\r
+                               if(tcp_tmp_pcb->next != NULL && tcp_tmp_pcb->next == npcb) { \\r
+                                  tcp_tmp_pcb->next = npcb->next; \\r
+                                  break; \\r
+                               } \\r
+                            } \\r
+                            npcb->next = NULL; \\r
+                            } while(0)\r
+#endif /* LWIP_DEBUG */\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_TCP */\r
+\r
+#endif /* __LWIP_TCP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/tcpip.h
new file mode 100644 (file)
index 0000000..7822437
--- /dev/null
@@ -0,0 +1,135 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_TCPIP_H__\r
+#define __LWIP_TCPIP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if !NO_SYS /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/api_msg.h"\r
+#include "lwip/netifapi.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/api.h"\r
+#include "lwip/sys.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+/** The global semaphore to lock the stack. */\r
+extern sys_sem_t lock_tcpip_core;\r
+#define LOCK_TCPIP_CORE()     sys_sem_wait(lock_tcpip_core)\r
+#define UNLOCK_TCPIP_CORE()   sys_sem_signal(lock_tcpip_core)\r
+#define TCPIP_APIMSG(m)       tcpip_apimsg_lock(m)\r
+#define TCPIP_APIMSG_ACK(m)\r
+#define TCPIP_NETIFAPI(m)     tcpip_netifapi_lock(m)\r
+#define TCPIP_NETIFAPI_ACK(m)\r
+#else\r
+#define LOCK_TCPIP_CORE()\r
+#define UNLOCK_TCPIP_CORE()\r
+#define TCPIP_APIMSG(m)       tcpip_apimsg(m)\r
+#define TCPIP_APIMSG_ACK(m)   sys_sem_signal(m->conn->op_completed)\r
+#define TCPIP_NETIFAPI(m)     tcpip_netifapi(m)\r
+#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem)\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+\r
+void tcpip_init(void (* tcpip_init_done)(void *), void *arg);\r
+\r
+#if LWIP_NETCONN\r
+err_t tcpip_apimsg(struct api_msg *apimsg);\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+err_t tcpip_apimsg_lock(struct api_msg *apimsg);\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+#endif /* LWIP_NETCONN */\r
+\r
+err_t tcpip_input(struct pbuf *p, struct netif *inp);\r
+\r
+#if LWIP_NETIF_API\r
+err_t tcpip_netifapi(struct netifapi_msg *netifapimsg);\r
+#if LWIP_TCPIP_CORE_LOCKING\r
+err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg);\r
+#endif /* LWIP_TCPIP_CORE_LOCKING */\r
+#endif /* LWIP_NETIF_API */\r
+\r
+err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block);\r
+#define tcpip_callback(f,ctx) tcpip_callback_with_block(f,ctx,1)\r
+\r
+err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg);\r
+#define tcpip_untimeout(h, arg) tcpip_timeout(0xffffffff, h, arg)\r
+\r
+enum tcpip_msg_type {\r
+#if LWIP_NETCONN\r
+  TCPIP_MSG_API,\r
+#endif /* LWIP_NETCONN */\r
+  TCPIP_MSG_INPKT,\r
+#if LWIP_NETIF_API\r
+  TCPIP_MSG_NETIFAPI,\r
+#endif /* LWIP_NETIF_API */\r
+  TCPIP_MSG_CALLBACK,\r
+  TCPIP_MSG_TIMEOUT\r
+};\r
+\r
+struct tcpip_msg {\r
+  enum tcpip_msg_type type;\r
+  sys_sem_t *sem;\r
+  union {\r
+#if LWIP_NETCONN\r
+    struct api_msg *apimsg;\r
+#endif /* LWIP_NETCONN */\r
+#if LWIP_NETIF_API\r
+    struct netifapi_msg *netifapimsg;\r
+#endif /* LWIP_NETIF_API */\r
+    struct {\r
+      struct pbuf *p;\r
+      struct netif *netif;\r
+    } inp;\r
+    struct {\r
+      void (*f)(void *ctx);\r
+      void *ctx;\r
+    } cb;\r
+    struct {\r
+      u32_t msecs;\r
+      sys_timeout_handler h;\r
+      void *arg;\r
+    } tmo;\r
+  } msg;\r
+};\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* !NO_SYS */\r
+\r
+#endif /* __LWIP_TCPIP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h b/Demo/Common/ethernet/lwIP_130/src/include/lwip/udp.h
new file mode 100644 (file)
index 0000000..ed03a0d
--- /dev/null
@@ -0,0 +1,150 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __LWIP_UDP_H__\r
+#define __LWIP_UDP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_UDP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/ip.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#define UDP_HLEN 8\r
+\r
+/* Fields are (of course) in network byte order. */\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct udp_hdr {\r
+  PACK_STRUCT_FIELD(u16_t src);\r
+  PACK_STRUCT_FIELD(u16_t dest);  /* src/dest UDP ports */\r
+  PACK_STRUCT_FIELD(u16_t len);\r
+  PACK_STRUCT_FIELD(u16_t chksum);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#define UDP_FLAGS_NOCHKSUM 0x01U\r
+#define UDP_FLAGS_UDPLITE  0x02U\r
+#define UDP_FLAGS_CONNECTED  0x04U\r
+\r
+struct udp_pcb {\r
+/* Common members of all PCB types */\r
+  IP_PCB;\r
+\r
+/* Protocol specific PCB members */\r
+\r
+  struct udp_pcb *next;\r
+\r
+  u8_t flags;\r
+  /* ports are in host byte order */\r
+  u16_t local_port, remote_port;\r
+\r
+#if LWIP_IGMP\r
+  /* outgoing network interface for multicast packets */\r
+  struct ip_addr multicast_ip;\r
+#endif /* LWIP_IGMP */\r
+\r
+#if LWIP_UDPLITE\r
+  /* used for UDP_LITE only */\r
+  u16_t chksum_len_rx, chksum_len_tx;\r
+#endif /* LWIP_UDPLITE */\r
+\r
+  /* receive callback function\r
+   * addr and port are in same byte order as in the pcb\r
+   * The callback is responsible for freeing the pbuf\r
+   * if it's not used any more.\r
+   *\r
+   * @param arg user supplied argument (udp_pcb.recv_arg)\r
+   * @param pcb the udp_pcb which received data\r
+   * @param p the packet buffer that was received\r
+   * @param addr the remote IP address from which the packet was received\r
+   * @param port the remote port from which the packet was received\r
+   */\r
+  void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p,\r
+    struct ip_addr *addr, u16_t port);\r
+  /* user-supplied argument for the recv callback */\r
+  void *recv_arg;\r
+};\r
+/* udp_pcbs export for exernal reference (e.g. SNMP agent) */\r
+extern struct udp_pcb *udp_pcbs;\r
+\r
+/* The following functions is the application layer interface to the\r
+   UDP code. */\r
+struct udp_pcb * udp_new        (void);\r
+void             udp_remove     (struct udp_pcb *pcb);\r
+err_t            udp_bind       (struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port);\r
+err_t            udp_connect    (struct udp_pcb *pcb, struct ip_addr *ipaddr,\r
+                 u16_t port);\r
+void             udp_disconnect    (struct udp_pcb *pcb);\r
+void             udp_recv       (struct udp_pcb *pcb,\r
+         void (* recv)(void *arg, struct udp_pcb *upcb,\r
+                 struct pbuf *p,\r
+                 struct ip_addr *addr,\r
+                 u16_t port),\r
+         void *recv_arg);\r
+err_t            udp_sendto_if  (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif);\r
+err_t            udp_sendto     (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port);\r
+err_t            udp_send       (struct udp_pcb *pcb, struct pbuf *p);\r
+\r
+#define          udp_flags(pcb)  ((pcb)->flags)\r
+#define          udp_setflags(pcb, f)  ((pcb)->flags = (f))\r
+\r
+/* The following functions are the lower layer interface to UDP. */\r
+void             udp_input      (struct pbuf *p, struct netif *inp);\r
+\r
+#define udp_init() /* Compatibility define, not init needed. */\r
+\r
+#if UDP_DEBUG\r
+void udp_debug_print(struct udp_hdr *udphdr);\r
+#else\r
+#define udp_debug_print(udphdr)\r
+#endif\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_UDP */\r
+\r
+#endif /* __LWIP_UDP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h b/Demo/Common/ethernet/lwIP_130/src/include/netif/etharp.h
new file mode 100644 (file)
index 0000000..021cffa
--- /dev/null
@@ -0,0 +1,175 @@
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+#ifndef __NETIF_ETHARP_H__\r
+#define __NETIF_ETHARP_H__\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/pbuf.h"\r
+#include "lwip/ip_addr.h"\r
+#include "lwip/netif.h"\r
+#include "lwip/ip.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#ifndef ETH_PAD_SIZE\r
+#define ETH_PAD_SIZE          0\r
+#endif\r
+\r
+#ifndef ETHARP_HWADDR_LEN\r
+#define ETHARP_HWADDR_LEN     6\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct eth_addr {\r
+  PACK_STRUCT_FIELD(u8_t addr[ETHARP_HWADDR_LEN]);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct eth_hdr {\r
+#if ETH_PAD_SIZE\r
+  PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);\r
+#endif\r
+  PACK_STRUCT_FIELD(struct eth_addr dest);\r
+  PACK_STRUCT_FIELD(struct eth_addr src);\r
+  PACK_STRUCT_FIELD(u16_t type);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+/** the ARP message */\r
+struct etharp_hdr {\r
+  PACK_STRUCT_FIELD(struct eth_hdr ethhdr);\r
+  PACK_STRUCT_FIELD(u16_t hwtype);\r
+  PACK_STRUCT_FIELD(u16_t proto);\r
+  PACK_STRUCT_FIELD(u16_t _hwlen_protolen);\r
+  PACK_STRUCT_FIELD(u16_t opcode);\r
+  PACK_STRUCT_FIELD(struct eth_addr shwaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr2 sipaddr);\r
+  PACK_STRUCT_FIELD(struct eth_addr dhwaddr);\r
+  PACK_STRUCT_FIELD(struct ip_addr2 dipaddr);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct ethip_hdr {\r
+  PACK_STRUCT_FIELD(struct eth_hdr eth);\r
+  PACK_STRUCT_FIELD(struct ip_hdr ip);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+/** 5 seconds period */\r
+#define ARP_TMR_INTERVAL 5000\r
+\r
+#define ETHTYPE_ARP       0x0806\r
+#define ETHTYPE_IP        0x0800\r
+#define ETHTYPE_PPPOEDISC 0x8863  /* PPP Over Ethernet Discovery Stage */\r
+#define ETHTYPE_PPPOE     0x8864  /* PPP Over Ethernet Session Stage */\r
+\r
+/** ARP message types (opcodes) */\r
+#define ARP_REQUEST 1\r
+#define ARP_REPLY   2\r
+\r
+#if ARP_QUEUEING\r
+/** struct for queueing outgoing packets for unknown address\r
+  * defined here to be accessed by memp.h\r
+  */\r
+struct etharp_q_entry {\r
+  struct etharp_q_entry *next;\r
+  struct pbuf *p;\r
+};\r
+#endif /* ARP_QUEUEING */\r
+\r
+#define etharp_init() /* Compatibility define, not init needed. */\r
+void etharp_tmr(void);\r
+s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,\r
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret);\r
+void etharp_ip_input(struct netif *netif, struct pbuf *p);\r
+void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr,\r
+         struct pbuf *p);\r
+err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr);\r
+err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q);\r
+err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr);\r
+\r
+err_t ethernet_input(struct pbuf *p, struct netif *netif);\r
+\r
+#if LWIP_AUTOIP\r
+err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,\r
+                 const struct eth_addr *ethdst_addr,\r
+                 const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,\r
+                 const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,\r
+                 const u16_t opcode);\r
+#endif /* LWIP_AUTOIP */\r
+\r
+#define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0)\r
+\r
+extern const struct eth_addr ethbroadcast, ethzero;\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* LWIP_ARP */\r
+\r
+#endif /* __NETIF_ARP_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h b/Demo/Common/ethernet/lwIP_130/src/include/netif/loopif.h
new file mode 100644 (file)
index 0000000..979ac7a
--- /dev/null
@@ -0,0 +1,52 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __NETIF_LOOPIF_H__\r
+#define __NETIF_LOOPIF_H__\r
+\r
+#include "lwip/netif.h"\r
+#include "lwip/err.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+#if !LWIP_LOOPIF_MULTITHREADING\r
+void loopif_poll(struct netif *netif);\r
+#endif\r
+\r
+err_t loopif_init(struct netif *netif);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
+\r
+#endif /* __NETIF_LOOPIF_H__ */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h b/Demo/Common/ethernet/lwIP_130/src/include/netif/ppp_oe.h
new file mode 100644 (file)
index 0000000..8db61e5
--- /dev/null
@@ -0,0 +1,161 @@
+/*****************************************************************************\r
+* ppp_oe.h - PPP Over Ethernet implementation for lwIP.\r
+*\r
+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any\r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.\r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 06-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+*****************************************************************************/\r
+\r
+\r
+\r
+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */\r
+\r
+/*-\r
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Martin Husemann <martin@NetBSD.org>.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. All advertising materials mentioning features or use of this software\r
+ *    must display the following acknowledgement:\r
+ *        This product includes software developed by the NetBSD\r
+ *        Foundation, Inc. and its contributors.\r
+ * 4. Neither the name of The NetBSD Foundation nor the names of its\r
+ *    contributors may be used to endorse or promote products derived\r
+ *    from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+#ifndef PPP_OE_H\r
+#define PPP_OE_H\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPPOE_SUPPORT > 0\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct pppoehdr {\r
+       PACK_STRUCT_FIELD(u8_t vertype);\r
+       PACK_STRUCT_FIELD(u8_t code);\r
+       PACK_STRUCT_FIELD(u16_t session);\r
+       PACK_STRUCT_FIELD(u16_t plen);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/bpstruct.h"\r
+#endif\r
+PACK_STRUCT_BEGIN\r
+struct pppoetag {\r
+       PACK_STRUCT_FIELD(u16_t tag);\r
+       PACK_STRUCT_FIELD(u16_t len);\r
+} PACK_STRUCT_STRUCT;\r
+PACK_STRUCT_END\r
+#ifdef PACK_STRUCT_USE_INCLUDES\r
+#  include "arch/epstruct.h"\r
+#endif\r
+\r
+\r
+#define PPPOE_STATE_INITIAL    0\r
+#define PPPOE_STATE_PADI_SENT  1\r
+#define        PPPOE_STATE_PADR_SENT   2\r
+#define        PPPOE_STATE_SESSION     3\r
+#define        PPPOE_STATE_CLOSING     4\r
+/* passive */\r
+#define        PPPOE_STATE_PADO_SENT   1\r
+\r
+#define PPPOE_HEADERLEN        sizeof(struct pppoehdr)\r
+#define        PPPOE_VERTYPE   0x11    /* VER=1, TYPE = 1 */\r
+\r
+#define        PPPOE_TAG_EOL           0x0000          /* end of list */\r
+#define        PPPOE_TAG_SNAME         0x0101          /* service name */\r
+#define        PPPOE_TAG_ACNAME        0x0102          /* access concentrator name */\r
+#define        PPPOE_TAG_HUNIQUE       0x0103          /* host unique */\r
+#define        PPPOE_TAG_ACCOOKIE      0x0104          /* AC cookie */\r
+#define        PPPOE_TAG_VENDOR        0x0105          /* vendor specific */\r
+#define        PPPOE_TAG_RELAYSID      0x0110          /* relay session id */\r
+#define        PPPOE_TAG_SNAME_ERR     0x0201          /* service name error */\r
+#define        PPPOE_TAG_ACSYS_ERR     0x0202          /* AC system error */\r
+#define        PPPOE_TAG_GENERIC_ERR   0x0203          /* gerneric error */\r
+\r
+#define PPPOE_CODE_PADI                0x09            /* Active Discovery Initiation */\r
+#define        PPPOE_CODE_PADO         0x07            /* Active Discovery Offer */\r
+#define        PPPOE_CODE_PADR         0x19            /* Active Discovery Request */\r
+#define        PPPOE_CODE_PADS         0x65            /* Active Discovery Session confirmation */\r
+#define        PPPOE_CODE_PADT         0xA7            /* Active Discovery Terminate */\r
+\r
+#ifndef ETHERMTU\r
+#define ETHERMTU 1500\r
+#endif\r
+\r
+/* two byte PPP protocol discriminator, then IP data */\r
+#define        PPPOE_MAXMTU    (ETHERMTU-PPPOE_HEADERLEN-2)\r
+\r
+struct pppoe_softc;\r
+\r
+\r
+void pppoe_init(void);\r
+\r
+err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr);\r
+err_t pppoe_destroy(struct netif *ifp);\r
+\r
+int pppoe_connect(struct pppoe_softc *sc);\r
+void pppoe_disconnect(struct pppoe_softc *sc);\r
+\r
+void pppoe_disc_input(struct netif *netif, struct pbuf *p);\r
+void pppoe_data_input(struct netif *netif, struct pbuf *p);\r
+\r
+err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb);\r
+\r
+extern int pppoe_hdrlen;\r
+\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#endif /* PPP_OE_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h b/Demo/Common/ethernet/lwIP_130/src/include/netif/slipif.h
new file mode 100644 (file)
index 0000000..ef11e97
--- /dev/null
@@ -0,0 +1,50 @@
+/*\r
+ * Copyright (c) 2001, Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ *\r
+ * Redistribution and use in source and binary forms, with or without \r
+ * modification, are permitted provided that the following conditions \r
+ * are met: \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ *    notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright \r
+ *    notice, this list of conditions and the following disclaimer in the \r
+ *    documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of the Institute nor the names of its contributors \r
+ *    may be used to endorse or promote products derived from this software \r
+ *    without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE. \r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#ifndef __NETIF_SLIPIF_H__\r
+#define __NETIF_SLIPIF_H__\r
+\r
+#include "lwip/netif.h"\r
+\r
+#ifdef __cplusplus\r
+extern "C" {\r
+#endif\r
+\r
+err_t slipif_init(struct netif * netif);\r
+\r
+#ifdef __cplusplus\r
+}\r
+#endif\r
\r
+#endif \r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/FILES b/Demo/Common/ethernet/lwIP_130/src/netif/FILES
new file mode 100644 (file)
index 0000000..a0dca19
--- /dev/null
@@ -0,0 +1,25 @@
+This directory contains generic network interface device drivers that\r
+do not contain any hardware or architecture specific code. The files\r
+are:\r
+\r
+etharp.c\r
+          Implements the ARP (Address Resolution Protocol) over\r
+          Ethernet. The code in this file should be used together with\r
+          Ethernet device drivers. Note that this module has been\r
+          largely made Ethernet independent so you should be able to\r
+          adapt this for other link layers (such as Firewire).\r
+\r
+ethernetif.c\r
+          An example of how an Ethernet device driver could look. This\r
+          file can be used as a "skeleton" for developing new Ethernet\r
+          network device drivers. It uses the etharp.c ARP code.\r
+\r
+loopif.c\r
+          A "loopback" network interface driver. It requires configuration\r
+          through the define LWIP_LOOPIF_MULTITHREADING (see opt.h).\r
+\r
+slipif.c\r
+          A generic implementation of the SLIP (Serial Line IP)\r
+          protocol. It requires a sio (serial I/O) module to work.\r
+\r
+ppp/      Point-to-Point Protocol stack\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/etharp.c b/Demo/Common/ethernet/lwIP_130/src/netif/etharp.c
new file mode 100644 (file)
index 0000000..27ae689
--- /dev/null
@@ -0,0 +1,1177 @@
+/**\r
+ * @file\r
+ * Address Resolution Protocol module for IP over Ethernet\r
+ *\r
+ * Functionally, ARP is divided into two parts. The first maps an IP address\r
+ * to a physical address when sending a packet, and the second part answers\r
+ * requests from other machines for our physical address.\r
+ *\r
+ * This implementation complies with RFC 826 (Ethernet ARP). It supports\r
+ * Gratuitious ARP from RFC3220 (IP Mobility Support for IPv4) section 4.6\r
+ * if an interface calls etharp_query(our_netif, its_ip_addr, NULL) upon\r
+ * address change.\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2003 Swedish Institute of Computer Science.\r
+ * Copyright (c) 2003-2004 Leon Woestenberg <leon.woestenberg@axon.tv>\r
+ * Copyright (c) 2003-2004 Axon Digital Design B.V., The Netherlands.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/inet.h"\r
+#include "lwip/ip.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/dhcp.h"\r
+#include "lwip/autoip.h"\r
+#include "netif/etharp.h"\r
+\r
+#if PPPOE_SUPPORT\r
+#include "netif/ppp_oe.h"\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#include <string.h>\r
+\r
+/** the time an ARP entry stays valid after its last update,\r
+ *  for ARP_TMR_INTERVAL = 5000, this is\r
+ *  (240 * 5) seconds = 20 minutes.\r
+ */\r
+#define ARP_MAXAGE 240\r
+/** the time an ARP entry stays pending after first request,\r
+ *  for ARP_TMR_INTERVAL = 5000, this is\r
+ *  (2 * 5) seconds = 10 seconds.\r
+ *\r
+ *  @internal Keep this number at least 2, otherwise it might\r
+ *  run out instantly if the timeout occurs directly after a request.\r
+ */\r
+#define ARP_MAXPENDING 2\r
+\r
+#define HWTYPE_ETHERNET 1\r
+\r
+#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8)\r
+#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff)\r
+\r
+#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8))\r
+#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8))\r
+\r
+enum etharp_state {\r
+  ETHARP_STATE_EMPTY = 0,\r
+  ETHARP_STATE_PENDING,\r
+  ETHARP_STATE_STABLE\r
+};\r
+\r
+struct etharp_entry {\r
+#if ARP_QUEUEING\r
+  /**\r
+   * Pointer to queue of pending outgoing packets on this ARP entry.\r
+   */\r
+  struct etharp_q_entry *q;\r
+#endif\r
+  struct ip_addr ipaddr;\r
+  struct eth_addr ethaddr;\r
+  enum etharp_state state;\r
+  u8_t ctime;\r
+  struct netif *netif;\r
+};\r
+\r
+const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}};\r
+const struct eth_addr ethzero = {{0,0,0,0,0,0}};\r
+static struct etharp_entry arp_table[ARP_TABLE_SIZE];\r
+#if !LWIP_NETIF_HWADDRHINT\r
+static u8_t etharp_cached_entry;\r
+#endif\r
+\r
+/**\r
+ * Try hard to create a new entry - we want the IP address to appear in\r
+ * the cache (even if this means removing an active entry or so). */\r
+#define ETHARP_TRY_HARD 1\r
+#define ETHARP_FIND_ONLY  2\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+#define NETIF_SET_HINT(netif, hint)  if (((netif) != NULL) && ((netif)->addr_hint != NULL))  \\r
+                                      *((netif)->addr_hint) = (hint);\r
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif);\r
+#else /* LWIP_NETIF_HWADDRHINT */\r
+static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags);\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+\r
+static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags);\r
+\r
+\r
+/* Some checks, instead of etharp_init(): */\r
+#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f))\r
+  #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"\r
+#endif\r
+\r
+\r
+#if ARP_QUEUEING\r
+/**\r
+ * Free a complete queue of etharp entries\r
+ *\r
+ * @param q a qeueue of etharp_q_entry's to free\r
+ */\r
+static void\r
+free_etharp_q(struct etharp_q_entry *q)\r
+{\r
+  struct etharp_q_entry *r;\r
+  LWIP_ASSERT("q != NULL", q != NULL);\r
+  LWIP_ASSERT("q->p != NULL", q->p != NULL);\r
+  while (q) {\r
+    r = q;\r
+    q = q->next;\r
+    LWIP_ASSERT("r->p != NULL", (r->p != NULL));\r
+    pbuf_free(r->p);\r
+    memp_free(MEMP_ARP_QUEUE, r);\r
+  }\r
+}\r
+#endif\r
+\r
+/**\r
+ * Clears expired entries in the ARP table.\r
+ *\r
+ * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds),\r
+ * in order to expire entries in the ARP table.\r
+ */\r
+void\r
+etharp_tmr(void)\r
+{\r
+  u8_t i;\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n"));\r
+  /* remove expired entries from the ARP table */\r
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
+    arp_table[i].ctime++;\r
+    if (((arp_table[i].state == ETHARP_STATE_STABLE) &&\r
+         (arp_table[i].ctime >= ARP_MAXAGE)) ||\r
+        ((arp_table[i].state == ETHARP_STATE_PENDING)  &&\r
+         (arp_table[i].ctime >= ARP_MAXPENDING))) {\r
+         /* pending or stable entry has become old! */\r
+      LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n",\r
+           arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i));\r
+      /* clean up entries that have just been expired */\r
+      /* remove from SNMP ARP index tree */\r
+      snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);\r
+#if ARP_QUEUEING\r
+      /* and empty packet queue */\r
+      if (arp_table[i].q != NULL) {\r
+        /* remove all queued packets */\r
+        LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q)));\r
+        free_etharp_q(arp_table[i].q);\r
+        arp_table[i].q = NULL;\r
+      }\r
+#endif\r
+      /* recycle entry for re-use */\r
+      arp_table[i].state = ETHARP_STATE_EMPTY;\r
+    }\r
+#if ARP_QUEUEING\r
+    /* still pending entry? (not expired) */\r
+    if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+        /* resend an ARP query here? */\r
+    }\r
+#endif\r
+  }\r
+}\r
+\r
+/**\r
+ * Search the ARP table for a matching or new entry.\r
+ *\r
+ * If an IP address is given, return a pending or stable ARP entry that matches\r
+ * the address. If no match is found, create a new entry with this address set,\r
+ * but in state ETHARP_EMPTY. The caller must check and possibly change the\r
+ * state of the returned entry.\r
+ *\r
+ * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY.\r
+ *\r
+ * In all cases, attempt to create new entries from an empty entry. If no\r
+ * empty entries are available and ETHARP_TRY_HARD flag is set, recycle\r
+ * old entries. Heuristic choose the least important entry for recycling.\r
+ *\r
+ * @param ipaddr IP address to find in ARP cache, or to add if not found.\r
+ * @param flags\r
+ * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of\r
+ * active (stable or pending) entries.\r
+ *\r
+ * @return The ARP entry index that matched or is created, ERR_MEM if no\r
+ * entry is found or could be recycled.\r
+ */\r
+static s8_t\r
+#if LWIP_NETIF_HWADDRHINT\r
+find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif)\r
+#else /* LWIP_NETIF_HWADDRHINT */\r
+find_entry(struct ip_addr *ipaddr, u8_t flags)\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+{\r
+  s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE;\r
+  s8_t empty = ARP_TABLE_SIZE;\r
+  u8_t i = 0, age_pending = 0, age_stable = 0;\r
+#if ARP_QUEUEING\r
+  /* oldest entry with packets on queue */\r
+  s8_t old_queue = ARP_TABLE_SIZE;\r
+  /* its age */\r
+  u8_t age_queue = 0;\r
+#endif\r
+\r
+  /* First, test if the last call to this function asked for the\r
+   * same address. If so, we're really fast! */\r
+  if (ipaddr) {\r
+    /* ipaddr to search for was given */\r
+#if LWIP_NETIF_HWADDRHINT\r
+    if ((netif != NULL) && (netif->addr_hint != NULL)) {\r
+      /* per-pcb cached entry was given */\r
+      u8_t per_pcb_cache = *(netif->addr_hint);\r
+      if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) {\r
+        /* the per-pcb-cached entry is stable */\r
+        if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) {\r
+          /* per-pcb cached entry was the right one! */\r
+          ETHARP_STATS_INC(etharp.cachehit);\r
+          return per_pcb_cache;\r
+        }\r
+      }\r
+    }\r
+#else /* #if LWIP_NETIF_HWADDRHINT */\r
+    if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) {\r
+      /* the cached entry is stable */\r
+      if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) {\r
+        /* cached entry was the right one! */\r
+        ETHARP_STATS_INC(etharp.cachehit);\r
+        return etharp_cached_entry;\r
+      }\r
+    }\r
+#endif /* #if LWIP_NETIF_HWADDRHINT */\r
+  }\r
+\r
+  /**\r
+   * a) do a search through the cache, remember candidates\r
+   * b) select candidate entry\r
+   * c) create new entry\r
+   */\r
+\r
+  /* a) in a single search sweep, do all of this\r
+   * 1) remember the first empty entry (if any)\r
+   * 2) remember the oldest stable entry (if any)\r
+   * 3) remember the oldest pending entry without queued packets (if any)\r
+   * 4) remember the oldest pending entry with queued packets (if any)\r
+   * 5) search for a matching IP entry, either pending or stable\r
+   *    until 5 matches, or all entries are searched for.\r
+   */\r
+\r
+  for (i = 0; i < ARP_TABLE_SIZE; ++i) {\r
+    /* no empty entry found yet and now we do find one? */\r
+    if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) {\r
+      LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i));\r
+      /* remember first empty entry */\r
+      empty = i;\r
+    }\r
+    /* pending entry? */\r
+    else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+      /* if given, does IP address match IP address in ARP entry? */\r
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i));\r
+        /* found exact IP address match, simply bail out */\r
+#if LWIP_NETIF_HWADDRHINT\r
+        NETIF_SET_HINT(netif, i);\r
+#else /* #if LWIP_NETIF_HWADDRHINT */\r
+        etharp_cached_entry = i;\r
+#endif /* #if LWIP_NETIF_HWADDRHINT */\r
+        return i;\r
+#if ARP_QUEUEING\r
+      /* pending with queued packets? */\r
+      } else if (arp_table[i].q != NULL) {\r
+        if (arp_table[i].ctime >= age_queue) {\r
+          old_queue = i;\r
+          age_queue = arp_table[i].ctime;\r
+        }\r
+#endif\r
+      /* pending without queued packets? */\r
+      } else {\r
+        if (arp_table[i].ctime >= age_pending) {\r
+          old_pending = i;\r
+          age_pending = arp_table[i].ctime;\r
+        }\r
+      }\r
+    }\r
+    /* stable entry? */\r
+    else if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
+      /* if given, does IP address match IP address in ARP entry? */\r
+      if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) {\r
+        LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i));\r
+        /* found exact IP address match, simply bail out */\r
+#if LWIP_NETIF_HWADDRHINT\r
+        NETIF_SET_HINT(netif, i);\r
+#else /* #if LWIP_NETIF_HWADDRHINT */\r
+        etharp_cached_entry = i;\r
+#endif /* #if LWIP_NETIF_HWADDRHINT */\r
+        return i;\r
+      /* remember entry with oldest stable entry in oldest, its age in maxtime */\r
+      } else if (arp_table[i].ctime >= age_stable) {\r
+        old_stable = i;\r
+        age_stable = arp_table[i].ctime;\r
+      }\r
+    }\r
+  }\r
+  /* { we have no match } => try to create a new entry */\r
+\r
+  /* no empty entry found and not allowed to recycle? */\r
+  if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0))\r
+      /* or don't create new entry, only search? */\r
+      || ((flags & ETHARP_FIND_ONLY) != 0)) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n"));\r
+    return (s8_t)ERR_MEM;\r
+  }\r
+\r
+  /* b) choose the least destructive entry to recycle:\r
+   * 1) empty entry\r
+   * 2) oldest stable entry\r
+   * 3) oldest pending entry without queued packets\r
+   * 4) oldest pending entry without queued packets\r
+   *\r
+   * { ETHARP_TRY_HARD is set at this point }\r
+   */\r
+\r
+  /* 1) empty entry available? */\r
+  if (empty < ARP_TABLE_SIZE) {\r
+    i = empty;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i));\r
+  }\r
+  /* 2) found recyclable stable entry? */\r
+  else if (old_stable < ARP_TABLE_SIZE) {\r
+    /* recycle oldest stable*/\r
+    i = old_stable;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i));\r
+#if ARP_QUEUEING\r
+    /* no queued packets should exist on stable entries */\r
+    LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL);\r
+#endif\r
+  /* 3) found recyclable pending entry without queued packets? */\r
+  } else if (old_pending < ARP_TABLE_SIZE) {\r
+    /* recycle oldest pending */\r
+    i = old_pending;\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i));\r
+#if ARP_QUEUEING\r
+  /* 4) found recyclable pending entry with queued packets? */\r
+  } else if (old_queue < ARP_TABLE_SIZE) {\r
+    /* recycle oldest pending */\r
+    i = old_queue;\r
+    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)));\r
+    free_etharp_q(arp_table[i].q);\r
+    arp_table[i].q = NULL;\r
+#endif\r
+    /* no empty or recyclable entries found */\r
+  } else {\r
+    return (s8_t)ERR_MEM;\r
+  }\r
+\r
+  /* { empty or recyclable entry found } */\r
+  LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE);\r
+\r
+  if (arp_table[i].state != ETHARP_STATE_EMPTY)\r
+  {\r
+    snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr);\r
+  }\r
+  /* recycle entry (no-op for an already empty entry) */\r
+  arp_table[i].state = ETHARP_STATE_EMPTY;\r
+\r
+  /* IP address given? */\r
+  if (ipaddr != NULL) {\r
+    /* set IP address */\r
+    ip_addr_set(&arp_table[i].ipaddr, ipaddr);\r
+  }\r
+  arp_table[i].ctime = 0;\r
+#if LWIP_NETIF_HWADDRHINT\r
+  NETIF_SET_HINT(netif, i);\r
+#else /* #if LWIP_NETIF_HWADDRHINT */\r
+  etharp_cached_entry = i;\r
+#endif /* #if LWIP_NETIF_HWADDRHINT */\r
+  return (err_t)i;\r
+}\r
+\r
+/**\r
+ * Send an IP packet on the network using netif->linkoutput\r
+ * The ethernet header is filled in before sending.\r
+ *\r
+ * @params netif the lwIP network interface on which to send the packet\r
+ * @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header\r
+ * @params src the source MAC address to be copied into the ethernet header\r
+ * @params dst the destination MAC address to be copied into the ethernet header\r
+ * @return ERR_OK if the packet was sent, any other err_t on failure\r
+ */\r
+static err_t\r
+etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)\r
+{\r
+  struct eth_hdr *ethhdr = p->payload;\r
+  u8_t k;\r
+\r
+  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",\r
+              (netif->hwaddr_len == ETHARP_HWADDR_LEN));\r
+  k = ETHARP_HWADDR_LEN;\r
+  while(k > 0) {\r
+    k--;\r
+    ethhdr->dest.addr[k] = dst->addr[k];\r
+    ethhdr->src.addr[k]  = src->addr[k];\r
+  }\r
+  ethhdr->type = htons(ETHTYPE_IP);\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p));\r
+  /* send the packet */\r
+  return netif->linkoutput(netif, p);\r
+}\r
+\r
+/**\r
+ * Update (or insert) a IP/MAC address pair in the ARP cache.\r
+ *\r
+ * If a pending entry is resolved, any queued packets will be sent\r
+ * at this point.\r
+ *\r
+ * @param ipaddr IP address of the inserted ARP entry.\r
+ * @param ethaddr Ethernet address of the inserted ARP entry.\r
+ * @param flags Defines behaviour:\r
+ * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified,\r
+ * only existing ARP entries will be updated.\r
+ *\r
+ * @return\r
+ * - ERR_OK Succesfully updated ARP cache.\r
+ * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set.\r
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+static err_t\r
+update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags)\r
+{\r
+  s8_t i;\r
+  u8_t k;\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 3, ("update_arp_entry()\n"));\r
+  LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN);\r
+  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",\r
+                                        ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr),\r
+                                        ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2],\r
+                                        ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5]));\r
+  /* non-unicast address? */\r
+  if (ip_addr_isany(ipaddr) ||\r
+      ip_addr_isbroadcast(ipaddr, netif) ||\r
+      ip_addr_ismulticast(ipaddr)) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: will not add non-unicast IP address to ARP cache\n"));\r
+    return ERR_ARG;\r
+  }\r
+  /* find or create ARP entry */\r
+#if LWIP_NETIF_HWADDRHINT\r
+  i = find_entry(ipaddr, flags, netif);\r
+#else /* LWIP_NETIF_HWADDRHINT */\r
+  i = find_entry(ipaddr, flags);\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+  /* bail out if no entry could be found */\r
+  if (i < 0)\r
+    return (err_t)i;\r
+\r
+  /* mark it stable */\r
+  arp_table[i].state = ETHARP_STATE_STABLE;\r
+  /* record network interface */\r
+  arp_table[i].netif = netif;\r
+\r
+  /* insert in SNMP ARP index tree */\r
+  snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr);\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i));\r
+  /* update address */\r
+  k = ETHARP_HWADDR_LEN;\r
+  while (k > 0) {\r
+    k--;\r
+    arp_table[i].ethaddr.addr[k] = ethaddr->addr[k];\r
+  }\r
+  /* reset time stamp */\r
+  arp_table[i].ctime = 0;\r
+#if ARP_QUEUEING\r
+  /* this is where we will send out queued packets! */\r
+  while (arp_table[i].q != NULL) {\r
+    struct pbuf *p;\r
+    /* remember remainder of queue */\r
+    struct etharp_q_entry *q = arp_table[i].q;\r
+    /* pop first item off the queue */\r
+    arp_table[i].q = q->next;\r
+    /* get the packet pointer */\r
+    p = q->p;\r
+    /* now queue entry can be freed */\r
+    memp_free(MEMP_ARP_QUEUE, q);\r
+    /* send the queued IP packet */\r
+    etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr);\r
+    /* free the queued IP packet */\r
+    pbuf_free(p);\r
+  }\r
+#endif\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Finds (stable) ethernet/IP address pair from ARP table\r
+ * using interface and IP address index.\r
+ * @note the addresses in the ARP table are in network order!\r
+ *\r
+ * @param netif points to interface index\r
+ * @param ipaddr points to the (network order) IP address index\r
+ * @param eth_ret points to return pointer\r
+ * @param ip_ret points to return pointer\r
+ * @return table index if found, -1 otherwise\r
+ */\r
+s8_t\r
+etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr,\r
+         struct eth_addr **eth_ret, struct ip_addr **ip_ret)\r
+{\r
+  s8_t i;\r
+\r
+  LWIP_UNUSED_ARG(netif);\r
+\r
+#if LWIP_NETIF_HWADDRHINT\r
+  i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL);\r
+#else /* LWIP_NETIF_HWADDRHINT */\r
+  i = find_entry(ipaddr, ETHARP_FIND_ONLY);\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+  if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) {\r
+      *eth_ret = &arp_table[i].ethaddr;\r
+      *ip_ret = &arp_table[i].ipaddr;\r
+      return i;\r
+  }\r
+  return -1;\r
+}\r
+\r
+/**\r
+ * Updates the ARP table using the given IP packet.\r
+ *\r
+ * Uses the incoming IP packet's source address to update the\r
+ * ARP cache for the local network. The function does not alter\r
+ * or free the packet. This function must be called before the\r
+ * packet p is passed to the IP layer.\r
+ *\r
+ * @param netif The lwIP network interface on which the IP packet pbuf arrived.\r
+ * @param p The IP packet that arrived on netif.\r
+ *\r
+ * @return NULL\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+void\r
+etharp_ip_input(struct netif *netif, struct pbuf *p)\r
+{\r
+  struct ethip_hdr *hdr;\r
+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);\r
+  /* Only insert an entry if the source IP address of the\r
+     incoming IP packet comes from a host on the local network. */\r
+  hdr = p->payload;\r
+  /* source is not on the local network? */\r
+  if (!ip_addr_netcmp(&(hdr->ip.src), &(netif->ip_addr), &(netif->netmask))) {\r
+    /* do nothing */\r
+    return;\r
+  }\r
+\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n"));\r
+  /* update ARP table */\r
+  /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk\r
+   * back soon (for example, if the destination IP address is ours. */\r
+  update_arp_entry(netif, &(hdr->ip.src), &(hdr->eth.src), 0);\r
+}\r
+\r
+\r
+/**\r
+ * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache\r
+ * send out queued IP packets. Updates cache with snooped address pairs.\r
+ *\r
+ * Should be called for incoming ARP packets. The pbuf in the argument\r
+ * is freed by this function.\r
+ *\r
+ * @param netif The lwIP network interface on which the ARP packet pbuf arrived.\r
+ * @param ethaddr Ethernet address of netif.\r
+ * @param p The ARP packet that arrived on netif. Is freed by this function.\r
+ *\r
+ * @return NULL\r
+ *\r
+ * @see pbuf_free()\r
+ */\r
+void\r
+etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p)\r
+{\r
+  struct etharp_hdr *hdr;\r
+  /* these are aligned properly, whereas the ARP header fields might not be */\r
+  struct ip_addr sipaddr, dipaddr;\r
+  u8_t i;\r
+  u8_t for_us;\r
+#if LWIP_AUTOIP\r
+  const u8_t * ethdst_hwaddr;\r
+#endif /* LWIP_AUTOIP */\r
+\r
+  LWIP_ERROR("netif != NULL", (netif != NULL), return;);\r
+\r
+  /* drop short ARP packets: we have to check for p->len instead of p->tot_len here\r
+     since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */\r
+  if (p->len < sizeof(struct etharp_hdr)) {\r
+    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)));\r
+    ETHARP_STATS_INC(etharp.lenerr);\r
+    ETHARP_STATS_INC(etharp.drop);\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+\r
+  hdr = p->payload;\r
+\r
+  /* RFC 826 "Packet Reception": */\r
+  if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) ||\r
+      (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) ||\r
+      (hdr->proto != htons(ETHTYPE_IP)) ||\r
+      (hdr->ethhdr.type != htons(ETHTYPE_ARP)))  {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 1,\r
+      ("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",\r
+      hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), hdr->ethhdr.type));\r
+    ETHARP_STATS_INC(etharp.proterr);\r
+    ETHARP_STATS_INC(etharp.drop);\r
+    pbuf_free(p);\r
+    return;\r
+  }\r
+  ETHARP_STATS_INC(etharp.recv);\r
+\r
+#if LWIP_AUTOIP\r
+  /* We have to check if a host already has configured our random\r
+   * created link local address and continously check if there is\r
+   * a host with this IP-address so we can detect collisions */\r
+  autoip_arp_reply(netif, hdr);\r
+#endif /* LWIP_AUTOIP */\r
+\r
+  /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without\r
+   * structure packing (not using structure copy which breaks strict-aliasing rules). */\r
+  SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));\r
+  SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr));\r
+\r
+  /* this interface is not configured? */\r
+  if (netif->ip_addr.addr == 0) {\r
+    for_us = 0;\r
+  } else {\r
+    /* ARP packet directed to us? */\r
+    for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr));\r
+  }\r
+\r
+  /* ARP message directed to us? */\r
+  if (for_us) {\r
+    /* add IP address in ARP cache; assume requester wants to talk to us.\r
+     * can result in directly sending the queued packets for this host. */\r
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD);\r
+  /* ARP message not directed to us? */\r
+  } else {\r
+    /* update the source IP address in the cache, if present */\r
+    update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0);\r
+  }\r
+\r
+  /* now act on the message itself */\r
+  switch (htons(hdr->opcode)) {\r
+  /* ARP request? */\r
+  case ARP_REQUEST:\r
+    /* ARP request. If it asked for our address, we send out a\r
+     * reply. In any case, we time-stamp any existing ARP entry,\r
+     * and possiby send out an IP packet that was queued on it. */\r
+\r
+    LWIP_DEBUGF (ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP request\n"));\r
+    /* ARP request for our address? */\r
+    if (for_us) {\r
+\r
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: replying to ARP request for our IP address\n"));\r
+      /* Re-use pbuf to send ARP reply.\r
+         Since we are re-using an existing pbuf, we can't call etharp_raw since\r
+         that would allocate a new pbuf. */\r
+      hdr->opcode = htons(ARP_REPLY);\r
+\r
+      hdr->dipaddr = hdr->sipaddr;\r
+      hdr->sipaddr = *(struct ip_addr2 *)&netif->ip_addr;\r
+\r
+      LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",\r
+                  (netif->hwaddr_len == ETHARP_HWADDR_LEN));\r
+      i = ETHARP_HWADDR_LEN;\r
+#if LWIP_AUTOIP\r
+      /* If we are using Link-Local, ARP packets must be broadcast on the\r
+       * link layer. (See RFC3927 Section 2.5) */\r
+      ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr;\r
+#endif /* LWIP_AUTOIP */\r
+\r
+      while(i > 0) {\r
+        i--;\r
+        hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i];\r
+#if LWIP_AUTOIP\r
+        hdr->ethhdr.dest.addr[i] = ethdst_hwaddr[i];\r
+#else  /* LWIP_AUTOIP */\r
+        hdr->ethhdr.dest.addr[i] = hdr->shwaddr.addr[i];\r
+#endif /* LWIP_AUTOIP */\r
+        hdr->shwaddr.addr[i] = ethaddr->addr[i];\r
+        hdr->ethhdr.src.addr[i] = ethaddr->addr[i];\r
+      }\r
+\r
+      /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header\r
+         are already correct, we tested that before */\r
+\r
+      /* return ARP reply */\r
+      netif->linkoutput(netif, p);\r
+    /* we are not configured? */\r
+    } else if (netif->ip_addr.addr == 0) {\r
+      /* { for_us == 0 and netif->ip_addr.addr == 0 } */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n"));\r
+    /* request was not directed to us */\r
+    } else {\r
+      /* { for_us == 0 and netif->ip_addr.addr != 0 } */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n"));\r
+    }\r
+    break;\r
+  case ARP_REPLY:\r
+    /* ARP reply. We already updated the ARP cache earlier. */\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n"));\r
+#if (LWIP_DHCP && DHCP_DOES_ARP_CHECK)\r
+    /* DHCP wants to know about ARP replies from any host with an\r
+     * IP address also offered to us by the DHCP server. We do not\r
+     * want to take a duplicate IP address on a single network.\r
+     * @todo How should we handle redundant (fail-over) interfaces? */\r
+    dhcp_arp_reply(netif, &sipaddr);\r
+#endif\r
+    break;\r
+  default:\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode)));\r
+    ETHARP_STATS_INC(etharp.err);\r
+    break;\r
+  }\r
+  /* free ARP packet */\r
+  pbuf_free(p);\r
+}\r
+\r
+/**\r
+ * Resolve and fill-in Ethernet address header for outgoing IP packet.\r
+ *\r
+ * For IP multicast and broadcast, corresponding Ethernet addresses\r
+ * are selected and the packet is transmitted on the link.\r
+ *\r
+ * For unicast addresses, the packet is submitted to etharp_query(). In\r
+ * case the IP address is outside the local network, the IP address of\r
+ * the gateway is used.\r
+ *\r
+ * @param netif The lwIP network interface which the IP packet will be sent on.\r
+ * @param q The pbuf(s) containing the IP packet to be sent.\r
+ * @param ipaddr The IP address of the packet destination.\r
+ *\r
+ * @return\r
+ * - ERR_RTE No route to destination (no gateway to external networks),\r
+ * or the return type of either etharp_query() or etharp_send_ip().\r
+ */\r
+err_t\r
+etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr)\r
+{\r
+  struct eth_addr *dest, mcastaddr;\r
+\r
+  /* make room for Ethernet header - should not fail */\r
+  if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {\r
+    /* bail out */\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_output: could not allocate room for header.\n"));\r
+    LINK_STATS_INC(link.lenerr);\r
+    return ERR_BUF;\r
+  }\r
+\r
+  /* assume unresolved Ethernet address */\r
+  dest = NULL;\r
+  /* Determine on destination hardware address. Broadcasts and multicasts\r
+   * are special, other IP addresses are looked up in the ARP table. */\r
+\r
+  /* broadcast destination IP address? */\r
+  if (ip_addr_isbroadcast(ipaddr, netif)) {\r
+    /* broadcast on Ethernet also */\r
+    dest = (struct eth_addr *)&ethbroadcast;\r
+  /* multicast destination IP address? */\r
+  } else if (ip_addr_ismulticast(ipaddr)) {\r
+    /* Hash IP multicast address to MAC address.*/\r
+    mcastaddr.addr[0] = 0x01;\r
+    mcastaddr.addr[1] = 0x00;\r
+    mcastaddr.addr[2] = 0x5e;\r
+    mcastaddr.addr[3] = ip4_addr2(ipaddr) & 0x7f;\r
+    mcastaddr.addr[4] = ip4_addr3(ipaddr);\r
+    mcastaddr.addr[5] = ip4_addr4(ipaddr);\r
+    /* destination Ethernet address is multicast */\r
+    dest = &mcastaddr;\r
+  /* unicast destination IP address? */\r
+  } else {\r
+    /* outside local network? */\r
+    if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) {\r
+      /* interface has default gateway? */\r
+      if (netif->gw.addr != 0) {\r
+        /* send to hardware address of default gateway IP address */\r
+        ipaddr = &(netif->gw);\r
+      /* no default gateway available */\r
+      } else {\r
+        /* no route to destination error (default gateway missing) */\r
+        return ERR_RTE;\r
+      }\r
+    }\r
+    /* queue on destination Ethernet address belonging to ipaddr */\r
+    return etharp_query(netif, ipaddr, q);\r
+  }\r
+\r
+  /* continuation for multicast/broadcast destinations */\r
+  /* obtain source Ethernet address of the given interface */\r
+  /* send packet directly on the link */\r
+  return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), dest);\r
+}\r
+\r
+/**\r
+ * Send an ARP request for the given IP address and/or queue a packet.\r
+ *\r
+ * If the IP address was not yet in the cache, a pending ARP cache entry\r
+ * is added and an ARP request is sent for the given address. The packet\r
+ * is queued on this entry.\r
+ *\r
+ * If the IP address was already pending in the cache, a new ARP request\r
+ * is sent for the given address. The packet is queued on this entry.\r
+ *\r
+ * If the IP address was already stable in the cache, and a packet is\r
+ * given, it is directly sent and no ARP request is sent out.\r
+ *\r
+ * If the IP address was already stable in the cache, and no packet is\r
+ * given, an ARP request is sent out.\r
+ *\r
+ * @param netif The lwIP network interface on which ipaddr\r
+ * must be queried for.\r
+ * @param ipaddr The IP address to be resolved.\r
+ * @param q If non-NULL, a pbuf that must be delivered to the IP address.\r
+ * q is not freed by this function.\r
+ *\r
+ * @note q must only be ONE packet, not a packet queue!\r
+ *\r
+ * @return\r
+ * - ERR_BUF Could not make room for Ethernet header.\r
+ * - ERR_MEM Hardware address unknown, and no more ARP entries available\r
+ *   to query for address or queue the packet.\r
+ * - ERR_MEM Could not queue packet due to memory shortage.\r
+ * - ERR_RTE No route to destination (no gateway to external networks).\r
+ * - ERR_ARG Non-unicast address given, those will not appear in ARP cache.\r
+ *\r
+ */\r
+err_t\r
+etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q)\r
+{\r
+  struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr;\r
+  err_t result = ERR_MEM;\r
+  s8_t i; /* ARP entry index */\r
+\r
+  /* non-unicast address? */\r
+  if (ip_addr_isbroadcast(ipaddr, netif) ||\r
+      ip_addr_ismulticast(ipaddr) ||\r
+      ip_addr_isany(ipaddr)) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: will not add non-unicast IP address to ARP cache\n"));\r
+    return ERR_ARG;\r
+  }\r
+\r
+  /* find entry in ARP cache, ask to create entry if queueing packet */\r
+#if LWIP_NETIF_HWADDRHINT\r
+  i = find_entry(ipaddr, ETHARP_TRY_HARD, netif);\r
+#else /* LWIP_NETIF_HWADDRHINT */\r
+  i = find_entry(ipaddr, ETHARP_TRY_HARD);\r
+#endif /* LWIP_NETIF_HWADDRHINT */\r
+\r
+  /* could not find or create entry? */\r
+  if (i < 0) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not create ARP entry\n"));\r
+    if (q) {\r
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: packet dropped\n"));\r
+      ETHARP_STATS_INC(etharp.memerr);\r
+    }\r
+    return (err_t)i;\r
+  }\r
+\r
+  /* mark a fresh entry as pending (we just sent a request) */\r
+  if (arp_table[i].state == ETHARP_STATE_EMPTY) {\r
+    arp_table[i].state = ETHARP_STATE_PENDING;\r
+  }\r
+\r
+  /* { i is either a STABLE or (new or existing) PENDING entry } */\r
+  LWIP_ASSERT("arp_table[i].state == PENDING or STABLE",\r
+  ((arp_table[i].state == ETHARP_STATE_PENDING) ||\r
+   (arp_table[i].state == ETHARP_STATE_STABLE)));\r
+\r
+  /* do we have a pending entry? or an implicit query request? */\r
+  if ((arp_table[i].state == ETHARP_STATE_PENDING) || (q == NULL)) {\r
+    /* try to resolve it; send out ARP request */\r
+    result = etharp_request(netif, ipaddr);\r
+    if (result != ERR_OK) {\r
+      /* ARP request couldn't be sent */\r
+      /* We don't re-send arp request in etharp_tmr, but we still queue packets,\r
+         since this failure could be temporary, and the next packet calling\r
+         etharp_query again could lead to sending the queued packets. */\r
+    }\r
+  }\r
+\r
+  /* packet given? */\r
+  if (q != NULL) {\r
+    /* stable entry? */\r
+    if (arp_table[i].state == ETHARP_STATE_STABLE) {\r
+      /* we have a valid IP->Ethernet address mapping */\r
+      /* send the packet */\r
+      result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr));\r
+    /* pending entry? (either just created or already pending */\r
+    } else if (arp_table[i].state == ETHARP_STATE_PENDING) {\r
+#if ARP_QUEUEING /* queue the given q packet */\r
+      struct pbuf *p;\r
+      int copy_needed = 0;\r
+      /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but\r
+       * to copy the whole queue into a new PBUF_RAM (see bug #11400)\r
+       * PBUF_ROMs can be left as they are, since ROM must not get changed. */\r
+      p = q;\r
+      while (p) {\r
+        LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0));\r
+        if(p->type != PBUF_ROM) {\r
+          copy_needed = 1;\r
+          break;\r
+        }\r
+        p = p->next;\r
+      }\r
+      if(copy_needed) {\r
+        /* copy the whole packet into new pbufs */\r
+        p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+        if(p != NULL) {\r
+          if (pbuf_copy(p, q) != ERR_OK) {\r
+            pbuf_free(p);\r
+            p = NULL;\r
+          }\r
+        }\r
+      } else {\r
+        /* referencing the old pbuf is enough */\r
+        p = q;\r
+        pbuf_ref(p);\r
+      }\r
+      /* packet could be taken over? */\r
+      if (p != NULL) {\r
+        /* queue packet ... */\r
+        struct etharp_q_entry *new_entry;\r
+        /* allocate a new arp queue entry */\r
+        new_entry = memp_malloc(MEMP_ARP_QUEUE);\r
+        if (new_entry != NULL) {\r
+          new_entry->next = 0;\r
+          new_entry->p = p;\r
+          if(arp_table[i].q != NULL) {\r
+            /* queue was already existent, append the new entry to the end */\r
+            struct etharp_q_entry *r;\r
+            r = arp_table[i].q;\r
+            while (r->next != NULL) {\r
+              r = r->next;\r
+            }\r
+            r->next = new_entry;\r
+          } else {\r
+            /* queue did not exist, first item in queue */\r
+            arp_table[i].q = new_entry;\r
+          }\r
+          LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i));\r
+          result = ERR_OK;\r
+        } else {\r
+          /* the pool MEMP_ARP_QUEUE is empty */\r
+          pbuf_free(p);\r
+          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));\r
+          /* { result == ERR_MEM } through initialization */\r
+        }\r
+      } else {\r
+        ETHARP_STATS_INC(etharp.memerr);\r
+        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));\r
+        /* { result == ERR_MEM } through initialization */\r
+      }\r
+#else /* ARP_QUEUEING == 0 */\r
+      /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */\r
+      /* { result == ERR_MEM } through initialization */\r
+      LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q));\r
+#endif\r
+    }\r
+  }\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Send a raw ARP packet (opcode and all addresses can be modified)\r
+ *\r
+ * @param netif the lwip network interface on which to send the ARP packet\r
+ * @param ethsrc_addr the source MAC address for the ethernet header\r
+ * @param ethdst_addr the destination MAC address for the ethernet header\r
+ * @param hwsrc_addr the source MAC address for the ARP protocol header\r
+ * @param ipsrc_addr the source IP address for the ARP protocol header\r
+ * @param hwdst_addr the destination MAC address for the ARP protocol header\r
+ * @param ipdst_addr the destination IP address for the ARP protocol header\r
+ * @param opcode the type of the ARP packet\r
+ * @return ERR_OK if the ARP packet has been sent\r
+ *         ERR_MEM if the ARP packet couldn't be allocated\r
+ *         any other err_t on failure\r
+ */\r
+#if !LWIP_AUTOIP\r
+static\r
+#endif /* LWIP_AUTOIP */\r
+err_t\r
+etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr,\r
+           const struct eth_addr *ethdst_addr,\r
+           const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr,\r
+           const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr,\r
+           const u16_t opcode)\r
+{\r
+  struct pbuf *p;\r
+  err_t result = ERR_OK;\r
+  u8_t k; /* ARP entry index */\r
+  struct etharp_hdr *hdr;\r
+#if LWIP_AUTOIP\r
+  const u8_t * ethdst_hwaddr;\r
+#endif /* LWIP_AUTOIP */\r
+\r
+  /* allocate a pbuf for the outgoing ARP request packet */\r
+  p = pbuf_alloc(PBUF_LINK, sizeof(struct etharp_hdr), PBUF_RAM);\r
+  /* could allocate a pbuf for an ARP request? */\r
+  if (p == NULL) {\r
+    LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | 2, ("etharp_raw: could not allocate pbuf for ARP request.\n"));\r
+    ETHARP_STATS_INC(etharp.memerr);\r
+    return ERR_MEM;\r
+  }\r
+  LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr",\r
+              (p->len >= sizeof(struct etharp_hdr)));\r
+\r
+  hdr = p->payload;\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n"));\r
+  hdr->opcode = htons(opcode);\r
+\r
+  LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!",\r
+              (netif->hwaddr_len == ETHARP_HWADDR_LEN));\r
+  k = ETHARP_HWADDR_LEN;\r
+#if LWIP_AUTOIP\r
+  /* If we are using Link-Local, ARP packets must be broadcast on the\r
+   * link layer. (See RFC3927 Section 2.5) */\r
+  ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr;\r
+#endif /* LWIP_AUTOIP */\r
+  /* Write MAC-Addresses (combined loop for both headers) */\r
+  while(k > 0) {\r
+    k--;\r
+    /* Write the ARP MAC-Addresses */\r
+    hdr->shwaddr.addr[k] = hwsrc_addr->addr[k];\r
+    hdr->dhwaddr.addr[k] = hwdst_addr->addr[k];\r
+    /* Write the Ethernet MAC-Addresses */\r
+#if LWIP_AUTOIP\r
+    hdr->ethhdr.dest.addr[k] = ethdst_hwaddr[k];\r
+#else  /* LWIP_AUTOIP */\r
+    hdr->ethhdr.dest.addr[k] = ethdst_addr->addr[k];\r
+#endif /* LWIP_AUTOIP */\r
+    hdr->ethhdr.src.addr[k]  = ethsrc_addr->addr[k];\r
+  }\r
+  hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr;\r
+  hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr;\r
+\r
+  hdr->hwtype = htons(HWTYPE_ETHERNET);\r
+  hdr->proto = htons(ETHTYPE_IP);\r
+  /* set hwlen and protolen together */\r
+  hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr));\r
+\r
+  hdr->ethhdr.type = htons(ETHTYPE_ARP);\r
+  /* send ARP query */\r
+  result = netif->linkoutput(netif, p);\r
+  ETHARP_STATS_INC(etharp.xmit);\r
+  /* free ARP query packet */\r
+  pbuf_free(p);\r
+  p = NULL;\r
+  /* could not allocate pbuf for ARP request */\r
+\r
+  return result;\r
+}\r
+\r
+/**\r
+ * Send an ARP request packet asking for ipaddr.\r
+ *\r
+ * @param netif the lwip network interface on which to send the request\r
+ * @param ipaddr the IP address for which to ask\r
+ * @return ERR_OK if the request has been sent\r
+ *         ERR_MEM if the ARP packet couldn't be allocated\r
+ *         any other err_t on failure\r
+ */\r
+err_t\r
+etharp_request(struct netif *netif, struct ip_addr *ipaddr)\r
+{\r
+  LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n"));\r
+  return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,\r
+                    (struct eth_addr *)netif->hwaddr, &netif->ip_addr, &ethzero,\r
+                    ipaddr, ARP_REQUEST);\r
+}\r
+\r
+/**\r
+ * Process received ethernet frames. Using this function instead of directly\r
+ * calling ip_input and passing ARP frames through etharp in ethernetif_input,\r
+ * the ARP cache is protected from concurrent access.\r
+ *\r
+ * @param p the recevied packet, p->payload pointing to the ethernet header\r
+ * @param netif the network interface on which the packet was received\r
+ */\r
+err_t\r
+ethernet_input(struct pbuf *p, struct netif *netif)\r
+{\r
+  struct eth_hdr* ethhdr;\r
+\r
+  /* points to packet payload, which starts with an Ethernet header */\r
+  ethhdr = p->payload;\r
+\r
+  switch (htons(ethhdr->type)) {\r
+    /* IP packet? */\r
+    case ETHTYPE_IP:\r
+#if ETHARP_TRUST_IP_MAC\r
+      /* update ARP table */\r
+      etharp_ip_input(netif, p);\r
+#endif /* ETHARP_TRUST_IP_MAC */\r
+      /* skip Ethernet header */\r
+      if(pbuf_header(p, -(s16_t)sizeof(struct eth_hdr))) {\r
+        LWIP_ASSERT("Can't move over header in packet", 0);\r
+        pbuf_free(p);\r
+        p = NULL;\r
+      } else {\r
+        /* pass to IP layer */\r
+        ip_input(p, netif);\r
+      }\r
+      break;\r
+\r
+    case ETHTYPE_ARP:\r
+      /* pass p to ARP module */\r
+      etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p);\r
+      break;\r
+\r
+#if PPPOE_SUPPORT\r
+    case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */\r
+      pppoe_disc_input(netif, p);\r
+      break;\r
+\r
+    case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */\r
+      pppoe_data_input(netif, p);\r
+      break;\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+    default:\r
+      pbuf_free(p);\r
+      p = NULL;\r
+      break;\r
+  }\r
+\r
+  /* This means the pbuf is freed or consumed,\r
+     so the caller doesn't have to free it again */\r
+  return ERR_OK;\r
+}\r
+#endif /* LWIP_ARP */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c b/Demo/Common/ethernet/lwIP_130/src/netif/ethernetif.c
new file mode 100644 (file)
index 0000000..58b879d
--- /dev/null
@@ -0,0 +1,313 @@
+/**\r
+ * @file\r
+ * Ethernet Interface Skeleton\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/*\r
+ * This file is a skeleton for developing Ethernet network interface\r
+ * drivers for lwIP. Add code to the low_level functions and do a\r
+ * search-and-replace for the word "ethernetif" to replace it with\r
+ * something that better describes your network interface.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if 0 /* don't build, this is only a skeleton, see previous comment */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include <lwip/stats.h>\r
+#include <lwip/snmp.h>\r
+#include "netif/etharp.h"\r
+#include "netif/ppp_oe.h"\r
+\r
+/* Define those to better describe your network interface. */\r
+#define IFNAME0 'e'\r
+#define IFNAME1 'n'\r
+\r
+/**\r
+ * Helper struct to hold private data used to operate your ethernet interface.\r
+ * Keeping the ethernet address of the MAC in this struct is not necessary\r
+ * as it is already kept in the struct netif.\r
+ * But this is only an example, anyway...\r
+ */\r
+struct ethernetif {\r
+  struct eth_addr *ethaddr;\r
+  /* Add whatever per-interface state that is needed here. */\r
+};\r
+\r
+/* Forward declarations. */\r
+static void  ethernetif_input(struct netif *netif);\r
+\r
+/**\r
+ * In this function, the hardware should be initialized.\r
+ * Called from ethernetif_init().\r
+ *\r
+ * @param netif the already initialized lwip network interface structure\r
+ *        for this ethernetif\r
+ */\r
+static void\r
+low_level_init(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  \r
+  /* set MAC hardware address length */\r
+  netif->hwaddr_len = ETHARP_HWADDR_LEN;\r
+\r
+  /* set MAC hardware address */\r
+  netif->hwaddr[0] = ;\r
+  ...\r
+  netif->hwaddr[5] = ;\r
+\r
+  /* maximum transfer unit */\r
+  netif->mtu = 1500;\r
+  \r
+  /* device capabilities */\r
+  /* don't set NETIF_FLAG_ETHARP if this device is not an ethernet one */\r
+  netif->flags = NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP | NETIF_FLAG_LINK_UP;\r
\r
+  /* Do whatever else is needed to initialize interface. */  \r
+}\r
+\r
+/**\r
+ * This function should do the actual transmission of the packet. The packet is\r
+ * contained in the pbuf that is passed to the function. This pbuf\r
+ * might be chained.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)\r
+ * @return ERR_OK if the packet could be sent\r
+ *         an err_t value if the packet couldn't be sent\r
+ *\r
+ * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to\r
+ *       strange results. You might consider waiting for space in the DMA queue\r
+ *       to become availale since the stack doesn't retry to send a packet\r
+ *       dropped because of memory failure (except for the TCP timers).\r
+ */\r
+\r
+static err_t\r
+low_level_output(struct netif *netif, struct pbuf *p)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  struct pbuf *q;\r
+\r
+  initiate transfer();\r
+  \r
+#if ETH_PAD_SIZE\r
+  pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */\r
+#endif\r
+\r
+  for(q = p; q != NULL; q = q->next) {\r
+    /* Send the data from the pbuf to the interface, one pbuf at a\r
+       time. The size of the data in each pbuf is kept in the ->len\r
+       variable. */\r
+    send data from(q->payload, q->len);\r
+  }\r
+\r
+  signal that packet should be sent();\r
+\r
+#if ETH_PAD_SIZE\r
+  pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */\r
+#endif\r
+  \r
+  LINK_STATS_INC(link.xmit);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Should allocate a pbuf and transfer the bytes of the incoming\r
+ * packet from the interface into the pbuf.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @return a pbuf filled with the received packet (including MAC header)\r
+ *         NULL on memory error\r
+ */\r
+static struct pbuf *\r
+low_level_input(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif = netif->state;\r
+  struct pbuf *p, *q;\r
+  u16_t len;\r
+\r
+  /* Obtain the size of the packet and put it into the "len"\r
+     variable. */\r
+  len = ;\r
+\r
+#if ETH_PAD_SIZE\r
+  len += ETH_PAD_SIZE; /* allow room for Ethernet padding */\r
+#endif\r
+\r
+  /* We allocate a pbuf chain of pbufs from the pool. */\r
+  p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);\r
+  \r
+  if (p != NULL) {\r
+\r
+#if ETH_PAD_SIZE\r
+    pbuf_header(p, -ETH_PAD_SIZE); /* drop the padding word */\r
+#endif\r
+\r
+    /* We iterate over the pbuf chain until we have read the entire\r
+     * packet into the pbuf. */\r
+    for(q = p; q != NULL; q = q->next) {\r
+      /* Read enough bytes to fill this pbuf in the chain. The\r
+       * available data in the pbuf is given by the q->len\r
+       * variable. */\r
+      read data into(q->payload, q->len);\r
+    }\r
+    acknowledge that packet has been read();\r
+\r
+#if ETH_PAD_SIZE\r
+    pbuf_header(p, ETH_PAD_SIZE); /* reclaim the padding word */\r
+#endif\r
+\r
+    LINK_STATS_INC(link.recv);\r
+  } else {\r
+    drop packet();\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.drop);\r
+  }\r
+\r
+  return p;  \r
+}\r
+\r
+/**\r
+ * This function should be called when a packet is ready to be read\r
+ * from the interface. It uses the function low_level_input() that\r
+ * should handle the actual reception of bytes from the network\r
+ * interface. Then the type of the received packet is determined and\r
+ * the appropriate input function is called.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ */\r
+static void\r
+ethernetif_input(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif;\r
+  struct eth_hdr *ethhdr;\r
+  struct pbuf *p;\r
+\r
+  ethernetif = netif->state;\r
+\r
+  /* move received packet into a new pbuf */\r
+  p = low_level_input(netif);\r
+  /* no packet could be read, silently ignore this */\r
+  if (p == NULL) return;\r
+  /* points to packet payload, which starts with an Ethernet header */\r
+  ethhdr = p->payload;\r
+\r
+  switch (htons(ethhdr->type)) {\r
+  /* IP or ARP packet? */\r
+  case ETHTYPE_IP:\r
+  case ETHTYPE_ARP:\r
+#if PPPOE_SUPPORT\r
+  /* PPPoE packet? */\r
+  case ETHTYPE_PPPOEDISC:\r
+  case ETHTYPE_PPPOE:\r
+#endif /* PPPOE_SUPPORT */\r
+    /* full packet send to tcpip_thread to process */\r
+    if (netif->input(p, netif)!=ERR_OK)\r
+     { LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));\r
+       pbuf_free(p);\r
+       p = NULL;\r
+     }\r
+    break;\r
+\r
+  default:\r
+    pbuf_free(p);\r
+    p = NULL;\r
+    break;\r
+  }\r
+}\r
+\r
+/**\r
+ * Should be called at the beginning of the program to set up the\r
+ * network interface. It calls the function low_level_init() to do the\r
+ * actual setup of the hardware.\r
+ *\r
+ * This function should be passed as a parameter to netif_add().\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @return ERR_OK if the loopif is initialized\r
+ *         ERR_MEM if private data couldn't be allocated\r
+ *         any other err_t on error\r
+ */\r
+err_t\r
+ethernetif_init(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif;\r
+\r
+  LWIP_ASSERT("netif != NULL", (netif != NULL));\r
+    \r
+  ethernetif = mem_malloc(sizeof(struct ethernetif));\r
+  if (ethernetif == NULL) {\r
+    LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));\r
+    return ERR_MEM;\r
+  }\r
+\r
+#if LWIP_NETIF_HOSTNAME\r
+  /* Initialize interface hostname */\r
+  netif->hostname = "lwip";\r
+#endif /* LWIP_NETIF_HOSTNAME */\r
+\r
+  /*\r
+   * Initialize the snmp variables and counters inside the struct netif.\r
+   * The last argument should be replaced with your link speed, in units\r
+   * of bits per second.\r
+   */\r
+  NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, ???);\r
+\r
+  netif->state = ethernetif;\r
+  netif->name[0] = IFNAME0;\r
+  netif->name[1] = IFNAME1;\r
+  /* We directly use etharp_output() here to save a function call.\r
+   * You can instead declare your own function an call etharp_output()\r
+   * from it if you have to do some checks before sending (e.g. if link\r
+   * is available...) */\r
+  netif->output = etharp_output;\r
+  netif->linkoutput = low_level_output;\r
+  \r
+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);\r
+  \r
+  /* initialize the hardware */\r
+  low_level_init(netif);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+#endif /* 0 */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/loopif.c b/Demo/Common/ethernet/lwIP_130/src/netif/loopif.c
new file mode 100644 (file)
index 0000000..a84c842
--- /dev/null
@@ -0,0 +1,217 @@
+/**\r
+ * @file\r
+ * Loop Interface\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ * \r
+ * Redistribution and use in source and binary forms, with or without modification, \r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED \r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF \r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT \r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, \r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT \r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS \r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN \r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING \r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY \r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ * \r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+#include "lwip/opt.h"\r
+\r
+#if LWIP_HAVE_LOOPIF\r
+\r
+#include "netif/loopif.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/snmp.h"\r
+\r
+#include <string.h>\r
+\r
+#if !LWIP_LOOPIF_MULTITHREADING\r
+\r
+#include "lwip/sys.h"\r
+#include "lwip/mem.h"\r
+\r
+/* helper struct for the linked list of pbufs */\r
+struct loopif_private {\r
+  struct pbuf *first;\r
+  struct pbuf *last;\r
+};\r
+\r
+/**\r
+ * Call loopif_poll() in the main loop of your application. This is to prevent\r
+ * reentering non-reentrant functions like tcp_input(). Packets passed to\r
+ * loopif_output() are put on a list that is passed to netif->input() by\r
+ * loopif_poll().\r
+ *\r
+ * @param netif the lwip network interface structure for this loopif\r
+ */\r
+void\r
+loopif_poll(struct netif *netif)\r
+{\r
+  SYS_ARCH_DECL_PROTECT(lev);\r
+  struct pbuf *in, *in_end;\r
+  struct loopif_private *priv = (struct loopif_private*)netif->state;\r
+\r
+  LWIP_ERROR("priv != NULL", (priv != NULL), return;);\r
+\r
+  do {\r
+    /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */\r
+    SYS_ARCH_PROTECT(lev);\r
+    in = priv->first;\r
+    if(in) {\r
+      in_end = in;\r
+      while(in_end->len != in_end->tot_len) {\r
+        LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);\r
+        in_end = in_end->next;\r
+      }\r
+      /* 'in_end' now points to the last pbuf from 'in' */\r
+      if(in_end == priv->last) {\r
+        /* this was the last pbuf in the list */\r
+        priv->first = priv->last = NULL;\r
+      } else {\r
+        /* pop the pbuf off the list */\r
+        priv->first = in_end->next;\r
+        LWIP_ASSERT("should not be null since first != last!", priv->first != NULL);\r
+      }\r
+    }\r
+    SYS_ARCH_UNPROTECT(lev);\r
+  \r
+    if(in != NULL) {\r
+      if(in_end->next != NULL) {\r
+        /* De-queue the pbuf from its successors on the 'priv' list. */\r
+        in_end->next = NULL;\r
+      }\r
+      if(netif->input(in, netif) != ERR_OK) {\r
+        pbuf_free(in);\r
+      }\r
+      /* Don't reference the packet any more! */\r
+      in = NULL;\r
+      in_end = NULL;\r
+    }\r
+  /* go on while there is a packet on the list */\r
+  } while(priv->first != NULL);\r
+}\r
+#endif /* LWIP_LOOPIF_MULTITHREADING */\r
+\r
+/**\r
+ * Send an IP packet over the loopback interface.\r
+ * The pbuf is simply copied and handed back to netif->input.\r
+ * In multithreaded mode, this is done directly since netif->input must put\r
+ * the packet on a queue.\r
+ * In callback mode, the packet is put on an internal queue and is fed to\r
+ * netif->input by loopif_poll().\r
+ *\r
+ * @param netif the lwip network interface structure for this loopif\r
+ * @param p the (IP) packet to 'send'\r
+ * @param ipaddr the ip address to send the packet to (not used for loopif)\r
+ * @return ERR_OK if the packet has been sent\r
+ *         ERR_MEM if the pbuf used to copy the packet couldn't be allocated\r
+ */\r
+static err_t\r
+loopif_output(struct netif *netif, struct pbuf *p,\r
+       struct ip_addr *ipaddr)\r
+{\r
+#if !LWIP_LOOPIF_MULTITHREADING\r
+  SYS_ARCH_DECL_PROTECT(lev);\r
+  struct loopif_private *priv;\r
+  struct pbuf *last;\r
+#endif /* LWIP_LOOPIF_MULTITHREADING */\r
+  struct pbuf *r;\r
+  err_t err;\r
+\r
+  LWIP_UNUSED_ARG(ipaddr);\r
+\r
+  /* Allocate a new pbuf */\r
+  r = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+  if (r == NULL) {\r
+    return ERR_MEM;\r
+  }\r
+\r
+  /* Copy the whole pbuf queue p into the single pbuf r */\r
+  if ((err = pbuf_copy(r, p)) != ERR_OK) {\r
+    pbuf_free(r);\r
+    r = NULL;\r
+    return err;\r
+  }\r
+\r
+#if LWIP_LOOPIF_MULTITHREADING\r
+  /* Multithreading environment, netif->input() is supposed to put the packet\r
+     into a mailbox, so we can safely call it here without risking to re-enter\r
+     functions that are not reentrant (TCP!!!) */\r
+  if(netif->input(r, netif) != ERR_OK) {\r
+    pbuf_free(r);\r
+    r = NULL;\r
+  }\r
+#else /* LWIP_LOOPIF_MULTITHREADING */\r
+  /* Raw API without threads: put the packet on a linked list which gets emptied\r
+     through calling loopif_poll(). */\r
+  priv = (struct loopif_private*)netif->state;\r
+\r
+  /* let last point to the last pbuf in chain r */\r
+  for (last = r; last->next != NULL; last = last->next);\r
+  SYS_ARCH_PROTECT(lev);\r
+  if(priv->first != NULL) {\r
+    LWIP_ASSERT("if first != NULL, last must also be != NULL", priv->last != NULL);\r
+    priv->last->next = r;\r
+    priv->last = last;\r
+  } else {\r
+    priv->first = r;\r
+    priv->last = last;\r
+  }\r
+  SYS_ARCH_UNPROTECT(lev);\r
+#endif /* LWIP_LOOPIF_MULTITHREADING */\r
+\r
+  return ERR_OK;    \r
+}\r
+\r
+/**\r
+ * Initialize a lwip network interface structure for a loopback interface\r
+ *\r
+ * @param netif the lwip network interface structure for this loopif\r
+ * @return ERR_OK if the loopif is initialized\r
+ *         ERR_MEM if private data couldn't be allocated\r
+ */\r
+err_t\r
+loopif_init(struct netif *netif)\r
+{\r
+#if !LWIP_LOOPIF_MULTITHREADING\r
+  struct loopif_private *priv;\r
+\r
+  priv = (struct loopif_private*)mem_malloc(sizeof(struct loopif_private));\r
+  if(priv == NULL) \r
+    return ERR_MEM;\r
+  priv->first = priv->last = NULL;\r
+  netif->state = priv;\r
+#endif /* LWIP_LOOPIF_MULTITHREADING */\r
+\r
+  /* initialize the snmp variables and counters inside the struct netif\r
+   * ifSpeed: no assumption can be made!\r
+   */\r
+  NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0);\r
+\r
+  netif->name[0] = 'l';\r
+  netif->name[1] = 'o';\r
+  netif->output = loopif_output;\r
+  return ERR_OK;\r
+}\r
+\r
+#endif /* LWIP_HAVE_LOOPIF */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.c
new file mode 100644 (file)
index 0000000..c637c2d
--- /dev/null
@@ -0,0 +1,988 @@
+/*****************************************************************************\r
+* auth.c - Network Authentication and Phase Control program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Ported from public pppd code.\r
+*****************************************************************************/\r
+/*\r
+ * auth.c - PPP authentication and phase control.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "fsm.h"\r
+#include "lcp.h"\r
+#include "pap.h"\r
+#include "chap.h"\r
+#include "auth.h"\r
+#include "ipcp.h"\r
+\r
+#if CBCP_SUPPORT\r
+#include "cbcp.h"\r
+#endif /* CBCP_SUPPORT */\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+/* Bits in auth_pending[] */\r
+#define PAP_WITHPEER    1\r
+#define PAP_PEER        2\r
+#define CHAP_WITHPEER   4\r
+#define CHAP_PEER       8\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+/* Used for storing a sequence of words.  Usually malloced. */\r
+struct wordlist {\r
+  struct wordlist *next;\r
+  char        word[1];\r
+};\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+extern char *crypt (const char *, const char *);\r
+\r
+/* Prototypes for procedures local to this file. */\r
+\r
+static void network_phase (int);\r
+static void check_idle (void *);\r
+static void connect_time_expired (void *);\r
+#if 0\r
+static int  login (char *, char *, char **, int *);\r
+#endif\r
+static void logout (void);\r
+static int  null_login (int);\r
+static int  get_pap_passwd (int, char *, char *);\r
+static int  have_pap_secret (void);\r
+static int  have_chap_secret (char *, char *, u32_t);\r
+static int  ip_addr_check (u32_t, struct wordlist *);\r
+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */\r
+static void set_allowed_addrs(int unit, struct wordlist *addrs);\r
+static void free_wordlist (struct wordlist *);\r
+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */\r
+#if CBCP_SUPPORT\r
+static void callback_phase (int);\r
+#endif /* CBCP_SUPPORT */\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+#if PAP_SUPPORT || CHAP_SUPPORT\r
+/* The name by which the peer authenticated itself to us. */\r
+static char peer_authname[MAXNAMELEN];\r
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+/* Records which authentication operations haven't completed yet. */\r
+static int auth_pending[NUM_PPP];\r
+\r
+/* Set if we have successfully called login() */\r
+static int logged_in;\r
+\r
+/* Set if we have run the /etc/ppp/auth-up script. */\r
+static int did_authup;\r
+\r
+/* List of addresses which the peer may use. */\r
+static struct wordlist *addresses[NUM_PPP];\r
+\r
+/* Number of network protocols which we have opened. */\r
+static int num_np_open;\r
+\r
+/* Number of network protocols which have come up. */\r
+static int num_np_up;\r
+\r
+#if PAP_SUPPORT || CHAP_SUPPORT\r
+/* Set if we got the contents of passwd[] from the pap-secrets file. */\r
+static int passwd_from_file;\r
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * An Open on LCP has requested a change from Dead to Establish phase.\r
+ * Do what's necessary to bring the physical layer up.\r
+ */\r
+void\r
+link_required(int unit)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+\r
+  AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit));\r
+}\r
+\r
+/*\r
+ * LCP has terminated the link; go to the Dead phase and take the\r
+ * physical layer down.\r
+ */\r
+void\r
+link_terminated(int unit)\r
+{\r
+  AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit));\r
+  if (lcp_phase[unit] == PHASE_DEAD) {\r
+    return;\r
+  }\r
+  if (logged_in) {\r
+    logout();\r
+  }\r
+  lcp_phase[unit] = PHASE_DEAD;\r
+  AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n"));\r
+  pppLinkTerminated(unit);\r
+}\r
+\r
+/*\r
+ * LCP has gone down; it will either die or try to re-establish.\r
+ */\r
+void\r
+link_down(int unit)\r
+{\r
+  int i;\r
+  struct protent *protp;\r
+  \r
+  AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit));\r
+  if (did_authup) {\r
+    /* XXX Do link down processing. */\r
+    did_authup = 0;\r
+  }\r
+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+    if (!protp->enabled_flag) {\r
+      continue;\r
+    }\r
+    if (protp->protocol != PPP_LCP && protp->lowerdown != NULL) {\r
+      (*protp->lowerdown)(unit);\r
+    }\r
+    if (protp->protocol < 0xC000 && protp->close != NULL) {\r
+      (*protp->close)(unit, "LCP down");\r
+    }\r
+  }\r
+  num_np_open = 0;\r
+  num_np_up = 0;\r
+  if (lcp_phase[unit] != PHASE_DEAD) {\r
+    lcp_phase[unit] = PHASE_TERMINATE;\r
+  }\r
+  pppLinkDown(unit);\r
+}\r
+\r
+/*\r
+ * The link is established.\r
+ * Proceed to the Dead, Authenticate or Network phase as appropriate.\r
+ */\r
+void\r
+link_established(int unit)\r
+{\r
+  int auth;\r
+  int i;\r
+  struct protent *protp;\r
+  lcp_options *wo = &lcp_wantoptions[unit];\r
+  lcp_options *go = &lcp_gotoptions[unit];\r
+#if PAP_SUPPORT || CHAP_SUPPORT\r
+  lcp_options *ho = &lcp_hisoptions[unit];\r
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+  AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit));\r
+  /*\r
+   * Tell higher-level protocols that LCP is up.\r
+   */\r
+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+    if (protp->protocol != PPP_LCP && protp->enabled_flag && protp->lowerup != NULL) {\r
+      (*protp->lowerup)(unit);\r
+    }\r
+  }\r
+  if (ppp_settings.auth_required && !(go->neg_chap || go->neg_upap)) {\r
+    /*\r
+     * We wanted the peer to authenticate itself, and it refused:\r
+     * treat it as though it authenticated with PAP using a username\r
+     * of "" and a password of "".  If that's not OK, boot it out.\r
+     */\r
+    if (!wo->neg_upap || !null_login(unit)) {\r
+      AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n"));\r
+      lcp_close(unit, "peer refused to authenticate");\r
+      return;\r
+    }\r
+  }\r
+    \r
+  lcp_phase[unit] = PHASE_AUTHENTICATE;\r
+  auth = 0;\r
+#if CHAP_SUPPORT\r
+  if (go->neg_chap) {\r
+    ChapAuthPeer(unit, ppp_settings.our_name, go->chap_mdtype);\r
+    auth |= CHAP_PEER;\r
+  } \r
+#endif /* CHAP_SUPPORT */\r
+#if PAP_SUPPORT && CHAP_SUPPORT\r
+  else\r
+#endif /* PAP_SUPPORT && CHAP_SUPPORT */\r
+#if PAP_SUPPORT\r
+  if (go->neg_upap) {\r
+    upap_authpeer(unit);\r
+    auth |= PAP_PEER;\r
+  }\r
+#endif /* PAP_SUPPORT */\r
+#if CHAP_SUPPORT\r
+  if (ho->neg_chap) {\r
+    ChapAuthWithPeer(unit, ppp_settings.user, ho->chap_mdtype);\r
+    auth |= CHAP_WITHPEER;\r
+  }\r
+#endif /* CHAP_SUPPORT */\r
+#if PAP_SUPPORT && CHAP_SUPPORT\r
+  else\r
+#endif /* PAP_SUPPORT && CHAP_SUPPORT */\r
+#if PAP_SUPPORT\r
+  if (ho->neg_upap) {\r
+    if (ppp_settings.passwd[0] == 0) {\r
+      passwd_from_file = 1;\r
+      if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) {\r
+        AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n"));\r
+      }\r
+    }\r
+    upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd);\r
+    auth |= PAP_WITHPEER;\r
+  }\r
+#endif /* PAP_SUPPORT */\r
+  auth_pending[unit] = auth;\r
+\r
+  if (!auth) {\r
+    network_phase(unit);\r
+  }\r
+}\r
+\r
+/*\r
+ * The peer has failed to authenticate himself using `protocol'.\r
+ */\r
+void\r
+auth_peer_fail(int unit, u16_t protocol)\r
+{\r
+  LWIP_UNUSED_ARG(protocol);\r
+\r
+  AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol));\r
+  /*\r
+   * Authentication failure: take the link down\r
+   */\r
+  lcp_close(unit, "Authentication failed");\r
+}\r
+\r
+\r
+#if PAP_SUPPORT || CHAP_SUPPORT\r
+/*\r
+ * The peer has been successfully authenticated using `protocol'.\r
+ */\r
+void\r
+auth_peer_success(int unit, u16_t protocol, char *name, int namelen)\r
+{\r
+  int pbit;\r
+  \r
+  AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol));\r
+  switch (protocol) {\r
+    case PPP_CHAP:\r
+      pbit = CHAP_PEER;\r
+      break;\r
+    case PPP_PAP:\r
+      pbit = PAP_PEER;\r
+      break;\r
+    default:\r
+      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol));\r
+      return;\r
+  }\r
+  \r
+  /*\r
+   * Save the authenticated name of the peer for later.\r
+   */\r
+  if (namelen > sizeof(peer_authname) - 1) {\r
+    namelen = sizeof(peer_authname) - 1;\r
+  }\r
+  BCOPY(name, peer_authname, namelen);\r
+  peer_authname[namelen] = 0;\r
+  \r
+  /*\r
+   * If there is no more authentication still to be done,\r
+   * proceed to the network (or callback) phase.\r
+   */\r
+  if ((auth_pending[unit] &= ~pbit) == 0) {\r
+    network_phase(unit);\r
+  }\r
+}\r
+\r
+/*\r
+ * We have failed to authenticate ourselves to the peer using `protocol'.\r
+ */\r
+void\r
+auth_withpeer_fail(int unit, u16_t protocol)\r
+{\r
+  int errCode = PPPERR_AUTHFAIL;\r
+  \r
+  LWIP_UNUSED_ARG(protocol);\r
+\r
+  AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol));\r
+  if (passwd_from_file) {\r
+    BZERO(ppp_settings.passwd, MAXSECRETLEN);\r
+  }\r
+  /* \r
+   * XXX Warning: the unit number indicates the interface which is\r
+   * not necessarily the PPP connection.  It works here as long\r
+   * as we are only supporting PPP interfaces.\r
+   */\r
+  pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode);\r
+\r
+  /*\r
+   * We've failed to authenticate ourselves to our peer.\r
+   * He'll probably take the link down, and there's not much\r
+   * we can do except wait for that.\r
+   */\r
+}\r
+\r
+/*\r
+ * We have successfully authenticated ourselves with the peer using `protocol'.\r
+ */\r
+void\r
+auth_withpeer_success(int unit, u16_t protocol)\r
+{\r
+  int pbit;\r
+  \r
+  AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol));\r
+  switch (protocol) {\r
+    case PPP_CHAP:\r
+      pbit = CHAP_WITHPEER;\r
+      break;\r
+    case PPP_PAP:\r
+      if (passwd_from_file) {\r
+        BZERO(ppp_settings.passwd, MAXSECRETLEN);\r
+      }\r
+      pbit = PAP_WITHPEER;\r
+      break;\r
+    default:\r
+      AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol));\r
+      pbit = 0;\r
+  }\r
+  \r
+  /*\r
+   * If there is no more authentication still being done,\r
+   * proceed to the network (or callback) phase.\r
+   */\r
+  if ((auth_pending[unit] &= ~pbit) == 0) {\r
+    network_phase(unit);\r
+  }\r
+}\r
+#endif /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+\r
+/*\r
+ * np_up - a network protocol has come up.\r
+ */\r
+void\r
+np_up(int unit, u16_t proto)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+  LWIP_UNUSED_ARG(proto);\r
+\r
+  AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto));\r
+  if (num_np_up == 0) {\r
+    AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit));\r
+    /*\r
+     * At this point we consider that the link has come up successfully.\r
+     */\r
+    if (ppp_settings.idle_time_limit > 0) {\r
+      TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit);\r
+    }\r
+    \r
+    /*\r
+     * Set a timeout to close the connection once the maximum\r
+     * connect time has expired.\r
+     */\r
+    if (ppp_settings.maxconnect > 0) {\r
+      TIMEOUT(connect_time_expired, 0, ppp_settings.maxconnect);\r
+    }\r
+  }\r
+  ++num_np_up;\r
+}\r
+\r
+/*\r
+ * np_down - a network protocol has gone down.\r
+ */\r
+void\r
+np_down(int unit, u16_t proto)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+  LWIP_UNUSED_ARG(proto);\r
+\r
+  AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto));\r
+  if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) {\r
+    UNTIMEOUT(check_idle, NULL);\r
+  }\r
+}\r
+\r
+/*\r
+ * np_finished - a network protocol has finished using the link.\r
+ */\r
+void\r
+np_finished(int unit, u16_t proto)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+  LWIP_UNUSED_ARG(proto);\r
+\r
+  AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto));\r
+  if (--num_np_open <= 0) {\r
+    /* no further use for the link: shut up shop. */\r
+    lcp_close(0, "No network protocols running");\r
+  }\r
+}\r
+\r
+/*\r
+ * auth_reset - called when LCP is starting negotiations to recheck\r
+ * authentication options, i.e. whether we have appropriate secrets\r
+ * to use for authenticating ourselves and/or the peer.\r
+ */\r
+void\r
+auth_reset(int unit)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[unit];\r
+  lcp_options *ao = &lcp_allowoptions[0];\r
+  ipcp_options *ipwo = &ipcp_wantoptions[0];\r
+  u32_t remote;\r
+\r
+  AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit));\r
+  ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL));\r
+  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)*/;\r
+\r
+  if (go->neg_upap && !have_pap_secret()) {\r
+    go->neg_upap = 0;\r
+  }\r
+  if (go->neg_chap) {\r
+    remote = ipwo->accept_remote? 0: ipwo->hisaddr;\r
+    if (!have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote)) {\r
+      go->neg_chap = 0;\r
+    }\r
+  }\r
+}\r
+\r
+#if PAP_SUPPORT\r
+/*\r
+ * check_passwd - Check the user name and passwd against the PAP secrets\r
+ * file.  If requested, also check against the system password database,\r
+ * and login the user if OK.\r
+ *\r
+ * returns:\r
+ *  UPAP_AUTHNAK: Authentication failed.\r
+ *  UPAP_AUTHACK: Authentication succeeded.\r
+ * In either case, msg points to an appropriate message.\r
+ */\r
+int\r
+check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen)\r
+{\r
+#if 1\r
+  LWIP_UNUSED_ARG(unit);\r
+  LWIP_UNUSED_ARG(auser);\r
+  LWIP_UNUSED_ARG(userlen);\r
+  LWIP_UNUSED_ARG(apasswd);\r
+  LWIP_UNUSED_ARG(passwdlen);\r
+  LWIP_UNUSED_ARG(msglen);\r
+  *msg = (char *) 0;\r
+  return UPAP_AUTHACK;     /* XXX Assume all entries OK. */\r
+#else\r
+  int ret = 0;\r
+  struct wordlist *addrs = NULL;\r
+  char passwd[256], user[256];\r
+  char secret[MAXWORDLEN];\r
+  static u_short attempts = 0;\r
+  \r
+  /*\r
+   * Make copies of apasswd and auser, then null-terminate them.\r
+   */\r
+  BCOPY(apasswd, passwd, passwdlen);\r
+  passwd[passwdlen] = '\0';\r
+  BCOPY(auser, user, userlen);\r
+  user[userlen] = '\0';\r
+  *msg = (char *) 0;\r
+\r
+  /* XXX Validate user name and password. */\r
+  ret = UPAP_AUTHACK;     /* XXX Assume all entries OK. */\r
+      \r
+  if (ret == UPAP_AUTHNAK) {\r
+    if (*msg == (char *) 0) {\r
+      *msg = "Login incorrect";\r
+    }\r
+    *msglen = strlen(*msg);\r
+    /*\r
+     * Frustrate passwd stealer programs.\r
+     * Allow 10 tries, but start backing off after 3 (stolen from login).\r
+     * On 10'th, drop the connection.\r
+     */\r
+    if (attempts++ >= 10) {\r
+      AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user));\r
+      /*ppp_panic("Excess Bad Logins");*/\r
+    }\r
+    if (attempts > 3) {\r
+      sys_msleep((attempts - 3) * 5);\r
+    }\r
+    if (addrs != NULL) {\r
+      free_wordlist(addrs);\r
+    }\r
+  } else {\r
+    attempts = 0; /* Reset count */\r
+    if (*msg == (char *) 0) {\r
+      *msg = "Login ok";\r
+    }\r
+    *msglen = strlen(*msg);\r
+    set_allowed_addrs(unit, addrs);\r
+  }\r
+\r
+  BZERO(passwd, sizeof(passwd));\r
+  BZERO(secret, sizeof(secret));\r
+\r
+  return ret;\r
+#endif\r
+}\r
+#endif /* PAP_SUPPORT */\r
+\r
+\r
+/*\r
+ * auth_ip_addr - check whether the peer is authorized to use\r
+ * a given IP address.  Returns 1 if authorized, 0 otherwise.\r
+ */\r
+int\r
+auth_ip_addr(int unit, u32_t addr)\r
+{\r
+  return ip_addr_check(addr, addresses[unit]);\r
+}\r
+\r
+/*\r
+ * bad_ip_adrs - return 1 if the IP address is one we don't want\r
+ * to use, such as an address in the loopback net or a multicast address.\r
+ * addr is in network byte order.\r
+ */\r
+int\r
+bad_ip_adrs(u32_t addr)\r
+{\r
+  addr = ntohl(addr);\r
+  return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET\r
+      || IN_MULTICAST(addr) || IN_BADCLASS(addr);\r
+}\r
+\r
+\r
+#if CHAP_SUPPORT\r
+/*\r
+ * get_secret - open the CHAP secret file and return the secret\r
+ * for authenticating the given client on the given server.\r
+ * (We could be either client or server).\r
+ */\r
+int get_secret( int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs)\r
+{\r
+#if 1\r
+  int len;\r
+  struct wordlist *addrs;\r
+\r
+  LWIP_UNUSED_ARG(unit);\r
+  LWIP_UNUSED_ARG(server);\r
+  LWIP_UNUSED_ARG(save_addrs);\r
+\r
+  addrs = NULL;\r
+\r
+  if(!client || !client[0] || strcmp(client, ppp_settings.user)) {\r
+    return 0;\r
+  }\r
+\r
+  len = strlen(ppp_settings.passwd);\r
+  if (len > MAXSECRETLEN) {\r
+    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));\r
+    len = MAXSECRETLEN;\r
+  }\r
+\r
+  BCOPY(ppp_settings.passwd, secret, len);\r
+  *secret_len = len;\r
+\r
+  return 1;\r
+#else\r
+  int ret = 0, len;\r
+  struct wordlist *addrs;\r
+  char secbuf[MAXWORDLEN];\r
+  \r
+  addrs = NULL;\r
+  secbuf[0] = 0;\r
+\r
+  /* XXX Find secret. */\r
+  if (ret < 0) {\r
+    return 0;\r
+  }\r
+\r
+  if (save_addrs) {\r
+    set_allowed_addrs(unit, addrs);\r
+  }\r
+\r
+  len = strlen(secbuf);\r
+  if (len > MAXSECRETLEN) {\r
+    AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server));\r
+    len = MAXSECRETLEN;\r
+  }\r
+\r
+  BCOPY(secbuf, secret, len);\r
+  BZERO(secbuf, sizeof(secbuf));\r
+  *secret_len = len;\r
+\r
+  return 1;\r
+#endif\r
+}\r
+#endif /* CHAP_SUPPORT */\r
+\r
+\r
+#if 0 /* UNUSED */\r
+/*\r
+ * auth_check_options - called to check authentication options.\r
+ */\r
+void\r
+auth_check_options(void)\r
+{\r
+  lcp_options *wo = &lcp_wantoptions[0];\r
+  int can_auth;\r
+  ipcp_options *ipwo = &ipcp_wantoptions[0];\r
+  u32_t remote;\r
+\r
+  /* Default our_name to hostname, and user to our_name */\r
+  if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) {\r
+      strcpy(ppp_settings.our_name, ppp_settings.hostname);\r
+  }\r
+\r
+  if (ppp_settings.user[0] == 0) {\r
+    strcpy(ppp_settings.user, ppp_settings.our_name);\r
+  }\r
+\r
+  /* If authentication is required, ask peer for CHAP or PAP. */\r
+  if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) {\r
+    wo->neg_chap = 1;\r
+    wo->neg_upap = 1;\r
+  }\r
+  \r
+  /*\r
+   * Check whether we have appropriate secrets to use\r
+   * to authenticate the peer.\r
+   */\r
+  can_auth = wo->neg_upap && have_pap_secret();\r
+  if (!can_auth && wo->neg_chap) {\r
+    remote = ipwo->accept_remote? 0: ipwo->hisaddr;\r
+    can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote);\r
+  }\r
+\r
+  if (ppp_settings.auth_required && !can_auth) {\r
+    ppp_panic("No auth secret");\r
+  }\r
+}\r
+#endif\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * Proceed to the network phase.\r
+ */\r
+static void\r
+network_phase(int unit)\r
+{\r
+  int i;\r
+  struct protent *protp;\r
+  lcp_options *go = &lcp_gotoptions[unit];\r
+  \r
+  /*\r
+   * If the peer had to authenticate, run the auth-up script now.\r
+   */\r
+  if ((go->neg_chap || go->neg_upap) && !did_authup) {\r
+    /* XXX Do setup for peer authentication. */\r
+    did_authup = 1;\r
+  }\r
+\r
+#if CBCP_SUPPORT\r
+  /*\r
+   * If we negotiated callback, do it now.\r
+   */\r
+  if (go->neg_cbcp) {\r
+    lcp_phase[unit] = PHASE_CALLBACK;\r
+    (*cbcp_protent.open)(unit);\r
+    return;\r
+  }\r
+#endif /* CBCP_SUPPORT */\r
+\r
+  lcp_phase[unit] = PHASE_NETWORK;\r
+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+    if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) {\r
+      (*protp->open)(unit);\r
+      if (protp->protocol != PPP_CCP) {\r
+        ++num_np_open;\r
+      }\r
+    }\r
+  }\r
+\r
+  if (num_np_open == 0) {\r
+    /* nothing to do */\r
+    lcp_close(0, "No network protocols running");\r
+  }\r
+}\r
+\r
+/*\r
+ * check_idle - check whether the link has been idle for long\r
+ * enough that we can shut it down.\r
+ */\r
+static void\r
+check_idle(void *arg)\r
+{\r
+  struct ppp_idle idle;\r
+  u_short itime;\r
+  \r
+  LWIP_UNUSED_ARG(arg);\r
+  if (!get_idle_time(0, &idle)) {\r
+    return;\r
+  }\r
+  itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle);\r
+  if (itime >= ppp_settings.idle_time_limit) {\r
+    /* link is idle: shut it down. */\r
+    AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n"));\r
+    lcp_close(0, "Link inactive");\r
+  } else {\r
+    TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime);\r
+  }\r
+}\r
+\r
+/*\r
+ * connect_time_expired - log a message and close the connection.\r
+ */\r
+static void\r
+connect_time_expired(void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(arg);\r
+\r
+  AUTHDEBUG((LOG_INFO, "Connect time expired\n"));\r
+  lcp_close(0, "Connect time expired");   /* Close connection */\r
+}\r
+\r
+#if 0\r
+/*\r
+ * login - Check the user name and password against the system\r
+ * password database, and login the user if OK.\r
+ *\r
+ * returns:\r
+ *  UPAP_AUTHNAK: Login failed.\r
+ *  UPAP_AUTHACK: Login succeeded.\r
+ * In either case, msg points to an appropriate message.\r
+ */\r
+static int\r
+login(char *user, char *passwd, char **msg, int *msglen)\r
+{\r
+  /* XXX Fail until we decide that we want to support logins. */\r
+  return (UPAP_AUTHNAK);\r
+}\r
+#endif\r
+\r
+/*\r
+ * logout - Logout the user.\r
+ */\r
+static void\r
+logout(void)\r
+{\r
+  logged_in = 0;\r
+}\r
+\r
+/*\r
+ * null_login - Check if a username of "" and a password of "" are\r
+ * acceptable, and iff so, set the list of acceptable IP addresses\r
+ * and return 1.\r
+ */\r
+static int\r
+null_login(int unit)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+  /* XXX Fail until we decide that we want to support logins. */\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * get_pap_passwd - get a password for authenticating ourselves with\r
+ * our peer using PAP.  Returns 1 on success, 0 if no suitable password\r
+ * could be found.\r
+ */\r
+static int\r
+get_pap_passwd(int unit, char *user, char *passwd)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+/* normally we would reject PAP if no password is provided,\r
+   but this causes problems with some providers (like CHT in Taiwan)\r
+   who incorrectly request PAP and expect a bogus/empty password, so\r
+   always provide a default user/passwd of "none"/"none"\r
+*/\r
+  if(user) {\r
+    strcpy(user, "none");\r
+  }\r
+  if(passwd) {\r
+    strcpy(passwd, "none");\r
+  }\r
+  return 1;\r
+}\r
+\r
+/*\r
+ * have_pap_secret - check whether we have a PAP file with any\r
+ * secrets that we could possibly use for authenticating the peer.\r
+ */\r
+static int\r
+have_pap_secret(void)\r
+{\r
+  /* XXX Fail until we set up our passwords. */\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * have_chap_secret - check whether we have a CHAP file with a\r
+ * secret that we could possibly use for authenticating `client'\r
+ * on `server'.  Either can be the null string, meaning we don't\r
+ * know the identity yet.\r
+ */\r
+static int\r
+have_chap_secret(char *client, char *server, u32_t remote)\r
+{\r
+  LWIP_UNUSED_ARG(client);\r
+  LWIP_UNUSED_ARG(server);\r
+  LWIP_UNUSED_ARG(remote);\r
+  /* XXX Fail until we set up our passwords. */\r
+  return 0;\r
+}\r
+\r
+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */\r
+/*\r
+ * set_allowed_addrs() - set the list of allowed addresses.\r
+ */\r
+static void\r
+set_allowed_addrs(int unit, struct wordlist *addrs)\r
+{\r
+  if (addresses[unit] != NULL) {\r
+    free_wordlist(addresses[unit]);\r
+  }\r
+  addresses[unit] = addrs;\r
+\r
+#if 0\r
+  /*\r
+   * If there's only one authorized address we might as well\r
+   * ask our peer for that one right away\r
+   */\r
+  if (addrs != NULL && addrs->next == NULL) {\r
+    char *p = addrs->word;\r
+    struct ipcp_options *wo = &ipcp_wantoptions[unit];\r
+    u32_t a;\r
+    struct hostent *hp;\r
+    \r
+    if (wo->hisaddr == 0 && *p != '!' && *p != '-' && strchr(p, '/') == NULL) {\r
+      hp = gethostbyname(p);\r
+      if (hp != NULL && hp->h_addrtype == AF_INET) {\r
+        a = *(u32_t *)hp->h_addr;\r
+      } else {\r
+        a = inet_addr(p);\r
+      }\r
+      if (a != (u32_t) -1) {\r
+        wo->hisaddr = a;\r
+      }\r
+    }\r
+  }\r
+#endif\r
+}\r
+#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+static int\r
+ip_addr_check(u32_t addr, struct wordlist *addrs)\r
+{\r
+  /* don't allow loopback or multicast address */\r
+  if (bad_ip_adrs(addr)) {\r
+    return 0;\r
+  }\r
+\r
+  if (addrs == NULL) {\r
+    return !ppp_settings.auth_required; /* no addresses authorized */\r
+  }\r
+\r
+  /* XXX All other addresses allowed. */\r
+  return 1;\r
+}\r
+\r
+#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */\r
+/*\r
+ * free_wordlist - release memory allocated for a wordlist.\r
+ */\r
+static void\r
+free_wordlist(struct wordlist *wp)\r
+{\r
+  struct wordlist *next;\r
+  \r
+  while (wp != NULL) {\r
+    next = wp->next;\r
+    free(wp);\r
+    wp = next;\r
+  }\r
+}\r
+#endif  /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/auth.h
new file mode 100644 (file)
index 0000000..6e9e000
--- /dev/null
@@ -0,0 +1,111 @@
+/*****************************************************************************\r
+* auth.h -  PPP Authentication and phase control header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original derived from BSD pppd.h.\r
+*****************************************************************************/\r
+/*\r
+ * pppd.h - PPP daemon global declarations.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ */\r
+\r
+#ifndef AUTH_H\r
+#define AUTH_H\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+/* we are starting to use the link */\r
+void link_required (int);\r
+\r
+/* we are finished with the link */\r
+void link_terminated (int);\r
+\r
+/* the LCP layer has left the Opened state */\r
+void link_down (int);\r
+\r
+/* the link is up; authenticate now */\r
+void link_established (int);\r
+\r
+/* a network protocol has come up */\r
+void np_up (int, u16_t);\r
+\r
+/* a network protocol has gone down */\r
+void np_down (int, u16_t);\r
+\r
+/* a network protocol no longer needs link */\r
+void np_finished (int, u16_t);\r
+\r
+/* peer failed to authenticate itself */\r
+void auth_peer_fail (int, u16_t);\r
+\r
+/* peer successfully authenticated itself */\r
+void auth_peer_success (int, u16_t, char *, int);\r
+\r
+/* we failed to authenticate ourselves */\r
+void auth_withpeer_fail (int, u16_t);\r
+\r
+/* we successfully authenticated ourselves */\r
+void auth_withpeer_success (int, u16_t);\r
+\r
+/* check authentication options supplied */\r
+void auth_check_options (void);\r
+\r
+/* check what secrets we have */\r
+void auth_reset (int);\r
+\r
+/* Check peer-supplied username/password */\r
+int  check_passwd (int, char *, int, char *, int, char **, int *);\r
+\r
+/* get "secret" for chap */\r
+int  get_secret (int, char *, char *, char *, int *, int);\r
+\r
+/* check if IP address is authorized */\r
+int  auth_ip_addr (int, u32_t);\r
+\r
+/* check if IP address is unreasonable */\r
+int  bad_ip_adrs (u32_t);\r
+\r
+#endif /* AUTH_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.c
new file mode 100644 (file)
index 0000000..938994a
--- /dev/null
@@ -0,0 +1,902 @@
+/*** WARNING - THIS HAS NEVER BEEN FINISHED ***/\r
+/*****************************************************************************\r
+* chap.c - Network Challenge Handshake Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original based on BSD chap.c.\r
+*****************************************************************************/\r
+/*\r
+ * chap.c - Challenge Handshake Authentication Protocol.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1991 Gregory M. Christy.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Gregory M. Christy.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT  /* don't build if not configured for use in lwipopts.h */\r
+\r
+#if CHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "magic.h"\r
+#include "randm.h"\r
+#include "auth.h"\r
+#include "md5.h"\r
+#include "chap.h"\r
+#include "chpms.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Protocol entry points.\r
+ */\r
+static void ChapInit (int);\r
+static void ChapLowerUp (int);\r
+static void ChapLowerDown (int);\r
+static void ChapInput (int, u_char *, int);\r
+static void ChapProtocolReject (int);\r
+#if 0\r
+static int  ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *);\r
+#endif\r
+\r
+static void ChapChallengeTimeout (void *);\r
+static void ChapResponseTimeout (void *);\r
+static void ChapReceiveChallenge (chap_state *, u_char *, int, int);\r
+static void ChapRechallenge (void *);\r
+static void ChapReceiveResponse (chap_state *, u_char *, int, int);\r
+static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len);\r
+static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len);\r
+static void ChapSendStatus (chap_state *, int);\r
+static void ChapSendChallenge (chap_state *);\r
+static void ChapSendResponse (chap_state *);\r
+static void ChapGenChallenge (chap_state *);\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */\r
+\r
+struct protent chap_protent = {\r
+  PPP_CHAP,\r
+  ChapInit,\r
+  ChapInput,\r
+  ChapProtocolReject,\r
+  ChapLowerUp,\r
+  ChapLowerDown,\r
+  NULL,\r
+  NULL,\r
+#if 0\r
+  ChapPrintPkt,\r
+  NULL,\r
+#endif\r
+  1,\r
+  "CHAP",\r
+#if 0\r
+  NULL,\r
+  NULL,\r
+  NULL\r
+#endif\r
+};\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * ChapAuthWithPeer - Authenticate us with our peer (start client).\r
+ *\r
+ */\r
+void\r
+ChapAuthWithPeer(int unit, char *our_name, int digest)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+\r
+  cstate->resp_name = our_name;\r
+  cstate->resp_type = digest;\r
+\r
+  if (cstate->clientstate == CHAPCS_INITIAL ||\r
+      cstate->clientstate == CHAPCS_PENDING) {\r
+    /* lower layer isn't up - wait until later */\r
+    cstate->clientstate = CHAPCS_PENDING;\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * We get here as a result of LCP coming up.\r
+   * So even if CHAP was open before, we will \r
+   * have to re-authenticate ourselves.\r
+   */\r
+  cstate->clientstate = CHAPCS_LISTEN;\r
+}\r
+\r
+\r
+/*\r
+ * ChapAuthPeer - Authenticate our peer (start server).\r
+ */\r
+void\r
+ChapAuthPeer(int unit, char *our_name, int digest)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+\r
+  cstate->chal_name = our_name;\r
+  cstate->chal_type = digest;\r
+  \r
+  if (cstate->serverstate == CHAPSS_INITIAL ||\r
+      cstate->serverstate == CHAPSS_PENDING) {\r
+    /* lower layer isn't up - wait until later */\r
+    cstate->serverstate = CHAPSS_PENDING;\r
+    return;\r
+  }\r
+\r
+  ChapGenChallenge(cstate);\r
+  ChapSendChallenge(cstate);    /* crank it up dude! */\r
+  cstate->serverstate = CHAPSS_INITIAL_CHAL;\r
+}\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * ChapInit - Initialize a CHAP unit.\r
+ */\r
+static void\r
+ChapInit(int unit)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+\r
+  BZERO(cstate, sizeof(*cstate));\r
+  cstate->unit = unit;\r
+  cstate->clientstate = CHAPCS_INITIAL;\r
+  cstate->serverstate = CHAPSS_INITIAL;\r
+  cstate->timeouttime = CHAP_DEFTIMEOUT;\r
+  cstate->max_transmits = CHAP_DEFTRANSMITS;\r
+  /* random number generator is initialized in magic_init */\r
+}\r
+\r
+\r
+/*\r
+ * ChapChallengeTimeout - Timeout expired on sending challenge.\r
+ */\r
+static void\r
+ChapChallengeTimeout(void *arg)\r
+{\r
+  chap_state *cstate = (chap_state *) arg;\r
+\r
+  /* if we aren't sending challenges, don't worry.  then again we */\r
+  /* probably shouldn't be here either */\r
+  if (cstate->serverstate != CHAPSS_INITIAL_CHAL &&\r
+      cstate->serverstate != CHAPSS_RECHALLENGE) {\r
+    return;\r
+  }\r
+\r
+  if (cstate->chal_transmits >= cstate->max_transmits) {\r
+    /* give up on peer */\r
+    CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n"));\r
+    cstate->serverstate = CHAPSS_BADAUTH;\r
+    auth_peer_fail(cstate->unit, PPP_CHAP);\r
+    return;\r
+  }\r
+\r
+  ChapSendChallenge(cstate); /* Re-send challenge */\r
+}\r
+\r
+\r
+/*\r
+ * ChapResponseTimeout - Timeout expired on sending response.\r
+ */\r
+static void\r
+ChapResponseTimeout(void *arg)\r
+{\r
+  chap_state *cstate = (chap_state *) arg;\r
+\r
+  /* if we aren't sending a response, don't worry. */\r
+  if (cstate->clientstate != CHAPCS_RESPONSE) {\r
+    return;\r
+  }\r
+\r
+  ChapSendResponse(cstate);    /* re-send response */\r
+}\r
+\r
+\r
+/*\r
+ * ChapRechallenge - Time to challenge the peer again.\r
+ */\r
+static void\r
+ChapRechallenge(void *arg)\r
+{\r
+  chap_state *cstate = (chap_state *) arg;\r
+  \r
+  /* if we aren't sending a response, don't worry. */\r
+  if (cstate->serverstate != CHAPSS_OPEN) {\r
+    return;\r
+  }\r
+\r
+  ChapGenChallenge(cstate);\r
+  ChapSendChallenge(cstate);\r
+  cstate->serverstate = CHAPSS_RECHALLENGE;\r
+}\r
+\r
+\r
+/*\r
+ * ChapLowerUp - The lower layer is up.\r
+ *\r
+ * Start up if we have pending requests.\r
+ */\r
+static void\r
+ChapLowerUp(int unit)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+\r
+  if (cstate->clientstate == CHAPCS_INITIAL) {\r
+    cstate->clientstate = CHAPCS_CLOSED;\r
+  } else if (cstate->clientstate == CHAPCS_PENDING) {\r
+    cstate->clientstate = CHAPCS_LISTEN;\r
+  }\r
+\r
+  if (cstate->serverstate == CHAPSS_INITIAL) {\r
+    cstate->serverstate = CHAPSS_CLOSED;\r
+  } else if (cstate->serverstate == CHAPSS_PENDING) {\r
+    ChapGenChallenge(cstate);\r
+    ChapSendChallenge(cstate);\r
+    cstate->serverstate = CHAPSS_INITIAL_CHAL;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * ChapLowerDown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts.\r
+ */\r
+static void\r
+ChapLowerDown(int unit)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+\r
+  /* Timeout(s) pending?  Cancel if so. */\r
+  if (cstate->serverstate == CHAPSS_INITIAL_CHAL ||\r
+      cstate->serverstate == CHAPSS_RECHALLENGE) {\r
+    UNTIMEOUT(ChapChallengeTimeout, cstate);\r
+  } else if (cstate->serverstate == CHAPSS_OPEN\r
+      && cstate->chal_interval != 0) {\r
+    UNTIMEOUT(ChapRechallenge, cstate);\r
+  }\r
+  if (cstate->clientstate == CHAPCS_RESPONSE) {\r
+    UNTIMEOUT(ChapResponseTimeout, cstate);\r
+  }\r
+  cstate->clientstate = CHAPCS_INITIAL;\r
+  cstate->serverstate = CHAPSS_INITIAL;\r
+}\r
+\r
+\r
+/*\r
+ * ChapProtocolReject - Peer doesn't grok CHAP.\r
+ */\r
+static void\r
+ChapProtocolReject(int unit)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+  \r
+  if (cstate->serverstate != CHAPSS_INITIAL &&\r
+      cstate->serverstate != CHAPSS_CLOSED) {\r
+    auth_peer_fail(unit, PPP_CHAP);\r
+  }\r
+  if (cstate->clientstate != CHAPCS_INITIAL &&\r
+      cstate->clientstate != CHAPCS_CLOSED) {\r
+    auth_withpeer_fail(unit, PPP_CHAP);\r
+  }\r
+  ChapLowerDown(unit); /* shutdown chap */\r
+}\r
+\r
+\r
+/*\r
+ * ChapInput - Input CHAP packet.\r
+ */\r
+static void\r
+ChapInput(int unit, u_char *inpacket, int packet_len)\r
+{\r
+  chap_state *cstate = &chap[unit];\r
+  u_char *inp;\r
+  u_char code, id;\r
+  int len;\r
+  \r
+  /*\r
+   * Parse header (code, id and length).\r
+   * If packet too short, drop it.\r
+   */\r
+  inp = inpacket;\r
+  if (packet_len < CHAP_HEADERLEN) {\r
+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(code, inp);\r
+  GETCHAR(id, inp);\r
+  GETSHORT(len, inp);\r
+  if (len < CHAP_HEADERLEN) {\r
+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n"));\r
+    return;\r
+  }\r
+  if (len > packet_len) {\r
+    CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  len -= CHAP_HEADERLEN;\r
+  \r
+  /*\r
+   * Action depends on code (as in fact it usually does :-).\r
+   */\r
+  switch (code) {\r
+    case CHAP_CHALLENGE:\r
+      ChapReceiveChallenge(cstate, inp, id, len);\r
+      break;\r
+    \r
+    case CHAP_RESPONSE:\r
+      ChapReceiveResponse(cstate, inp, id, len);\r
+      break;\r
+    \r
+    case CHAP_FAILURE:\r
+      ChapReceiveFailure(cstate, inp, id, len);\r
+      break;\r
+    \r
+    case CHAP_SUCCESS:\r
+      ChapReceiveSuccess(cstate, inp, id, len);\r
+      break;\r
+    \r
+    default:        /* Need code reject? */\r
+      CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code));\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveChallenge - Receive Challenge and send Response.\r
+ */\r
+static void\r
+ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len)\r
+{\r
+  int rchallenge_len;\r
+  u_char *rchallenge;\r
+  int secret_len;\r
+  char secret[MAXSECRETLEN];\r
+  char rhostname[256];\r
+  MD5_CTX mdContext;\r
+  u_char hash[MD5_SIGNATURE_SIZE];\r
+  \r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id));\r
+  if (cstate->clientstate == CHAPCS_CLOSED ||\r
+    cstate->clientstate == CHAPCS_PENDING) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n",\r
+         cstate->clientstate));\r
+    return;\r
+  }\r
+\r
+  if (len < 2) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+\r
+  GETCHAR(rchallenge_len, inp);\r
+  len -= sizeof (u_char) + rchallenge_len;  /* now name field length */\r
+  if (len < 0) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  rchallenge = inp;\r
+  INCPTR(rchallenge_len, inp);\r
+\r
+  if (len >= sizeof(rhostname)) {\r
+    len = sizeof(rhostname) - 1;\r
+  }\r
+  BCOPY(inp, rhostname, len);\r
+  rhostname[len] = '\000';\r
+\r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname));\r
+\r
+  /* Microsoft doesn't send their name back in the PPP packet */\r
+  if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) {\r
+    strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname));\r
+    rhostname[sizeof(rhostname) - 1] = 0;\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname));\r
+  }\r
+\r
+  /* get secret for authenticating ourselves with the specified host */\r
+  if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) {\r
+    secret_len = 0;    /* assume null secret if can't find one */\r
+    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname));\r
+  }\r
+\r
+  /* cancel response send timeout if necessary */\r
+  if (cstate->clientstate == CHAPCS_RESPONSE) {\r
+    UNTIMEOUT(ChapResponseTimeout, cstate);\r
+  }\r
+\r
+  cstate->resp_id = id;\r
+  cstate->resp_transmits = 0;\r
+\r
+  /*  generate MD based on negotiated type */\r
+  switch (cstate->resp_type) { \r
+\r
+  case CHAP_DIGEST_MD5:\r
+    MD5Init(&mdContext);\r
+    MD5Update(&mdContext, &cstate->resp_id, 1);\r
+    MD5Update(&mdContext, (u_char*)secret, secret_len);\r
+    MD5Update(&mdContext, rchallenge, rchallenge_len);\r
+    MD5Final(hash, &mdContext);\r
+    BCOPY(hash, cstate->response, MD5_SIGNATURE_SIZE);\r
+    cstate->resp_length = MD5_SIGNATURE_SIZE;\r
+    break;\r
+  \r
+#ifdef CHAPMS\r
+  case CHAP_MICROSOFT:\r
+    ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len);\r
+    break;\r
+#endif\r
+\r
+  default:\r
+    CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type));\r
+    return;\r
+  }\r
+\r
+  BZERO(secret, sizeof(secret));\r
+  ChapSendResponse(cstate);\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveResponse - Receive and process response.\r
+ */\r
+static void\r
+ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len)\r
+{\r
+  u_char *remmd, remmd_len;\r
+  int secret_len, old_state;\r
+  int code;\r
+  char rhostname[256];\r
+  MD5_CTX mdContext;\r
+  char secret[MAXSECRETLEN];\r
+  u_char hash[MD5_SIGNATURE_SIZE];\r
+  \r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id));\r
+  \r
+  if (cstate->serverstate == CHAPSS_CLOSED ||\r
+      cstate->serverstate == CHAPSS_PENDING) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n",\r
+    cstate->serverstate));\r
+    return;\r
+  }\r
+\r
+  if (id != cstate->chal_id) {\r
+    return;      /* doesn't match ID of last challenge */\r
+  }\r
+\r
+  /*\r
+  * If we have received a duplicate or bogus Response,\r
+  * we have to send the same answer (Success/Failure)\r
+  * as we did for the first Response we saw.\r
+  */\r
+  if (cstate->serverstate == CHAPSS_OPEN) {\r
+    ChapSendStatus(cstate, CHAP_SUCCESS);\r
+    return;\r
+  }\r
+  if (cstate->serverstate == CHAPSS_BADAUTH) {\r
+    ChapSendStatus(cstate, CHAP_FAILURE);\r
+    return;\r
+  }\r
+  \r
+  if (len < 2) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(remmd_len, inp); /* get length of MD */\r
+  remmd = inp;             /* get pointer to MD */\r
+  INCPTR(remmd_len, inp);\r
+  \r
+  len -= sizeof (u_char) + remmd_len;\r
+  if (len < 0) {\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+\r
+  UNTIMEOUT(ChapChallengeTimeout, cstate);\r
+  \r
+  if (len >= sizeof(rhostname)) {\r
+    len = sizeof(rhostname) - 1;\r
+  }\r
+  BCOPY(inp, rhostname, len);\r
+  rhostname[len] = '\000';\r
+\r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname));\r
+\r
+  /*\r
+  * Get secret for authenticating them with us,\r
+  * do the hash ourselves, and compare the result.\r
+  */\r
+  code = CHAP_FAILURE;\r
+  if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) {\r
+    /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */\r
+    CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n",\r
+    rhostname));\r
+  } else {\r
+    /*  generate MD based on negotiated type */\r
+    switch (cstate->chal_type) {\r
+\r
+      case CHAP_DIGEST_MD5:    /* only MD5 is defined for now */\r
+        if (remmd_len != MD5_SIGNATURE_SIZE) {\r
+          break;      /* it's not even the right length */\r
+        }\r
+        MD5Init(&mdContext);\r
+        MD5Update(&mdContext, &cstate->chal_id, 1);\r
+        MD5Update(&mdContext, (u_char*)secret, secret_len);\r
+        MD5Update(&mdContext, cstate->challenge, cstate->chal_len);\r
+        MD5Final(hash, &mdContext); \r
+        \r
+        /* compare local and remote MDs and send the appropriate status */\r
+        if (memcmp (hash, remmd, MD5_SIGNATURE_SIZE) == 0) {\r
+          code = CHAP_SUCCESS;  /* they are the same! */\r
+        }\r
+        break;\r
+      \r
+      default:\r
+        CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type));\r
+    }\r
+  }\r
+  \r
+  BZERO(secret, sizeof(secret));\r
+  ChapSendStatus(cstate, code);\r
+\r
+  if (code == CHAP_SUCCESS) {\r
+    old_state = cstate->serverstate;\r
+    cstate->serverstate = CHAPSS_OPEN;\r
+    if (old_state == CHAPSS_INITIAL_CHAL) {\r
+      auth_peer_success(cstate->unit, PPP_CHAP, rhostname, len);\r
+    }\r
+    if (cstate->chal_interval != 0) {\r
+      TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval);\r
+    }\r
+  } else {\r
+    CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n"));\r
+    cstate->serverstate = CHAPSS_BADAUTH;\r
+    auth_peer_fail(cstate->unit, PPP_CHAP);\r
+  }\r
+}\r
+\r
+/*\r
+ * ChapReceiveSuccess - Receive Success\r
+ */\r
+static void\r
+ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len)\r
+{\r
+  LWIP_UNUSED_ARG(id);\r
+  LWIP_UNUSED_ARG(inp);\r
+\r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id));\r
+\r
+  if (cstate->clientstate == CHAPCS_OPEN) {\r
+    /* presumably an answer to a duplicate response */\r
+    return;\r
+  }\r
+\r
+  if (cstate->clientstate != CHAPCS_RESPONSE) {\r
+    /* don't know what this is */\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate));\r
+    return;\r
+  }\r
+  \r
+  UNTIMEOUT(ChapResponseTimeout, cstate);\r
+  \r
+  /*\r
+   * Print message.\r
+   */\r
+  if (len > 0) {\r
+    PRINTMSG(inp, len);\r
+  }\r
+\r
+  cstate->clientstate = CHAPCS_OPEN;\r
+\r
+  auth_withpeer_success(cstate->unit, PPP_CHAP);\r
+}\r
+\r
+\r
+/*\r
+ * ChapReceiveFailure - Receive failure.\r
+ */\r
+static void\r
+ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len)\r
+{\r
+  LWIP_UNUSED_ARG(id);\r
+  LWIP_UNUSED_ARG(inp);\r
+\r
+  CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id));\r
+\r
+  if (cstate->clientstate != CHAPCS_RESPONSE) {\r
+    /* don't know what this is */\r
+    CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate));\r
+    return;\r
+  }\r
+\r
+  UNTIMEOUT(ChapResponseTimeout, cstate);\r
+\r
+  /*\r
+   * Print message.\r
+   */\r
+  if (len > 0) {\r
+    PRINTMSG(inp, len);\r
+  }\r
+\r
+  CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n"));\r
+  auth_withpeer_fail(cstate->unit, PPP_CHAP);\r
+}\r
+\r
+\r
+/*\r
+ * ChapSendChallenge - Send an Authenticate challenge.\r
+ */\r
+static void\r
+ChapSendChallenge(chap_state *cstate)\r
+{\r
+  u_char *outp;\r
+  int chal_len, name_len;\r
+  int outlen;\r
+  \r
+  chal_len = cstate->chal_len;\r
+  name_len = strlen(cstate->chal_name);\r
+  outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len;\r
+  outp = outpacket_buf[cstate->unit];\r
+  \r
+  MAKEHEADER(outp, PPP_CHAP);    /* paste in a CHAP header */\r
+  \r
+  PUTCHAR(CHAP_CHALLENGE, outp);\r
+  PUTCHAR(cstate->chal_id, outp);\r
+  PUTSHORT(outlen, outp);\r
+  \r
+  PUTCHAR(chal_len, outp);    /* put length of challenge */\r
+  BCOPY(cstate->challenge, outp, chal_len);\r
+  INCPTR(chal_len, outp);\r
+  \r
+  BCOPY(cstate->chal_name, outp, name_len);  /* append hostname */\r
+  \r
+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+  \r
+  CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id));\r
+  \r
+  TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime);\r
+  ++cstate->chal_transmits;\r
+}\r
+\r
+\r
+/*\r
+ * ChapSendStatus - Send a status response (ack or nak).\r
+ */\r
+static void\r
+ChapSendStatus(chap_state *cstate, int code)\r
+{\r
+  u_char *outp;\r
+  int outlen, msglen;\r
+  char msg[256];\r
+  \r
+  if (code == CHAP_SUCCESS) {\r
+    strcpy(msg, "Welcome!");\r
+  } else {\r
+    strcpy(msg, "I don't like you.  Go 'way.");\r
+  }\r
+  msglen = strlen(msg);\r
+  \r
+  outlen = CHAP_HEADERLEN + msglen;\r
+  outp = outpacket_buf[cstate->unit];\r
+  \r
+  MAKEHEADER(outp, PPP_CHAP);    /* paste in a header */\r
+  \r
+  PUTCHAR(code, outp);\r
+  PUTCHAR(cstate->chal_id, outp);\r
+  PUTSHORT(outlen, outp);\r
+  BCOPY(msg, outp, msglen);\r
+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+  \r
+  CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id));\r
+}\r
+\r
+/*\r
+ * ChapGenChallenge is used to generate a pseudo-random challenge string of\r
+ * a pseudo-random length between min_len and max_len.  The challenge\r
+ * string and its length are stored in *cstate, and various other fields of\r
+ * *cstate are initialized.\r
+ */\r
+\r
+static void\r
+ChapGenChallenge(chap_state *cstate)\r
+{\r
+  int chal_len;\r
+  u_char *ptr = cstate->challenge;\r
+  int i;\r
+  \r
+  /* pick a random challenge length between MIN_CHALLENGE_LENGTH and \r
+     MAX_CHALLENGE_LENGTH */  \r
+  chal_len = (unsigned)\r
+        ((((magic() >> 16) *\r
+              (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16)\r
+           + MIN_CHALLENGE_LENGTH);\r
+  cstate->chal_len = chal_len;\r
+  cstate->chal_id = ++cstate->id;\r
+  cstate->chal_transmits = 0;\r
+  \r
+  /* generate a random string */\r
+  for (i = 0; i < chal_len; i++ ) {\r
+    *ptr++ = (char) (magic() & 0xff);\r
+  }\r
+}\r
+\r
+/*\r
+ * ChapSendResponse - send a response packet with values as specified\r
+ * in *cstate.\r
+ */\r
+/* ARGSUSED */\r
+static void\r
+ChapSendResponse(chap_state *cstate)\r
+{\r
+  u_char *outp;\r
+  int outlen, md_len, name_len;\r
+  \r
+  md_len = cstate->resp_length;\r
+  name_len = strlen(cstate->resp_name);\r
+  outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len;\r
+  outp = outpacket_buf[cstate->unit];\r
+  \r
+  MAKEHEADER(outp, PPP_CHAP);\r
+  \r
+  PUTCHAR(CHAP_RESPONSE, outp);  /* we are a response */\r
+  PUTCHAR(cstate->resp_id, outp);  /* copy id from challenge packet */\r
+  PUTSHORT(outlen, outp);      /* packet length */\r
+  \r
+  PUTCHAR(md_len, outp);      /* length of MD */\r
+  BCOPY(cstate->response, outp, md_len);    /* copy MD to buffer */\r
+  INCPTR(md_len, outp);\r
+  \r
+  BCOPY(cstate->resp_name, outp, name_len);  /* append our name */\r
+  \r
+  /* send the packet */\r
+  pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN);\r
+  \r
+  cstate->clientstate = CHAPCS_RESPONSE;\r
+  TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime);\r
+  ++cstate->resp_transmits;\r
+}\r
+\r
+#if 0\r
+static char *ChapCodenames[] = {\r
+  "Challenge", "Response", "Success", "Failure"\r
+};\r
+/*\r
+ * ChapPrintPkt - print the contents of a CHAP packet.\r
+ */\r
+static int\r
+ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)\r
+{\r
+  int code, id, len;\r
+  int clen, nlen;\r
+  u_char x;\r
+  \r
+  if (plen < CHAP_HEADERLEN) {\r
+    return 0;\r
+  }\r
+  GETCHAR(code, p);\r
+  GETCHAR(id, p);\r
+  GETSHORT(len, p);\r
+  if (len < CHAP_HEADERLEN || len > plen) {\r
+    return 0;\r
+  }\r
+  if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) {\r
+    printer(arg, " %s", ChapCodenames[code-1]);\r
+  } else {\r
+    printer(arg, " code=0x%x", code);\r
+  }\r
+  printer(arg, " id=0x%x", id);\r
+  len -= CHAP_HEADERLEN;\r
+  switch (code) {\r
+    case CHAP_CHALLENGE:\r
+    case CHAP_RESPONSE:\r
+      if (len < 1) {\r
+        break;\r
+      }\r
+      clen = p[0];\r
+      if (len < clen + 1) {\r
+        break;\r
+      }\r
+      ++p;\r
+      nlen = len - clen - 1;\r
+      printer(arg, " <");\r
+      for (; clen > 0; --clen) {\r
+        GETCHAR(x, p);\r
+        printer(arg, "%.2x", x);\r
+      }\r
+      printer(arg, ">, name = %.*Z", nlen, p);\r
+      break;\r
+    case CHAP_FAILURE:\r
+    case CHAP_SUCCESS:\r
+      printer(arg, " %.*Z", len, p);\r
+      break;\r
+    default:\r
+      for (clen = len; clen > 0; --clen) {\r
+        GETCHAR(x, p);\r
+        printer(arg, " %.2x", x);\r
+      }\r
+  }\r
+\r
+  return len + CHAP_HEADERLEN;\r
+}\r
+#endif\r
+\r
+#endif /* CHAP_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chap.h
new file mode 100644 (file)
index 0000000..b48eecb
--- /dev/null
@@ -0,0 +1,166 @@
+/*****************************************************************************\r
+* chap.h - Network Challenge Handshake Authentication Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original built from BSD network code.\r
+******************************************************************************/\r
+/*\r
+ * chap.h - Challenge Handshake Authentication Protocol definitions.\r
+ *\r
+ * Copyright (c) 1993 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the Australian National University.  The name of the University\r
+ * may not be used to endorse or promote products derived from this\r
+ * software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Copyright (c) 1991 Gregory M. Christy\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the author.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $\r
+ */\r
+\r
+#ifndef CHAP_H\r
+#define CHAP_H\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+\r
+/* Code + ID + length */\r
+#define CHAP_HEADERLEN 4\r
+\r
+/*\r
+ * CHAP codes.\r
+ */\r
+\r
+#define CHAP_DIGEST_MD5      5    /* use MD5 algorithm */\r
+#define MD5_SIGNATURE_SIZE   16   /* 16 bytes in a MD5 message digest */\r
+#define CHAP_MICROSOFT       0x80 /* use Microsoft-compatible alg. */\r
+#define MS_CHAP_RESPONSE_LEN 49   /* Response length for MS-CHAP */\r
+\r
+#define CHAP_CHALLENGE       1\r
+#define CHAP_RESPONSE        2\r
+#define CHAP_SUCCESS         3\r
+#define CHAP_FAILURE         4\r
+\r
+/*\r
+ *  Challenge lengths (for challenges we send) and other limits.\r
+ */\r
+#define MIN_CHALLENGE_LENGTH 32\r
+#define MAX_CHALLENGE_LENGTH 64\r
+#define MAX_RESPONSE_LENGTH  64 /* sufficient for MD5 or MS-CHAP */\r
+\r
+/*\r
+ * Client (peer) states.\r
+ */\r
+#define CHAPCS_INITIAL       0 /* Lower layer down, not opened */\r
+#define CHAPCS_CLOSED        1 /* Lower layer up, not opened */\r
+#define CHAPCS_PENDING       2 /* Auth us to peer when lower up */\r
+#define CHAPCS_LISTEN        3 /* Listening for a challenge */\r
+#define CHAPCS_RESPONSE      4 /* Sent response, waiting for status */\r
+#define CHAPCS_OPEN          5 /* We've received Success */\r
+\r
+/*\r
+ * Server (authenticator) states.\r
+ */\r
+#define CHAPSS_INITIAL       0 /* Lower layer down, not opened */\r
+#define CHAPSS_CLOSED        1 /* Lower layer up, not opened */\r
+#define CHAPSS_PENDING       2 /* Auth peer when lower up */\r
+#define CHAPSS_INITIAL_CHAL  3 /* We've sent the first challenge */\r
+#define CHAPSS_OPEN          4 /* We've sent a Success msg */\r
+#define CHAPSS_RECHALLENGE   5 /* We've sent another challenge */\r
+#define CHAPSS_BADAUTH       6 /* We've sent a Failure msg */\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * Each interface is described by a chap structure.\r
+ */\r
+\r
+typedef struct chap_state {\r
+  int unit;                               /* Interface unit number */\r
+  int clientstate;                        /* Client state */\r
+  int serverstate;                        /* Server state */\r
+  u_char challenge[MAX_CHALLENGE_LENGTH]; /* last challenge string sent */\r
+  u_char chal_len;                        /* challenge length */\r
+  u_char chal_id;                         /* ID of last challenge */\r
+  u_char chal_type;                       /* hash algorithm for challenges */\r
+  u_char id;                              /* Current id */\r
+  char *chal_name;                        /* Our name to use with challenge */\r
+  int chal_interval;                      /* Time until we challenge peer again */\r
+  int timeouttime;                        /* Timeout time in seconds */\r
+  int max_transmits;                      /* Maximum # of challenge transmissions */\r
+  int chal_transmits;                     /* Number of transmissions of challenge */\r
+  int resp_transmits;                     /* Number of transmissions of response */\r
+  u_char response[MAX_RESPONSE_LENGTH];   /* Response to send */\r
+  u_char resp_length;                     /* length of response */\r
+  u_char resp_id;                         /* ID for response messages */\r
+  u_char resp_type;                       /* hash algorithm for responses */\r
+  char *resp_name;                        /* Our name to send with response */\r
+} chap_state;\r
+\r
+\r
+/******************\r
+*** PUBLIC DATA ***\r
+******************/\r
+extern chap_state chap[];\r
+\r
+extern struct protent chap_protent;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+void ChapAuthWithPeer (int, char *, int);\r
+void ChapAuthPeer (int, char *, int);\r
+\r
+#endif /* CHAP_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.c
new file mode 100644 (file)
index 0000000..900db42
--- /dev/null
@@ -0,0 +1,396 @@
+/*** WARNING - THIS CODE HAS NOT BEEN FINISHED! ***/\r
+/*****************************************************************************\r
+* chpms.c - Network MicroSoft Challenge Handshake Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 by Global Election Systems Inc.  All rights reserved.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original based on BSD chap_ms.c.\r
+*****************************************************************************/\r
+/*\r
+ * chap_ms.c - Microsoft MS-CHAP compatible implementation.\r
+ *\r
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.\r
+ * http://www.strataware.com/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Eric Rosenquist.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+/*\r
+ * Modifications by Lauri Pesonen / lpesonen@clinet.fi, april 1997\r
+ *\r
+ *   Implemented LANManager type password response to MS-CHAP challenges.\r
+ *   Now pppd provides both NT style and LANMan style blocks, and the\r
+ *   prefered is set by option "ms-lanman". Default is to use NT.\r
+ *   The hash text (StdText) was taken from Win95 RASAPI32.DLL.\r
+ *\r
+ *   You should also use DOMAIN\\USERNAME as described in README.MSCHAP80\r
+ */\r
+\r
+#define USE_CRYPT\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#if MSCHAP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "md4.h"\r
+#ifndef USE_CRYPT\r
+#include "des.h"\r
+#endif\r
+#include "chap.h"\r
+#include "chpms.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+typedef struct {\r
+    u_char LANManResp[24];\r
+    u_char NTResp[24];\r
+    u_char UseNT; /* If 1, ignore the LANMan response field */\r
+} MS_ChapResponse;\r
+/* We use MS_CHAP_RESPONSE_LEN, rather than sizeof(MS_ChapResponse),\r
+   in case this struct gets padded. */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+\r
+/* XXX Don't know what to do with these. */\r
+extern void setkey(const char *);\r
+extern void encrypt(char *, int);\r
+\r
+static void DesEncrypt (u_char *, u_char *, u_char *);\r
+static void MakeKey (u_char *, u_char *);\r
+\r
+#ifdef USE_CRYPT\r
+static void Expand (u_char *, u_char *);\r
+static void Collapse (u_char *, u_char *);\r
+#endif\r
+\r
+static void ChallengeResponse(\r
+  u_char *challenge, /* IN   8 octets */\r
+  u_char *pwHash,    /* IN  16 octets */\r
+  u_char *response   /* OUT 24 octets */\r
+);\r
+static void ChapMS_NT(\r
+  char *rchallenge,\r
+  int rchallenge_len,\r
+  char *secret,\r
+  int secret_len,\r
+  MS_ChapResponse *response\r
+);\r
+static u_char Get7Bits(\r
+  u_char *input,\r
+  int startBit\r
+);\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+void\r
+ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len)\r
+{\r
+  MS_ChapResponse response;\r
+#ifdef MSLANMAN\r
+  extern int ms_lanman;\r
+#endif\r
+\r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret));\r
+#endif\r
+  BZERO(&response, sizeof(response));\r
+\r
+  /* Calculate both always */\r
+  ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response);\r
+\r
+#ifdef MSLANMAN\r
+  ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response);\r
+\r
+  /* prefered method is set by option  */\r
+  response.UseNT = !ms_lanman;\r
+#else\r
+  response.UseNT = 1;\r
+#endif\r
+\r
+  BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN);\r
+  cstate->resp_length = MS_CHAP_RESPONSE_LEN;\r
+}\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+static void\r
+ChallengeResponse( u_char *challenge, /* IN   8 octets */\r
+                   u_char *pwHash,    /* IN  16 octets */\r
+                   u_char *response   /* OUT 24 octets */)\r
+{\r
+  char    ZPasswordHash[21];\r
+\r
+  BZERO(ZPasswordHash, sizeof(ZPasswordHash));\r
+  BCOPY(pwHash, ZPasswordHash, 16);\r
+\r
+#if 0\r
+  log_packet(ZPasswordHash, sizeof(ZPasswordHash), "ChallengeResponse - ZPasswordHash", LOG_DEBUG);\r
+#endif\r
+\r
+  DesEncrypt(challenge, ZPasswordHash +  0, response + 0);\r
+  DesEncrypt(challenge, ZPasswordHash +  7, response + 8);\r
+  DesEncrypt(challenge, ZPasswordHash + 14, response + 16);\r
+\r
+#if 0\r
+  log_packet(response, 24, "ChallengeResponse - response", LOG_DEBUG);\r
+#endif\r
+}\r
+\r
+\r
+#ifdef USE_CRYPT\r
+static void\r
+DesEncrypt( u_char *clear, /* IN  8 octets */\r
+            u_char *key,   /* IN  7 octets */\r
+            u_char *cipher /* OUT 8 octets */)\r
+{\r
+  u_char des_key[8];\r
+  u_char crypt_key[66];\r
+  u_char des_input[66];\r
+\r
+  MakeKey(key, des_key);\r
+\r
+  Expand(des_key, crypt_key);\r
+  setkey(crypt_key);\r
+\r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));\r
+#endif\r
+\r
+  Expand(clear, des_input);\r
+  encrypt(des_input, 0);\r
+  Collapse(des_input, cipher);\r
+\r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));\r
+#endif\r
+}\r
+\r
+#else /* USE_CRYPT */\r
+\r
+static void\r
+DesEncrypt( u_char *clear, /* IN  8 octets */\r
+            u_char *key,   /* IN  7 octets */\r
+            u_char *cipher /* OUT 8 octets */)\r
+{\r
+  des_cblock    des_key;\r
+  des_key_schedule  key_schedule;\r
+\r
+  MakeKey(key, des_key);\r
+\r
+  des_set_key(&des_key, key_schedule);\r
+\r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+             clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7]));\r
+#endif\r
+\r
+  des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1);\r
+\r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+             cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7]));\r
+#endif\r
+}\r
+\r
+#endif /* USE_CRYPT */\r
+\r
+\r
+static u_char\r
+Get7Bits( u_char *input, int startBit)\r
+{\r
+  register unsigned int  word;\r
+\r
+  word  = (unsigned)input[startBit / 8] << 8;\r
+  word |= (unsigned)input[startBit / 8 + 1];\r
+\r
+  word >>= 15 - (startBit % 8 + 7);\r
+\r
+  return word & 0xFE;\r
+}\r
+\r
+#ifdef USE_CRYPT\r
+\r
+/* in == 8-byte string (expanded version of the 56-bit key)\r
+ * out == 64-byte string where each byte is either 1 or 0\r
+ * Note that the low-order "bit" is always ignored by by setkey()\r
+ */\r
+static void\r
+Expand(u_char *in, u_char *out)\r
+{\r
+  int j, c;\r
+  int i;\r
+\r
+  for(i = 0; i < 64; in++){\r
+    c = *in;\r
+    for(j = 7; j >= 0; j--) {\r
+      *out++ = (c >> j) & 01;\r
+    }\r
+    i += 8;\r
+  }\r
+}\r
+\r
+/* The inverse of Expand\r
+ */\r
+static void\r
+Collapse(u_char *in, u_char *out)\r
+{\r
+  int j;\r
+  int i;\r
+  unsigned int c;\r
+\r
+  for (i = 0; i < 64; i += 8, out++) {\r
+    c = 0;\r
+    for (j = 7; j >= 0; j--, in++) {\r
+      c |= *in << j;\r
+    }\r
+    *out = c & 0xff;\r
+  }\r
+}\r
+#endif\r
+\r
+static void\r
+MakeKey( u_char *key,    /* IN  56 bit DES key missing parity bits */\r
+         u_char *des_key /* OUT 64 bit DES key with parity bits added */)\r
+{\r
+  des_key[0] = Get7Bits(key,  0);\r
+  des_key[1] = Get7Bits(key,  7);\r
+  des_key[2] = Get7Bits(key, 14);\r
+  des_key[3] = Get7Bits(key, 21);\r
+  des_key[4] = Get7Bits(key, 28);\r
+  des_key[5] = Get7Bits(key, 35);\r
+  des_key[6] = Get7Bits(key, 42);\r
+  des_key[7] = Get7Bits(key, 49);\r
+  \r
+#ifndef USE_CRYPT\r
+  des_set_odd_parity((des_cblock *)des_key);\r
+#endif\r
+  \r
+#if 0\r
+  CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n",\r
+             key[0], key[1], key[2], key[3], key[4], key[5], key[6]));\r
+  CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n",\r
+             des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7]));\r
+#endif\r
+}\r
+\r
+static void\r
+ChapMS_NT( char *rchallenge,\r
+           int rchallenge_len,\r
+           char *secret,\r
+           int secret_len,\r
+           MS_ChapResponse *response)\r
+{\r
+  int      i;\r
+  MDstruct  md4Context;\r
+  u_char    unicodePassword[MAX_NT_PASSWORD * 2];\r
+  static int  low_byte_first = -1;\r
+\r
+  /* Initialize the Unicode version of the secret (== password). */\r
+  /* This implicitly supports 8-bit ISO8859/1 characters. */\r
+  BZERO(unicodePassword, sizeof(unicodePassword));\r
+  for (i = 0; i < secret_len; i++) {\r
+    unicodePassword[i * 2] = (u_char)secret[i];\r
+  }\r
+  MDbegin(&md4Context);\r
+  MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8);  /* Unicode is 2 bytes/char, *8 for bit count */\r
+\r
+  if (low_byte_first == -1) {\r
+    low_byte_first = (htons((unsigned short int)1) != 1);\r
+  }\r
+  if (low_byte_first == 0) {\r
+    MDreverse((u_long *)&md4Context);  /*  sfb 961105 */\r
+  }\r
+\r
+  MDupdate(&md4Context, NULL, 0);  /* Tell MD4 we're done */\r
+\r
+  ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp);\r
+}\r
+\r
+#ifdef MSLANMAN\r
+static u_char *StdText = (u_char *)"KGS!@#$%"; /* key from rasapi32.dll */\r
+\r
+static void\r
+ChapMS_LANMan( char *rchallenge,\r
+               int rchallenge_len,\r
+               char *secret,\r
+               int secret_len,\r
+               MS_ChapResponse  *response)\r
+{\r
+  int      i;\r
+  u_char    UcasePassword[MAX_NT_PASSWORD]; /* max is actually 14 */\r
+  u_char    PasswordHash[16];\r
+  \r
+  /* LANMan password is case insensitive */\r
+  BZERO(UcasePassword, sizeof(UcasePassword));\r
+  for (i = 0; i < secret_len; i++) {\r
+    UcasePassword[i] = (u_char)toupper(secret[i]);\r
+  }\r
+  DesEncrypt( StdText, UcasePassword + 0, PasswordHash + 0 );\r
+  DesEncrypt( StdText, UcasePassword + 7, PasswordHash + 8 );\r
+  ChallengeResponse(rchallenge, PasswordHash, response->LANManResp);\r
+}\r
+#endif\r
+\r
+#endif /* MSCHAP_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/chpms.h
new file mode 100644 (file)
index 0000000..f023cce
--- /dev/null
@@ -0,0 +1,64 @@
+/*****************************************************************************\r
+* chpms.h - Network Microsoft Challenge Handshake Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-01-30 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original built from BSD network code.\r
+******************************************************************************/\r
+/*\r
+ * chap.h - Challenge Handshake Authentication Protocol definitions.\r
+ *\r
+ * Copyright (c) 1995 Eric Rosenquist, Strata Software Limited.\r
+ * http://www.strataware.com/\r
+ *\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Eric Rosenquist.  The name of the author may not be used to\r
+ * endorse or promote products derived from this software without\r
+ * specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: chpms.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $\r
+ */\r
+\r
+#ifndef CHPMS_H\r
+#define CHPMS_H\r
+\r
+#define MAX_NT_PASSWORD 256 /* Maximum number of (Unicode) chars in an NT password */\r
+\r
+void ChapMS (chap_state *, char *, int, char *, int);\r
+\r
+#endif /* CHPMS_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.c
new file mode 100644 (file)
index 0000000..8c2fab4
--- /dev/null
@@ -0,0 +1,906 @@
+/*****************************************************************************\r
+* fsm.c - Network Control Protocol Finite State Machine program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original based on BSD fsm.c.\r
+*****************************************************************************/\r
+/*\r
+ * fsm.c - {Link, IP} Control Protocol Finite State Machine.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+/*\r
+ * TODO:\r
+ * Randomize fsm id on link/init.\r
+ * Deal with variable outgoing MTU.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "fsm.h"\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+#if PPP_DEBUG\r
+\r
+static const char *ppperr_strerr[] = {\r
+           "LS_INITIAL",  /* LS_INITIAL  0 */\r
+           "LS_STARTING", /* LS_STARTING 1 */\r
+           "LS_CLOSED",   /* LS_CLOSED   2 */\r
+           "LS_STOPPED",  /* LS_STOPPED  3 */\r
+           "LS_CLOSING",  /* LS_CLOSING  4 */\r
+           "LS_STOPPING", /* LS_STOPPING 5 */\r
+           "LS_REQSENT",  /* LS_REQSENT  6 */\r
+           "LS_ACKRCVD",  /* LS_ACKRCVD  7 */\r
+           "LS_ACKSENT",  /* LS_ACKSENT  8 */\r
+           "LS_OPENED"    /* LS_OPENED   9 */\r
+};\r
+\r
+#endif /* PPP_DEBUG */\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+static void fsm_timeout (void *);\r
+static void fsm_rconfreq (fsm *, u_char, u_char *, int);\r
+static void fsm_rconfack (fsm *, int, u_char *, int);\r
+static void fsm_rconfnakrej (fsm *, int, int, u_char *, int);\r
+static void fsm_rtermreq (fsm *, int, u_char *, int);\r
+static void fsm_rtermack (fsm *);\r
+static void fsm_rcoderej (fsm *, u_char *, int);\r
+static void fsm_sconfreq (fsm *, int);\r
+\r
+#define PROTO_NAME(f) ((f)->callbacks->proto_name)\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+int peer_mru[NUM_PPP];\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+\r
+/*\r
+ * fsm_init - Initialize fsm.\r
+ *\r
+ * Initialize fsm state.\r
+ */\r
+void\r
+fsm_init(fsm *f)\r
+{\r
+  f->state = LS_INITIAL;\r
+  f->flags = 0;\r
+  f->id = 0;        /* XXX Start with random id? */\r
+  f->timeouttime = FSM_DEFTIMEOUT;\r
+  f->maxconfreqtransmits = FSM_DEFMAXCONFREQS;\r
+  f->maxtermtransmits = FSM_DEFMAXTERMREQS;\r
+  f->maxnakloops = FSM_DEFMAXNAKLOOPS;\r
+  f->term_reason_len = 0;\r
+}\r
+\r
+\r
+/*\r
+ * fsm_lowerup - The lower layer is up.\r
+ */\r
+void\r
+fsm_lowerup(fsm *f)\r
+{\r
+  int oldState = f->state;\r
+\r
+  LWIP_UNUSED_ARG(oldState);\r
+\r
+  switch( f->state ) {\r
+    case LS_INITIAL:\r
+      f->state = LS_CLOSED;\r
+      break;\r
+\r
+    case LS_STARTING:\r
+      if( f->flags & OPT_SILENT ) {\r
+        f->state = LS_STOPPED;\r
+      } else {\r
+        /* Send an initial configure-request */\r
+        fsm_sconfreq(f, 0);\r
+        f->state = LS_REQSENT;\r
+      }\r
+    break;\r
+\r
+    default:\r
+      FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n",\r
+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+  }\r
+  \r
+  FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n",\r
+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_lowerdown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts and inform upper layers.\r
+ */\r
+void\r
+fsm_lowerdown(fsm *f)\r
+{\r
+  int oldState = f->state;\r
+\r
+  LWIP_UNUSED_ARG(oldState);\r
+\r
+  switch( f->state ) {\r
+    case LS_CLOSED:\r
+      f->state = LS_INITIAL;\r
+      break;\r
+\r
+    case LS_STOPPED:\r
+      f->state = LS_STARTING;\r
+      if( f->callbacks->starting ) {\r
+        (*f->callbacks->starting)(f);\r
+      }\r
+      break;\r
+\r
+    case LS_CLOSING:\r
+      f->state = LS_INITIAL;\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      break;\r
+\r
+    case LS_STOPPING:\r
+    case LS_REQSENT:\r
+    case LS_ACKRCVD:\r
+    case LS_ACKSENT:\r
+      f->state = LS_STARTING;\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      break;\r
+\r
+    case LS_OPENED:\r
+      if( f->callbacks->down ) {\r
+        (*f->callbacks->down)(f);\r
+      }\r
+      f->state = LS_STARTING;\r
+      break;\r
+\r
+    default:\r
+      FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n",\r
+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+  }\r
+\r
+  FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n",\r
+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_open - Link is allowed to come up.\r
+ */\r
+void\r
+fsm_open(fsm *f)\r
+{\r
+  int oldState = f->state;\r
+\r
+  LWIP_UNUSED_ARG(oldState);\r
+\r
+  switch( f->state ) {\r
+    case LS_INITIAL:\r
+      f->state = LS_STARTING;\r
+      if( f->callbacks->starting ) {\r
+        (*f->callbacks->starting)(f);\r
+      }\r
+      break;\r
+\r
+    case LS_CLOSED:\r
+      if( f->flags & OPT_SILENT ) {\r
+        f->state = LS_STOPPED;\r
+      } else {\r
+        /* Send an initial configure-request */\r
+        fsm_sconfreq(f, 0);\r
+        f->state = LS_REQSENT;\r
+      }\r
+      break;\r
+  \r
+    case LS_CLOSING:\r
+      f->state = LS_STOPPING;\r
+      /* fall through */\r
+    case LS_STOPPED:\r
+    case LS_OPENED:\r
+      if( f->flags & OPT_RESTART ) {\r
+        fsm_lowerdown(f);\r
+        fsm_lowerup(f);\r
+      }\r
+      break;\r
+  }\r
+\r
+  FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n",\r
+      PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_close - Start closing connection.\r
+ *\r
+ * Cancel timeouts and either initiate close or possibly go directly to\r
+ * the LS_CLOSED state.\r
+ */\r
+void\r
+fsm_close(fsm *f, char *reason)\r
+{\r
+  int oldState = f->state;\r
+\r
+  LWIP_UNUSED_ARG(oldState);\r
+\r
+  f->term_reason = reason;\r
+  f->term_reason_len = (reason == NULL? 0: strlen(reason));\r
+  switch( f->state ) {\r
+    case LS_STARTING:\r
+      f->state = LS_INITIAL;\r
+      break;\r
+    case LS_STOPPED:\r
+      f->state = LS_CLOSED;\r
+      break;\r
+    case LS_STOPPING:\r
+      f->state = LS_CLOSING;\r
+      break;\r
+\r
+    case LS_REQSENT:\r
+    case LS_ACKRCVD:\r
+    case LS_ACKSENT:\r
+    case LS_OPENED:\r
+      if( f->state != LS_OPENED ) {\r
+        UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      } else if( f->callbacks->down ) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers we're down */\r
+      }\r
+      /* Init restart counter, send Terminate-Request */\r
+      f->retransmits = f->maxtermtransmits;\r
+      fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+            (u_char *) f->term_reason, f->term_reason_len);\r
+      TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+      --f->retransmits;\r
+\r
+      f->state = LS_CLOSING;\r
+      break;\r
+  }\r
+\r
+  FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n",\r
+      PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state]));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_sdata - Send some data.\r
+ *\r
+ * Used for all packets sent to our peer by this module.\r
+ */\r
+void\r
+fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen)\r
+{\r
+  u_char *outp;\r
+  int outlen;\r
+\r
+  /* Adjust length to be smaller than MTU */\r
+  outp = outpacket_buf[f->unit];\r
+  if (datalen > peer_mru[f->unit] - (int)HEADERLEN) {\r
+    datalen = peer_mru[f->unit] - HEADERLEN;\r
+  }\r
+  if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) {\r
+    BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen);\r
+  }\r
+  outlen = datalen + HEADERLEN;\r
+  MAKEHEADER(outp, f->protocol);\r
+  PUTCHAR(code, outp);\r
+  PUTCHAR(id, outp);\r
+  PUTSHORT(outlen, outp);\r
+  pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN);\r
+  FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n",\r
+        PROTO_NAME(f), code, id, outlen));\r
+}\r
+\r
+\r
+/*\r
+ * fsm_input - Input packet.\r
+ */\r
+void\r
+fsm_input(fsm *f, u_char *inpacket, int l)\r
+{\r
+  u_char *inp = inpacket;\r
+  u_char code, id;\r
+  int len;\r
+\r
+  /*\r
+  * Parse header (code, id and length).\r
+  * If packet too short, drop it.\r
+  */\r
+  if (l < HEADERLEN) {\r
+    FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n",\r
+          f->protocol));\r
+    return;\r
+  }\r
+  GETCHAR(code, inp);\r
+  GETCHAR(id, inp);\r
+  GETSHORT(len, inp);\r
+  if (len < HEADERLEN) {\r
+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n",\r
+        f->protocol));\r
+    return;\r
+  }\r
+  if (len > l) {\r
+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n",\r
+        f->protocol));\r
+    return;\r
+  }\r
+  len -= HEADERLEN;    /* subtract header length */\r
+\r
+  if( f->state == LS_INITIAL || f->state == LS_STARTING ) {\r
+    FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n",\r
+        f->protocol, f->state, ppperr_strerr[f->state]));\r
+    return;\r
+  }\r
+  FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l));\r
+  /*\r
+   * Action depends on code.\r
+   */\r
+  switch (code) {\r
+    case CONFREQ:\r
+      fsm_rconfreq(f, id, inp, len);\r
+      break;\r
+    \r
+    case CONFACK:\r
+      fsm_rconfack(f, id, inp, len);\r
+      break;\r
+    \r
+    case CONFNAK:\r
+    case CONFREJ:\r
+      fsm_rconfnakrej(f, code, id, inp, len);\r
+      break;\r
+    \r
+    case TERMREQ:\r
+      fsm_rtermreq(f, id, inp, len);\r
+      break;\r
+    \r
+    case TERMACK:\r
+      fsm_rtermack(f);\r
+      break;\r
+    \r
+    case CODEREJ:\r
+      fsm_rcoderej(f, inp, len);\r
+      break;\r
+    \r
+    default:\r
+      if( !f->callbacks->extcode ||\r
+          !(*f->callbacks->extcode)(f, code, id, inp, len) ) {\r
+        fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN);\r
+      }\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_protreject - Peer doesn't speak this protocol.\r
+ *\r
+ * Treat this as a catastrophic error (RXJ-).\r
+ */\r
+void\r
+fsm_protreject(fsm *f)\r
+{\r
+  switch( f->state ) {\r
+    case LS_CLOSING:\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      /* fall through */\r
+    case LS_CLOSED:\r
+      f->state = LS_CLOSED;\r
+      if( f->callbacks->finished ) {\r
+        (*f->callbacks->finished)(f);\r
+      }\r
+      break;\r
+\r
+    case LS_STOPPING:\r
+    case LS_REQSENT:\r
+    case LS_ACKRCVD:\r
+    case LS_ACKSENT:\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      /* fall through */\r
+    case LS_STOPPED:\r
+      f->state = LS_STOPPED;\r
+      if( f->callbacks->finished ) {\r
+        (*f->callbacks->finished)(f);\r
+      }\r
+      break;\r
+    \r
+    case LS_OPENED:\r
+      if( f->callbacks->down ) {\r
+        (*f->callbacks->down)(f);\r
+      }\r
+      /* Init restart counter, send Terminate-Request */\r
+      f->retransmits = f->maxtermtransmits;\r
+      fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+            (u_char *) f->term_reason, f->term_reason_len);\r
+      TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+      --f->retransmits;\r
+      \r
+      f->state = LS_STOPPING;\r
+      break;\r
+    \r
+    default:\r
+      FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n",\r
+            PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+    }\r
+}\r
+\r
+\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+\r
+/*\r
+ * fsm_timeout - Timeout expired.\r
+ */\r
+static void\r
+fsm_timeout(void *arg)\r
+{\r
+  fsm *f = (fsm *) arg;\r
+\r
+  switch (f->state) {\r
+    case LS_CLOSING:\r
+    case LS_STOPPING:\r
+      if( f->retransmits <= 0 ) {\r
+        FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n",\r
+             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+        /*\r
+         * We've waited for an ack long enough.  Peer probably heard us.\r
+         */\r
+        f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED;\r
+        if( f->callbacks->finished ) {\r
+          (*f->callbacks->finished)(f);\r
+        }\r
+      } else {\r
+        FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n",\r
+             PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+        /* Send Terminate-Request */\r
+        fsm_sdata(f, TERMREQ, f->reqid = ++f->id,\r
+            (u_char *) f->term_reason, f->term_reason_len);\r
+        TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+        --f->retransmits;\r
+      }\r
+      break;\r
+\r
+    case LS_REQSENT:\r
+    case LS_ACKRCVD:\r
+    case LS_ACKSENT:\r
+      if (f->retransmits <= 0) {\r
+        FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n",\r
+         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+        f->state = LS_STOPPED;\r
+        if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) {\r
+          (*f->callbacks->finished)(f);\r
+        }\r
+      } else {\r
+        FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n",\r
+         PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+        /* Retransmit the configure-request */\r
+        if (f->callbacks->retransmit) {\r
+          (*f->callbacks->retransmit)(f);\r
+        }\r
+        fsm_sconfreq(f, 1);    /* Re-send Configure-Request */\r
+        if( f->state == LS_ACKRCVD ) {\r
+          f->state = LS_REQSENT;\r
+        }\r
+      }\r
+      break;\r
+\r
+    default:\r
+      FSMDEBUG((LOG_INFO, "%s: Timeout event in state %d (%s)!\n",\r
+          PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfreq - Receive Configure-Request.\r
+ */\r
+static void\r
+fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len)\r
+{\r
+  int code, reject_if_disagree;\r
+\r
+  FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", \r
+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));\r
+  switch( f->state ) {\r
+    case LS_CLOSED:\r
+      /* Go away, we're closed */\r
+      fsm_sdata(f, TERMACK, id, NULL, 0);\r
+      return;\r
+    case LS_CLOSING:\r
+    case LS_STOPPING:\r
+      return;\r
+\r
+    case LS_OPENED:\r
+      /* Go down and restart negotiation */\r
+      if( f->callbacks->down ) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers */\r
+      }\r
+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */\r
+      break;\r
+\r
+    case LS_STOPPED:\r
+      /* Negotiation started by our peer */\r
+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */\r
+      f->state = LS_REQSENT;\r
+      break;\r
+  }\r
+  \r
+  /*\r
+  * Pass the requested configuration options\r
+  * to protocol-specific code for checking.\r
+  */\r
+  if (f->callbacks->reqci) {    /* Check CI */\r
+    reject_if_disagree = (f->nakloops >= f->maxnakloops);\r
+    code = (*f->callbacks->reqci)(f, inp, &len, reject_if_disagree);\r
+  } else if (len) {\r
+    code = CONFREJ;      /* Reject all CI */\r
+  } else {\r
+    code = CONFACK;\r
+  }\r
+  \r
+  /* send the Ack, Nak or Rej to the peer */\r
+  fsm_sdata(f, (u_char)code, id, inp, len);\r
+  \r
+  if (code == CONFACK) {\r
+    if (f->state == LS_ACKRCVD) {\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      f->state = LS_OPENED;\r
+      if (f->callbacks->up) {\r
+        (*f->callbacks->up)(f);  /* Inform upper layers */\r
+      }\r
+    } else {\r
+      f->state = LS_ACKSENT;\r
+    }\r
+    f->nakloops = 0;\r
+  } else {\r
+    /* we sent CONFACK or CONFREJ */\r
+    if (f->state != LS_ACKRCVD) {\r
+      f->state = LS_REQSENT;\r
+    }\r
+    if( code == CONFNAK ) {\r
+      ++f->nakloops;\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfack - Receive Configure-Ack.\r
+ */\r
+static void\r
+fsm_rconfack(fsm *f, int id, u_char *inp, int len)\r
+{\r
+  FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n",\r
+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));\r
+  \r
+  if (id != f->reqid || f->seen_ack) {   /* Expected id? */\r
+    return; /* Nope, toss... */\r
+  }\r
+  if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) {\r
+    /* Ack is bad - ignore it */\r
+    FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n",\r
+          PROTO_NAME(f), len));\r
+    return;\r
+  }\r
+  f->seen_ack = 1;\r
+  \r
+  switch (f->state) {\r
+    case LS_CLOSED:\r
+    case LS_STOPPED:\r
+      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+      break;\r
+    \r
+    case LS_REQSENT:\r
+      f->state = LS_ACKRCVD;\r
+      f->retransmits = f->maxconfreqtransmits;\r
+      break;\r
+    \r
+    case LS_ACKRCVD:\r
+      /* Huh? an extra valid Ack? oh well... */\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      fsm_sconfreq(f, 0);\r
+      f->state = LS_REQSENT;\r
+      break;\r
+    \r
+    case LS_ACKSENT:\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      f->state = LS_OPENED;\r
+      f->retransmits = f->maxconfreqtransmits;\r
+      if (f->callbacks->up) {\r
+        (*f->callbacks->up)(f);  /* Inform upper layers */\r
+      }\r
+      break;\r
+    \r
+    case LS_OPENED:\r
+      /* Go down and restart negotiation */\r
+      if (f->callbacks->down) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers */\r
+      }\r
+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */\r
+      f->state = LS_REQSENT;\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rconfnakrej - Receive Configure-Nak or Configure-Reject.\r
+ */\r
+static void\r
+fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len)\r
+{\r
+  int (*proc) (fsm *, u_char *, int);\r
+  int ret;\r
+\r
+  FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n",\r
+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));\r
+\r
+  if (id != f->reqid || f->seen_ack) { /* Expected id? */\r
+    return;        /* Nope, toss... */\r
+  }\r
+  proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci;\r
+  if (!proc || !((ret = proc(f, inp, len)))) {\r
+    /* Nak/reject is bad - ignore it */\r
+    FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n",\r
+          PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len));\r
+    return;\r
+  }\r
+  f->seen_ack = 1;\r
+\r
+  switch (f->state) {\r
+    case LS_CLOSED:\r
+    case LS_STOPPED:\r
+      fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+      break;\r
+    \r
+    case LS_REQSENT:\r
+    case LS_ACKSENT:\r
+      /* They didn't agree to what we wanted - try another request */\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      if (ret < 0) {\r
+        f->state = LS_STOPPED;    /* kludge for stopping CCP */\r
+      } else {\r
+        fsm_sconfreq(f, 0);    /* Send Configure-Request */\r
+      }\r
+      break;\r
+    \r
+    case LS_ACKRCVD:\r
+      /* Got a Nak/reject when we had already had an Ack?? oh well... */\r
+      UNTIMEOUT(fsm_timeout, f);  /* Cancel timeout */\r
+      fsm_sconfreq(f, 0);\r
+      f->state = LS_REQSENT;\r
+      break;\r
+    \r
+    case LS_OPENED:\r
+      /* Go down and restart negotiation */\r
+      if (f->callbacks->down) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers */\r
+      }\r
+      fsm_sconfreq(f, 0);    /* Send initial Configure-Request */\r
+      f->state = LS_REQSENT;\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rtermreq - Receive Terminate-Req.\r
+ */\r
+static void\r
+fsm_rtermreq(fsm *f, int id, u_char *p, int len)\r
+{\r
+  LWIP_UNUSED_ARG(p);\r
+\r
+  FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n",\r
+        PROTO_NAME(f), id, f->state, ppperr_strerr[f->state]));\r
+\r
+  switch (f->state) {\r
+    case LS_ACKRCVD:\r
+    case LS_ACKSENT:\r
+      f->state = LS_REQSENT;    /* Start over but keep trying */\r
+      break;\r
+\r
+    case LS_OPENED:\r
+      if (len > 0) {\r
+        FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p));\r
+      } else {\r
+        FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f)));\r
+      }\r
+      if (f->callbacks->down) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers */\r
+      }\r
+      f->retransmits = 0;\r
+      f->state = LS_STOPPING;\r
+      TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+      break;\r
+  }\r
+\r
+  fsm_sdata(f, TERMACK, (u_char)id, NULL, 0);\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rtermack - Receive Terminate-Ack.\r
+ */\r
+static void\r
+fsm_rtermack(fsm *f)\r
+{\r
+  FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n", \r
+        PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+  \r
+  switch (f->state) {\r
+    case LS_CLOSING:\r
+      UNTIMEOUT(fsm_timeout, f);\r
+      f->state = LS_CLOSED;\r
+      if( f->callbacks->finished ) {\r
+        (*f->callbacks->finished)(f);\r
+      }\r
+      break;\r
+\r
+    case LS_STOPPING:\r
+      UNTIMEOUT(fsm_timeout, f);\r
+      f->state = LS_STOPPED;\r
+      if( f->callbacks->finished ) {\r
+        (*f->callbacks->finished)(f);\r
+      }\r
+      break;\r
+    \r
+    case LS_ACKRCVD:\r
+      f->state = LS_REQSENT;\r
+      break;\r
+    \r
+    case LS_OPENED:\r
+      if (f->callbacks->down) {\r
+        (*f->callbacks->down)(f);  /* Inform upper layers */\r
+      }\r
+      fsm_sconfreq(f, 0);\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_rcoderej - Receive an Code-Reject.\r
+ */\r
+static void\r
+fsm_rcoderej(fsm *f, u_char *inp, int len)\r
+{\r
+  u_char code, id;\r
+  \r
+  FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n", \r
+        PROTO_NAME(f), f->state, ppperr_strerr[f->state]));\r
+  \r
+  if (len < HEADERLEN) {\r
+    FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n"));\r
+    return;\r
+  }\r
+  GETCHAR(code, inp);\r
+  GETCHAR(id, inp);\r
+  FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n",\r
+        PROTO_NAME(f), code, id));\r
+  \r
+  if( f->state == LS_ACKRCVD ) {\r
+    f->state = LS_REQSENT;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * fsm_sconfreq - Send a Configure-Request.\r
+ */\r
+static void\r
+fsm_sconfreq(fsm *f, int retransmit)\r
+{\r
+  u_char *outp;\r
+  int cilen;\r
+  \r
+  if( f->state != LS_REQSENT && f->state != LS_ACKRCVD && f->state != LS_ACKSENT ) {\r
+    /* Not currently negotiating - reset options */\r
+    if( f->callbacks->resetci ) {\r
+      (*f->callbacks->resetci)(f);\r
+    }\r
+    f->nakloops = 0;\r
+  }\r
+  \r
+  if( !retransmit ) {\r
+    /* New request - reset retransmission counter, use new ID */\r
+    f->retransmits = f->maxconfreqtransmits;\r
+    f->reqid = ++f->id;\r
+  }\r
+  \r
+  f->seen_ack = 0;\r
+  \r
+  /*\r
+   * Make up the request packet\r
+   */\r
+  outp = outpacket_buf[f->unit] + PPP_HDRLEN + HEADERLEN;\r
+  if( f->callbacks->cilen && f->callbacks->addci ) {\r
+    cilen = (*f->callbacks->cilen)(f);\r
+    if( cilen > peer_mru[f->unit] - (int)HEADERLEN ) {\r
+      cilen = peer_mru[f->unit] - HEADERLEN;\r
+    }\r
+    if (f->callbacks->addci) {\r
+      (*f->callbacks->addci)(f, outp, &cilen);\r
+    }\r
+  } else {\r
+    cilen = 0;\r
+  }\r
+\r
+  /* send the request to our peer */\r
+  fsm_sdata(f, CONFREQ, f->reqid, outp, cilen);\r
+  \r
+  /* start the retransmit timer */\r
+  --f->retransmits;\r
+  TIMEOUT(fsm_timeout, f, f->timeouttime);\r
+  \r
+  FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n",\r
+        PROTO_NAME(f), f->reqid));\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/fsm.h
new file mode 100644 (file)
index 0000000..02af4ee
--- /dev/null
@@ -0,0 +1,169 @@
+/*****************************************************************************\r
+* fsm.h - Network Control Protocol Finite State Machine header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original based on BSD code.\r
+*****************************************************************************/\r
+/*\r
+ * fsm.h - {Link, IP} Control Protocol Finite State Machine definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $\r
+ */\r
+\r
+#ifndef FSM_H\r
+#define FSM_H\r
+\r
+/*****************************************************************************\r
+************************* PUBLIC DEFINITIONS *********************************\r
+*****************************************************************************/\r
+/*\r
+ * LCP Packet header = Code, id, length.\r
+ */\r
+#define HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))\r
+\r
+\r
+/*\r
+ *  CP (LCP, IPCP, etc.) codes.\r
+ */\r
+#define CONFREQ     1 /* Configuration Request */\r
+#define CONFACK     2 /* Configuration Ack */\r
+#define CONFNAK     3 /* Configuration Nak */\r
+#define CONFREJ     4 /* Configuration Reject */\r
+#define TERMREQ     5 /* Termination Request */\r
+#define TERMACK     6 /* Termination Ack */\r
+#define CODEREJ     7 /* Code Reject */\r
+\r
+/*\r
+ * Link states.\r
+ */\r
+#define LS_INITIAL  0 /* Down, hasn't been opened */\r
+#define LS_STARTING 1 /* Down, been opened */\r
+#define LS_CLOSED   2 /* Up, hasn't been opened */\r
+#define LS_STOPPED  3 /* Open, waiting for down event */\r
+#define LS_CLOSING  4 /* Terminating the connection, not open */\r
+#define LS_STOPPING 5 /* Terminating, but open */\r
+#define LS_REQSENT  6 /* We've sent a Config Request */\r
+#define LS_ACKRCVD  7 /* We've received a Config Ack */\r
+#define LS_ACKSENT  8 /* We've sent a Config Ack */\r
+#define LS_OPENED   9 /* Connection available */\r
+\r
+/*\r
+ * Flags - indicate options controlling FSM operation\r
+ */\r
+#define OPT_PASSIVE 1 /* Don't die if we don't get a response */\r
+#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */\r
+#define OPT_SILENT  4 /* Wait for peer to speak first */\r
+\r
+\r
+/*****************************************************************************\r
+************************* PUBLIC DATA TYPES **********************************\r
+*****************************************************************************/\r
+/*\r
+ * Each FSM is described by an fsm structure and fsm callbacks.\r
+ */\r
+typedef struct fsm {\r
+  int unit;                        /* Interface unit number */\r
+  u_short protocol;                /* Data Link Layer Protocol field value */\r
+  int state;                       /* State */\r
+  int flags;                       /* Contains option bits */\r
+  u_char id;                       /* Current id */\r
+  u_char reqid;                    /* Current request id */\r
+  u_char seen_ack;                 /* Have received valid Ack/Nak/Rej to Req */\r
+  int timeouttime;                 /* Timeout time in milliseconds */\r
+  int maxconfreqtransmits;         /* Maximum Configure-Request transmissions */\r
+  int retransmits;                 /* Number of retransmissions left */\r
+  int maxtermtransmits;            /* Maximum Terminate-Request transmissions */\r
+  int nakloops;                    /* Number of nak loops since last ack */\r
+  int maxnakloops;                 /* Maximum number of nak loops tolerated */\r
+  struct fsm_callbacks* callbacks; /* Callback routines */\r
+  char* term_reason;               /* Reason for closing protocol */\r
+  int term_reason_len;             /* Length of term_reason */\r
+} fsm;\r
+\r
+\r
+typedef struct fsm_callbacks {\r
+  void (*resetci)(fsm*);                            /* Reset our Configuration Information */\r
+  int  (*cilen)(fsm*);                              /* Length of our Configuration Information */\r
+  void (*addci)(fsm*, u_char*, int*);               /* Add our Configuration Information */\r
+  int  (*ackci)(fsm*, u_char*, int);                /* ACK our Configuration Information */\r
+  int  (*nakci)(fsm*, u_char*, int);                /* NAK our Configuration Information */\r
+  int  (*rejci)(fsm*, u_char*, int);                /* Reject our Configuration Information */\r
+  int  (*reqci)(fsm*, u_char*, int*, int);          /* Request peer's Configuration Information */\r
+  void (*up)(fsm*);                                 /* Called when fsm reaches LS_OPENED state */\r
+  void (*down)(fsm*);                               /* Called when fsm leaves LS_OPENED state */\r
+  void (*starting)(fsm*);                           /* Called when we want the lower layer */\r
+  void (*finished)(fsm*);                           /* Called when we don't want the lower layer */\r
+  void (*protreject)(int);                          /* Called when Protocol-Reject received */\r
+  void (*retransmit)(fsm*);                         /* Retransmission is necessary */\r
+  int  (*extcode)(fsm*, int, u_char, u_char*, int); /* Called when unknown code received */\r
+  char *proto_name;                                 /* String name for protocol (for messages) */\r
+} fsm_callbacks;\r
+\r
+\r
+/*****************************************************************************\r
+*********************** PUBLIC DATA STRUCTURES *******************************\r
+*****************************************************************************/\r
+/*\r
+ * Variables\r
+ */\r
+extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */\r
+\r
+\r
+/*****************************************************************************\r
+************************** PUBLIC FUNCTIONS **********************************\r
+*****************************************************************************/\r
+\r
+/*\r
+ * Prototypes\r
+ */\r
+void fsm_init (fsm*);\r
+void fsm_lowerup (fsm*);\r
+void fsm_lowerdown (fsm*);\r
+void fsm_open (fsm*);\r
+void fsm_close (fsm*, char*);\r
+void fsm_input (fsm*, u_char*, int);\r
+void fsm_protreject (fsm*);\r
+void fsm_sdata (fsm*, u_char, u_char, u_char*, int);\r
+\r
+#endif /* FSM_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.c
new file mode 100644 (file)
index 0000000..7567091
--- /dev/null
@@ -0,0 +1,1440 @@
+/*****************************************************************************\r
+* ipcp.c - Network PPP IP Control Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-08 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*****************************************************************************/\r
+/*\r
+ * ipcp.c - PPP IP Control Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "auth.h"\r
+#include "fsm.h"\r
+#include "vj.h"\r
+#include "ipcp.h"\r
+\r
+#include <string.h>\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+/* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */\r
+\r
+/*\r
+ * Lengths of configuration options.\r
+ */\r
+#define CILEN_VOID     2\r
+#define CILEN_COMPRESS 4  /* min length for compression protocol opt. */\r
+#define CILEN_VJ       6  /* length for RFC1332 Van-Jacobson opt. */\r
+#define CILEN_ADDR     6  /* new-style single address option */\r
+#define CILEN_ADDRS    10 /* old-style dual address option */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Callbacks for fsm code.  (CI = Configuration Information)\r
+ */\r
+static void ipcp_resetci (fsm *);                     /* Reset our CI */\r
+static int  ipcp_cilen (fsm *);                       /* Return length of our CI */\r
+static void ipcp_addci (fsm *, u_char *, int *);      /* Add our CI */\r
+static int  ipcp_ackci (fsm *, u_char *, int);        /* Peer ack'd our CI */\r
+static int  ipcp_nakci (fsm *, u_char *, int);        /* Peer nak'd our CI */\r
+static int  ipcp_rejci (fsm *, u_char *, int);        /* Peer rej'd our CI */\r
+static int  ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */\r
+static void ipcp_up (fsm *);                          /* We're UP */\r
+static void ipcp_down (fsm *);                        /* We're DOWN */\r
+#if 0\r
+static void ipcp_script (fsm *, char *); /* Run an up/down script */\r
+#endif\r
+static void ipcp_finished (fsm *);                    /* Don't need lower layer */\r
+\r
+/*\r
+ * Protocol entry points from main code.\r
+ */\r
+static void ipcp_init (int);\r
+static void ipcp_open (int);\r
+static void ipcp_close (int, char *);\r
+static void ipcp_lowerup (int);\r
+static void ipcp_lowerdown (int);\r
+static void ipcp_input (int, u_char *, int);\r
+static void ipcp_protrej (int);\r
+\r
+static void ipcp_clear_addrs (int);\r
+\r
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : \\r
+                     (x) == CONFNAK ? "NAK" : "REJ")\r
+\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+/* global vars */\r
+ipcp_options ipcp_wantoptions[NUM_PPP];  /* Options that we want to request */\r
+ipcp_options ipcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */\r
+ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */\r
+ipcp_options ipcp_hisoptions[NUM_PPP];   /* Options that we ack'd */\r
+\r
+fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */\r
+\r
+struct protent ipcp_protent = {\r
+  PPP_IPCP,\r
+  ipcp_init,\r
+  ipcp_input,\r
+  ipcp_protrej,\r
+  ipcp_lowerup,\r
+  ipcp_lowerdown,\r
+  ipcp_open,\r
+  ipcp_close,\r
+#if 0\r
+  ipcp_printpkt,\r
+  NULL,\r
+#endif\r
+  1,\r
+  "IPCP",\r
+#if 0\r
+  ip_check_options,\r
+  NULL,\r
+  ip_active_pkt\r
+#endif\r
+};\r
+\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+/* local vars */\r
+static int cis_received[NUM_PPP];      /* # Conf-Reqs received */\r
+static int default_route_set[NUM_PPP]; /* Have set up a default route */\r
+\r
+static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */\r
+  ipcp_resetci,  /* Reset our Configuration Information */\r
+  ipcp_cilen,    /* Length of our Configuration Information */\r
+  ipcp_addci,    /* Add our Configuration Information */\r
+  ipcp_ackci,    /* ACK our Configuration Information */\r
+  ipcp_nakci,    /* NAK our Configuration Information */\r
+  ipcp_rejci,    /* Reject our Configuration Information */\r
+  ipcp_reqci,    /* Request peer's Configuration Information */\r
+  ipcp_up,       /* Called when fsm reaches LS_OPENED state */\r
+  ipcp_down,     /* Called when fsm leaves LS_OPENED state */\r
+  NULL,          /* Called when we want the lower layer up */\r
+  ipcp_finished, /* Called when we want the lower layer down */\r
+  NULL,          /* Called when Protocol-Reject received */\r
+  NULL,          /* Retransmission is necessary */\r
+  NULL,          /* Called to handle protocol-specific codes */\r
+  "IPCP"         /* String name of protocol */\r
+};\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+\r
+/*\r
+ * Non-standard inet_ntoa left here for compat with original ppp\r
+ * sources. Assumes u32_t instead of struct in_addr.\r
+ */ \r
+\r
+char *\r
+_inet_ntoa(u32_t n)\r
+{\r
+  struct in_addr ia;\r
+  ia.s_addr = n;\r
+  return inet_ntoa(ia);\r
+}\r
+\r
+#define inet_ntoa _inet_ntoa\r
+\r
+/*\r
+ * ipcp_init - Initialize IPCP.\r
+ */\r
+static void\r
+ipcp_init(int unit)\r
+{\r
+  fsm           *f = &ipcp_fsm[unit];\r
+  ipcp_options *wo = &ipcp_wantoptions[unit];\r
+  ipcp_options *ao = &ipcp_allowoptions[unit];\r
+\r
+  f->unit      = unit;\r
+  f->protocol  = PPP_IPCP;\r
+  f->callbacks = &ipcp_callbacks;\r
+  fsm_init(&ipcp_fsm[unit]);\r
+\r
+  memset(wo, 0, sizeof(*wo));\r
+  memset(ao, 0, sizeof(*ao));\r
+\r
+  wo->neg_addr      = 1;\r
+  wo->ouraddr       = 0;\r
+#if VJ_SUPPORT\r
+  wo->neg_vj        = 1;\r
+#else  /* VJ_SUPPORT */\r
+  wo->neg_vj        = 0;\r
+#endif /* VJ_SUPPORT */\r
+  wo->vj_protocol   = IPCP_VJ_COMP;\r
+  wo->maxslotindex  = MAX_SLOTS - 1;\r
+  wo->cflag         = 0;\r
+  wo->default_route = 1;\r
+\r
+  ao->neg_addr      = 1;\r
+#if VJ_SUPPORT\r
+  ao->neg_vj        = 1;\r
+#else  /* VJ_SUPPORT */\r
+  ao->neg_vj        = 0;\r
+#endif /* VJ_SUPPORT */\r
+  ao->maxslotindex  = MAX_SLOTS - 1;\r
+  ao->cflag         = 1;\r
+  ao->default_route = 1;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_open - IPCP is allowed to come up.\r
+ */\r
+static void\r
+ipcp_open(int unit)\r
+{\r
+  fsm_open(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_close - Take IPCP down.\r
+ */\r
+static void\r
+ipcp_close(int unit, char *reason)\r
+{\r
+  fsm_close(&ipcp_fsm[unit], reason);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_lowerup - The lower layer is up.\r
+ */\r
+static void\r
+ipcp_lowerup(int unit)\r
+{\r
+  fsm_lowerup(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_lowerdown - The lower layer is down.\r
+ */\r
+static void\r
+ipcp_lowerdown(int unit)\r
+{\r
+  fsm_lowerdown(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_input - Input IPCP packet.\r
+ */\r
+static void\r
+ipcp_input(int unit, u_char *p, int len)\r
+{\r
+  fsm_input(&ipcp_fsm[unit], p, len);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_protrej - A Protocol-Reject was received for IPCP.\r
+ *\r
+ * Pretend the lower layer went down, so we shut up.\r
+ */\r
+static void\r
+ipcp_protrej(int unit)\r
+{\r
+  fsm_lowerdown(&ipcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_resetci - Reset our CI.\r
+ */\r
+static void\r
+ipcp_resetci(fsm *f)\r
+{\r
+  ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+  \r
+  wo->req_addr = wo->neg_addr && ipcp_allowoptions[f->unit].neg_addr;\r
+  if (wo->ouraddr == 0) {\r
+    wo->accept_local = 1;\r
+  }\r
+  if (wo->hisaddr == 0) {\r
+    wo->accept_remote = 1;\r
+  }\r
+  /* Request DNS addresses from the peer */\r
+  wo->req_dns1 = ppp_settings.usepeerdns;\r
+  wo->req_dns2 = ppp_settings.usepeerdns;\r
+  ipcp_gotoptions[f->unit] = *wo;\r
+  cis_received[f->unit] = 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_cilen - Return length of our CI.\r
+ */\r
+static int\r
+ipcp_cilen(fsm *f)\r
+{\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+  ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+\r
+#define LENCIVJ(neg, old)   (neg ? (old? CILEN_COMPRESS : CILEN_VJ) : 0)\r
+#define LENCIADDR(neg, old) (neg ? (old? CILEN_ADDRS : CILEN_ADDR) : 0)\r
+#define LENCIDNS(neg)       (neg ? (CILEN_ADDR) : 0)\r
+\r
+  /*\r
+   * First see if we want to change our options to the old\r
+   * forms because we have received old forms from the peer.\r
+   */\r
+  if (wo->neg_addr && !go->neg_addr && !go->old_addrs) {\r
+    /* use the old style of address negotiation */\r
+    go->neg_addr = 1;\r
+    go->old_addrs = 1;\r
+  }\r
+  if (wo->neg_vj && !go->neg_vj && !go->old_vj) {\r
+    /* try an older style of VJ negotiation */\r
+    if (cis_received[f->unit] == 0) {\r
+      /* keep trying the new style until we see some CI from the peer */\r
+      go->neg_vj = 1;\r
+    } else {\r
+      /* use the old style only if the peer did */\r
+      if (ho->neg_vj && ho->old_vj) {\r
+        go->neg_vj = 1;\r
+        go->old_vj = 1;\r
+        go->vj_protocol = ho->vj_protocol;\r
+      }\r
+    }\r
+  }\r
+\r
+  return (LENCIADDR(go->neg_addr, go->old_addrs) +\r
+          LENCIVJ(go->neg_vj, go->old_vj) +\r
+          LENCIDNS(go->req_dns1) +\r
+          LENCIDNS(go->req_dns2));\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_addci - Add our desired CIs to a packet.\r
+ */\r
+static void\r
+ipcp_addci(fsm *f, u_char *ucp, int *lenp)\r
+{\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  int len = *lenp;\r
+\r
+#define ADDCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
+  if (neg) { \\r
+    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
+    if (len >= vjlen) { \\r
+      PUTCHAR(opt, ucp); \\r
+      PUTCHAR(vjlen, ucp); \\r
+      PUTSHORT(val, ucp); \\r
+      if (!old) { \\r
+        PUTCHAR(maxslotindex, ucp); \\r
+        PUTCHAR(cflag, ucp); \\r
+      } \\r
+      len -= vjlen; \\r
+    } else { \\r
+      neg = 0; \\r
+    } \\r
+  }\r
+\r
+#define ADDCIADDR(opt, neg, old, val1, val2) \\r
+  if (neg) { \\r
+    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
+    if (len >= addrlen) { \\r
+      u32_t l; \\r
+      PUTCHAR(opt, ucp); \\r
+      PUTCHAR(addrlen, ucp); \\r
+      l = ntohl(val1); \\r
+      PUTLONG(l, ucp); \\r
+      if (old) { \\r
+        l = ntohl(val2); \\r
+        PUTLONG(l, ucp); \\r
+      } \\r
+      len -= addrlen; \\r
+    } else { \\r
+      neg = 0; \\r
+    } \\r
+  }\r
+\r
+#define ADDCIDNS(opt, neg, addr) \\r
+  if (neg) { \\r
+    if (len >= CILEN_ADDR) { \\r
+      u32_t l; \\r
+      PUTCHAR(opt, ucp); \\r
+      PUTCHAR(CILEN_ADDR, ucp); \\r
+      l = ntohl(addr); \\r
+      PUTLONG(l, ucp); \\r
+      len -= CILEN_ADDR; \\r
+    } else { \\r
+      neg = 0; \\r
+    } \\r
+  }\r
+\r
+  ADDCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
+      go->old_addrs, go->ouraddr, go->hisaddr);\r
+\r
+  ADDCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
+      go->maxslotindex, go->cflag);\r
+\r
+  ADDCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
+\r
+  ADDCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
+\r
+  *lenp -= len;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_ackci - Ack our CIs.\r
+ *\r
+ * Returns:\r
+ *  0 - Ack was bad.\r
+ *  1 - Ack was good.\r
+ */\r
+static int\r
+ipcp_ackci(fsm *f, u_char *p, int len)\r
+{\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  u_short cilen, citype, cishort;\r
+  u32_t cilong;\r
+  u_char cimaxslotindex, cicflag;\r
+\r
+  /*\r
+   * CIs must be in exactly the same order that we sent...\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+\r
+#define ACKCIVJ(opt, neg, val, old, maxslotindex, cflag) \\r
+  if (neg) { \\r
+    int vjlen = old? CILEN_COMPRESS : CILEN_VJ; \\r
+    if ((len -= vjlen) < 0) { \\r
+      goto bad; \\r
+    } \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != vjlen || \\r
+        citype != opt) { \\r
+      goto bad; \\r
+    } \\r
+    GETSHORT(cishort, p); \\r
+    if (cishort != val) { \\r
+      goto bad; \\r
+    } \\r
+    if (!old) { \\r
+      GETCHAR(cimaxslotindex, p); \\r
+      if (cimaxslotindex != maxslotindex) { \\r
+        goto bad; \\r
+      } \\r
+      GETCHAR(cicflag, p); \\r
+      if (cicflag != cflag) { \\r
+        goto bad; \\r
+      } \\r
+    } \\r
+  }\r
+  \r
+#define ACKCIADDR(opt, neg, old, val1, val2) \\r
+  if (neg) { \\r
+    int addrlen = (old? CILEN_ADDRS: CILEN_ADDR); \\r
+    u32_t l; \\r
+    if ((len -= addrlen) < 0) { \\r
+      goto bad; \\r
+    } \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != addrlen || \\r
+        citype != opt) { \\r
+      goto bad; \\r
+    } \\r
+    GETLONG(l, p); \\r
+    cilong = htonl(l); \\r
+    if (val1 != cilong) { \\r
+      goto bad; \\r
+    } \\r
+    if (old) { \\r
+      GETLONG(l, p); \\r
+      cilong = htonl(l); \\r
+      if (val2 != cilong) { \\r
+        goto bad; \\r
+      } \\r
+    } \\r
+  }\r
+\r
+#define ACKCIDNS(opt, neg, addr) \\r
+  if (neg) { \\r
+    u32_t l; \\r
+    if ((len -= CILEN_ADDR) < 0) { \\r
+      goto bad; \\r
+    } \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_ADDR || \\r
+        citype != opt) { \\r
+      goto bad; \\r
+    } \\r
+    GETLONG(l, p); \\r
+    cilong = htonl(l); \\r
+    if (addr != cilong) { \\r
+      goto bad; \\r
+    } \\r
+  }\r
+\r
+  ACKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), go->neg_addr,\r
+        go->old_addrs, go->ouraddr, go->hisaddr);\r
+\r
+  ACKCIVJ(CI_COMPRESSTYPE, go->neg_vj, go->vj_protocol, go->old_vj,\r
+      go->maxslotindex, go->cflag);\r
+\r
+  ACKCIDNS(CI_MS_DNS1, go->req_dns1, go->dnsaddr[0]);\r
+\r
+  ACKCIDNS(CI_MS_DNS2, go->req_dns2, go->dnsaddr[1]);\r
+\r
+  /*\r
+   * If there are any remaining CIs, then this packet is bad.\r
+   */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+  return (1);\r
+  \r
+bad:\r
+  IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n"));\r
+  return (0);\r
+}\r
+\r
+/*\r
+ * ipcp_nakci - Peer has sent a NAK for some of our CIs.\r
+ * This should not modify any state if the Nak is bad\r
+ * or if IPCP is in the LS_OPENED state.\r
+ *\r
+ * Returns:\r
+ *  0 - Nak was bad.\r
+ *  1 - Nak was good.\r
+ */\r
+static int\r
+ipcp_nakci(fsm *f, u_char *p, int len)\r
+{\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  u_char cimaxslotindex, cicflag;\r
+  u_char citype, cilen, *next;\r
+  u_short cishort;\r
+  u32_t ciaddr1, ciaddr2, l, cidnsaddr;\r
+  ipcp_options no;    /* options we've seen Naks for */\r
+  ipcp_options try;    /* options to request next time */\r
+\r
+  BZERO(&no, sizeof(no));\r
+  try = *go;\r
+\r
+  /*\r
+   * Any Nak'd CIs must be in exactly the same order that we sent.\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+#define NAKCIADDR(opt, neg, old, code) \\r
+  if (go->neg && \\r
+      len >= (cilen = (old? CILEN_ADDRS: CILEN_ADDR)) && \\r
+      p[1] == cilen && \\r
+      p[0] == opt) { \\r
+    len -= cilen; \\r
+    INCPTR(2, p); \\r
+    GETLONG(l, p); \\r
+    ciaddr1 = htonl(l); \\r
+    if (old) { \\r
+      GETLONG(l, p); \\r
+      ciaddr2 = htonl(l); \\r
+      no.old_addrs = 1; \\r
+    } else { \\r
+      ciaddr2 = 0; \\r
+    } \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+\r
+#define NAKCIVJ(opt, neg, code) \\r
+  if (go->neg && \\r
+      ((cilen = p[1]) == CILEN_COMPRESS || cilen == CILEN_VJ) && \\r
+      len >= cilen && \\r
+      p[0] == opt) { \\r
+    len -= cilen; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+  \r
+#define NAKCIDNS(opt, neg, code) \\r
+  if (go->neg && \\r
+      ((cilen = p[1]) == CILEN_ADDR) && \\r
+      len >= cilen && \\r
+      p[0] == opt) { \\r
+    len -= cilen; \\r
+    INCPTR(2, p); \\r
+    GETLONG(l, p); \\r
+    cidnsaddr = htonl(l); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+\r
+  /*\r
+   * Accept the peer's idea of {our,his} address, if different\r
+   * from our idea, only if the accept_{local,remote} flag is set.\r
+   */\r
+  NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs,\r
+    if (go->accept_local && ciaddr1) { /* Do we know our address? */\r
+      try.ouraddr = ciaddr1;\r
+      IPCPDEBUG((LOG_INFO, "local IP address %s\n",\r
+           inet_ntoa(ciaddr1)));\r
+    }\r
+    if (go->accept_remote && ciaddr2) { /* Does he know his? */\r
+      try.hisaddr = ciaddr2;\r
+      IPCPDEBUG((LOG_INFO, "remote IP address %s\n",\r
+           inet_ntoa(ciaddr2)));\r
+    }\r
+  );\r
+\r
+  /*\r
+   * Accept the peer's value of maxslotindex provided that it\r
+   * is less than what we asked for.  Turn off slot-ID compression\r
+   * if the peer wants.  Send old-style compress-type option if\r
+   * the peer wants.\r
+   */\r
+  NAKCIVJ(CI_COMPRESSTYPE, neg_vj,\r
+    if (cilen == CILEN_VJ) {\r
+      GETCHAR(cimaxslotindex, p);\r
+      GETCHAR(cicflag, p);\r
+      if (cishort == IPCP_VJ_COMP) {\r
+        try.old_vj = 0;\r
+        if (cimaxslotindex < go->maxslotindex) {\r
+          try.maxslotindex = cimaxslotindex;\r
+        }\r
+        if (!cicflag) {\r
+          try.cflag = 0;\r
+        }\r
+      } else {\r
+        try.neg_vj = 0;\r
+      }\r
+    } else {\r
+      if (cishort == IPCP_VJ_COMP || cishort == IPCP_VJ_COMP_OLD) {\r
+        try.old_vj = 1;\r
+        try.vj_protocol = cishort;\r
+      } else {\r
+        try.neg_vj = 0;\r
+      }\r
+    }\r
+  );\r
+\r
+  NAKCIDNS(CI_MS_DNS1, req_dns1,\r
+      try.dnsaddr[0] = cidnsaddr;\r
+        IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
+      );\r
+\r
+  NAKCIDNS(CI_MS_DNS2, req_dns2,\r
+      try.dnsaddr[1] = cidnsaddr;\r
+        IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr)));\r
+      );\r
+\r
+  /*\r
+  * There may be remaining CIs, if the peer is requesting negotiation\r
+  * on an option that we didn't include in our request packet.\r
+  * If they want to negotiate about IP addresses, we comply.\r
+  * If they want us to ask for compression, we refuse.\r
+  */\r
+  while (len > CILEN_VOID) {\r
+    GETCHAR(citype, p);\r
+    GETCHAR(cilen, p);\r
+    if( (len -= cilen) < 0 ) {\r
+      goto bad;\r
+    }\r
+    next = p + cilen - 2;\r
+\r
+    switch (citype) {\r
+      case CI_COMPRESSTYPE:\r
+        if (go->neg_vj || no.neg_vj ||\r
+            (cilen != CILEN_VJ && cilen != CILEN_COMPRESS)) {\r
+          goto bad;\r
+        }\r
+        no.neg_vj = 1;\r
+        break;\r
+      case CI_ADDRS:\r
+        if ((go->neg_addr && go->old_addrs) || no.old_addrs\r
+            || cilen != CILEN_ADDRS) {\r
+          goto bad;\r
+        }\r
+        try.neg_addr = 1;\r
+        try.old_addrs = 1;\r
+        GETLONG(l, p);\r
+        ciaddr1 = htonl(l);\r
+        if (ciaddr1 && go->accept_local) {\r
+          try.ouraddr = ciaddr1;\r
+        }\r
+        GETLONG(l, p);\r
+        ciaddr2 = htonl(l);\r
+        if (ciaddr2 && go->accept_remote) {\r
+          try.hisaddr = ciaddr2;\r
+        }\r
+        no.old_addrs = 1;\r
+        break;\r
+      case CI_ADDR:\r
+        if (go->neg_addr || no.neg_addr || cilen != CILEN_ADDR) {\r
+          goto bad;\r
+        }\r
+        try.old_addrs = 0;\r
+        GETLONG(l, p);\r
+        ciaddr1 = htonl(l);\r
+        if (ciaddr1 && go->accept_local) {\r
+          try.ouraddr = ciaddr1;\r
+        }\r
+        if (try.ouraddr != 0) {\r
+          try.neg_addr = 1;\r
+        }\r
+        no.neg_addr = 1;\r
+        break;\r
+    }\r
+    p = next;\r
+  }\r
+\r
+  /* If there is still anything left, this packet is bad. */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+\r
+  /*\r
+   * OK, the Nak is good.  Now we can update state.\r
+   */\r
+  if (f->state != LS_OPENED) {\r
+    *go = try;\r
+  }\r
+\r
+  return 1;\r
+\r
+bad:\r
+  IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n"));\r
+  return 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_rejci - Reject some of our CIs.\r
+ */\r
+static int\r
+ipcp_rejci(fsm *f, u_char *p, int len)\r
+{\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  u_char cimaxslotindex, ciflag, cilen;\r
+  u_short cishort;\r
+  u32_t cilong;\r
+  ipcp_options try;    /* options to request next time */\r
+\r
+  try = *go;\r
+  /*\r
+   * Any Rejected CIs must be in exactly the same order that we sent.\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+#define REJCIADDR(opt, neg, old, val1, val2) \\r
+  if (go->neg && \\r
+      len >= (cilen = old? CILEN_ADDRS: CILEN_ADDR) && \\r
+      p[1] == cilen && \\r
+      p[0] == opt) { \\r
+    u32_t l; \\r
+    len -= cilen; \\r
+    INCPTR(2, p); \\r
+    GETLONG(l, p); \\r
+    cilong = htonl(l); \\r
+    /* Check rejected value. */ \\r
+    if (cilong != val1) { \\r
+      goto bad; \\r
+    } \\r
+    if (old) { \\r
+      GETLONG(l, p); \\r
+      cilong = htonl(l); \\r
+      /* Check rejected value. */ \\r
+      if (cilong != val2) { \\r
+        goto bad; \\r
+      } \\r
+    } \\r
+    try.neg = 0; \\r
+  }\r
+\r
+#define REJCIVJ(opt, neg, val, old, maxslot, cflag) \\r
+  if (go->neg && \\r
+      p[1] == (old? CILEN_COMPRESS : CILEN_VJ) && \\r
+      len >= p[1] && \\r
+      p[0] == opt) { \\r
+    len -= p[1]; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    /* Check rejected value. */  \\r
+    if (cishort != val) { \\r
+      goto bad; \\r
+    } \\r
+    if (!old) { \\r
+      GETCHAR(cimaxslotindex, p); \\r
+      if (cimaxslotindex != maxslot) { \\r
+        goto bad; \\r
+      } \\r
+      GETCHAR(ciflag, p); \\r
+      if (ciflag != cflag) { \\r
+        goto bad; \\r
+      } \\r
+    } \\r
+    try.neg = 0; \\r
+  }\r
+\r
+#define REJCIDNS(opt, neg, dnsaddr) \\r
+  if (go->neg && \\r
+      ((cilen = p[1]) == CILEN_ADDR) && \\r
+      len >= cilen && \\r
+      p[0] == opt) { \\r
+    u32_t l; \\r
+    len -= cilen; \\r
+    INCPTR(2, p); \\r
+    GETLONG(l, p); \\r
+    cilong = htonl(l); \\r
+    /* Check rejected value. */ \\r
+    if (cilong != dnsaddr) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+  }\r
+\r
+  REJCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr,\r
+        go->old_addrs, go->ouraddr, go->hisaddr);\r
+\r
+  REJCIVJ(CI_COMPRESSTYPE, neg_vj, go->vj_protocol, go->old_vj,\r
+      go->maxslotindex, go->cflag);\r
+\r
+  REJCIDNS(CI_MS_DNS1, req_dns1, go->dnsaddr[0]);\r
+\r
+  REJCIDNS(CI_MS_DNS2, req_dns2, go->dnsaddr[1]);\r
+\r
+  /*\r
+   * If there are any remaining CIs, then this packet is bad.\r
+   */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+  /*\r
+   * Now we can update state.\r
+   */\r
+  if (f->state != LS_OPENED) {\r
+    *go = try;\r
+  }\r
+  return 1;\r
+\r
+bad:\r
+  IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n"));\r
+  return 0;\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_reqci - Check the peer's requested CIs and send appropriate response.\r
+ *\r
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified\r
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return\r
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.\r
+ */\r
+static int\r
+ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested CIs */,int reject_if_disagree)\r
+{\r
+  ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+  ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+  ipcp_options *ao = &ipcp_allowoptions[f->unit];\r
+#ifdef OLD_CI_ADDRS\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+#endif\r
+  u_char *cip, *next;     /* Pointer to current and next CIs */\r
+  u_short cilen, citype;  /* Parsed len, type */\r
+  u_short cishort;        /* Parsed short value */\r
+  u32_t tl, ciaddr1;      /* Parsed address values */\r
+#ifdef OLD_CI_ADDRS\r
+  u32_t ciaddr2;          /* Parsed address values */\r
+#endif\r
+  int rc = CONFACK;       /* Final packet return code */\r
+  int orc;                /* Individual option return code */\r
+  u_char *p;              /* Pointer to next char to parse */\r
+  u_char *ucp = inp;      /* Pointer to current output char */\r
+  int l = *len;           /* Length left */\r
+  u_char maxslotindex, cflag;\r
+  int d;\r
+\r
+  cis_received[f->unit] = 1;\r
+\r
+  /*\r
+   * Reset all his options.\r
+   */\r
+  BZERO(ho, sizeof(*ho));\r
+\r
+  /*\r
+   * Process all his options.\r
+   */\r
+  next = inp;\r
+  while (l) {\r
+    orc = CONFACK;       /* Assume success */\r
+    cip = p = next;      /* Remember begining of CI */\r
+    if (l < 2 ||         /* Not enough data for CI header or */\r
+        p[1] < 2 ||      /*  CI length too small or */\r
+        p[1] > l) {      /*  CI length too big? */\r
+      IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n"));\r
+      orc = CONFREJ;     /* Reject bad CI */\r
+      cilen = l;         /* Reject till end of packet */\r
+      l = 0;             /* Don't loop again */\r
+      goto endswitch;\r
+    }\r
+    GETCHAR(citype, p);  /* Parse CI type */\r
+    GETCHAR(cilen, p);   /* Parse CI length */\r
+    l -= cilen;          /* Adjust remaining length */\r
+    next += cilen;       /* Step to next CI */\r
+\r
+    switch (citype) {      /* Check CI type */\r
+#ifdef OLD_CI_ADDRS /* Need to save space... */\r
+      case CI_ADDRS:\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n"));\r
+        if (!ao->neg_addr ||\r
+            cilen != CILEN_ADDRS) {  /* Check CI length */\r
+          orc = CONFREJ;    /* Reject CI */\r
+          break;\r
+        }\r
+\r
+        /*\r
+         * If he has no address, or if we both have his address but\r
+         * disagree about it, then NAK it with our idea.\r
+         * In particular, if we don't know his address, but he does,\r
+         * then accept it.\r
+         */\r
+        GETLONG(tl, p);    /* Parse source address (his) */\r
+        ciaddr1 = htonl(tl);\r
+        IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1)));\r
+        if (ciaddr1 != wo->hisaddr\r
+            && (ciaddr1 == 0 || !wo->accept_remote)) {\r
+          orc = CONFNAK;\r
+          if (!reject_if_disagree) {\r
+            DECPTR(sizeof(u32_t), p);\r
+            tl = ntohl(wo->hisaddr);\r
+            PUTLONG(tl, p);\r
+          }\r
+        } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
+          /*\r
+           * If neither we nor he knows his address, reject the option.\r
+           */\r
+          orc = CONFREJ;\r
+          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */\r
+          break;\r
+        }\r
+\r
+        /*\r
+         * If he doesn't know our address, or if we both have our address\r
+         * but disagree about it, then NAK it with our idea.\r
+         */\r
+        GETLONG(tl, p);    /* Parse desination address (ours) */\r
+        ciaddr2 = htonl(tl);\r
+        IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2)));\r
+        if (ciaddr2 != wo->ouraddr) {\r
+          if (ciaddr2 == 0 || !wo->accept_local) {\r
+            orc = CONFNAK;\r
+            if (!reject_if_disagree) {\r
+              DECPTR(sizeof(u32_t), p);\r
+              tl = ntohl(wo->ouraddr);\r
+              PUTLONG(tl, p);\r
+            }\r
+          } else {\r
+            go->ouraddr = ciaddr2;  /* accept peer's idea */\r
+          }\r
+        }\r
+\r
+        ho->neg_addr = 1;\r
+        ho->old_addrs = 1;\r
+        ho->hisaddr = ciaddr1;\r
+        ho->ouraddr = ciaddr2;\r
+        break;\r
+#endif\r
+\r
+      case CI_ADDR:\r
+        if (!ao->neg_addr) {\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n"));\r
+          orc = CONFREJ;        /* Reject CI */\r
+          break;\r
+        } else if (cilen != CILEN_ADDR) {  /* Check CI length */\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n"));\r
+          orc = CONFREJ;        /* Reject CI */\r
+          break;\r
+        }\r
+\r
+        /*\r
+         * If he has no address, or if we both have his address but\r
+         * disagree about it, then NAK it with our idea.\r
+         * In particular, if we don't know his address, but he does,\r
+         * then accept it.\r
+         */\r
+        GETLONG(tl, p);  /* Parse source address (his) */\r
+        ciaddr1 = htonl(tl);\r
+        if (ciaddr1 != wo->hisaddr\r
+            && (ciaddr1 == 0 || !wo->accept_remote)) {\r
+          orc = CONFNAK;\r
+          if (!reject_if_disagree) {\r
+            DECPTR(sizeof(u32_t), p);\r
+            tl = ntohl(wo->hisaddr);\r
+            PUTLONG(tl, p);\r
+          }\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1)));\r
+        } else if (ciaddr1 == 0 && wo->hisaddr == 0) {\r
+          /*\r
+           * Don't ACK an address of 0.0.0.0 - reject it instead.\r
+           */\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1)));\r
+          orc = CONFREJ;\r
+          wo->req_addr = 0;  /* don't NAK with 0.0.0.0 later */\r
+          break;\r
+        }\r
+\r
+        ho->neg_addr = 1;\r
+        ho->hisaddr = ciaddr1;\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1)));\r
+        break;\r
+\r
+      case CI_MS_DNS1:\r
+      case CI_MS_DNS2:\r
+        /* Microsoft primary or secondary DNS request */\r
+        d = citype == CI_MS_DNS2;\r
+\r
+        /* If we do not have a DNS address then we cannot send it */\r
+        if (ao->dnsaddr[d] == 0 ||\r
+            cilen != CILEN_ADDR) {  /* Check CI length */\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1));\r
+          orc = CONFREJ;        /* Reject CI */\r
+          break;\r
+        }\r
+        GETLONG(tl, p);\r
+        if (htonl(tl) != ao->dnsaddr[d]) {\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n",\r
+                d+1, inet_ntoa(tl)));\r
+          DECPTR(sizeof(u32_t), p);\r
+          tl = ntohl(ao->dnsaddr[d]);\r
+          PUTLONG(tl, p);\r
+          orc = CONFNAK;\r
+        }\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1));\r
+        break;\r
+\r
+      case CI_MS_WINS1:\r
+      case CI_MS_WINS2:\r
+        /* Microsoft primary or secondary WINS request */\r
+        d = citype == CI_MS_WINS2;\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1));\r
+\r
+        /* If we do not have a DNS address then we cannot send it */\r
+        if (ao->winsaddr[d] == 0 ||\r
+          cilen != CILEN_ADDR) {  /* Check CI length */\r
+          orc = CONFREJ;      /* Reject CI */\r
+          break;\r
+        }\r
+        GETLONG(tl, p);\r
+        if (htonl(tl) != ao->winsaddr[d]) {\r
+          DECPTR(sizeof(u32_t), p);\r
+          tl = ntohl(ao->winsaddr[d]);\r
+          PUTLONG(tl, p);\r
+          orc = CONFNAK;\r
+        }\r
+        break;\r
+\r
+      case CI_COMPRESSTYPE:\r
+        if (!ao->neg_vj) {\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n"));\r
+          orc = CONFREJ;\r
+          break;\r
+        } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) {\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen));\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        GETSHORT(cishort, p);\r
+\r
+        if (!(cishort == IPCP_VJ_COMP ||\r
+            (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) {\r
+          IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort));\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+\r
+        ho->neg_vj = 1;\r
+        ho->vj_protocol = cishort;\r
+        if (cilen == CILEN_VJ) {\r
+          GETCHAR(maxslotindex, p);\r
+          if (maxslotindex > ao->maxslotindex) { \r
+            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex));\r
+            orc = CONFNAK;\r
+            if (!reject_if_disagree) {\r
+              DECPTR(1, p);\r
+              PUTCHAR(ao->maxslotindex, p);\r
+            }\r
+          }\r
+          GETCHAR(cflag, p);\r
+          if (cflag && !ao->cflag) {\r
+            IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag));\r
+            orc = CONFNAK;\r
+            if (!reject_if_disagree) {\r
+              DECPTR(1, p);\r
+              PUTCHAR(wo->cflag, p);\r
+            }\r
+          }\r
+          ho->maxslotindex = maxslotindex;\r
+          ho->cflag = cflag;\r
+        } else {\r
+          ho->old_vj = 1;\r
+          ho->maxslotindex = MAX_SLOTS - 1;\r
+          ho->cflag = 1;\r
+        }\r
+        IPCPDEBUG((LOG_INFO, \r
+              "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n",\r
+              ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag));\r
+        break;\r
+\r
+      default:\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype));\r
+        orc = CONFREJ;\r
+        break;\r
+    }\r
+\r
+endswitch:\r
+    if (orc == CONFACK &&    /* Good CI */\r
+        rc != CONFACK) {     /*  but prior CI wasnt? */\r
+      continue;              /* Don't send this one */\r
+    }\r
+\r
+    if (orc == CONFNAK) {    /* Nak this CI? */\r
+      if (reject_if_disagree) {  /* Getting fed up with sending NAKs? */\r
+        IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n"));\r
+        orc = CONFREJ;       /* Get tough if so */\r
+      } else {\r
+        if (rc == CONFREJ) { /* Rejecting prior CI? */\r
+          continue;          /* Don't send this one */\r
+        }\r
+        if (rc == CONFACK) { /* Ack'd all prior CIs? */\r
+          rc = CONFNAK;      /* Not anymore... */\r
+          ucp = inp;         /* Backup */\r
+        }\r
+      }\r
+    }\r
+\r
+    if (orc == CONFREJ &&    /* Reject this CI */\r
+        rc != CONFREJ) {  /*  but no prior ones? */\r
+      rc = CONFREJ;\r
+      ucp = inp;        /* Backup */\r
+    }\r
+    \r
+    /* Need to move CI? */\r
+    if (ucp != cip) {\r
+      BCOPY(cip, ucp, cilen);  /* Move it */\r
+    }\r
+\r
+    /* Update output pointer */\r
+    INCPTR(cilen, ucp);\r
+  }\r
+\r
+  /*\r
+   * If we aren't rejecting this packet, and we want to negotiate\r
+   * their address, and they didn't send their address, then we\r
+   * send a NAK with a CI_ADDR option appended.  We assume the\r
+   * input buffer is long enough that we can append the extra\r
+   * option safely.\r
+   */\r
+  if (rc != CONFREJ && !ho->neg_addr &&\r
+      wo->req_addr && !reject_if_disagree) {\r
+    IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n"));\r
+    if (rc == CONFACK) {\r
+      rc = CONFNAK;\r
+      ucp = inp;        /* reset pointer */\r
+      wo->req_addr = 0;    /* don't ask again */\r
+    }\r
+    PUTCHAR(CI_ADDR, ucp);\r
+    PUTCHAR(CILEN_ADDR, ucp);\r
+    tl = ntohl(wo->hisaddr);\r
+    PUTLONG(tl, ucp);\r
+  }\r
+\r
+  *len = (int)(ucp - inp);    /* Compute output length */\r
+  IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc)));\r
+  return (rc);      /* Return final code */\r
+}\r
+\r
+\r
+#if 0\r
+/*\r
+ * ip_check_options - check that any IP-related options are OK,\r
+ * and assign appropriate defaults.\r
+ */\r
+static void\r
+ip_check_options(u_long localAddr)\r
+{\r
+  ipcp_options *wo = &ipcp_wantoptions[0];\r
+\r
+  /*\r
+   * Load our default IP address but allow the remote host to give us\r
+   * a new address.\r
+   */\r
+  if (wo->ouraddr == 0 && !ppp_settings.disable_defaultip) {\r
+    wo->accept_local = 1;  /* don't insist on this default value */\r
+    wo->ouraddr = htonl(localAddr);\r
+  }\r
+}\r
+#endif\r
+\r
+\r
+/*\r
+ * ipcp_up - IPCP has come UP.\r
+ *\r
+ * Configure the IP network interface appropriately and bring it up.\r
+ */\r
+static void\r
+ipcp_up(fsm *f)\r
+{\r
+  u32_t mask;\r
+  ipcp_options *ho = &ipcp_hisoptions[f->unit];\r
+  ipcp_options *go = &ipcp_gotoptions[f->unit];\r
+  ipcp_options *wo = &ipcp_wantoptions[f->unit];\r
+\r
+  np_up(f->unit, PPP_IP);\r
+  IPCPDEBUG((LOG_INFO, "ipcp: up\n"));\r
+\r
+  /*\r
+   * We must have a non-zero IP address for both ends of the link.\r
+   */\r
+  if (!ho->neg_addr) {\r
+    ho->hisaddr = wo->hisaddr;\r
+  }\r
+\r
+  if (ho->hisaddr == 0) {\r
+    IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n"));\r
+    ipcp_close(f->unit, "Could not determine remote IP address");\r
+    return;\r
+  }\r
+  if (go->ouraddr == 0) {\r
+    IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n"));\r
+    ipcp_close(f->unit, "Could not determine local IP address");\r
+    return;\r
+  }\r
+\r
+  if (ppp_settings.usepeerdns && (go->dnsaddr[0] || go->dnsaddr[1])) {\r
+    /*pppGotDNSAddrs(go->dnsaddr[0], go->dnsaddr[1]);*/\r
+  }\r
+\r
+  /*\r
+   * Check that the peer is allowed to use the IP address it wants.\r
+   */\r
+  if (!auth_ip_addr(f->unit, ho->hisaddr)) {\r
+    IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n",\r
+        inet_ntoa(ho->hisaddr)));\r
+    ipcp_close(f->unit, "Unauthorized remote IP address");\r
+    return;\r
+  }\r
+\r
+  /* set tcp compression */\r
+  sifvjcomp(f->unit, ho->neg_vj, ho->cflag, ho->maxslotindex);\r
+\r
+  /*\r
+   * Set IP addresses and (if specified) netmask.\r
+   */\r
+  mask = GetMask(go->ouraddr);\r
+\r
+  if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) {\r
+    IPCPDEBUG((LOG_WARNING, "sifaddr failed\n"));\r
+    ipcp_close(f->unit, "Interface configuration failed");\r
+    return;\r
+  }\r
+\r
+  /* bring the interface up for IP */\r
+  if (!sifup(f->unit)) {\r
+    IPCPDEBUG((LOG_WARNING, "sifup failed\n"));\r
+    ipcp_close(f->unit, "Interface configuration failed");\r
+    return;\r
+  }\r
+\r
+  sifnpmode(f->unit, PPP_IP, NPMODE_PASS);\r
+\r
+  /* assign a default route through the interface if required */\r
+  if (ipcp_wantoptions[f->unit].default_route) {\r
+    if (sifdefaultroute(f->unit, go->ouraddr, ho->hisaddr)) {\r
+      default_route_set[f->unit] = 1;\r
+    }\r
+  }\r
+\r
+  IPCPDEBUG((LOG_NOTICE, "local  IP address %s\n", inet_ntoa(go->ouraddr)));\r
+  IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr)));\r
+  if (go->dnsaddr[0]) {\r
+    IPCPDEBUG((LOG_NOTICE, "primary   DNS address %s\n", inet_ntoa(go->dnsaddr[0])));\r
+  }\r
+  if (go->dnsaddr[1]) {\r
+    IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1])));\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_down - IPCP has gone DOWN.\r
+ *\r
+ * Take the IP network interface down, clear its addresses\r
+ * and delete routes through it.\r
+ */\r
+static void\r
+ipcp_down(fsm *f)\r
+{\r
+  IPCPDEBUG((LOG_INFO, "ipcp: down\n"));\r
+  np_down(f->unit, PPP_IP);\r
+  sifvjcomp(f->unit, 0, 0, 0);\r
+\r
+  sifdown(f->unit);\r
+  ipcp_clear_addrs(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_clear_addrs() - clear the interface addresses, routes, etc.\r
+ */\r
+static void\r
+ipcp_clear_addrs(int unit)\r
+{\r
+  u32_t ouraddr, hisaddr;\r
+\r
+  ouraddr = ipcp_gotoptions[unit].ouraddr;\r
+  hisaddr = ipcp_hisoptions[unit].hisaddr;\r
+  if (default_route_set[unit]) {\r
+    cifdefaultroute(unit, ouraddr, hisaddr);\r
+    default_route_set[unit] = 0;\r
+  }\r
+  cifaddr(unit, ouraddr, hisaddr);\r
+}\r
+\r
+\r
+/*\r
+ * ipcp_finished - possibly shut down the lower layers.\r
+ */\r
+static void\r
+ipcp_finished(fsm *f)\r
+{\r
+  np_finished(f->unit, PPP_IP);\r
+}\r
+\r
+#if 0\r
+static int\r
+ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)\r
+{\r
+  LWIP_UNUSED_ARG(p);\r
+  LWIP_UNUSED_ARG(plen);\r
+  LWIP_UNUSED_ARG(printer);\r
+  LWIP_UNUSED_ARG(arg);\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * ip_active_pkt - see if this IP packet is worth bringing the link up for.\r
+ * We don't bring the link up for IP fragments or for TCP FIN packets\r
+ * with no data.\r
+ */\r
+#define IP_HDRLEN   20  /* bytes */\r
+#define IP_OFFMASK  0x1fff\r
+#define IPPROTO_TCP 6\r
+#define TCP_HDRLEN  20\r
+#define TH_FIN      0x01\r
+\r
+/*\r
+ * We use these macros because the IP header may be at an odd address,\r
+ * and some compilers might use word loads to get th_off or ip_hl.\r
+ */\r
+\r
+#define net_short(x)    (((x)[0] << 8) + (x)[1])\r
+#define get_iphl(x)     (((unsigned char *)(x))[0] & 0xF)\r
+#define get_ipoff(x)    net_short((unsigned char *)(x) + 6)\r
+#define get_ipproto(x)  (((unsigned char *)(x))[9])\r
+#define get_tcpoff(x)   (((unsigned char *)(x))[12] >> 4)\r
+#define get_tcpflags(x) (((unsigned char *)(x))[13])\r
+\r
+static int\r
+ip_active_pkt(u_char *pkt, int len)\r
+{\r
+  u_char *tcp;\r
+  int hlen;\r
+\r
+  len -= PPP_HDRLEN;\r
+  pkt += PPP_HDRLEN;\r
+  if (len < IP_HDRLEN) {\r
+    return 0;\r
+  }\r
+  if ((get_ipoff(pkt) & IP_OFFMASK) != 0) {\r
+    return 0;\r
+  }\r
+  if (get_ipproto(pkt) != IPPROTO_TCP) {\r
+    return 1;\r
+  }\r
+  hlen = get_iphl(pkt) * 4;\r
+  if (len < hlen + TCP_HDRLEN) {\r
+    return 0;\r
+  }\r
+  tcp = pkt + hlen;\r
+  if ((get_tcpflags(tcp) & TH_FIN) != 0 && len == hlen + get_tcpoff(tcp) * 4) {\r
+    return 0;\r
+  }\r
+  return 1;\r
+}\r
+#endif\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ipcp.h
new file mode 100644 (file)
index 0000000..80e0190
--- /dev/null
@@ -0,0 +1,124 @@
+/*****************************************************************************\r
+* ipcp.h -  PPP IP NCP: Internet Protocol Network Control Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * ipcp.h - IP Control Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: ipcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $\r
+ */\r
+\r
+#ifndef IPCP_H\r
+#define IPCP_H\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+/*\r
+ * Options.\r
+ */\r
+#define CI_ADDRS            1      /* IP Addresses */\r
+#define CI_COMPRESSTYPE     2      /* Compression Type */\r
+#define CI_ADDR             3\r
+\r
+#define CI_MS_WINS1         128    /* Primary WINS value */\r
+#define CI_MS_DNS1          129    /* Primary DNS value */\r
+#define CI_MS_WINS2         130    /* Secondary WINS value */\r
+#define CI_MS_DNS2          131    /* Secondary DNS value */\r
+\r
+#define IPCP_VJMODE_OLD     1      /* "old" mode (option # = 0x0037) */\r
+#define IPCP_VJMODE_RFC1172 2      /* "old-rfc"mode (option # = 0x002d) */\r
+#define IPCP_VJMODE_RFC1332 3      /* "new-rfc"mode (option # = 0x002d, */\r
+                                   /*  maxslot and slot number compression) */\r
+\r
+#define IPCP_VJ_COMP        0x002d /* current value for VJ compression option */\r
+#define IPCP_VJ_COMP_OLD    0x0037 /* "old" (i.e, broken) value for VJ */\r
+                                   /* compression option */ \r
+\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+typedef struct ipcp_options {\r
+  u_int   neg_addr      : 1; /* Negotiate IP Address? */\r
+  u_int   old_addrs     : 1; /* Use old (IP-Addresses) option? */\r
+  u_int   req_addr      : 1; /* Ask peer to send IP address? */\r
+  u_int   default_route : 1; /* Assign default route through interface? */\r
+  u_int   proxy_arp     : 1; /* Make proxy ARP entry for peer? */\r
+  u_int   neg_vj        : 1; /* Van Jacobson Compression? */\r
+  u_int   old_vj        : 1; /* use old (short) form of VJ option? */\r
+  u_int   accept_local  : 1; /* accept peer's value for ouraddr */\r
+  u_int   accept_remote : 1; /* accept peer's value for hisaddr */\r
+  u_int   req_dns1      : 1; /* Ask peer to send primary DNS address? */\r
+  u_int   req_dns2      : 1; /* Ask peer to send secondary DNS address? */\r
+  u_short vj_protocol;       /* protocol value to use in VJ option */\r
+  u_char  maxslotindex;      /* VJ slots - 1. */\r
+  u_char  cflag;             /* VJ slot compression flag. */\r
+  u32_t   ouraddr, hisaddr;  /* Addresses in NETWORK BYTE ORDER */\r
+  u32_t   dnsaddr[2];        /* Primary and secondary MS DNS entries */\r
+  u32_t   winsaddr[2];       /* Primary and secondary MS WINS entries */\r
+} ipcp_options;\r
+\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+\r
+extern fsm ipcp_fsm[];\r
+extern ipcp_options ipcp_wantoptions[];\r
+extern ipcp_options ipcp_gotoptions[];\r
+extern ipcp_options ipcp_allowoptions[];\r
+extern ipcp_options ipcp_hisoptions[];\r
+\r
+extern struct protent ipcp_protent;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+#endif /* IPCP_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.c
new file mode 100644 (file)
index 0000000..f8af228
--- /dev/null
@@ -0,0 +1,2035 @@
+/*****************************************************************************\r
+* lcp.c - Network Link Control Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-01 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*****************************************************************************/\r
+\r
+/*\r
+ * lcp.c - PPP Link Control Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "fsm.h"\r
+#include "chap.h"\r
+#include "magic.h"\r
+#include "auth.h"\r
+#include "lcp.h"\r
+\r
+#include <string.h>\r
+\r
+#if PPPOE_SUPPORT\r
+#include "netif/ppp_oe.h"\r
+#else\r
+#define PPPOE_MAXMTU PPP_MAXMRU\r
+#endif\r
+\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+/*\r
+ * Length of each type of configuration option (in octets)\r
+ */\r
+#define CILEN_VOID  2\r
+#define CILEN_CHAR  3\r
+#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */\r
+#define CILEN_CHAP  5 /* CILEN_VOID + sizeof(short) + 1 */\r
+#define CILEN_LONG  6 /* CILEN_VOID + sizeof(long) */\r
+#define CILEN_LQR   8 /* CILEN_VOID + sizeof(short) + sizeof(long) */\r
+#define CILEN_CBCP  3\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Callbacks for fsm code.  (CI = Configuration Information)\r
+ */\r
+static void lcp_resetci (fsm*);                   /* Reset our CI */\r
+static int  lcp_cilen (fsm*);                     /* Return length of our CI */\r
+static void lcp_addci (fsm*, u_char*, int*);      /* Add our CI to pkt */\r
+static int  lcp_ackci (fsm*, u_char*, int);       /* Peer ack'd our CI */\r
+static int  lcp_nakci (fsm*, u_char*, int);       /* Peer nak'd our CI */\r
+static int  lcp_rejci (fsm*, u_char*, int);       /* Peer rej'd our CI */\r
+static int  lcp_reqci (fsm*, u_char*, int*, int); /* Rcv peer CI */\r
+static void lcp_up (fsm*);                        /* We're UP */\r
+static void lcp_down (fsm*);                      /* We're DOWN */\r
+static void lcp_starting (fsm*);                  /* We need lower layer up */\r
+static void lcp_finished (fsm*);                  /* We need lower layer down */\r
+static int  lcp_extcode (fsm*, int, u_char, u_char*, int);\r
+\r
+static void lcp_rprotrej (fsm*, u_char*, int);\r
+\r
+/*\r
+ * routines to send LCP echos to peer\r
+ */\r
+static void lcp_echo_lowerup (int);\r
+static void lcp_echo_lowerdown (int);\r
+static void LcpEchoTimeout (void*);\r
+static void lcp_received_echo_reply (fsm*, int, u_char*, int);\r
+static void LcpSendEchoRequest (fsm*);\r
+static void LcpLinkFailure (fsm*);\r
+static void LcpEchoCheck (fsm*);\r
+\r
+/*\r
+ * Protocol entry points.\r
+ * Some of these are called directly.\r
+ */\r
+static void lcp_input (int, u_char *, int);\r
+static void lcp_protrej (int);\r
+\r
+#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ")\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+/* global vars */\r
+LinkPhase lcp_phase[NUM_PPP];          /* Phase of link session (RFC 1661) */\r
+lcp_options lcp_wantoptions[NUM_PPP];  /* Options that we want to request */\r
+lcp_options lcp_gotoptions[NUM_PPP];   /* Options that peer ack'd */\r
+lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */\r
+lcp_options lcp_hisoptions[NUM_PPP];   /* Options that we ack'd */\r
+ext_accm xmit_accm[NUM_PPP];           /* extended transmit ACCM */\r
+\r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static fsm lcp_fsm[NUM_PPP];                            /* LCP fsm structure (global)*/\r
+static u_int lcp_echo_interval      = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */\r
+static u_int lcp_echo_fails         = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */\r
+static u32_t lcp_echos_pending      = 0;                /* Number of outstanding echo msgs */\r
+static u32_t lcp_echo_number        = 0;                /* ID number of next echo frame */\r
+static u32_t lcp_echo_timer_running = 0;                /* TRUE if a timer is running */\r
+\r
+static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */\r
+\r
+static fsm_callbacks lcp_callbacks = { /* LCP callback routines */\r
+  lcp_resetci,  /* Reset our Configuration Information */\r
+  lcp_cilen,    /* Length of our Configuration Information */\r
+  lcp_addci,    /* Add our Configuration Information */\r
+  lcp_ackci,    /* ACK our Configuration Information */\r
+  lcp_nakci,    /* NAK our Configuration Information */\r
+  lcp_rejci,    /* Reject our Configuration Information */\r
+  lcp_reqci,    /* Request peer's Configuration Information */\r
+  lcp_up,       /* Called when fsm reaches LS_OPENED state */\r
+  lcp_down,     /* Called when fsm leaves LS_OPENED state */\r
+  lcp_starting, /* Called when we want the lower layer up */\r
+  lcp_finished, /* Called when we want the lower layer down */\r
+  NULL,         /* Called when Protocol-Reject received */\r
+  NULL,         /* Retransmission is necessary */\r
+  lcp_extcode,  /* Called to handle LCP-specific codes */\r
+  "LCP"         /* String name of protocol */\r
+};\r
+\r
+struct protent lcp_protent = {\r
+    PPP_LCP,\r
+    lcp_init,\r
+    lcp_input,\r
+    lcp_protrej,\r
+    lcp_lowerup,\r
+    lcp_lowerdown,\r
+    lcp_open,\r
+    lcp_close,\r
+#if 0\r
+    lcp_printpkt,\r
+    NULL,\r
+#endif\r
+    1,\r
+    "LCP",\r
+#if 0\r
+    NULL,\r
+    NULL,\r
+    NULL\r
+#endif\r
+};\r
+\r
+int lcp_loopbackfail = DEFLOOPBACKFAIL;\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * lcp_init - Initialize LCP.\r
+ */\r
+void\r
+lcp_init(int unit)\r
+{\r
+  fsm         *f  = &lcp_fsm[unit];\r
+  lcp_options *wo = &lcp_wantoptions[unit];\r
+  lcp_options *ao = &lcp_allowoptions[unit];\r
+  \r
+  f->unit      = unit;\r
+  f->protocol  = PPP_LCP;\r
+  f->callbacks = &lcp_callbacks;\r
+  \r
+  fsm_init(f);\r
+  \r
+  wo->passive           = 0;\r
+  wo->silent            = 0;\r
+  wo->restart           = 0;               /* Set to 1 in kernels or multi-line implementations */\r
+  wo->neg_mru           = 1;\r
+  wo->mru               = PPP_DEFMRU;\r
+  wo->neg_asyncmap      = 1;\r
+  wo->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */\r
+  wo->neg_chap          = 0;               /* Set to 1 on server */\r
+  wo->neg_upap          = 0;               /* Set to 1 on server */\r
+  wo->chap_mdtype       = CHAP_DIGEST_MD5;\r
+  wo->neg_magicnumber   = 1;\r
+  wo->neg_pcompression  = 1;\r
+  wo->neg_accompression = 1;\r
+  wo->neg_lqr           = 0;               /* no LQR implementation yet */\r
+  wo->neg_cbcp          = 0;\r
+  \r
+  ao->neg_mru           = 1;\r
+  ao->mru               = PPP_MAXMRU;\r
+  ao->neg_asyncmap      = 1;\r
+  ao->asyncmap          = 0x00000000l;     /* Assume don't need to escape any ctl chars. */\r
+  ao->neg_chap          = (CHAP_SUPPORT != 0);\r
+  ao->chap_mdtype       = CHAP_DIGEST_MD5;\r
+  ao->neg_upap          = (PAP_SUPPORT != 0);\r
+  ao->neg_magicnumber   = 1;\r
+  ao->neg_pcompression  = 1;\r
+  ao->neg_accompression = 1;\r
+  ao->neg_lqr           = 0;               /* no LQR implementation yet */\r
+  ao->neg_cbcp          = (CBCP_SUPPORT != 0);\r
+\r
+  /* \r
+   * Set transmit escape for the flag and escape characters plus anything\r
+   * set for the allowable options.\r
+   */\r
+  memset(xmit_accm[unit], 0, sizeof(xmit_accm[0]));\r
+  xmit_accm[unit][15] = 0x60;\r
+  xmit_accm[unit][0]  = (u_char)((ao->asyncmap        & 0xFF));\r
+  xmit_accm[unit][1]  = (u_char)((ao->asyncmap >> 8)  & 0xFF);\r
+  xmit_accm[unit][2]  = (u_char)((ao->asyncmap >> 16) & 0xFF);\r
+  xmit_accm[unit][3]  = (u_char)((ao->asyncmap >> 24) & 0xFF);\r
+  LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n",\r
+        xmit_accm[unit][0],\r
+        xmit_accm[unit][1],\r
+        xmit_accm[unit][2],\r
+        xmit_accm[unit][3]));\r
+  \r
+  lcp_phase[unit] = PHASE_INITIALIZE;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_open - LCP is allowed to come up.\r
+ */\r
+void\r
+lcp_open(int unit)\r
+{\r
+  fsm         *f  = &lcp_fsm[unit];\r
+  lcp_options *wo = &lcp_wantoptions[unit];\r
+\r
+  f->flags = 0;\r
+  if (wo->passive) {\r
+    f->flags |= OPT_PASSIVE;\r
+  }\r
+  if (wo->silent) {\r
+    f->flags |= OPT_SILENT;\r
+  }\r
+  fsm_open(f);\r
+\r
+  lcp_phase[unit] = PHASE_ESTABLISH;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_close - Take LCP down.\r
+ */\r
+void\r
+lcp_close(int unit, char *reason)\r
+{\r
+  fsm *f = &lcp_fsm[unit];\r
+\r
+  if (lcp_phase[unit] != PHASE_DEAD) {\r
+    lcp_phase[unit] = PHASE_TERMINATE;\r
+  }\r
+  if (f->state == LS_STOPPED && f->flags & (OPT_PASSIVE|OPT_SILENT)) {\r
+    /*\r
+     * This action is not strictly according to the FSM in RFC1548,\r
+     * but it does mean that the program terminates if you do an\r
+     * lcp_close() in passive/silent mode when a connection hasn't\r
+     * been established.\r
+     */\r
+    f->state = LS_CLOSED;\r
+    lcp_finished(f);\r
+  } else {\r
+    fsm_close(&lcp_fsm[unit], reason);\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * lcp_lowerup - The lower layer is up.\r
+ */\r
+void\r
+lcp_lowerup(int unit)\r
+{\r
+  lcp_options *wo = &lcp_wantoptions[unit];\r
+\r
+  /*\r
+   * Don't use A/C or protocol compression on transmission,\r
+   * but accept A/C and protocol compressed packets\r
+   * if we are going to ask for A/C and protocol compression.\r
+   */\r
+  ppp_set_xaccm(unit, &xmit_accm[unit]);\r
+  ppp_send_config(unit, PPP_MRU, 0xffffffffl, 0, 0);\r
+  ppp_recv_config(unit, PPP_MRU, 0x00000000l,\r
+  wo->neg_pcompression, wo->neg_accompression);\r
+  peer_mru[unit] = PPP_MRU;\r
+  lcp_allowoptions[unit].asyncmap = (u_long)xmit_accm[unit][0]\r
+                                 | ((u_long)xmit_accm[unit][1] << 8)\r
+                                 | ((u_long)xmit_accm[unit][2] << 16)\r
+                                 | ((u_long)xmit_accm[unit][3] << 24);\r
+  LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n",\r
+            xmit_accm[unit][3],\r
+            xmit_accm[unit][2],\r
+            xmit_accm[unit][1],\r
+            xmit_accm[unit][0]));\r
+\r
+  fsm_lowerup(&lcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_lowerdown - The lower layer is down.\r
+ */\r
+void\r
+lcp_lowerdown(int unit)\r
+{\r
+  fsm_lowerdown(&lcp_fsm[unit]);\r
+}\r
+\r
+/*\r
+ * lcp_sprotrej - Send a Protocol-Reject for some protocol.\r
+ */\r
+void\r
+lcp_sprotrej(int unit, u_char *p, int len)\r
+{\r
+  /*\r
+   * Send back the protocol and the information field of the\r
+   * rejected packet.  We only get here if LCP is in the LS_OPENED state.\r
+   */\r
+\r
+  fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len);\r
+}\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * lcp_input - Input LCP packet.\r
+ */\r
+static void\r
+lcp_input(int unit, u_char *p, int len)\r
+{\r
+  fsm *f = &lcp_fsm[unit];\r
+\r
+  fsm_input(f, p, len);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_extcode - Handle a LCP-specific code.\r
+ */\r
+static int\r
+lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len)\r
+{\r
+  u_char *magp;\r
+\r
+  switch( code ){\r
+    case PROTREJ:\r
+      lcp_rprotrej(f, inp, len);\r
+      break;\r
+  \r
+    case ECHOREQ:\r
+      if (f->state != LS_OPENED) {\r
+        break;\r
+      }\r
+      LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id));\r
+      magp = inp;\r
+      PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp);\r
+      fsm_sdata(f, ECHOREP, id, inp, len);\r
+      break;\r
+\r
+    case ECHOREP:\r
+      lcp_received_echo_reply(f, id, inp, len);\r
+      break;\r
+    \r
+    case DISCREQ:\r
+      break;\r
+    \r
+    default:\r
+      return 0;\r
+  }\r
+  return 1;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_rprotrej - Receive an Protocol-Reject.\r
+ *\r
+ * Figure out which protocol is rejected and inform it.\r
+ */\r
+static void\r
+lcp_rprotrej(fsm *f, u_char *inp, int len)\r
+{\r
+  int i;\r
+  struct protent *protp;\r
+  u_short prot;\r
+\r
+  if (len < sizeof (u_short)) {\r
+    LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n"));\r
+    return;\r
+  }\r
+\r
+  GETSHORT(prot, inp);\r
+\r
+  LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot));\r
+\r
+  /*\r
+   * Protocol-Reject packets received in any state other than the LCP\r
+   * LS_OPENED state SHOULD be silently discarded.\r
+   */\r
+  if( f->state != LS_OPENED ) {\r
+    LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state));\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * Upcall the proper Protocol-Reject routine.\r
+   */\r
+  for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+    if (protp->protocol == prot && protp->enabled_flag) {\r
+      (*protp->protrej)(f->unit);\r
+      return;\r
+    }\r
+  }\r
+\r
+  LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot));\r
+}\r
+\r
+\r
+/*\r
+ * lcp_protrej - A Protocol-Reject was received.\r
+ */\r
+static void\r
+lcp_protrej(int unit)\r
+{\r
+  LWIP_UNUSED_ARG(unit);\r
+  /*\r
+   * Can't reject LCP!\r
+   */\r
+  LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n"));\r
+  fsm_protreject(&lcp_fsm[unit]);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_resetci - Reset our CI.\r
+ */\r
+static void\r
+lcp_resetci(fsm *f)\r
+{\r
+  lcp_wantoptions[f->unit].magicnumber = magic();\r
+  lcp_wantoptions[f->unit].numloops = 0;\r
+  lcp_gotoptions[f->unit] = lcp_wantoptions[f->unit];\r
+  peer_mru[f->unit] = PPP_MRU;\r
+  auth_reset(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_cilen - Return length of our CI.\r
+ */\r
+static int lcp_cilen(fsm *f)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+\r
+#define LENCIVOID(neg)  ((neg) ? CILEN_VOID : 0)\r
+#define LENCICHAP(neg)  ((neg) ? CILEN_CHAP : 0)\r
+#define LENCISHORT(neg) ((neg) ? CILEN_SHORT : 0)\r
+#define LENCILONG(neg)  ((neg) ? CILEN_LONG : 0)\r
+#define LENCILQR(neg)   ((neg) ? CILEN_LQR: 0)\r
+#define LENCICBCP(neg)  ((neg) ? CILEN_CBCP: 0)\r
+  /*\r
+   * NB: we only ask for one of CHAP and UPAP, even if we will\r
+   * accept either.\r
+   */\r
+  return (LENCISHORT(go->neg_mru && go->mru != PPP_DEFMRU) +\r
+          LENCILONG(go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) +\r
+          LENCICHAP(go->neg_chap) +\r
+          LENCISHORT(!go->neg_chap && go->neg_upap) +\r
+          LENCILQR(go->neg_lqr) +\r
+          LENCICBCP(go->neg_cbcp) +\r
+          LENCILONG(go->neg_magicnumber) +\r
+          LENCIVOID(go->neg_pcompression) +\r
+          LENCIVOID(go->neg_accompression));\r
+}\r
+\r
+\r
+/*\r
+ * lcp_addci - Add our desired CIs to a packet.\r
+ */\r
+static void\r
+lcp_addci(fsm *f, u_char *ucp, int *lenp)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  u_char *start_ucp = ucp;\r
+\r
+#define ADDCIVOID(opt, neg) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_VOID, ucp); \\r
+  }\r
+#define ADDCISHORT(opt, neg, val) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_SHORT, ucp); \\r
+    PUTSHORT(val, ucp); \\r
+  }\r
+#define ADDCICHAP(opt, neg, val, digest) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_CHAP, ucp); \\r
+    PUTSHORT(val, ucp); \\r
+    PUTCHAR(digest, ucp); \\r
+  }\r
+#define ADDCILONG(opt, neg, val) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_LONG, ucp); \\r
+    PUTLONG(val, ucp); \\r
+  }\r
+#define ADDCILQR(opt, neg, val) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_LQR, ucp); \\r
+    PUTSHORT(PPP_LQR, ucp); \\r
+    PUTLONG(val, ucp); \\r
+  }\r
+#define ADDCICHAR(opt, neg, val) \\r
+  if (neg) { \\r
+    LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \\r
+    PUTCHAR(opt, ucp); \\r
+    PUTCHAR(CILEN_CHAR, ucp); \\r
+    PUTCHAR(val, ucp); \\r
+  }\r
+\r
+  ADDCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);\r
+  ADDCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);\r
+  ADDCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);\r
+  ADDCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);\r
+  ADDCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);\r
+  ADDCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);\r
+  ADDCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);\r
+  ADDCIVOID(CI_PCOMPRESSION, go->neg_pcompression);\r
+  ADDCIVOID(CI_ACCOMPRESSION, go->neg_accompression);\r
+\r
+  if (ucp - start_ucp != *lenp) {\r
+    /* this should never happen, because peer_mtu should be 1500 */\r
+    LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n"));\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * lcp_ackci - Ack our CIs.\r
+ * This should not modify any state if the Ack is bad.\r
+ *\r
+ * Returns:\r
+ *  0 - Ack was bad.\r
+ *  1 - Ack was good.\r
+ */\r
+static int\r
+lcp_ackci(fsm *f, u_char *p, int len)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  u_char cilen, citype, cichar;\r
+  u_short cishort;\r
+  u32_t cilong;\r
+\r
+  /*\r
+   * CIs must be in exactly the same order that we sent.\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+#define ACKCIVOID(opt, neg) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_VOID) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_VOID || citype != opt) \\r
+      goto bad; \\r
+  }\r
+#define ACKCISHORT(opt, neg, val) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_SHORT) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_SHORT || citype != opt) \\r
+      goto bad; \\r
+    GETSHORT(cishort, p); \\r
+    if (cishort != val) \\r
+      goto bad; \\r
+  }\r
+#define ACKCICHAR(opt, neg, val) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_CHAR) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_CHAR || citype != opt) \\r
+      goto bad; \\r
+    GETCHAR(cichar, p); \\r
+    if (cichar != val) \\r
+      goto bad; \\r
+  }\r
+#define ACKCICHAP(opt, neg, val, digest) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_CHAP) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_CHAP || citype != opt) \\r
+      goto bad; \\r
+    GETSHORT(cishort, p); \\r
+    if (cishort != val) \\r
+      goto bad; \\r
+    GETCHAR(cichar, p); \\r
+    if (cichar != digest) \\r
+      goto bad; \\r
+  }\r
+#define ACKCILONG(opt, neg, val) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_LONG) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_LONG ||  citype != opt) \\r
+      goto bad; \\r
+    GETLONG(cilong, p); \\r
+    if (cilong != val) \\r
+      goto bad; \\r
+  }\r
+#define ACKCILQR(opt, neg, val) \\r
+  if (neg) { \\r
+    if ((len -= CILEN_LQR) < 0) \\r
+      goto bad; \\r
+    GETCHAR(citype, p); \\r
+    GETCHAR(cilen, p); \\r
+    if (cilen != CILEN_LQR || citype != opt) \\r
+      goto bad; \\r
+    GETSHORT(cishort, p); \\r
+    if (cishort != PPP_LQR) \\r
+      goto bad; \\r
+    GETLONG(cilong, p); \\r
+    if (cilong != val) \\r
+      goto bad; \\r
+  }\r
+\r
+  ACKCISHORT(CI_MRU, go->neg_mru && go->mru != PPP_DEFMRU, go->mru);\r
+  ACKCILONG(CI_ASYNCMAP, go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl, go->asyncmap);\r
+  ACKCICHAP(CI_AUTHTYPE, go->neg_chap, PPP_CHAP, go->chap_mdtype);\r
+  ACKCISHORT(CI_AUTHTYPE, !go->neg_chap && go->neg_upap, PPP_PAP);\r
+  ACKCILQR(CI_QUALITY, go->neg_lqr, go->lqr_period);\r
+  ACKCICHAR(CI_CALLBACK, go->neg_cbcp, CBCP_OPT);\r
+  ACKCILONG(CI_MAGICNUMBER, go->neg_magicnumber, go->magicnumber);\r
+  ACKCIVOID(CI_PCOMPRESSION, go->neg_pcompression);\r
+  ACKCIVOID(CI_ACCOMPRESSION, go->neg_accompression);\r
+\r
+  /*\r
+   * If there are any remaining CIs, then this packet is bad.\r
+   */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+  LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n"));\r
+  return (1);\r
+bad:\r
+  LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n"));\r
+  return (0);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_nakci - Peer has sent a NAK for some of our CIs.\r
+ * This should not modify any state if the Nak is bad\r
+ * or if LCP is in the LS_OPENED state.\r
+ *\r
+ * Returns:\r
+ *  0 - Nak was bad.\r
+ *  1 - Nak was good.\r
+ */\r
+static int\r
+lcp_nakci(fsm *f, u_char *p, int len)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  lcp_options *wo = &lcp_wantoptions[f->unit];\r
+  u_char citype, cichar, *next;\r
+  u_short cishort;\r
+  u32_t cilong;\r
+  lcp_options no;     /* options we've seen Naks for */\r
+  lcp_options try;    /* options to request next time */\r
+  int looped_back = 0;\r
+  int cilen;\r
+\r
+  BZERO(&no, sizeof(no));\r
+  try = *go;\r
+\r
+  /*\r
+   * Any Nak'd CIs must be in exactly the same order that we sent.\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+#define NAKCIVOID(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_VOID && \\r
+      p[1] == CILEN_VOID && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_VOID; \\r
+    INCPTR(CILEN_VOID, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+#define NAKCICHAP(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_CHAP && \\r
+      p[1] == CILEN_CHAP && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_CHAP; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    GETCHAR(cichar, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+#define NAKCICHAR(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_CHAR && \\r
+      p[1] == CILEN_CHAR && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_CHAR; \\r
+    INCPTR(2, p); \\r
+    GETCHAR(cichar, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+#define NAKCISHORT(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_SHORT && \\r
+      p[1] == CILEN_SHORT && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_SHORT; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+#define NAKCILONG(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_LONG && \\r
+      p[1] == CILEN_LONG && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_LONG; \\r
+    INCPTR(2, p); \\r
+    GETLONG(cilong, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+#define NAKCILQR(opt, neg, code) \\r
+  if (go->neg && \\r
+      len >= CILEN_LQR && \\r
+      p[1] == CILEN_LQR && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_LQR; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    GETLONG(cilong, p); \\r
+    no.neg = 1; \\r
+    code \\r
+  }\r
+\r
+  /*\r
+   * We don't care if they want to send us smaller packets than\r
+   * we want.  Therefore, accept any MRU less than what we asked for,\r
+   * but then ignore the new value when setting the MRU in the kernel.\r
+   * If they send us a bigger MRU than what we asked, accept it, up to\r
+   * the limit of the default MRU we'd get if we didn't negotiate.\r
+   */\r
+  if (go->neg_mru && go->mru != PPP_DEFMRU) {\r
+    NAKCISHORT(CI_MRU, neg_mru,\r
+      if (cishort <= wo->mru || cishort < PPP_DEFMRU) {\r
+        try.mru = cishort;\r
+      }\r
+    );\r
+  }\r
+\r
+  /*\r
+   * Add any characters they want to our (receive-side) asyncmap.\r
+   */\r
+  if (go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl) {\r
+    NAKCILONG(CI_ASYNCMAP, neg_asyncmap,\r
+      try.asyncmap = go->asyncmap | cilong;\r
+    );\r
+  }\r
+\r
+  /*\r
+   * If they've nak'd our authentication-protocol, check whether\r
+   * they are proposing a different protocol, or a different\r
+   * hash algorithm for CHAP.\r
+   */\r
+  if ((go->neg_chap || go->neg_upap)\r
+      && len >= CILEN_SHORT\r
+      && p[0] == CI_AUTHTYPE && p[1] >= CILEN_SHORT && p[1] <= len) {\r
+    cilen = p[1];\r
+    len -= cilen;\r
+    no.neg_chap = go->neg_chap;\r
+    no.neg_upap = go->neg_upap;\r
+    INCPTR(2, p);\r
+    GETSHORT(cishort, p);\r
+    if (cishort == PPP_PAP && cilen == CILEN_SHORT) {\r
+      /*\r
+       * If we were asking for CHAP, they obviously don't want to do it.\r
+       * If we weren't asking for CHAP, then we were asking for PAP,\r
+       * in which case this Nak is bad.\r
+       */\r
+      if (!go->neg_chap) {\r
+        goto bad;\r
+      }\r
+      try.neg_chap = 0;\r
+    \r
+    } else if (cishort == PPP_CHAP && cilen == CILEN_CHAP) {\r
+      GETCHAR(cichar, p);\r
+      if (go->neg_chap) {\r
+        /*\r
+         * We were asking for CHAP/MD5; they must want a different\r
+         * algorithm.  If they can't do MD5, we'll have to stop\r
+         * asking for CHAP.\r
+         */\r
+        if (cichar != go->chap_mdtype) {\r
+          try.neg_chap = 0;\r
+        }\r
+      } else {\r
+        /*\r
+         * Stop asking for PAP if we were asking for it.\r
+         */\r
+        try.neg_upap = 0;\r
+      }\r
+    \r
+    } else {\r
+      /*\r
+       * We don't recognize what they're suggesting.\r
+       * Stop asking for what we were asking for.\r
+       */\r
+      if (go->neg_chap) {\r
+        try.neg_chap = 0;\r
+      } else {\r
+        try.neg_upap = 0;\r
+      }\r
+      p += cilen - CILEN_SHORT;\r
+    }\r
+  }\r
+\r
+  /*\r
+   * If they can't cope with our link quality protocol, we'll have\r
+   * to stop asking for LQR.  We haven't got any other protocol.\r
+   * If they Nak the reporting period, take their value XXX ?\r
+   */\r
+  NAKCILQR(CI_QUALITY, neg_lqr,\r
+    if (cishort != PPP_LQR) {\r
+      try.neg_lqr = 0;\r
+    } else {\r
+      try.lqr_period = cilong;\r
+    }\r
+  );\r
+\r
+  /*\r
+   * Only implementing CBCP...not the rest of the callback options\r
+   */\r
+  NAKCICHAR(CI_CALLBACK, neg_cbcp,\r
+    try.neg_cbcp = 0;\r
+  );\r
+\r
+  /*\r
+   * Check for a looped-back line.\r
+   */\r
+  NAKCILONG(CI_MAGICNUMBER, neg_magicnumber,\r
+    try.magicnumber = magic();\r
+    looped_back = 1;\r
+  );\r
+\r
+  /*\r
+   * Peer shouldn't send Nak for protocol compression or\r
+   * address/control compression requests; they should send\r
+   * a Reject instead.  If they send a Nak, treat it as a Reject.\r
+   */\r
+  NAKCIVOID(CI_PCOMPRESSION, neg_pcompression,\r
+    try.neg_pcompression = 0;\r
+  );\r
+  NAKCIVOID(CI_ACCOMPRESSION, neg_accompression,\r
+    try.neg_accompression = 0;\r
+  );\r
+\r
+  /*\r
+   * There may be remaining CIs, if the peer is requesting negotiation\r
+   * on an option that we didn't include in our request packet.\r
+   * If we see an option that we requested, or one we've already seen\r
+   * in this packet, then this packet is bad.\r
+   * If we wanted to respond by starting to negotiate on the requested\r
+   * option(s), we could, but we don't, because except for the\r
+   * authentication type and quality protocol, if we are not negotiating\r
+   * an option, it is because we were told not to.\r
+   * For the authentication type, the Nak from the peer means\r
+   * `let me authenticate myself with you' which is a bit pointless.\r
+   * For the quality protocol, the Nak means `ask me to send you quality\r
+   * reports', but if we didn't ask for them, we don't want them.\r
+   * An option we don't recognize represents the peer asking to\r
+   * negotiate some option we don't support, so ignore it.\r
+   */\r
+  while (len > CILEN_VOID) {\r
+    GETCHAR(citype, p);\r
+    GETCHAR(cilen, p);\r
+    if (cilen < CILEN_VOID || (len -= cilen) < 0) {\r
+      goto bad;\r
+    }\r
+    next = p + cilen - 2;\r
+\r
+    switch (citype) {\r
+      case CI_MRU:\r
+        if ((go->neg_mru && go->mru != PPP_DEFMRU)\r
+            || no.neg_mru || cilen != CILEN_SHORT) {\r
+          goto bad;\r
+        }\r
+        GETSHORT(cishort, p);\r
+        if (cishort < PPP_DEFMRU) {\r
+          try.mru = cishort;\r
+        }\r
+        break;\r
+      case CI_ASYNCMAP:\r
+        if ((go->neg_asyncmap && go->asyncmap != 0xFFFFFFFFl)\r
+            || no.neg_asyncmap || cilen != CILEN_LONG) {\r
+          goto bad;\r
+        }\r
+        break;\r
+      case CI_AUTHTYPE:\r
+        if (go->neg_chap || no.neg_chap || go->neg_upap || no.neg_upap) {\r
+          goto bad;\r
+        }\r
+        break;\r
+      case CI_MAGICNUMBER:\r
+        if (go->neg_magicnumber || no.neg_magicnumber ||\r
+            cilen != CILEN_LONG) {\r
+          goto bad;\r
+        }\r
+        break;\r
+      case CI_PCOMPRESSION:\r
+        if (go->neg_pcompression || no.neg_pcompression\r
+            || cilen != CILEN_VOID) {\r
+          goto bad;\r
+        }\r
+        break;\r
+      case CI_ACCOMPRESSION:\r
+        if (go->neg_accompression || no.neg_accompression\r
+            || cilen != CILEN_VOID) {\r
+          goto bad;\r
+        }\r
+        break;\r
+      case CI_QUALITY:\r
+        if (go->neg_lqr || no.neg_lqr || cilen != CILEN_LQR) {\r
+          goto bad;\r
+        }\r
+        break;\r
+    }\r
+    p = next;\r
+  }\r
+\r
+  /* If there is still anything left, this packet is bad. */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+\r
+  /*\r
+  * OK, the Nak is good.  Now we can update state.\r
+  */\r
+  if (f->state != LS_OPENED) {\r
+    if (looped_back) {\r
+      if (++try.numloops >= lcp_loopbackfail) {\r
+        LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n"));\r
+        lcp_close(f->unit, "Loopback detected");\r
+      }\r
+    } else {\r
+      try.numloops = 0;\r
+    }\r
+    *go = try;\r
+  }\r
+\r
+  return 1;\r
+\r
+bad:\r
+  LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n"));\r
+  return 0;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_rejci - Peer has Rejected some of our CIs.\r
+ * This should not modify any state if the Reject is bad\r
+ * or if LCP is in the LS_OPENED state.\r
+ *\r
+ * Returns:\r
+ *  0 - Reject was bad.\r
+ *  1 - Reject was good.\r
+ */\r
+static int\r
+lcp_rejci(fsm *f, u_char *p, int len)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  u_char cichar;\r
+  u_short cishort;\r
+  u32_t cilong;\r
+  lcp_options try; /* options to request next time */\r
+\r
+  try = *go;\r
+\r
+  /*\r
+   * Any Rejected CIs must be in exactly the same order that we sent.\r
+   * Check packet length and CI length at each step.\r
+   * If we find any deviations, then this packet is bad.\r
+   */\r
+#define REJCIVOID(opt, neg) \\r
+  if (go->neg && \\r
+      len >= CILEN_VOID && \\r
+      p[1] == CILEN_VOID && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_VOID; \\r
+    INCPTR(CILEN_VOID, p); \\r
+    try.neg = 0; \\r
+    LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \\r
+  }\r
+#define REJCISHORT(opt, neg, val) \\r
+  if (go->neg && \\r
+      len >= CILEN_SHORT && \\r
+      p[1] == CILEN_SHORT && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_SHORT; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    /* Check rejected value. */ \\r
+    if (cishort != val) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+    LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \\r
+  }\r
+#define REJCICHAP(opt, neg, val, digest) \\r
+  if (go->neg && \\r
+      len >= CILEN_CHAP && \\r
+      p[1] == CILEN_CHAP && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_CHAP; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    GETCHAR(cichar, p); \\r
+    /* Check rejected value. */ \\r
+    if (cishort != val || cichar != digest) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+    try.neg_upap = 0; \\r
+    LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \\r
+  }\r
+#define REJCILONG(opt, neg, val) \\r
+  if (go->neg && \\r
+      len >= CILEN_LONG && \\r
+      p[1] == CILEN_LONG && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_LONG; \\r
+    INCPTR(2, p); \\r
+    GETLONG(cilong, p); \\r
+    /* Check rejected value. */ \\r
+    if (cilong != val) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+    LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \\r
+  }\r
+#define REJCILQR(opt, neg, val) \\r
+  if (go->neg && \\r
+      len >= CILEN_LQR && \\r
+      p[1] == CILEN_LQR && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_LQR; \\r
+    INCPTR(2, p); \\r
+    GETSHORT(cishort, p); \\r
+    GETLONG(cilong, p); \\r
+    /* Check rejected value. */ \\r
+    if (cishort != PPP_LQR || cilong != val) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+    LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \\r
+  }\r
+#define REJCICBCP(opt, neg, val) \\r
+  if (go->neg && \\r
+      len >= CILEN_CBCP && \\r
+      p[1] == CILEN_CBCP && \\r
+      p[0] == opt) { \\r
+    len -= CILEN_CBCP; \\r
+    INCPTR(2, p); \\r
+    GETCHAR(cichar, p); \\r
+    /* Check rejected value. */ \\r
+    if (cichar != val) { \\r
+      goto bad; \\r
+    } \\r
+    try.neg = 0; \\r
+    LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \\r
+  }\r
+  \r
+  REJCISHORT(CI_MRU, neg_mru, go->mru);\r
+  REJCILONG(CI_ASYNCMAP, neg_asyncmap, go->asyncmap);\r
+  REJCICHAP(CI_AUTHTYPE, neg_chap, PPP_CHAP, go->chap_mdtype);\r
+  if (!go->neg_chap) {\r
+    REJCISHORT(CI_AUTHTYPE, neg_upap, PPP_PAP);\r
+  }\r
+  REJCILQR(CI_QUALITY, neg_lqr, go->lqr_period);\r
+  REJCICBCP(CI_CALLBACK, neg_cbcp, CBCP_OPT);\r
+  REJCILONG(CI_MAGICNUMBER, neg_magicnumber, go->magicnumber);\r
+  REJCIVOID(CI_PCOMPRESSION, neg_pcompression);\r
+  REJCIVOID(CI_ACCOMPRESSION, neg_accompression);\r
+  \r
+  /*\r
+   * If there are any remaining CIs, then this packet is bad.\r
+   */\r
+  if (len != 0) {\r
+    goto bad;\r
+  }\r
+  /*\r
+   * Now we can update state.\r
+   */\r
+  if (f->state != LS_OPENED) {\r
+    *go = try;\r
+  }\r
+  return 1;\r
+  \r
+bad:\r
+  LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n"));\r
+  return 0;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_reqci - Check the peer's requested CIs and send appropriate response.\r
+ *\r
+ * Returns: CONFACK, CONFNAK or CONFREJ and input packet modified\r
+ * appropriately.  If reject_if_disagree is non-zero, doesn't return\r
+ * CONFNAK; returns CONFREJ if it can't return CONFACK.\r
+ */\r
+static int\r
+lcp_reqci(fsm *f, \r
+          u_char *inp,    /* Requested CIs */\r
+          int *lenp,      /* Length of requested CIs */\r
+          int reject_if_disagree)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  lcp_options *ho = &lcp_hisoptions[f->unit];\r
+  lcp_options *ao = &lcp_allowoptions[f->unit];\r
+  u_char *cip, *next;         /* Pointer to current and next CIs */\r
+  int cilen, citype, cichar;  /* Parsed len, type, char value */\r
+  u_short cishort;            /* Parsed short value */\r
+  u32_t cilong;               /* Parse long value */\r
+  int rc = CONFACK;           /* Final packet return code */\r
+  int orc;                    /* Individual option return code */\r
+  u_char *p;                  /* Pointer to next char to parse */\r
+  u_char *rejp;               /* Pointer to next char in reject frame */\r
+  u_char *nakp;               /* Pointer to next char in Nak frame */\r
+  int l = *lenp;              /* Length left */\r
+#if TRACELCP > 0\r
+  char traceBuf[80];\r
+  int traceNdx = 0;\r
+#endif\r
+\r
+  /*\r
+   * Reset all his options.\r
+   */\r
+  BZERO(ho, sizeof(*ho));\r
+\r
+  /*\r
+   * Process all his options.\r
+   */\r
+  next = inp;\r
+  nakp = nak_buffer;\r
+  rejp = inp;\r
+  while (l) {\r
+    orc = CONFACK;      /* Assume success */\r
+    cip = p = next;     /* Remember begining of CI */\r
+    if (l < 2 ||        /* Not enough data for CI header or */\r
+        p[1] < 2 ||     /*  CI length too small or */\r
+        p[1] > l) {     /*  CI length too big? */\r
+      LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n"));\r
+      orc = CONFREJ;    /* Reject bad CI */\r
+      cilen = l;        /* Reject till end of packet */\r
+      l = 0;            /* Don't loop again */\r
+      citype = 0;\r
+      goto endswitch;\r
+    }\r
+    GETCHAR(citype, p); /* Parse CI type */\r
+    GETCHAR(cilen, p);  /* Parse CI length */\r
+    l -= cilen;         /* Adjust remaining length */\r
+    next += cilen;      /* Step to next CI */\r
+\r
+    switch (citype) {   /* Check CI type */\r
+      case CI_MRU:\r
+        if (!ao->neg_mru) {    /* Allow option? */\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n"));\r
+          orc = CONFREJ;    /* Reject CI */\r
+          break;\r
+        } else if (cilen != CILEN_SHORT) {  /* Check CI length */\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n"));\r
+          orc = CONFREJ;    /* Reject CI */\r
+          break;\r
+        }\r
+        GETSHORT(cishort, p);  /* Parse MRU */\r
+\r
+        /*\r
+         * He must be able to receive at least our minimum.\r
+         * No need to check a maximum.  If he sends a large number,\r
+         * we'll just ignore it.\r
+         */\r
+        if (cishort < PPP_MINMRU) {\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n"));\r
+          orc = CONFNAK;    /* Nak CI */\r
+          PUTCHAR(CI_MRU, nakp);\r
+          PUTCHAR(CILEN_SHORT, nakp);\r
+          PUTSHORT(PPP_MINMRU, nakp);  /* Give him a hint */\r
+          break;\r
+        }\r
+        ho->neg_mru = 1;    /* Remember he sent MRU */\r
+        ho->mru = cishort;    /* And remember value */\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MRU %d", cishort);\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        break;\r
+\r
+      case CI_ASYNCMAP:\r
+        if (!ao->neg_asyncmap) {\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n"));\r
+          orc = CONFREJ;\r
+          break;\r
+        } else if (cilen != CILEN_LONG) {\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n"));\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        GETLONG(cilong, p);\r
+        \r
+        /*\r
+         * Asyncmap must have set at least the bits\r
+         * which are set in lcp_allowoptions[unit].asyncmap.\r
+         */\r
+        if ((ao->asyncmap & ~cilong) != 0) {\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", \r
+                    cilong, ao->asyncmap));\r
+          orc = CONFNAK;\r
+          PUTCHAR(CI_ASYNCMAP, nakp);\r
+          PUTCHAR(CILEN_LONG, nakp);\r
+          PUTLONG(ao->asyncmap | cilong, nakp);\r
+          break;\r
+        }\r
+        ho->neg_asyncmap = 1;\r
+        ho->asyncmap = cilong;\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ASYNCMAP=%lX", cilong);\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        break;\r
+\r
+      case CI_AUTHTYPE:\r
+        if (cilen < CILEN_SHORT) {\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n"));\r
+          orc = CONFREJ;\r
+          break;\r
+        } else if (!(ao->neg_upap || ao->neg_chap)) {\r
+          /*\r
+           * Reject the option if we're not willing to authenticate.\r
+           */\r
+          LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n"));\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        GETSHORT(cishort, p);\r
+        \r
+        /*\r
+         * Authtype must be UPAP or CHAP.\r
+         *\r
+         * Note: if both ao->neg_upap and ao->neg_chap are set,\r
+         * and the peer sends a Configure-Request with two\r
+         * authenticate-protocol requests, one for CHAP and one\r
+         * for UPAP, then we will reject the second request.\r
+         * Whether we end up doing CHAP or UPAP depends then on\r
+         * the ordering of the CIs in the peer's Configure-Request.\r
+         */\r
+        \r
+        if (cishort == PPP_PAP) {\r
+          if (ho->neg_chap) {  /* we've already accepted CHAP */\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n"));\r
+            orc = CONFREJ;\r
+            break;\r
+          } else if (cilen != CILEN_SHORT) {\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n"));\r
+            orc = CONFREJ;\r
+            break;\r
+          }\r
+          if (!ao->neg_upap) {  /* we don't want to do PAP */\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n"));\r
+            orc = CONFNAK;  /* NAK it and suggest CHAP */\r
+            PUTCHAR(CI_AUTHTYPE, nakp);\r
+            PUTCHAR(CILEN_CHAP, nakp);\r
+            PUTSHORT(PPP_CHAP, nakp);\r
+            PUTCHAR(ao->chap_mdtype, nakp);\r
+            break;\r
+          }\r
+          ho->neg_upap = 1;\r
+#if TRACELCP > 0\r
+          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PAP (%X)", cishort);\r
+          traceNdx = strlen(traceBuf);\r
+#endif\r
+          break;\r
+        }\r
+        if (cishort == PPP_CHAP) {\r
+          if (ho->neg_upap) {  /* we've already accepted PAP */\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n"));\r
+            orc = CONFREJ;\r
+            break;\r
+          } else if (cilen != CILEN_CHAP) {\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n"));\r
+            orc = CONFREJ;\r
+            break;\r
+          }\r
+          if (!ao->neg_chap) {  /* we don't want to do CHAP */\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n"));\r
+            orc = CONFNAK;  /* NAK it and suggest PAP */\r
+            PUTCHAR(CI_AUTHTYPE, nakp);\r
+            PUTCHAR(CILEN_SHORT, nakp);\r
+            PUTSHORT(PPP_PAP, nakp);\r
+            break;\r
+          }\r
+          GETCHAR(cichar, p);  /* get digest type*/\r
+          if (cichar != CHAP_DIGEST_MD5\r
+#ifdef CHAPMS\r
+              && cichar != CHAP_MICROSOFT\r
+#endif\r
+          ) {\r
+            LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar));\r
+            orc = CONFNAK;\r
+            PUTCHAR(CI_AUTHTYPE, nakp);\r
+            PUTCHAR(CILEN_CHAP, nakp);\r
+            PUTSHORT(PPP_CHAP, nakp);\r
+            PUTCHAR(ao->chap_mdtype, nakp);\r
+            break;\r
+          }\r
+#if TRACELCP > 0\r
+          snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar);\r
+          traceNdx = strlen(traceBuf);\r
+#endif\r
+          ho->chap_mdtype = cichar; /* save md type */\r
+          ho->neg_chap = 1;\r
+          break;\r
+        }\r
+        \r
+        /*\r
+         * We don't recognize the protocol they're asking for.\r
+         * Nak it with something we're willing to do.\r
+         * (At this point we know ao->neg_upap || ao->neg_chap.)\r
+         */\r
+        orc = CONFNAK;\r
+        PUTCHAR(CI_AUTHTYPE, nakp);\r
+        if (ao->neg_chap) {\r
+          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort));\r
+          PUTCHAR(CILEN_CHAP, nakp);\r
+          PUTSHORT(PPP_CHAP, nakp);\r
+          PUTCHAR(ao->chap_mdtype, nakp);\r
+        } else {\r
+          LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort));\r
+          PUTCHAR(CILEN_SHORT, nakp);\r
+          PUTSHORT(PPP_PAP, nakp);\r
+        }\r
+        break;\r
+      \r
+      case CI_QUALITY:\r
+        GETSHORT(cishort, p);\r
+        GETLONG(cilong, p);\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " QUALITY (%x %x)", cishort, (unsigned int) cilong);\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+\r
+        if (!ao->neg_lqr ||\r
+            cilen != CILEN_LQR) {\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        \r
+        /*\r
+         * Check the protocol and the reporting period.\r
+         * XXX When should we Nak this, and what with?\r
+         */\r
+        if (cishort != PPP_LQR) {\r
+          orc = CONFNAK;\r
+          PUTCHAR(CI_QUALITY, nakp);\r
+          PUTCHAR(CILEN_LQR, nakp);\r
+          PUTSHORT(PPP_LQR, nakp);\r
+          PUTLONG(ao->lqr_period, nakp);\r
+          break;\r
+        }\r
+        break;\r
+      \r
+      case CI_MAGICNUMBER:\r
+        if (!(ao->neg_magicnumber || go->neg_magicnumber) ||\r
+            cilen != CILEN_LONG) {\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        GETLONG(cilong, p);\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " MAGICNUMBER (%lX)", cilong);\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+\r
+        /*\r
+         * He must have a different magic number.\r
+         */\r
+        if (go->neg_magicnumber &&\r
+            cilong == go->magicnumber) {\r
+          cilong = magic();  /* Don't put magic() inside macro! */\r
+          orc = CONFNAK;\r
+          PUTCHAR(CI_MAGICNUMBER, nakp);\r
+          PUTCHAR(CILEN_LONG, nakp);\r
+          PUTLONG(cilong, nakp);\r
+          break;\r
+        }\r
+        ho->neg_magicnumber = 1;\r
+        ho->magicnumber = cilong;\r
+        break;\r
+      \r
+      \r
+      case CI_PCOMPRESSION:\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " PCOMPRESSION");\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        if (!ao->neg_pcompression ||\r
+            cilen != CILEN_VOID) {\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        ho->neg_pcompression = 1;\r
+        break;\r
+      \r
+      case CI_ACCOMPRESSION:\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " ACCOMPRESSION");\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        if (!ao->neg_accompression ||\r
+            cilen != CILEN_VOID) {\r
+          orc = CONFREJ;\r
+          break;\r
+        }\r
+        ho->neg_accompression = 1;\r
+        break;\r
+      \r
+      case CI_MRRU:\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_MRRU");\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        orc = CONFREJ;\r
+        break;\r
+      \r
+      case CI_SSNHF:\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_SSNHF");\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        orc = CONFREJ;\r
+        break;\r
+      \r
+      case CI_EPDISC:\r
+#if TRACELCP > 0\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CI_EPDISC");\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        orc = CONFREJ;\r
+        break;\r
+      \r
+      default:\r
+#if TRACELCP\r
+        snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " unknown %d", citype);\r
+        traceNdx = strlen(traceBuf);\r
+#endif\r
+        orc = CONFREJ;\r
+        break;\r
+    }\r
+\r
+  endswitch:\r
+#if TRACELCP\r
+    if (traceNdx >= 80 - 32) {\r
+      LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf));\r
+      traceNdx = 0;\r
+    }\r
+#endif\r
+    if (orc == CONFACK && /* Good CI */\r
+        rc != CONFACK) {  /*  but prior CI wasnt? */\r
+      continue;           /* Don't send this one */\r
+    }\r
+\r
+    if (orc == CONFNAK) {     /* Nak this CI? */\r
+      if (reject_if_disagree  /* Getting fed up with sending NAKs? */\r
+          && citype != CI_MAGICNUMBER) {\r
+        orc = CONFREJ;        /* Get tough if so */\r
+      } else {\r
+        if (rc == CONFREJ) {  /* Rejecting prior CI? */\r
+          continue;           /* Don't send this one */\r
+        }\r
+        rc = CONFNAK;\r
+      }\r
+    }\r
+    if (orc == CONFREJ) {        /* Reject this CI */\r
+      rc = CONFREJ;\r
+      if (cip != rejp) {         /* Need to move rejected CI? */\r
+        BCOPY(cip, rejp, cilen); /* Move it */\r
+      }\r
+      INCPTR(cilen, rejp);       /* Update output pointer */\r
+    }\r
+  }\r
+\r
+  /*\r
+   * If we wanted to send additional NAKs (for unsent CIs), the\r
+   * code would go here.  The extra NAKs would go at *nakp.\r
+   * At present there are no cases where we want to ask the\r
+   * peer to negotiate an option.\r
+   */\r
+\r
+  switch (rc) {\r
+    case CONFACK:\r
+      *lenp = (int)(next - inp);\r
+      break;\r
+    case CONFNAK:\r
+      /*\r
+       * Copy the Nak'd options from the nak_buffer to the caller's buffer.\r
+       */\r
+      *lenp = (int)(nakp - nak_buffer);\r
+      BCOPY(nak_buffer, inp, *lenp);\r
+      break;\r
+    case CONFREJ:\r
+      *lenp = (int)(rejp - inp);\r
+      break;\r
+  }\r
+\r
+#if TRACELCP > 0\r
+  if (traceNdx > 0) {\r
+    LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf));\r
+  }\r
+#endif\r
+  LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc)));\r
+  return (rc);      /* Return final code */\r
+}\r
+\r
+\r
+/*\r
+ * lcp_up - LCP has come UP.\r
+ */\r
+static void\r
+lcp_up(fsm *f)\r
+{\r
+  lcp_options *wo = &lcp_wantoptions[f->unit];\r
+  lcp_options *ho = &lcp_hisoptions[f->unit];\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+  lcp_options *ao = &lcp_allowoptions[f->unit];\r
+\r
+  if (!go->neg_magicnumber) {\r
+    go->magicnumber = 0;\r
+  }\r
+  if (!ho->neg_magicnumber) {\r
+    ho->magicnumber = 0;\r
+  }\r
+\r
+  /*\r
+   * Set our MTU to the smaller of the MTU we wanted and\r
+   * the MRU our peer wanted.  If we negotiated an MRU,\r
+   * set our MRU to the larger of value we wanted and\r
+   * the value we got in the negotiation.\r
+   */\r
+  ppp_send_config(f->unit, LWIP_MIN(ao->mru, (ho->neg_mru? ho->mru: PPP_MRU)),\r
+                 (ho->neg_asyncmap? ho->asyncmap: 0xffffffffl),\r
+                  ho->neg_pcompression, ho->neg_accompression);\r
+  /*\r
+   * If the asyncmap hasn't been negotiated, we really should\r
+   * set the receive asyncmap to ffffffff, but we set it to 0\r
+   * for backwards contemptibility.\r
+   */\r
+  ppp_recv_config(f->unit, (go->neg_mru? LWIP_MAX(wo->mru, go->mru): PPP_MRU),\r
+                 (go->neg_asyncmap? go->asyncmap: 0x00000000),\r
+                  go->neg_pcompression, go->neg_accompression);\r
+\r
+  if (ho->neg_mru) {\r
+    peer_mru[f->unit] = ho->mru;\r
+  }\r
+\r
+  lcp_echo_lowerup(f->unit); /* Enable echo messages */\r
+\r
+  link_established(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_down - LCP has gone DOWN.\r
+ *\r
+ * Alert other protocols.\r
+ */\r
+static void\r
+lcp_down(fsm *f)\r
+{\r
+  lcp_options *go = &lcp_gotoptions[f->unit];\r
+\r
+  lcp_echo_lowerdown(f->unit);\r
+\r
+  link_down(f->unit);\r
+\r
+  ppp_send_config(f->unit, PPP_MRU, 0xffffffffl, 0, 0);\r
+  ppp_recv_config(f->unit, PPP_MRU,\r
+                  (go->neg_asyncmap? go->asyncmap: 0x00000000),\r
+                   go->neg_pcompression, go->neg_accompression);\r
+  peer_mru[f->unit] = PPP_MRU;\r
+}\r
+\r
+\r
+/*\r
+ * lcp_starting - LCP needs the lower layer up.\r
+ */\r
+static void\r
+lcp_starting(fsm *f)\r
+{\r
+  link_required(f->unit);\r
+}\r
+\r
+\r
+/*\r
+ * lcp_finished - LCP has finished with the lower layer.\r
+ */\r
+static void\r
+lcp_finished(fsm *f)\r
+{\r
+  link_terminated(f->unit);\r
+}\r
+\r
+\r
+#if 0\r
+/*\r
+ * print_string - print a readable representation of a string using\r
+ * printer.\r
+ */\r
+static void\r
+print_string( char *p, int len, void (*printer) (void *, char *, ...), void *arg)\r
+{\r
+  int c;\r
+  \r
+  printer(arg, "\"");\r
+  for (; len > 0; --len) {\r
+    c = *p++;\r
+    if (' ' <= c && c <= '~') {\r
+        if (c == '\\' || c == '"') {\r
+          printer(arg, "\\");\r
+        }\r
+        printer(arg, "%c", c);\r
+    } else {\r
+      switch (c) {\r
+        case '\n':\r
+          printer(arg, "\\n");\r
+          break;\r
+        case '\r':\r
+          printer(arg, "\\r");\r
+          break;\r
+        case '\t':\r
+          printer(arg, "\\t");\r
+          break;\r
+        default:\r
+          printer(arg, "\\%.3o", c);\r
+        }\r
+    }\r
+  }\r
+  printer(arg, "\"");\r
+}\r
+\r
+\r
+/*\r
+ * lcp_printpkt - print the contents of an LCP packet.\r
+ */\r
+static char *lcp_codenames[] = {\r
+  "ConfReq", "ConfAck", "ConfNak", "ConfRej",\r
+  "TermReq", "TermAck", "CodeRej", "ProtRej",\r
+  "EchoReq", "EchoRep", "DiscReq"\r
+};\r
+\r
+static int\r
+lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg)\r
+{\r
+  int code, id, len, olen;\r
+  u_char *pstart, *optend;\r
+  u_short cishort;\r
+  u32_t cilong;\r
+\r
+  if (plen < HEADERLEN) {\r
+    return 0;\r
+  }\r
+  pstart = p;\r
+  GETCHAR(code, p);\r
+  GETCHAR(id, p);\r
+  GETSHORT(len, p);\r
+  if (len < HEADERLEN || len > plen) {\r
+    return 0;\r
+  }\r
+\r
+  if (code >= 1 && code <= sizeof(lcp_codenames) / sizeof(char *)) {\r
+    printer(arg, " %s", lcp_codenames[code-1]);\r
+  } else {\r
+    printer(arg, " code=0x%x", code);\r
+  }\r
+  printer(arg, " id=0x%x", id);\r
+  len -= HEADERLEN;\r
+  switch (code) {\r
+    case CONFREQ:\r
+    case CONFACK:\r
+    case CONFNAK:\r
+    case CONFREJ:\r
+      /* print option list */\r
+      while (len >= 2) {\r
+        GETCHAR(code, p);\r
+        GETCHAR(olen, p);\r
+        p -= 2;\r
+        if (olen < 2 || olen > len) {\r
+          break;\r
+        }\r
+        printer(arg, " <");\r
+        len -= olen;\r
+        optend = p + olen;\r
+        switch (code) {\r
+          case CI_MRU:\r
+            if (olen == CILEN_SHORT) {\r
+              p += 2;\r
+              GETSHORT(cishort, p);\r
+              printer(arg, "mru %d", cishort);\r
+            }\r
+            break;\r
+          case CI_ASYNCMAP:\r
+            if (olen == CILEN_LONG) {\r
+              p += 2;\r
+              GETLONG(cilong, p);\r
+              printer(arg, "asyncmap 0x%lx", cilong);\r
+            }\r
+            break;\r
+          case CI_AUTHTYPE:\r
+            if (olen >= CILEN_SHORT) {\r
+              p += 2;\r
+              printer(arg, "auth ");\r
+              GETSHORT(cishort, p);\r
+              switch (cishort) {\r
+                case PPP_PAP:\r
+                  printer(arg, "pap");\r
+                  break;\r
+                case PPP_CHAP:\r
+                  printer(arg, "chap");\r
+                  break;\r
+                default:\r
+                  printer(arg, "0x%x", cishort);\r
+              }\r
+            }\r
+            break;\r
+          case CI_QUALITY:\r
+            if (olen >= CILEN_SHORT) {\r
+              p += 2;\r
+              printer(arg, "quality ");\r
+              GETSHORT(cishort, p);\r
+              switch (cishort) {\r
+                case PPP_LQR:\r
+                  printer(arg, "lqr");\r
+                  break;\r
+                default:\r
+                  printer(arg, "0x%x", cishort);\r
+              }\r
+            }\r
+            break;\r
+          case CI_CALLBACK:\r
+            if (olen >= CILEN_CHAR) {\r
+              p += 2;\r
+              printer(arg, "callback ");\r
+              GETSHORT(cishort, p);\r
+              switch (cishort) {\r
+                case CBCP_OPT:\r
+                  printer(arg, "CBCP");\r
+                  break;\r
+                default:\r
+                  printer(arg, "0x%x", cishort);\r
+              }\r
+            }\r
+            break;\r
+          case CI_MAGICNUMBER:\r
+            if (olen == CILEN_LONG) {\r
+              p += 2;\r
+              GETLONG(cilong, p);\r
+              printer(arg, "magic 0x%x", cilong);\r
+            }\r
+            break;\r
+          case CI_PCOMPRESSION:\r
+            if (olen == CILEN_VOID) {\r
+              p += 2;\r
+              printer(arg, "pcomp");\r
+            }\r
+            break;\r
+          case CI_ACCOMPRESSION:\r
+            if (olen == CILEN_VOID) {\r
+              p += 2;\r
+              printer(arg, "accomp");\r
+            }\r
+            break;\r
+        }\r
+        while (p < optend) {\r
+          GETCHAR(code, p);\r
+          printer(arg, " %.2x", code);\r
+        }\r
+        printer(arg, ">");\r
+      }\r
+      break;\r
+    \r
+    case TERMACK:\r
+    case TERMREQ:\r
+      if (len > 0 && *p >= ' ' && *p < 0x7f) {\r
+        printer(arg, " ");\r
+        print_string((char*)p, len, printer, arg);\r
+        p += len;\r
+        len = 0;\r
+      }\r
+      break;\r
+    \r
+    case ECHOREQ:\r
+    case ECHOREP:\r
+    case DISCREQ:\r
+      if (len >= 4) {\r
+        GETLONG(cilong, p);\r
+        printer(arg, " magic=0x%x", cilong);\r
+        p += 4;\r
+        len -= 4;\r
+      }\r
+      break;\r
+  }\r
+\r
+  /* print the rest of the bytes in the packet */\r
+  for (; len > 0; --len) {\r
+    GETCHAR(code, p);\r
+    printer(arg, " %.2x", code);\r
+  }\r
+\r
+  return (int)(p - pstart);\r
+}\r
+#endif\r
+\r
+/*\r
+ * Time to shut down the link because there is nothing out there.\r
+ */\r
+static void\r
+LcpLinkFailure (fsm *f)\r
+{\r
+  if (f->state == LS_OPENED) {\r
+    LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending));\r
+    LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n"));\r
+    lcp_close(f->unit, "Peer not responding");\r
+  }\r
+}\r
+\r
+/*\r
+ * Timer expired for the LCP echo requests from this process.\r
+ */\r
+static void\r
+LcpEchoCheck (fsm *f)\r
+{\r
+  LcpSendEchoRequest (f);\r
+\r
+  /*\r
+   * Start the timer for the next interval.\r
+   */\r
+  LWIP_ASSERT("lcp_echo_timer_running == 0", lcp_echo_timer_running == 0);\r
+\r
+  TIMEOUT (LcpEchoTimeout, f, lcp_echo_interval);\r
+  lcp_echo_timer_running = 1;\r
+}\r
+\r
+/*\r
+ * LcpEchoTimeout - Timer expired on the LCP echo\r
+ */\r
+static void\r
+LcpEchoTimeout (void *arg)\r
+{\r
+  if (lcp_echo_timer_running != 0) {\r
+    lcp_echo_timer_running = 0;\r
+    LcpEchoCheck ((fsm *) arg);\r
+  }\r
+}\r
+\r
+/*\r
+ * LcpEchoReply - LCP has received a reply to the echo\r
+ */\r
+static void\r
+lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len)\r
+{\r
+  u32_t magic;\r
+\r
+  LWIP_UNUSED_ARG(id);\r
+\r
+  /* Check the magic number - don't count replies from ourselves. */\r
+  if (len < 4) {\r
+    LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len));\r
+    return;\r
+  }\r
+  GETLONG(magic, inp);\r
+  if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) {\r
+    LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n"));\r
+    return;\r
+  }\r
+  \r
+  /* Reset the number of outstanding echo frames */\r
+  lcp_echos_pending = 0;\r
+}\r
+\r
+/*\r
+ * LcpSendEchoRequest - Send an echo request frame to the peer\r
+ */\r
+static void\r
+LcpSendEchoRequest (fsm *f)\r
+{\r
+  u32_t lcp_magic;\r
+  u_char pkt[4], *pktp;\r
+\r
+  /*\r
+   * Detect the failure of the peer at this point.\r
+   */\r
+  if (lcp_echo_fails != 0) {\r
+    if (lcp_echos_pending++ >= lcp_echo_fails) {\r
+      LcpLinkFailure(f);\r
+      lcp_echos_pending = 0;\r
+    }\r
+  }\r
+\r
+  /*\r
+   * Make and send the echo request frame.\r
+   */\r
+  if (f->state == LS_OPENED) {\r
+    lcp_magic = lcp_gotoptions[f->unit].magicnumber;\r
+    pktp = pkt;\r
+    PUTLONG(lcp_magic, pktp);\r
+    fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt));\r
+  }\r
+}\r
+\r
+/*\r
+ * lcp_echo_lowerup - Start the timer for the LCP frame\r
+ */\r
+\r
+static void\r
+lcp_echo_lowerup (int unit)\r
+{\r
+  fsm *f = &lcp_fsm[unit];\r
+\r
+  /* Clear the parameters for generating echo frames */\r
+  lcp_echos_pending      = 0;\r
+  lcp_echo_number        = 0;\r
+  lcp_echo_timer_running = 0;\r
+\r
+  /* If a timeout interval is specified then start the timer */\r
+  if (lcp_echo_interval != 0) {\r
+    LcpEchoCheck (f);\r
+  }\r
+}\r
+\r
+/*\r
+ * lcp_echo_lowerdown - Stop the timer for the LCP frame\r
+ */\r
+\r
+static void\r
+lcp_echo_lowerdown (int unit)\r
+{\r
+  fsm *f = &lcp_fsm[unit];\r
+\r
+  if (lcp_echo_timer_running != 0) {\r
+    UNTIMEOUT (LcpEchoTimeout, f);\r
+    lcp_echo_timer_running = 0;\r
+  }\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/lcp.h
new file mode 100644 (file)
index 0000000..5e3f757
--- /dev/null
@@ -0,0 +1,167 @@
+/*****************************************************************************\r
+* lcp.h - Network Link Control Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * lcp.h - Link Control Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: lcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $\r
+ */\r
+\r
+#ifndef LCP_H\r
+#define LCP_H\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+/*\r
+ * Options.\r
+ */\r
+#define CI_MRU           1  /* Maximum Receive Unit */\r
+#define CI_ASYNCMAP      2  /* Async Control Character Map */\r
+#define CI_AUTHTYPE      3  /* Authentication Type */\r
+#define CI_QUALITY       4  /* Quality Protocol */\r
+#define CI_MAGICNUMBER   5  /* Magic Number */\r
+#define CI_PCOMPRESSION  7  /* Protocol Field Compression */\r
+#define CI_ACCOMPRESSION 8  /* Address/Control Field Compression */\r
+#define CI_CALLBACK      13 /* callback */\r
+#define CI_MRRU          17 /* max reconstructed receive unit; multilink */\r
+#define CI_SSNHF         18 /* short sequence numbers for multilink */\r
+#define CI_EPDISC        19 /* endpoint discriminator */\r
+\r
+/*\r
+ * LCP-specific packet types.\r
+ */\r
+#define PROTREJ          8  /* Protocol Reject */\r
+#define ECHOREQ          9  /* Echo Request */\r
+#define ECHOREP          10 /* Echo Reply */\r
+#define DISCREQ          11 /* Discard Request */\r
+#define CBCP_OPT         6  /* Use callback control protocol */\r
+\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * The state of options is described by an lcp_options structure.\r
+ */\r
+typedef struct lcp_options {\r
+    u_int passive           : 1; /* Don't die if we don't get a response */\r
+    u_int silent            : 1; /* Wait for the other end to start first */\r
+    u_int restart           : 1; /* Restart vs. exit after close */\r
+    u_int neg_mru           : 1; /* Negotiate the MRU? */\r
+    u_int neg_asyncmap      : 1; /* Negotiate the async map? */\r
+    u_int neg_upap          : 1; /* Ask for UPAP authentication? */\r
+    u_int neg_chap          : 1; /* Ask for CHAP authentication? */\r
+    u_int neg_magicnumber   : 1; /* Ask for magic number? */\r
+    u_int neg_pcompression  : 1; /* HDLC Protocol Field Compression? */\r
+    u_int neg_accompression : 1; /* HDLC Address/Control Field Compression? */\r
+    u_int neg_lqr           : 1; /* Negotiate use of Link Quality Reports */\r
+    u_int neg_cbcp          : 1; /* Negotiate use of CBCP */\r
+#ifdef PPP_MULTILINK\r
+    u_int neg_mrru          : 1; /* Negotiate multilink MRRU */\r
+    u_int neg_ssnhf         : 1; /* Negotiate short sequence numbers */\r
+    u_int neg_endpoint      : 1; /* Negotiate endpoint discriminator */\r
+#endif\r
+    u_short mru;                 /* Value of MRU */\r
+#ifdef PPP_MULTILINK\r
+    u_short mrru;                /* Value of MRRU, and multilink enable */\r
+#endif\r
+    u_char chap_mdtype;          /* which MD type (hashing algorithm) */\r
+    u32_t asyncmap;              /* Value of async map */\r
+    u32_t magicnumber;\r
+    int numloops;                /* Number of loops during magic number neg. */\r
+    u32_t lqr_period;            /* Reporting period for LQR 1/100ths second */\r
+#ifdef PPP_MULTILINK\r
+    struct epdisc endpoint;      /* endpoint discriminator */\r
+#endif\r
+} lcp_options;\r
+\r
+/*\r
+ * Values for phase from BSD pppd.h based on RFC 1661.\r
+ */\r
+typedef enum {\r
+  PHASE_DEAD = 0,\r
+  PHASE_INITIALIZE,\r
+  PHASE_ESTABLISH,\r
+  PHASE_AUTHENTICATE,\r
+  PHASE_CALLBACK,\r
+  PHASE_NETWORK,\r
+  PHASE_TERMINATE\r
+} LinkPhase;\r
+\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+\r
+extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */\r
+extern lcp_options lcp_wantoptions[];\r
+extern lcp_options lcp_gotoptions[];\r
+extern lcp_options lcp_allowoptions[];\r
+extern lcp_options lcp_hisoptions[];\r
+extern ext_accm xmit_accm[];\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+void lcp_init     (int);\r
+void lcp_open     (int);\r
+void lcp_close    (int, char *);\r
+void lcp_lowerup  (int);\r
+void lcp_lowerdown(int);\r
+void lcp_sprotrej (int, u_char *, int); /* send protocol reject */\r
+\r
+extern struct protent lcp_protent;\r
+\r
+/* Default number of times we receive our magic number from the peer\r
+   before deciding the link is looped-back. */\r
+#define DEFLOOPBACKFAIL 10\r
+\r
+#endif /* LCP_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.c
new file mode 100644 (file)
index 0000000..e4ff2e6
--- /dev/null
@@ -0,0 +1,82 @@
+/*****************************************************************************\r
+* magic.c - Network Random Number Generator program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original based on BSD magic.c.\r
+*****************************************************************************/\r
+/*\r
+ * magic.c - PPP Magic Number routines.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT\r
+\r
+#include "ppp.h"\r
+#include "randm.h"\r
+#include "magic.h"\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * magicInit - Initialize the magic number generator.\r
+ *\r
+ * Since we use another random number generator that has its own\r
+ * initialization, we do nothing here.\r
+ */\r
+void magicInit()\r
+{\r
+  return;\r
+}\r
+\r
+/*\r
+ * magic - Returns the next magic number.\r
+ */\r
+u32_t magic()\r
+{\r
+  return avRandom();\r
+}\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/magic.h
new file mode 100644 (file)
index 0000000..2082349
--- /dev/null
@@ -0,0 +1,67 @@
+/*****************************************************************************\r
+* magic.h - Network Random Number Generator header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * magic.h - PPP Magic Number definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * $Id: magic.h,v 1.2 2007/12/02 22:35:55 fbernon Exp $\r
+ */\r
+\r
+#ifndef MAGIC_H\r
+#define MAGIC_H\r
+\r
+/*****************************************************************************\r
+************************** PUBLIC FUNCTIONS **********************************\r
+*****************************************************************************/\r
+\r
+/* Initialize the magic number generator */\r
+void  magicInit(void);\r
+\r
+/* Returns the next magic number */\r
+u32_t magic(void);\r
+\r
+#endif /* MAGIC_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.c
new file mode 100644 (file)
index 0000000..87c219c
--- /dev/null
@@ -0,0 +1,318 @@
+/*\r
+ ***********************************************************************\r
+ ** md5.c -- the source code for MD5 routines                         **\r
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **\r
+ ** Created: 2/17/90 RLR                                              **\r
+ ** Revised: 1/91 SRD,AJ,BSK,JT Reference C ver., 7/10 constant corr. **\r
+ ***********************************************************************\r
+ */\r
+\r
+/*\r
+ ***********************************************************************\r
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **\r
+ **                                                                   **\r
+ ** License to copy and use this software is granted provided that    **\r
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **\r
+ ** Digest Algorithm" in all material mentioning or referencing this  **\r
+ ** software or this function.                                        **\r
+ **                                                                   **\r
+ ** License is also granted to make and use derivative works          **\r
+ ** provided that such works are identified as "derived from the RSA  **\r
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **\r
+ ** material mentioning or referencing the derived work.              **\r
+ **                                                                   **\r
+ ** RSA Data Security, Inc. makes no representations concerning       **\r
+ ** either the merchantability of this software or the suitability    **\r
+ ** of this software for any particular purpose.  It is provided "as  **\r
+ ** is" without express or implied warranty of any kind.              **\r
+ **                                                                   **\r
+ ** These notices must be retained in any copies of any part of this  **\r
+ ** documentation and/or software.                                    **\r
+ ***********************************************************************\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#if CHAP_SUPPORT || MD5_SUPPORT\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "md5.h"\r
+\r
+/*\r
+ ***********************************************************************\r
+ **  Message-digest routines:                                         **\r
+ **  To form the message digest for a message M                       **\r
+ **    (1) Initialize a context buffer mdContext using MD5Init        **\r
+ **    (2) Call MD5Update on mdContext and M                          **\r
+ **    (3) Call MD5Final on mdContext                                 **\r
+ **  The message digest is now in mdContext->digest[0...15]           **\r
+ ***********************************************************************\r
+ */\r
+\r
+/* forward declaration */\r
+static void Transform (u32_t *buf, u32_t *in);\r
+\r
+static unsigned char PADDING[64] = {\r
+  0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,\r
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00\r
+};\r
+\r
+/* F, G, H and I are basic MD5 functions */\r
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))\r
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))\r
+#define H(x, y, z) ((x) ^ (y) ^ (z))\r
+#define I(x, y, z) ((y) ^ ((x) | (~z)))\r
+\r
+/* ROTATE_LEFT rotates x left n bits */\r
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))\r
+\r
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4 */\r
+/* Rotation is separate from addition to prevent recomputation */\r
+#define FF(a, b, c, d, x, s, ac) \\r
+  {(a) += F ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define GG(a, b, c, d, x, s, ac) \\r
+  {(a) += G ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define HH(a, b, c, d, x, s, ac) \\r
+  {(a) += H ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+#define II(a, b, c, d, x, s, ac) \\r
+  {(a) += I ((b), (c), (d)) + (x) + (u32_t)(ac); \\r
+   (a) = ROTATE_LEFT ((a), (s)); \\r
+   (a) += (b); \\r
+  }\r
+\r
+#ifdef __STDC__\r
+#define UL(x) x##UL\r
+#else\r
+#ifdef WIN32\r
+#define UL(x) x##UL\r
+#else\r
+#define UL(x) x\r
+#endif\r
+#endif\r
+\r
+/* The routine MD5Init initializes the message-digest context\r
+   mdContext. All fields are set to zero.\r
+ */\r
+void\r
+MD5Init (MD5_CTX *mdContext)\r
+{\r
+  mdContext->i[0] = mdContext->i[1] = (u32_t)0;\r
+\r
+  /* Load magic initialization constants. */\r
+  mdContext->buf[0] = (u32_t)0x67452301UL;\r
+  mdContext->buf[1] = (u32_t)0xefcdab89UL;\r
+  mdContext->buf[2] = (u32_t)0x98badcfeUL;\r
+  mdContext->buf[3] = (u32_t)0x10325476UL;\r
+}\r
+\r
+/* The routine MD5Update updates the message-digest context to\r
+   account for the presence of each of the characters inBuf[0..inLen-1]\r
+   in the message whose digest is being computed.\r
+ */\r
+void\r
+MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen)\r
+{\r
+  u32_t in[16];\r
+  int mdi;\r
+  unsigned int i, ii;\r
+\r
+#if 0\r
+  ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf);\r
+  ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf);\r
+#endif\r
+  \r
+  /* compute number of bytes mod 64 */\r
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);\r
+\r
+  /* update number of bits */\r
+  if ((mdContext->i[0] + ((u32_t)inLen << 3)) < mdContext->i[0]) {\r
+    mdContext->i[1]++;\r
+  }\r
+  mdContext->i[0] += ((u32_t)inLen << 3);\r
+  mdContext->i[1] += ((u32_t)inLen >> 29);\r
+\r
+  while (inLen--) {\r
+    /* add new character to buffer, increment mdi */\r
+    mdContext->in[mdi++] = *inBuf++;\r
+\r
+    /* transform if necessary */\r
+    if (mdi == 0x40) {\r
+      for (i = 0, ii = 0; i < 16; i++, ii += 4) {\r
+        in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |\r
+                (((u32_t)mdContext->in[ii+2]) << 16) |\r
+                (((u32_t)mdContext->in[ii+1]) << 8)  |\r
+                ((u32_t)mdContext->in[ii]);\r
+      }\r
+      Transform (mdContext->buf, in);\r
+      mdi = 0;\r
+    }\r
+  }\r
+}\r
+\r
+/* The routine MD5Final terminates the message-digest computation and\r
+   ends with the desired message digest in mdContext->digest[0...15].\r
+ */\r
+void\r
+MD5Final (unsigned char hash[], MD5_CTX *mdContext)\r
+{\r
+  u32_t in[16];\r
+  int mdi;\r
+  unsigned int i, ii;\r
+  unsigned int padLen;\r
+\r
+  /* save number of bits */\r
+  in[14] = mdContext->i[0];\r
+  in[15] = mdContext->i[1];\r
+\r
+  /* compute number of bytes mod 64 */\r
+  mdi = (int)((mdContext->i[0] >> 3) & 0x3F);\r
+\r
+  /* pad out to 56 mod 64 */\r
+  padLen = (mdi < 56) ? (56 - mdi) : (120 - mdi);\r
+  MD5Update (mdContext, PADDING, padLen);\r
+\r
+  /* append length in bits and transform */\r
+  for (i = 0, ii = 0; i < 14; i++, ii += 4) {\r
+    in[i] = (((u32_t)mdContext->in[ii+3]) << 24) |\r
+            (((u32_t)mdContext->in[ii+2]) << 16) |\r
+            (((u32_t)mdContext->in[ii+1]) << 8)  |\r
+            ((u32_t)mdContext->in[ii]);\r
+  }\r
+  Transform (mdContext->buf, in);\r
+\r
+  /* store buffer in digest */\r
+  for (i = 0, ii = 0; i < 4; i++, ii += 4) {\r
+    mdContext->digest[ii]   = (unsigned char)(mdContext->buf[i] & 0xFF);\r
+    mdContext->digest[ii+1] =\r
+      (unsigned char)((mdContext->buf[i] >> 8)  & 0xFF);\r
+    mdContext->digest[ii+2] =\r
+      (unsigned char)((mdContext->buf[i] >> 16) & 0xFF);\r
+    mdContext->digest[ii+3] =\r
+      (unsigned char)((mdContext->buf[i] >> 24) & 0xFF);\r
+  }\r
+  SMEMCPY(hash, mdContext->digest, 16);\r
+}\r
+\r
+/* Basic MD5 step. Transforms buf based on in.\r
+ */\r
+static void\r
+Transform (u32_t *buf, u32_t *in)\r
+{\r
+  u32_t a = buf[0], b = buf[1], c = buf[2], d = buf[3];\r
+\r
+  /* Round 1 */\r
+#define S11 7\r
+#define S12 12\r
+#define S13 17\r
+#define S14 22\r
+  FF ( a, b, c, d, in[ 0], S11, UL(3614090360)); /* 1 */\r
+  FF ( d, a, b, c, in[ 1], S12, UL(3905402710)); /* 2 */\r
+  FF ( c, d, a, b, in[ 2], S13, UL( 606105819)); /* 3 */\r
+  FF ( b, c, d, a, in[ 3], S14, UL(3250441966)); /* 4 */\r
+  FF ( a, b, c, d, in[ 4], S11, UL(4118548399)); /* 5 */\r
+  FF ( d, a, b, c, in[ 5], S12, UL(1200080426)); /* 6 */\r
+  FF ( c, d, a, b, in[ 6], S13, UL(2821735955)); /* 7 */\r
+  FF ( b, c, d, a, in[ 7], S14, UL(4249261313)); /* 8 */\r
+  FF ( a, b, c, d, in[ 8], S11, UL(1770035416)); /* 9 */\r
+  FF ( d, a, b, c, in[ 9], S12, UL(2336552879)); /* 10 */\r
+  FF ( c, d, a, b, in[10], S13, UL(4294925233)); /* 11 */\r
+  FF ( b, c, d, a, in[11], S14, UL(2304563134)); /* 12 */\r
+  FF ( a, b, c, d, in[12], S11, UL(1804603682)); /* 13 */\r
+  FF ( d, a, b, c, in[13], S12, UL(4254626195)); /* 14 */\r
+  FF ( c, d, a, b, in[14], S13, UL(2792965006)); /* 15 */\r
+  FF ( b, c, d, a, in[15], S14, UL(1236535329)); /* 16 */\r
+\r
+  /* Round 2 */\r
+#define S21 5\r
+#define S22 9\r
+#define S23 14\r
+#define S24 20\r
+  GG ( a, b, c, d, in[ 1], S21, UL(4129170786)); /* 17 */\r
+  GG ( d, a, b, c, in[ 6], S22, UL(3225465664)); /* 18 */\r
+  GG ( c, d, a, b, in[11], S23, UL( 643717713)); /* 19 */\r
+  GG ( b, c, d, a, in[ 0], S24, UL(3921069994)); /* 20 */\r
+  GG ( a, b, c, d, in[ 5], S21, UL(3593408605)); /* 21 */\r
+  GG ( d, a, b, c, in[10], S22, UL(  38016083)); /* 22 */\r
+  GG ( c, d, a, b, in[15], S23, UL(3634488961)); /* 23 */\r
+  GG ( b, c, d, a, in[ 4], S24, UL(3889429448)); /* 24 */\r
+  GG ( a, b, c, d, in[ 9], S21, UL( 568446438)); /* 25 */\r
+  GG ( d, a, b, c, in[14], S22, UL(3275163606)); /* 26 */\r
+  GG ( c, d, a, b, in[ 3], S23, UL(4107603335)); /* 27 */\r
+  GG ( b, c, d, a, in[ 8], S24, UL(1163531501)); /* 28 */\r
+  GG ( a, b, c, d, in[13], S21, UL(2850285829)); /* 29 */\r
+  GG ( d, a, b, c, in[ 2], S22, UL(4243563512)); /* 30 */\r
+  GG ( c, d, a, b, in[ 7], S23, UL(1735328473)); /* 31 */\r
+  GG ( b, c, d, a, in[12], S24, UL(2368359562)); /* 32 */\r
+\r
+  /* Round 3 */\r
+#define S31 4\r
+#define S32 11\r
+#define S33 16\r
+#define S34 23\r
+  HH ( a, b, c, d, in[ 5], S31, UL(4294588738)); /* 33 */\r
+  HH ( d, a, b, c, in[ 8], S32, UL(2272392833)); /* 34 */\r
+  HH ( c, d, a, b, in[11], S33, UL(1839030562)); /* 35 */\r
+  HH ( b, c, d, a, in[14], S34, UL(4259657740)); /* 36 */\r
+  HH ( a, b, c, d, in[ 1], S31, UL(2763975236)); /* 37 */\r
+  HH ( d, a, b, c, in[ 4], S32, UL(1272893353)); /* 38 */\r
+  HH ( c, d, a, b, in[ 7], S33, UL(4139469664)); /* 39 */\r
+  HH ( b, c, d, a, in[10], S34, UL(3200236656)); /* 40 */\r
+  HH ( a, b, c, d, in[13], S31, UL( 681279174)); /* 41 */\r
+  HH ( d, a, b, c, in[ 0], S32, UL(3936430074)); /* 42 */\r
+  HH ( c, d, a, b, in[ 3], S33, UL(3572445317)); /* 43 */\r
+  HH ( b, c, d, a, in[ 6], S34, UL(  76029189)); /* 44 */\r
+  HH ( a, b, c, d, in[ 9], S31, UL(3654602809)); /* 45 */\r
+  HH ( d, a, b, c, in[12], S32, UL(3873151461)); /* 46 */\r
+  HH ( c, d, a, b, in[15], S33, UL( 530742520)); /* 47 */\r
+  HH ( b, c, d, a, in[ 2], S34, UL(3299628645)); /* 48 */\r
+\r
+  /* Round 4 */\r
+#define S41 6\r
+#define S42 10\r
+#define S43 15\r
+#define S44 21\r
+  II ( a, b, c, d, in[ 0], S41, UL(4096336452)); /* 49 */\r
+  II ( d, a, b, c, in[ 7], S42, UL(1126891415)); /* 50 */\r
+  II ( c, d, a, b, in[14], S43, UL(2878612391)); /* 51 */\r
+  II ( b, c, d, a, in[ 5], S44, UL(4237533241)); /* 52 */\r
+  II ( a, b, c, d, in[12], S41, UL(1700485571)); /* 53 */\r
+  II ( d, a, b, c, in[ 3], S42, UL(2399980690)); /* 54 */\r
+  II ( c, d, a, b, in[10], S43, UL(4293915773)); /* 55 */\r
+  II ( b, c, d, a, in[ 1], S44, UL(2240044497)); /* 56 */\r
+  II ( a, b, c, d, in[ 8], S41, UL(1873313359)); /* 57 */\r
+  II ( d, a, b, c, in[15], S42, UL(4264355552)); /* 58 */\r
+  II ( c, d, a, b, in[ 6], S43, UL(2734768916)); /* 59 */\r
+  II ( b, c, d, a, in[13], S44, UL(1309151649)); /* 60 */\r
+  II ( a, b, c, d, in[ 4], S41, UL(4149444226)); /* 61 */\r
+  II ( d, a, b, c, in[11], S42, UL(3174756917)); /* 62 */\r
+  II ( c, d, a, b, in[ 2], S43, UL( 718787259)); /* 63 */\r
+  II ( b, c, d, a, in[ 9], S44, UL(3951481745)); /* 64 */\r
+\r
+  buf[0] += a;\r
+  buf[1] += b;\r
+  buf[2] += c;\r
+  buf[3] += d;\r
+}\r
+\r
+#endif /* CHAP_SUPPORT || MD5_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/md5.h
new file mode 100644 (file)
index 0000000..0bcb23c
--- /dev/null
@@ -0,0 +1,55 @@
+/*\r
+ ***********************************************************************\r
+ ** md5.h -- header file for implementation of MD5                    **\r
+ ** RSA Data Security, Inc. MD5 Message-Digest Algorithm              **\r
+ ** Created: 2/17/90 RLR                                              **\r
+ ** Revised: 12/27/90 SRD,AJ,BSK,JT Reference C version               **\r
+ ** Revised (for MD5): RLR 4/27/91                                    **\r
+ **   -- G modified to have y&~z instead of y&z                       **\r
+ **   -- FF, GG, HH modified to add in last register done             **\r
+ **   -- Access pattern: round 2 works mod 5, round 3 works mod 3     **\r
+ **   -- distinct additive constant for each step                     **\r
+ **   -- round 4 added, working mod 7                                 **\r
+ ***********************************************************************\r
+ */\r
+\r
+/*\r
+ ***********************************************************************\r
+ ** Copyright (C) 1990, RSA Data Security, Inc. All rights reserved.  **\r
+ **                                                                   **\r
+ ** License to copy and use this software is granted provided that    **\r
+ ** it is identified as the "RSA Data Security, Inc. MD5 Message-     **\r
+ ** Digest Algorithm" in all material mentioning or referencing this  **\r
+ ** software or this function.                                        **\r
+ **                                                                   **\r
+ ** License is also granted to make and use derivative works          **\r
+ ** provided that such works are identified as "derived from the RSA  **\r
+ ** Data Security, Inc. MD5 Message-Digest Algorithm" in all          **\r
+ ** material mentioning or referencing the derived work.              **\r
+ **                                                                   **\r
+ ** RSA Data Security, Inc. makes no representations concerning       **\r
+ ** either the merchantability of this software or the suitability    **\r
+ ** of this software for any particular purpose.  It is provided "as  **\r
+ ** is" without express or implied warranty of any kind.              **\r
+ **                                                                   **\r
+ ** These notices must be retained in any copies of any part of this  **\r
+ ** documentation and/or software.                                    **\r
+ ***********************************************************************\r
+ */\r
+\r
+#ifndef MD5_H\r
+#define MD5_H\r
+\r
+/* Data structure for MD5 (Message-Digest) computation */\r
+typedef struct {\r
+  u32_t i[2];               /* number of _bits_ handled mod 2^64 */\r
+  u32_t buf[4];             /* scratch buffer */\r
+  unsigned char in[64];     /* input buffer */\r
+  unsigned char digest[16]; /* actual digest after MD5Final call */\r
+} MD5_CTX;\r
+\r
+void MD5Init  ( MD5_CTX *mdContext);\r
+void MD5Update( MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen);\r
+void MD5Final ( unsigned char hash[], MD5_CTX *mdContext);\r
+\r
+#endif /* MD5_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.c
new file mode 100644 (file)
index 0000000..fea7bbd
--- /dev/null
@@ -0,0 +1,617 @@
+/*****************************************************************************\r
+* pap.c - Network Password Authentication Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-12 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*****************************************************************************/\r
+/*\r
+ * upap.c - User/Password Authentication Protocol.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "auth.h"\r
+#include "pap.h"\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+/*\r
+ * Protocol entry points.\r
+ */\r
+static void upap_init      (int);\r
+static void upap_lowerup   (int);\r
+static void upap_lowerdown (int);\r
+static void upap_input     (int, u_char *, int);\r
+static void upap_protrej   (int);\r
+\r
+static void upap_timeout   (void *);\r
+static void upap_reqtimeout(void *);\r
+static void upap_rauthreq  (upap_state *, u_char *, int, int);\r
+static void upap_rauthack  (upap_state *, u_char *, int, int);\r
+static void upap_rauthnak  (upap_state *, u_char *, int, int);\r
+static void upap_sauthreq  (upap_state *);\r
+static void upap_sresp     (upap_state *, u_char, u_char, char *, int);\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+struct protent pap_protent = {\r
+  PPP_PAP,\r
+  upap_init,\r
+  upap_input,\r
+  upap_protrej,\r
+  upap_lowerup,\r
+  upap_lowerdown,\r
+  NULL,\r
+  NULL,\r
+#if 0\r
+  upap_printpkt,\r
+  NULL,\r
+#endif\r
+  1,\r
+  "PAP",\r
+#if 0\r
+  NULL,\r
+  NULL,\r
+  NULL\r
+#endif\r
+};\r
+\r
+upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */\r
+\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ *  Set the default login name and password for the pap sessions\r
+ */\r
+void\r
+upap_setloginpasswd(int unit, const char *luser, const char *lpassword)\r
+{\r
+  upap_state *u = &upap[unit];\r
+  \r
+  /* Save the username and password we're given */\r
+  u->us_user = luser;\r
+  u->us_userlen = strlen(luser);\r
+  u->us_passwd = lpassword;\r
+  u->us_passwdlen = strlen(lpassword);\r
+}\r
+\r
+\r
+/*\r
+ * upap_authwithpeer - Authenticate us with our peer (start client).\r
+ *\r
+ * Set new state and send authenticate's.\r
+ */\r
+void\r
+upap_authwithpeer(int unit, char *user, char *password)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n",\r
+             unit, user, password, u->us_clientstate));\r
+\r
+  upap_setloginpasswd(unit, user, password);\r
+\r
+  u->us_transmits = 0;\r
+\r
+  /* Lower layer up yet? */\r
+  if (u->us_clientstate == UPAPCS_INITIAL ||\r
+      u->us_clientstate == UPAPCS_PENDING) {\r
+    u->us_clientstate = UPAPCS_PENDING;\r
+    return;\r
+  }\r
+\r
+  upap_sauthreq(u);      /* Start protocol */\r
+}\r
+\r
+\r
+/*\r
+ * upap_authpeer - Authenticate our peer (start server).\r
+ *\r
+ * Set new state.\r
+ */\r
+void\r
+upap_authpeer(int unit)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  /* Lower layer up yet? */\r
+  if (u->us_serverstate == UPAPSS_INITIAL ||\r
+      u->us_serverstate == UPAPSS_PENDING) {\r
+    u->us_serverstate = UPAPSS_PENDING;\r
+    return;\r
+  }\r
+\r
+  u->us_serverstate = UPAPSS_LISTEN;\r
+  if (u->us_reqtimeout > 0) {\r
+    TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);\r
+  }\r
+}\r
+\r
+\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+/*\r
+ * upap_init - Initialize a UPAP unit.\r
+ */\r
+static void\r
+upap_init(int unit)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit));\r
+  u->us_unit         = unit;\r
+  u->us_user         = NULL;\r
+  u->us_userlen      = 0;\r
+  u->us_passwd       = NULL;\r
+  u->us_passwdlen    = 0;\r
+  u->us_clientstate  = UPAPCS_INITIAL;\r
+  u->us_serverstate  = UPAPSS_INITIAL;\r
+  u->us_id           = 0;\r
+  u->us_timeouttime  = UPAP_DEFTIMEOUT;\r
+  u->us_maxtransmits = 10;\r
+  u->us_reqtimeout   = UPAP_DEFREQTIME;\r
+}\r
+\r
+/*\r
+ * upap_timeout - Retransmission timer for sending auth-reqs expired.\r
+ */\r
+static void\r
+upap_timeout(void *arg)\r
+{\r
+  upap_state *u = (upap_state *) arg;\r
+\r
+  UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n", \r
+        u->us_unit, u->us_timeouttime, u->us_clientstate));\r
+\r
+  if (u->us_clientstate != UPAPCS_AUTHREQ) {\r
+    return;\r
+  }\r
+\r
+  if (u->us_transmits >= u->us_maxtransmits) {\r
+    /* give up in disgust */\r
+    UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n"));\r
+    u->us_clientstate = UPAPCS_BADAUTH;\r
+    auth_withpeer_fail(u->us_unit, PPP_PAP);\r
+    return;\r
+  }\r
+\r
+  upap_sauthreq(u);    /* Send Authenticate-Request */\r
+}\r
+\r
+\r
+/*\r
+ * upap_reqtimeout - Give up waiting for the peer to send an auth-req.\r
+ */\r
+static void\r
+upap_reqtimeout(void *arg)\r
+{\r
+  upap_state *u = (upap_state *) arg;\r
+\r
+  if (u->us_serverstate != UPAPSS_LISTEN) {\r
+    return; /* huh?? */\r
+  }\r
+\r
+  auth_peer_fail(u->us_unit, PPP_PAP);\r
+  u->us_serverstate = UPAPSS_BADAUTH;\r
+}\r
+\r
+\r
+/*\r
+ * upap_lowerup - The lower layer is up.\r
+ *\r
+ * Start authenticating if pending.\r
+ */\r
+static void\r
+upap_lowerup(int unit)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate));\r
+\r
+  if (u->us_clientstate == UPAPCS_INITIAL) {\r
+    u->us_clientstate = UPAPCS_CLOSED;\r
+  } else if (u->us_clientstate == UPAPCS_PENDING) {\r
+    upap_sauthreq(u);  /* send an auth-request */\r
+  }\r
+\r
+  if (u->us_serverstate == UPAPSS_INITIAL) {\r
+    u->us_serverstate = UPAPSS_CLOSED;\r
+  } else if (u->us_serverstate == UPAPSS_PENDING) {\r
+    u->us_serverstate = UPAPSS_LISTEN;\r
+    if (u->us_reqtimeout > 0) {\r
+      TIMEOUT(upap_reqtimeout, u, u->us_reqtimeout);\r
+    }\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * upap_lowerdown - The lower layer is down.\r
+ *\r
+ * Cancel all timeouts.\r
+ */\r
+static void\r
+upap_lowerdown(int unit)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate));\r
+\r
+  if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */\r
+    UNTIMEOUT(upap_timeout, u);    /* Cancel timeout */\r
+  }\r
+  if (u->us_serverstate == UPAPSS_LISTEN && u->us_reqtimeout > 0) {\r
+    UNTIMEOUT(upap_reqtimeout, u);\r
+  }\r
+\r
+  u->us_clientstate = UPAPCS_INITIAL;\r
+  u->us_serverstate = UPAPSS_INITIAL;\r
+}\r
+\r
+\r
+/*\r
+ * upap_protrej - Peer doesn't speak this protocol.\r
+ *\r
+ * This shouldn't happen.  In any case, pretend lower layer went down.\r
+ */\r
+static void\r
+upap_protrej(int unit)\r
+{\r
+  upap_state *u = &upap[unit];\r
+\r
+  if (u->us_clientstate == UPAPCS_AUTHREQ) {\r
+    UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n"));\r
+    auth_withpeer_fail(unit, PPP_PAP);\r
+  }\r
+  if (u->us_serverstate == UPAPSS_LISTEN) {\r
+    UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n"));\r
+    auth_peer_fail(unit, PPP_PAP);\r
+  }\r
+  upap_lowerdown(unit);\r
+}\r
+\r
+\r
+/*\r
+ * upap_input - Input UPAP packet.\r
+ */\r
+static void\r
+upap_input(int unit, u_char *inpacket, int l)\r
+{\r
+  upap_state *u = &upap[unit];\r
+  u_char *inp;\r
+  u_char code, id;\r
+  int len;\r
+\r
+  /*\r
+   * Parse header (code, id and length).\r
+   * If packet too short, drop it.\r
+   */\r
+  inp = inpacket;\r
+  if (l < UPAP_HEADERLEN) {\r
+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(code, inp);\r
+  GETCHAR(id, inp);\r
+  GETSHORT(len, inp);\r
+  if (len < UPAP_HEADERLEN) {\r
+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n"));\r
+    return;\r
+  }\r
+  if (len > l) {\r
+    UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  len -= UPAP_HEADERLEN;\r
+\r
+  /*\r
+   * Action depends on code.\r
+   */\r
+  switch (code) {\r
+    case UPAP_AUTHREQ:\r
+      upap_rauthreq(u, inp, id, len);\r
+      break;\r
+\r
+    case UPAP_AUTHACK:\r
+      upap_rauthack(u, inp, id, len);\r
+      break;\r
+\r
+    case UPAP_AUTHNAK:\r
+      upap_rauthnak(u, inp, id, len);\r
+      break;\r
+\r
+    default:        /* XXX Need code reject */\r
+      break;\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauth - Receive Authenticate.\r
+ */\r
+static void\r
+upap_rauthreq(upap_state *u, u_char *inp, int id, int len)\r
+{\r
+  u_char ruserlen, rpasswdlen;\r
+  char *ruser, *rpasswd;\r
+  int retcode;\r
+  char *msg;\r
+  int msglen;\r
+\r
+  UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id));\r
+\r
+  if (u->us_serverstate < UPAPSS_LISTEN) {\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * If we receive a duplicate authenticate-request, we are\r
+   * supposed to return the same status as for the first request.\r
+   */\r
+  if (u->us_serverstate == UPAPSS_OPEN) {\r
+    upap_sresp(u, UPAP_AUTHACK, id, "", 0);  /* return auth-ack */\r
+    return;\r
+  }\r
+  if (u->us_serverstate == UPAPSS_BADAUTH) {\r
+    upap_sresp(u, UPAP_AUTHNAK, id, "", 0);  /* return auth-nak */\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * Parse user/passwd.\r
+   */\r
+  if (len < sizeof (u_char)) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(ruserlen, inp);\r
+  len -= sizeof (u_char) + ruserlen + sizeof (u_char);\r
+  if (len < 0) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  ruser = (char *) inp;\r
+  INCPTR(ruserlen, inp);\r
+  GETCHAR(rpasswdlen, inp);\r
+  if (len < rpasswdlen) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  rpasswd = (char *) inp;\r
+\r
+  /*\r
+   * Check the username and password given.\r
+   */\r
+  retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen);\r
+  BZERO(rpasswd, rpasswdlen);\r
+\r
+  upap_sresp(u, retcode, id, msg, msglen);\r
+\r
+  if (retcode == UPAP_AUTHACK) {\r
+    u->us_serverstate = UPAPSS_OPEN;\r
+    auth_peer_success(u->us_unit, PPP_PAP, ruser, ruserlen);\r
+  } else {\r
+    u->us_serverstate = UPAPSS_BADAUTH;\r
+    auth_peer_fail(u->us_unit, PPP_PAP);\r
+  }\r
+\r
+  if (u->us_reqtimeout > 0) {\r
+    UNTIMEOUT(upap_reqtimeout, u);\r
+  }\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauthack - Receive Authenticate-Ack.\r
+ */\r
+static void\r
+upap_rauthack(upap_state *u, u_char *inp, int id, int len)\r
+{\r
+  u_char msglen;\r
+  char *msg;\r
+\r
+  LWIP_UNUSED_ARG(id);\r
+\r
+  UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate));\r
+\r
+  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * Parse message.\r
+   */\r
+  if (len < sizeof (u_char)) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(msglen, inp);\r
+  len -= sizeof (u_char);\r
+  if (len < msglen) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  msg = (char *) inp;\r
+  PRINTMSG(msg, msglen);\r
+\r
+  u->us_clientstate = UPAPCS_OPEN;\r
+\r
+  auth_withpeer_success(u->us_unit, PPP_PAP);\r
+}\r
+\r
+\r
+/*\r
+ * upap_rauthnak - Receive Authenticate-Nakk.\r
+ */\r
+static void\r
+upap_rauthnak(upap_state *u, u_char *inp, int id, int len)\r
+{\r
+  u_char msglen;\r
+  char *msg;\r
+\r
+  LWIP_UNUSED_ARG(id);\r
+\r
+  UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate));\r
+\r
+  if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */\r
+    return;\r
+  }\r
+\r
+  /*\r
+   * Parse message.\r
+   */\r
+  if (len < sizeof (u_char)) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  GETCHAR(msglen, inp);\r
+  len -= sizeof (u_char);\r
+  if (len < msglen) {\r
+    UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n"));\r
+    return;\r
+  }\r
+  msg = (char *) inp;\r
+  PRINTMSG(msg, msglen);\r
+\r
+  u->us_clientstate = UPAPCS_BADAUTH;\r
+\r
+  UPAPDEBUG((LOG_ERR, "PAP authentication failed\n"));\r
+  auth_withpeer_fail(u->us_unit, PPP_PAP);\r
+}\r
+\r
+\r
+/*\r
+ * upap_sauthreq - Send an Authenticate-Request.\r
+ */\r
+static void\r
+upap_sauthreq(upap_state *u)\r
+{\r
+  u_char *outp;\r
+  int outlen;\r
+\r
+  outlen = UPAP_HEADERLEN + 2 * sizeof (u_char) \r
+         + u->us_userlen + u->us_passwdlen;\r
+  outp = outpacket_buf[u->us_unit];\r
+\r
+  MAKEHEADER(outp, PPP_PAP);\r
+\r
+  PUTCHAR(UPAP_AUTHREQ, outp);\r
+  PUTCHAR(++u->us_id, outp);\r
+  PUTSHORT(outlen, outp);\r
+  PUTCHAR(u->us_userlen, outp);\r
+  BCOPY(u->us_user, outp, u->us_userlen);\r
+  INCPTR(u->us_userlen, outp);\r
+  PUTCHAR(u->us_passwdlen, outp);\r
+  BCOPY(u->us_passwd, outp, u->us_passwdlen);\r
+\r
+  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);\r
+\r
+  UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id));\r
+\r
+  TIMEOUT(upap_timeout, u, u->us_timeouttime);\r
+  ++u->us_transmits;\r
+  u->us_clientstate = UPAPCS_AUTHREQ;\r
+}\r
+\r
+\r
+/*\r
+ * upap_sresp - Send a response (ack or nak).\r
+ */\r
+static void\r
+upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen)\r
+{\r
+  u_char *outp;\r
+  int outlen;\r
+\r
+  outlen = UPAP_HEADERLEN + sizeof (u_char) + msglen;\r
+  outp = outpacket_buf[u->us_unit];\r
+  MAKEHEADER(outp, PPP_PAP);\r
+\r
+  PUTCHAR(code, outp);\r
+  PUTCHAR(id, outp);\r
+  PUTSHORT(outlen, outp);\r
+  PUTCHAR(msglen, outp);\r
+  BCOPY(msg, outp, msglen);\r
+  pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN);\r
+\r
+  UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate));\r
+}\r
+\r
+#if 0\r
+/*\r
+ * upap_printpkt - print the contents of a PAP packet.\r
+ */\r
+static int upap_printpkt(\r
+  u_char *p,\r
+  int plen,\r
+  void (*printer) (void *, char *, ...),\r
+  void *arg\r
+)\r
+{\r
+  LWIP_UNUSED_ARG(p);\r
+  LWIP_UNUSED_ARG(plen);\r
+  LWIP_UNUSED_ARG(printer);\r
+  LWIP_UNUSED_ARG(arg);\r
+  return 0;\r
+}\r
+#endif /* 0 */\r
+\r
+#endif /* PAP_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pap.h
new file mode 100644 (file)
index 0000000..fdff86e
--- /dev/null
@@ -0,0 +1,131 @@
+/*****************************************************************************\r
+* pap.h -  PPP Password Authentication Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-12-04 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+/*\r
+ * upap.h - User/Password Authentication Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#ifndef PAP_H\r
+#define PAP_H\r
+\r
+#if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+/*\r
+ * Packet header = Code, id, length.\r
+ */\r
+#define UPAP_HEADERLEN (sizeof (u_char) + sizeof (u_char) + sizeof (u_short))\r
+\r
+\r
+/*\r
+ * UPAP codes.\r
+ */\r
+#define UPAP_AUTHREQ 1 /* Authenticate-Request */\r
+#define UPAP_AUTHACK 2 /* Authenticate-Ack */\r
+#define UPAP_AUTHNAK 3 /* Authenticate-Nak */\r
+\r
+/*\r
+ * Client states.\r
+ */\r
+#define UPAPCS_INITIAL 0 /* Connection down */\r
+#define UPAPCS_CLOSED  1 /* Connection up, haven't requested auth */\r
+#define UPAPCS_PENDING 2 /* Connection down, have requested auth */\r
+#define UPAPCS_AUTHREQ 3 /* We've sent an Authenticate-Request */\r
+#define UPAPCS_OPEN    4 /* We've received an Ack */\r
+#define UPAPCS_BADAUTH 5 /* We've received a Nak */\r
+\r
+/*\r
+ * Server states.\r
+ */\r
+#define UPAPSS_INITIAL 0 /* Connection down */\r
+#define UPAPSS_CLOSED  1 /* Connection up, haven't requested auth */\r
+#define UPAPSS_PENDING 2 /* Connection down, have requested auth */\r
+#define UPAPSS_LISTEN  3 /* Listening for an Authenticate */\r
+#define UPAPSS_OPEN    4 /* We've sent an Ack */\r
+#define UPAPSS_BADAUTH 5 /* We've sent a Nak */\r
+\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * Each interface is described by upap structure.\r
+ */\r
+typedef struct upap_state {\r
+  int us_unit;           /* Interface unit number */\r
+  const char *us_user;   /* User */\r
+  int us_userlen;        /* User length */\r
+  const char *us_passwd; /* Password */\r
+  int us_passwdlen;      /* Password length */\r
+  int us_clientstate;    /* Client state */\r
+  int us_serverstate;    /* Server state */\r
+  u_char us_id;          /* Current id */\r
+  int us_timeouttime;    /* Timeout (seconds) for auth-req retrans. */\r
+  int us_transmits;      /* Number of auth-reqs sent */\r
+  int us_maxtransmits;   /* Maximum number of auth-reqs to send */\r
+  int us_reqtimeout;     /* Time to wait for auth-req from peer */\r
+} upap_state;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+extern upap_state upap[];\r
+\r
+void upap_setloginpasswd(int unit, const char *luser, const char *lpassword);\r
+void upap_authwithpeer  (int, char *, char *);\r
+void upap_authpeer      (int);\r
+\r
+extern struct protent pap_protent;\r
+\r
+#endif /* PAP_SUPPORT */\r
+\r
+#endif /* PAP_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.c
new file mode 100644 (file)
index 0000000..9267dd2
--- /dev/null
@@ -0,0 +1,2003 @@
+/*****************************************************************************\r
+* ppp.c - Network Point to Point Protocol program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*****************************************************************************/\r
+\r
+/*\r
+ * ppp_defs.h - PPP definitions.\r
+ *\r
+ * if_pppvar.h - private structures and declarations for PPP.\r
+ *\r
+ * Copyright (c) 1994 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation is hereby granted, provided that the above copyright\r
+ * notice appears in all copies.  This software is provided without any\r
+ * warranty, express or implied. The Australian National University\r
+ * makes no representations about the suitability of this software for\r
+ * any purpose.\r
+ *\r
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY\r
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\r
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\r
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO\r
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,\r
+ * OR MODIFICATIONS.\r
+ */\r
+\r
+/*\r
+ * if_ppp.h - Point-to-Point Protocol definitions.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/ip.h" /* for ip_input() */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "randm.h"\r
+#include "fsm.h"\r
+#if PAP_SUPPORT\r
+#include "pap.h"\r
+#endif /* PAP_SUPPORT */\r
+#if CHAP_SUPPORT\r
+#include "chap.h"\r
+#endif /* CHAP_SUPPORT */\r
+#include "ipcp.h"\r
+#include "lcp.h"\r
+#include "magic.h"\r
+#include "auth.h"\r
+#if VJ_SUPPORT\r
+#include "vj.h"\r
+#endif /* VJ_SUPPORT */\r
+#if PPPOE_SUPPORT\r
+#include "netif/ppp_oe.h"\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#include <string.h>\r
+\r
+/*************************/\r
+/*** LOCAL DEFINITIONS ***/\r
+/*************************/\r
+\r
+/*\r
+ * The basic PPP frame.\r
+ */\r
+#define PPP_ADDRESS(p)  (((u_char *)(p))[0])\r
+#define PPP_CONTROL(p)  (((u_char *)(p))[1])\r
+#define PPP_PROTOCOL(p) ((((u_char *)(p))[2] << 8) + ((u_char *)(p))[3])\r
+\r
+/* PPP packet parser states.  Current state indicates operation yet to be\r
+ * completed. */\r
+typedef enum {\r
+  PDIDLE = 0,  /* Idle state - waiting. */\r
+  PDSTART,     /* Process start flag. */\r
+  PDADDRESS,   /* Process address field. */\r
+  PDCONTROL,   /* Process control field. */\r
+  PDPROTOCOL1, /* Process protocol field 1. */\r
+  PDPROTOCOL2, /* Process protocol field 2. */\r
+  PDDATA       /* Process data byte. */\r
+} PPPDevStates;\r
+\r
+#define ESCAPE_P(accm, c) ((accm)[(c) >> 3] & pppACCMMask[c & 0x07])\r
+\r
+/************************/\r
+/*** LOCAL DATA TYPES ***/\r
+/************************/\r
+/*\r
+ * PPP interface control block.\r
+ */\r
+typedef struct PPPControl_s {\r
+  char openFlag;                /* True when in use. */\r
+#if PPPOE_SUPPORT\r
+  struct netif *ethif;\r
+  struct pppoe_softc *pppoe_sc;\r
+#endif /* PPPOE_SUPPORT */\r
+  int  if_up;                   /* True when the interface is up. */\r
+  int  errCode;                 /* Code indicating why interface is down. */\r
+#if PPPOS_SUPPORT\r
+  sio_fd_t fd;                  /* File device ID of port. */\r
+  int  kill_link;               /* Shut the link down. */\r
+  int  sig_hup;                 /* Carrier lost. */\r
+  struct pbuf *inHead, *inTail; /* The input packet. */\r
+  PPPDevStates inState;         /* The input process state. */\r
+  char inEscaped;               /* Escape next character. */\r
+  u16_t inProtocol;             /* The input protocol code. */\r
+  u16_t inFCS;                  /* Input Frame Check Sequence value. */\r
+#endif /* PPPOS_SUPPORT */\r
+  int  mtu;                     /* Peer's mru */\r
+  int  pcomp;                   /* Does peer accept protocol compression? */\r
+  int  accomp;                  /* Does peer accept addr/ctl compression? */\r
+  u_long lastXMit;              /* Time of last transmission. */\r
+  ext_accm inACCM;              /* Async-Ctl-Char-Map for input. */\r
+  ext_accm outACCM;             /* Async-Ctl-Char-Map for output. */\r
+#if PPPOS_SUPPORT && VJ_SUPPORT\r
+  int  vjEnabled;               /* Flag indicating VJ compression enabled. */\r
+  struct vjcompress vjComp;     /* Van Jabobsen compression header. */\r
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */\r
+\r
+  struct netif netif;\r
+\r
+  struct ppp_addrs addrs;\r
+\r
+  void (*linkStatusCB)(void *ctx, int errCode, void *arg);\r
+  void *linkStatusCtx;\r
+\r
+} PPPControl;\r
+\r
+\r
+/*\r
+ * Ioctl definitions.\r
+ */\r
+\r
+struct npioctl {\r
+  int         protocol; /* PPP procotol, e.g. PPP_IP */\r
+  enum NPmode mode;\r
+};\r
+\r
+\r
+\r
+/***********************************/\r
+/*** LOCAL FUNCTION DECLARATIONS ***/\r
+/***********************************/\r
+#if PPPOS_SUPPORT\r
+static void pppMain(void *pd);\r
+static void pppDrop(PPPControl *pc);\r
+static void pppInProc(int pd, u_char *s, int l);\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+\r
+/******************************/\r
+/*** PUBLIC DATA STRUCTURES ***/\r
+/******************************/\r
+u_long subnetMask;\r
+\r
+static PPPControl pppControl[NUM_PPP]; /* The PPP interface control blocks. */\r
+\r
+/*\r
+ * PPP Data Link Layer "protocol" table.\r
+ * One entry per supported protocol.\r
+ * The last entry must be NULL.\r
+ */\r
+struct protent *ppp_protocols[] = {\r
+  &lcp_protent,\r
+#if PAP_SUPPORT\r
+  &pap_protent,\r
+#endif /* PAP_SUPPORT */\r
+#if CHAP_SUPPORT\r
+  &chap_protent,\r
+#endif /* CHAP_SUPPORT */\r
+#if CBCP_SUPPORT\r
+  &cbcp_protent,\r
+#endif /* CBCP_SUPPORT */\r
+  &ipcp_protent,\r
+#if CCP_SUPPORT\r
+  &ccp_protent,\r
+#endif /* CCP_SUPPORT */\r
+  NULL\r
+};\r
+\r
+\r
+/*\r
+ * Buffers for outgoing packets.  This must be accessed only from the appropriate\r
+ * PPP task so that it doesn't need to be protected to avoid collisions.\r
+ */\r
+u_char *outpacket_buf[NUM_PPP];  \r
+\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+\r
+#if PPPOS_SUPPORT\r
+/*\r
+ * FCS lookup table as calculated by genfcstab.\r
+ */\r
+static const u_short fcstab[256] = {\r
+  0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf,\r
+  0x8c48, 0x9dc1, 0xaf5a, 0xbed3, 0xca6c, 0xdbe5, 0xe97e, 0xf8f7,\r
+  0x1081, 0x0108, 0x3393, 0x221a, 0x56a5, 0x472c, 0x75b7, 0x643e,\r
+  0x9cc9, 0x8d40, 0xbfdb, 0xae52, 0xdaed, 0xcb64, 0xf9ff, 0xe876,\r
+  0x2102, 0x308b, 0x0210, 0x1399, 0x6726, 0x76af, 0x4434, 0x55bd,\r
+  0xad4a, 0xbcc3, 0x8e58, 0x9fd1, 0xeb6e, 0xfae7, 0xc87c, 0xd9f5,\r
+  0x3183, 0x200a, 0x1291, 0x0318, 0x77a7, 0x662e, 0x54b5, 0x453c,\r
+  0xbdcb, 0xac42, 0x9ed9, 0x8f50, 0xfbef, 0xea66, 0xd8fd, 0xc974,\r
+  0x4204, 0x538d, 0x6116, 0x709f, 0x0420, 0x15a9, 0x2732, 0x36bb,\r
+  0xce4c, 0xdfc5, 0xed5e, 0xfcd7, 0x8868, 0x99e1, 0xab7a, 0xbaf3,\r
+  0x5285, 0x430c, 0x7197, 0x601e, 0x14a1, 0x0528, 0x37b3, 0x263a,\r
+  0xdecd, 0xcf44, 0xfddf, 0xec56, 0x98e9, 0x8960, 0xbbfb, 0xaa72,\r
+  0x6306, 0x728f, 0x4014, 0x519d, 0x2522, 0x34ab, 0x0630, 0x17b9,\r
+  0xef4e, 0xfec7, 0xcc5c, 0xddd5, 0xa96a, 0xb8e3, 0x8a78, 0x9bf1,\r
+  0x7387, 0x620e, 0x5095, 0x411c, 0x35a3, 0x242a, 0x16b1, 0x0738,\r
+  0xffcf, 0xee46, 0xdcdd, 0xcd54, 0xb9eb, 0xa862, 0x9af9, 0x8b70,\r
+  0x8408, 0x9581, 0xa71a, 0xb693, 0xc22c, 0xd3a5, 0xe13e, 0xf0b7,\r
+  0x0840, 0x19c9, 0x2b52, 0x3adb, 0x4e64, 0x5fed, 0x6d76, 0x7cff,\r
+  0x9489, 0x8500, 0xb79b, 0xa612, 0xd2ad, 0xc324, 0xf1bf, 0xe036,\r
+  0x18c1, 0x0948, 0x3bd3, 0x2a5a, 0x5ee5, 0x4f6c, 0x7df7, 0x6c7e,\r
+  0xa50a, 0xb483, 0x8618, 0x9791, 0xe32e, 0xf2a7, 0xc03c, 0xd1b5,\r
+  0x2942, 0x38cb, 0x0a50, 0x1bd9, 0x6f66, 0x7eef, 0x4c74, 0x5dfd,\r
+  0xb58b, 0xa402, 0x9699, 0x8710, 0xf3af, 0xe226, 0xd0bd, 0xc134,\r
+  0x39c3, 0x284a, 0x1ad1, 0x0b58, 0x7fe7, 0x6e6e, 0x5cf5, 0x4d7c,\r
+  0xc60c, 0xd785, 0xe51e, 0xf497, 0x8028, 0x91a1, 0xa33a, 0xb2b3,\r
+  0x4a44, 0x5bcd, 0x6956, 0x78df, 0x0c60, 0x1de9, 0x2f72, 0x3efb,\r
+  0xd68d, 0xc704, 0xf59f, 0xe416, 0x90a9, 0x8120, 0xb3bb, 0xa232,\r
+  0x5ac5, 0x4b4c, 0x79d7, 0x685e, 0x1ce1, 0x0d68, 0x3ff3, 0x2e7a,\r
+  0xe70e, 0xf687, 0xc41c, 0xd595, 0xa12a, 0xb0a3, 0x8238, 0x93b1,\r
+  0x6b46, 0x7acf, 0x4854, 0x59dd, 0x2d62, 0x3ceb, 0x0e70, 0x1ff9,\r
+  0xf78f, 0xe606, 0xd49d, 0xc514, 0xb1ab, 0xa022, 0x92b9, 0x8330,\r
+  0x7bc7, 0x6a4e, 0x58d5, 0x495c, 0x3de3, 0x2c6a, 0x1ef1, 0x0f78\r
+};\r
+\r
+/* PPP's Asynchronous-Control-Character-Map.  The mask array is used\r
+ * to select the specific bit for a character. */\r
+static u_char pppACCMMask[] = {\r
+  0x01,\r
+  0x02,\r
+  0x04,\r
+  0x08,\r
+  0x10,\r
+  0x20,\r
+  0x40,\r
+  0x80\r
+};\r
+\r
+\r
+void\r
+pppMainWakeup(int pd)\r
+{\r
+  PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd));\r
+  sio_read_abort(pppControl[pd].fd);\r
+}\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+void\r
+pppLinkTerminated(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd));\r
+\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    pppoe_disconnect(pc->pppoe_sc);\r
+  } else\r
+#endif /* PPPOE_SUPPORT */\r
+  {\r
+#if PPPOS_SUPPORT\r
+    pppMainWakeup(pd);\r
+#endif /* PPPOS_SUPPORT */\r
+  }\r
+}\r
+\r
+void\r
+pppLinkDown(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd));\r
+\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    pppoe_disconnect(pc->pppoe_sc);\r
+  } else\r
+#endif /* PPPOE_SUPPORT */\r
+  {\r
+#if PPPOS_SUPPORT\r
+    pppMainWakeup(pd);\r
+#endif /* PPPOS_SUPPORT */\r
+  }\r
+}\r
+\r
+/* these callbacks are necessary because lcp_* functions\r
+   must be called in the same context as pppInput(),\r
+   namely the tcpip_thread(), essentially because\r
+   they manipulate timeouts which are thread-private\r
+*/\r
+\r
+static void\r
+pppStartCB(void *arg)\r
+{\r
+  int pd = (int)arg;\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd));\r
+  lcp_lowerup(pd);\r
+  lcp_open(pd); /* Start protocol */\r
+}\r
+\r
+static void\r
+pppStopCB(void *arg)\r
+{\r
+  int pd = (int)arg;\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd));\r
+  lcp_close(pd, "User request");\r
+}\r
+\r
+static void\r
+pppHupCB(void *arg)\r
+{\r
+  int pd = (int)arg;\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd));\r
+  lcp_lowerdown(pd);\r
+  link_terminated(pd);\r
+}\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/* Initialize the PPP subsystem. */\r
+\r
+struct ppp_settings ppp_settings;\r
+\r
+err_t\r
+pppInit(void)\r
+{\r
+  struct protent *protp;\r
+  int i, j;\r
+\r
+  memset(&ppp_settings, 0, sizeof(ppp_settings));\r
+  ppp_settings.usepeerdns = 1;\r
+  pppSetAuth(PPPAUTHTYPE_NONE, NULL, NULL);\r
+\r
+  magicInit();\r
+\r
+  for (i = 0; i < NUM_PPP; i++) {\r
+    pppControl[i].openFlag = 0;\r
+\r
+    subnetMask = htonl(0xffffff00);\r
+\r
+    outpacket_buf[i] = (u_char *)mem_malloc(PPP_MRU+PPP_HDRLEN);\r
+    if(!outpacket_buf[i]) {\r
+      return ERR_MEM;\r
+    }\r
+\r
+    /*\r
+     * Initialize to the standard option set.\r
+     */\r
+    for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) {\r
+      (*protp->init)(i);\r
+    }\r
+  }\r
+\r
+#if LINK_STATS\r
+  /** @todo already done in stats_init (in fact, zeroed at boot). So, remove it? */\r
+  /* Clear the statistics. */\r
+  memset(&lwip_stats.link, 0, sizeof(lwip_stats.link));\r
+#endif /* LINK_STATS */\r
+\r
+#if PPPOE_SUPPORT\r
+  pppoe_init();\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+void\r
+pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd)\r
+{\r
+  switch(authType) {\r
+    case PPPAUTHTYPE_NONE:\r
+    default:\r
+#ifdef LWIP_PPP_STRICT_PAP_REJECT\r
+      ppp_settings.refuse_pap = 1;\r
+#else  /* LWIP_PPP_STRICT_PAP_REJECT */\r
+      /* some providers request pap and accept an empty login/pw */\r
+      ppp_settings.refuse_pap = 0;\r
+#endif /* LWIP_PPP_STRICT_PAP_REJECT */\r
+      ppp_settings.refuse_chap = 1;\r
+      break;\r
+\r
+    case PPPAUTHTYPE_ANY:\r
+      /* Warning: Using PPPAUTHTYPE_ANY might have security consequences.\r
+       * RFC 1994 says:\r
+       *\r
+       * In practice, within or associated with each PPP server, there is a\r
+       * database which associates "user" names with authentication\r
+       * information ("secrets").  It is not anticipated that a particular\r
+       * named user would be authenticated by multiple methods.  This would\r
+       * make the user vulnerable to attacks which negotiate the least secure\r
+       * method from among a set (such as PAP rather than CHAP).  If the same\r
+       * secret was used, PAP would reveal the secret to be used later with\r
+       * CHAP.\r
+       *\r
+       * Instead, for each user name there should be an indication of exactly\r
+       * one method used to authenticate that user name.  If a user needs to\r
+       * make use of different authentication methods under different\r
+       * circumstances, then distinct user names SHOULD be employed, each of\r
+       * which identifies exactly one authentication method.\r
+       *\r
+       */\r
+      ppp_settings.refuse_pap = 0;\r
+      ppp_settings.refuse_chap = 0;\r
+      break;\r
+\r
+    case PPPAUTHTYPE_PAP:\r
+      ppp_settings.refuse_pap = 0;\r
+      ppp_settings.refuse_chap = 1;\r
+      break;\r
+\r
+    case PPPAUTHTYPE_CHAP:\r
+      ppp_settings.refuse_pap = 1;\r
+      ppp_settings.refuse_chap = 0;\r
+      break;\r
+  }\r
+\r
+  if(user) {\r
+    strncpy(ppp_settings.user, user, sizeof(ppp_settings.user)-1);\r
+    ppp_settings.user[sizeof(ppp_settings.user)-1] = '\0';\r
+  } else {\r
+    ppp_settings.user[0] = '\0';\r
+  }\r
+\r
+  if(passwd) {\r
+    strncpy(ppp_settings.passwd, passwd, sizeof(ppp_settings.passwd)-1);\r
+    ppp_settings.passwd[sizeof(ppp_settings.passwd)-1] = '\0';\r
+  } else {\r
+    ppp_settings.passwd[0] = '\0';\r
+  }\r
+}\r
+\r
+#if PPPOS_SUPPORT\r
+/* Open a new PPP connection using the given I/O device.\r
+ * This initializes the PPP control block but does not\r
+ * attempt to negotiate the LCP session.  If this port\r
+ * connects to a modem, the modem connection must be\r
+ * established before calling this.\r
+ * Return a new PPP connection descriptor on success or\r
+ * an error code (negative) on failure. */\r
+int\r
+pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)\r
+{\r
+  PPPControl *pc;\r
+  int pd;\r
+\r
+  /* Find a free PPP session descriptor. Critical region? */\r
+  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);\r
+\r
+  if (pd >= NUM_PPP) {\r
+    pd = PPPERR_OPEN;\r
+  } else {\r
+    pppControl[pd].openFlag = !0;\r
+  }\r
+\r
+  /* Launch a deamon thread. */\r
+  if (pd >= 0) {\r
+    pppControl[pd].openFlag = 1;\r
+\r
+    lcp_init(pd);\r
+    pc = &pppControl[pd];\r
+    pc->fd = fd;\r
+#if PPPOE_SUPPORT\r
+    pc->ethif= NULL;\r
+#endif /* PPPOE_SUPPORT */\r
+    pc->kill_link = 0;\r
+    pc->sig_hup = 0;\r
+    pc->if_up = 0;\r
+    pc->errCode = 0;\r
+    pc->inState = PDIDLE;\r
+    pc->inHead = NULL;\r
+    pc->inTail = NULL;\r
+    pc->inEscaped = 0;\r
+    pc->lastXMit = 0;\r
+\r
+#if VJ_SUPPORT\r
+    pc->vjEnabled = 0;\r
+    vj_compress_init(&pc->vjComp);\r
+#endif /* VJ_SUPPORT */\r
+\r
+    /* \r
+     * Default the in and out accm so that escape and flag characters\r
+     * are always escaped. \r
+     */\r
+    memset(pc->inACCM, 0, sizeof(ext_accm));\r
+    pc->inACCM[15] = 0x60;\r
+    memset(pc->outACCM, 0, sizeof(ext_accm));\r
+    pc->outACCM[15] = 0x60;\r
+\r
+    pc->linkStatusCB = linkStatusCB;\r
+    pc->linkStatusCtx = linkStatusCtx;\r
+\r
+    sys_thread_new(PPP_THREAD_NAME, pppMain, (void*)pd, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO);\r
+    if(!linkStatusCB) {\r
+      while(pd >= 0 && !pc->if_up) {\r
+        sys_msleep(500);\r
+        if (lcp_phase[pd] == PHASE_DEAD) {\r
+          pppClose(pd);\r
+          if (pc->errCode) {\r
+            pd = pc->errCode;\r
+          } else {\r
+            pd = PPPERR_CONNECT;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return pd;\r
+}\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+#if PPPOE_SUPPORT\r
+static void pppOverEthernetLinkStatusCB(int pd, int up);\r
+\r
+void\r
+pppOverEthernetClose(int pd)\r
+{\r
+  PPPControl* pc = &pppControl[pd];\r
+\r
+  /* *TJL* There's no lcp_deinit */\r
+  lcp_close(pd, NULL);\r
+\r
+  pppoe_destroy(&pc->netif);\r
+}\r
+\r
+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx)\r
+{\r
+  PPPControl *pc;\r
+  int pd;\r
+\r
+  LWIP_UNUSED_ARG(service_name);\r
+  LWIP_UNUSED_ARG(concentrator_name);\r
+\r
+  /* Find a free PPP session descriptor. Critical region? */\r
+  for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++);\r
+  if (pd >= NUM_PPP) {\r
+    pd = PPPERR_OPEN;\r
+  } else {\r
+    pppControl[pd].openFlag = !0;\r
+  }\r
+\r
+  /* Launch a deamon thread. */\r
+  if (pd >= 0) {\r
+\r
+    pppControl[pd].openFlag = 1;\r
+\r
+    lcp_init(pd);\r
+\r
+    lcp_wantoptions[pd].mru = PPPOE_MAXMTU;\r
+    lcp_wantoptions[pd].neg_asyncmap = 0;\r
+    lcp_wantoptions[pd].neg_pcompression = 0;\r
+    lcp_wantoptions[pd].neg_accompression = 0;\r
+\r
+    lcp_allowoptions[pd].mru = PPPOE_MAXMTU;\r
+    lcp_allowoptions[pd].neg_asyncmap = 0;\r
+    lcp_allowoptions[pd].neg_pcompression = 0;\r
+    lcp_allowoptions[pd].neg_accompression = 0;\r
+\r
+    pc = &pppControl[pd];\r
+    pc->if_up = 0;\r
+    pc->errCode = 0;\r
+    pc->lastXMit = 0;\r
+#if PPPOS_SUPPORT\r
+    pc->kill_link = 0;\r
+    pc->sig_hup = 0;\r
+    pc->inState = PDIDLE;\r
+    pc->inHead = NULL;\r
+    pc->inTail = NULL;\r
+    pc->inEscaped = 0;\r
+#if VJ_SUPPORT\r
+    pc->vjEnabled = 0;\r
+#endif /* VJ_SUPPORT */\r
+#endif /* PPPOS_SUPPORT */\r
+    pc->ethif= ethif;\r
+\r
+    memset(pc->inACCM,  0, sizeof(ext_accm));\r
+    memset(pc->outACCM, 0, sizeof(ext_accm));\r
+\r
+    pc->linkStatusCB  = linkStatusCB;\r
+    pc->linkStatusCtx = linkStatusCtx;\r
+\r
+    if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) {\r
+      pc->openFlag = 0;\r
+      return PPPERR_OPEN;\r
+    }\r
+\r
+    pppoe_connect(pc->pppoe_sc);\r
+\r
+    if(!linkStatusCB) {\r
+      while(pd >= 0 && !pc->if_up) {\r
+        sys_msleep(500);\r
+        if (lcp_phase[pd] == PHASE_DEAD) {\r
+          pppClose(pd);\r
+          if (pc->errCode) {\r
+            pd = pc->errCode;\r
+          } else {\r
+            pd = PPPERR_CONNECT;\r
+          }\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  return pd;\r
+}\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+\r
+/* Close a PPP connection and release the descriptor. \r
+ * Any outstanding packets in the queues are dropped.\r
+ * Return 0 on success, an error code on failure. */\r
+int\r
+pppClose(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 0;\r
+\r
+  /* Disconnect */\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    PPPDEBUG((LOG_DEBUG, "pppClose: unit %d kill_link -> pppStopCB\n", pd));\r
+    pc->errCode = PPPERR_USER;\r
+    /* This will leave us at PHASE_DEAD. */\r
+    tcpip_callback(pppStopCB, (void*)pd);\r
+  } else\r
+#endif /* PPPOE_SUPPORT */\r
+  {\r
+#if PPPOS_SUPPORT\r
+    pc->kill_link = !0;\r
+    pppMainWakeup(pd);\r
+#endif /* PPPOS_SUPPORT */\r
+  }\r
+\r
+  if(!pc->linkStatusCB) {\r
+    while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) {\r
+      sys_msleep(500);\r
+      break;\r
+    }\r
+  }\r
+\r
+  return st;\r
+}\r
+\r
+/* This function is called when carrier is lost on the PPP channel. */\r
+void\r
+pppSigHUP(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    PPPDEBUG((LOG_DEBUG, "pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd));\r
+    tcpip_callback(pppHupCB, (void*)pd);\r
+  } else\r
+#endif /* PPPOE_SUPPORT */\r
+  {\r
+#if PPPOS_SUPPORT\r
+    pc->sig_hup = 1;\r
+    pppMainWakeup(pd);\r
+#endif /* PPPOS_SUPPORT */\r
+  }\r
+}\r
+\r
+#if PPPOS_SUPPORT\r
+static void\r
+nPut(PPPControl *pc, struct pbuf *nb)\r
+{\r
+  struct pbuf *b;\r
+  int c;\r
+\r
+  for(b = nb; b != NULL; b = b->next) {\r
+    if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) {\r
+      PPPDEBUG((LOG_WARNING,\r
+               "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c));\r
+      LINK_STATS_INC(link.err);\r
+      pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */\r
+      break;\r
+    }\r
+  }\r
+\r
+  pbuf_free(nb);\r
+  LINK_STATS_INC(link.xmit);\r
+}\r
+\r
+/* \r
+ * pppAppend - append given character to end of given pbuf.  If outACCM\r
+ * is not NULL and the character needs to be escaped, do so.\r
+ * If pbuf is full, append another.\r
+ * Return the current pbuf.\r
+ */\r
+static struct pbuf *\r
+pppAppend(u_char c, struct pbuf *nb, ext_accm *outACCM)\r
+{\r
+  struct pbuf *tb = nb;\r
+  \r
+  /* Make sure there is room for the character and an escape code.\r
+   * Sure we don't quite fill the buffer if the character doesn't\r
+   * get escaped but is one character worth complicating this? */\r
+  /* Note: We assume no packet header. */\r
+  if (nb && (PBUF_POOL_BUFSIZE - nb->len) < 2) {\r
+    tb = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+    if (tb) {\r
+      nb->next = tb;\r
+    } else {\r
+      LINK_STATS_INC(link.memerr);\r
+    }\r
+    nb = tb;\r
+  }\r
+\r
+  if (nb) {\r
+    if (outACCM && ESCAPE_P(*outACCM, c)) {\r
+      *((u_char*)nb->payload + nb->len++) = PPP_ESCAPE;\r
+      *((u_char*)nb->payload + nb->len++) = c ^ PPP_TRANS;\r
+    } else {\r
+      *((u_char*)nb->payload + nb->len++) = c;\r
+    }\r
+  }\r
+\r
+  return tb;\r
+}\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+#if PPPOE_SUPPORT\r
+static err_t\r
+pppifOutputOverEthernet(int pd, struct pbuf *p)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  struct pbuf *pb;\r
+  u_short protocol = PPP_IP;\r
+  int i=0;\r
+\r
+  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + sizeof(protocol), PBUF_RAM);\r
+  if(!pb) {\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.proterr);\r
+    return ERR_MEM;\r
+  }\r
+\r
+  pbuf_header(pb, -pppoe_hdrlen);\r
+\r
+  pc->lastXMit = sys_jiffies();\r
+\r
+  if (!pc->pcomp || protocol > 0xFF) {\r
+    *((u_char*)pb->payload + i++) = (protocol >> 8) & 0xFF;\r
+  }\r
+  *((u_char*)pb->payload + i) = protocol & 0xFF;\r
+\r
+  pbuf_chain(pb, p);\r
+\r
+  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {\r
+    LINK_STATS_INC(link.err);\r
+    return PPPERR_DEVICE;\r
+  }\r
+\r
+  LINK_STATS_INC(link.xmit);\r
+  return ERR_OK;\r
+}\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+/* Send a packet on the given connection. */\r
+static err_t\r
+pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr)\r
+{\r
+  int pd = (int)netif->state;\r
+  u_short protocol = PPP_IP;\r
+  PPPControl *pc = &pppControl[pd];\r
+#if PPPOS_SUPPORT\r
+  u_int fcsOut = PPP_INITFCS;\r
+  struct pbuf *headMB = NULL, *tailMB = NULL, *p;\r
+  u_char c;\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+  LWIP_UNUSED_ARG(ipaddr);\r
+\r
+  /* Validate parameters. */\r
+  /* We let any protocol value go through - it can't hurt us\r
+   * and the peer will just drop it if it's not accepting it. */\r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) {\r
+    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n",\r
+              pd, protocol, pb));\r
+    LINK_STATS_INC(link.opterr);\r
+    LINK_STATS_INC(link.drop);\r
+    return ERR_ARG;\r
+  }\r
+\r
+  /* Check that the link is up. */\r
+  if (lcp_phase[pd] == PHASE_DEAD) {\r
+    PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd));\r
+    LINK_STATS_INC(link.rterr);\r
+    LINK_STATS_INC(link.drop);\r
+    return ERR_RTE;\r
+  }\r
+\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    return pppifOutputOverEthernet(pd, pb);\r
+  }\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#if PPPOS_SUPPORT\r
+  /* Grab an output buffer. */\r
+  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+  if (headMB == NULL) {\r
+    PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd));\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.drop);\r
+    return ERR_MEM;\r
+  }\r
+\r
+#if VJ_SUPPORT\r
+  /* \r
+   * Attempt Van Jacobson header compression if VJ is configured and\r
+   * this is an IP packet. \r
+   */\r
+  if (protocol == PPP_IP && pc->vjEnabled) {\r
+    switch (vj_compress_tcp(&pc->vjComp, pb)) {\r
+      case TYPE_IP:\r
+        /* No change...\r
+           protocol = PPP_IP_PROTOCOL; */\r
+        break;\r
+      case TYPE_COMPRESSED_TCP:\r
+        protocol = PPP_VJC_COMP;\r
+        break;\r
+      case TYPE_UNCOMPRESSED_TCP:\r
+        protocol = PPP_VJC_UNCOMP;\r
+        break;\r
+      default:\r
+        PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd));\r
+        LINK_STATS_INC(link.proterr);\r
+        LINK_STATS_INC(link.drop);\r
+        pbuf_free(headMB);\r
+        return ERR_VAL;\r
+    }\r
+  }\r
+#endif /* VJ_SUPPORT */\r
+\r
+  tailMB = headMB;\r
+\r
+  /* Build the PPP header. */\r
+  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {\r
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+  }\r
+\r
+  pc->lastXMit = sys_jiffies();\r
+  if (!pc->accomp) {\r
+    fcsOut = PPP_FCS(fcsOut, PPP_ALLSTATIONS);\r
+    tailMB = pppAppend(PPP_ALLSTATIONS, tailMB, &pc->outACCM);\r
+    fcsOut = PPP_FCS(fcsOut, PPP_UI);\r
+    tailMB = pppAppend(PPP_UI, tailMB, &pc->outACCM);\r
+  }\r
+  if (!pc->pcomp || protocol > 0xFF) {\r
+    c = (protocol >> 8) & 0xFF;\r
+    fcsOut = PPP_FCS(fcsOut, c);\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  }\r
+  c = protocol & 0xFF;\r
+  fcsOut = PPP_FCS(fcsOut, c);\r
+  tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+\r
+  /* Load packet. */\r
+  for(p = pb; p; p = p->next) {\r
+    int n;\r
+    u_char *sPtr;\r
+\r
+    sPtr = (u_char*)p->payload;\r
+    n = p->len;\r
+    while (n-- > 0) {\r
+      c = *sPtr++;\r
+\r
+      /* Update FCS before checking for special characters. */\r
+      fcsOut = PPP_FCS(fcsOut, c);\r
+      \r
+      /* Copy to output buffer escaping special characters. */\r
+      tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+    }\r
+  }\r
+\r
+  /* Add FCS and trailing flag. */\r
+  c = ~fcsOut & 0xFF;\r
+  tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  c = (~fcsOut >> 8) & 0xFF;\r
+  tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+\r
+  /* If we failed to complete the packet, throw it away. */\r
+  if (!tailMB) {\r
+    PPPDEBUG((LOG_WARNING,\r
+             "pppifOutput[%d]: Alloc err - dropping proto=%d\n", \r
+              pd, protocol));\r
+    pbuf_free(headMB);\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.drop);\r
+    return ERR_MEM;\r
+  }\r
+\r
+  /* Send it. */\r
+  PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol));\r
+\r
+  nPut(pc, headMB);\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/* Get and set parameters for the given connection.\r
+ * Return 0 on success, an error code on failure. */\r
+int\r
+pppIOCtl(int pd, int cmd, void *arg)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 0;\r
+\r
+  if (pd < 0 || pd >= NUM_PPP) {\r
+    st = PPPERR_PARAM;\r
+  } else {\r
+    switch(cmd) {\r
+    case PPPCTLG_UPSTATUS:      /* Get the PPP up status. */\r
+      if (arg) {\r
+        *(int *)arg = (int)(pc->if_up);\r
+      } else {\r
+        st = PPPERR_PARAM;\r
+      }\r
+      break;\r
+    case PPPCTLS_ERRCODE:       /* Set the PPP error code. */\r
+      if (arg) {\r
+        pc->errCode = *(int *)arg;\r
+      } else {\r
+        st = PPPERR_PARAM;\r
+      }\r
+      break;\r
+    case PPPCTLG_ERRCODE:       /* Get the PPP error code. */\r
+      if (arg) {\r
+        *(int *)arg = (int)(pc->errCode);\r
+      } else {\r
+        st = PPPERR_PARAM;\r
+      }\r
+      break;\r
+#if PPPOS_SUPPORT\r
+    case PPPCTLG_FD:\r
+      if (arg) {\r
+        *(sio_fd_t *)arg = pc->fd;\r
+      } else {\r
+        st = PPPERR_PARAM;\r
+      }\r
+      break;\r
+#endif /* PPPOS_SUPPORT */\r
+    default:\r
+      st = PPPERR_PARAM;\r
+      break;\r
+    }\r
+  }\r
+\r
+  return st;\r
+}\r
+\r
+/*\r
+ * Return the Maximum Transmission Unit for the given PPP connection.\r
+ */\r
+u_int\r
+pppMTU(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  u_int st;\r
+\r
+  /* Validate parameters. */\r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+  } else {\r
+    st = pc->mtu;\r
+  }\r
+\r
+  return st;\r
+}\r
+\r
+#if PPPOE_SUPPORT\r
+int\r
+pppWriteOverEthernet(int pd, const u_char *s, int n)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  struct pbuf *pb;\r
+\r
+  /* skip address & flags */\r
+  s += 2;\r
+  n -= 2;\r
+\r
+  pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + n, PBUF_RAM);\r
+  if(!pb) {\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.proterr);\r
+    return PPPERR_ALLOC;\r
+  }\r
+\r
+  pbuf_header(pb, -pppoe_hdrlen);\r
+\r
+  pc->lastXMit = sys_jiffies();\r
+\r
+  SMEMCPY(pb->payload, s, n);\r
+\r
+  if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) {\r
+    LINK_STATS_INC(link.err);\r
+    return PPPERR_DEVICE;\r
+  }\r
+\r
+  LINK_STATS_INC(link.xmit);\r
+  return PPPERR_NONE;\r
+}\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+/*\r
+ * Write n characters to a ppp link.\r
+ *  RETURN: >= 0 Number of characters written\r
+ *           -1 Failed to write to device\r
+ */\r
+int\r
+pppWrite(int pd, const u_char *s, int n)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+#if PPPOS_SUPPORT\r
+  u_char c;\r
+  u_int fcsOut;\r
+  struct pbuf *headMB, *tailMB;\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+#if PPPOE_SUPPORT\r
+  if(pc->ethif) {\r
+    return pppWriteOverEthernet(pd, s, n);\r
+  }\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#if PPPOS_SUPPORT\r
+  headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+  if (headMB == NULL) {\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.proterr);\r
+    return PPPERR_ALLOC;\r
+  }\r
+\r
+  tailMB = headMB;\r
+\r
+  /* If the link has been idle, we'll send a fresh flag character to\r
+   * flush any noise. */\r
+  if ((sys_jiffies() - pc->lastXMit) >= PPP_MAXIDLEFLAG) {\r
+    tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+  }\r
+  pc->lastXMit = sys_jiffies();\r
+\r
+  fcsOut = PPP_INITFCS;\r
+  /* Load output buffer. */\r
+  while (n-- > 0) {\r
+    c = *s++;\r
+\r
+    /* Update FCS before checking for special characters. */\r
+    fcsOut = PPP_FCS(fcsOut, c);\r
+\r
+    /* Copy to output buffer escaping special characters. */\r
+    tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  }\r
+    \r
+  /* Add FCS and trailing flag. */\r
+  c = ~fcsOut & 0xFF;\r
+  tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  c = (~fcsOut >> 8) & 0xFF;\r
+  tailMB = pppAppend(c, tailMB, &pc->outACCM);\r
+  tailMB = pppAppend(PPP_FLAG, tailMB, NULL);\r
+\r
+  /* If we failed to complete the packet, throw it away.\r
+   * Otherwise send it. */\r
+  if (!tailMB) {\r
+    PPPDEBUG((LOG_WARNING,\r
+             "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len));\r
+           /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */\r
+    pbuf_free(headMB);\r
+    LINK_STATS_INC(link.memerr);\r
+    LINK_STATS_INC(link.proterr);\r
+    return PPPERR_ALLOC;\r
+  }\r
+\r
+  PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len));\r
+                   /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */\r
+  nPut(pc, headMB);\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+  return PPPERR_NONE;\r
+}\r
+\r
+/*\r
+ * ppp_send_config - configure the transmit characteristics of\r
+ * the ppp interface.\r
+ */\r
+void\r
+ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp)\r
+{\r
+  PPPControl *pc = &pppControl[unit];\r
+  int i;\r
+  \r
+  pc->mtu = mtu;\r
+  pc->pcomp = pcomp;\r
+  pc->accomp = accomp;\r
+  \r
+  /* Load the ACCM bits for the 32 control codes. */\r
+  for (i = 0; i < 32/8; i++) {\r
+    pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF);\r
+  }\r
+  PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n",\r
+            unit,\r
+            pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3]));\r
+}\r
+\r
+\r
+/*\r
+ * ppp_set_xaccm - set the extended transmit ACCM for the interface.\r
+ */\r
+void\r
+ppp_set_xaccm(int unit, ext_accm *accm)\r
+{\r
+  SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm));\r
+  PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n",\r
+            unit,\r
+            pppControl[unit].outACCM[0],\r
+            pppControl[unit].outACCM[1],\r
+            pppControl[unit].outACCM[2],\r
+            pppControl[unit].outACCM[3]));\r
+}\r
+\r
+\r
+/*\r
+ * ppp_recv_config - configure the receive-side characteristics of\r
+ * the ppp interface.\r
+ */\r
+void\r
+ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp)\r
+{\r
+  PPPControl *pc = &pppControl[unit];\r
+  int i;\r
+\r
+  LWIP_UNUSED_ARG(accomp);\r
+  LWIP_UNUSED_ARG(pcomp);\r
+  LWIP_UNUSED_ARG(mru);\r
+\r
+  /* Load the ACCM bits for the 32 control codes. */\r
+  for (i = 0; i < 32 / 8; i++) {\r
+    pc->inACCM[i] = (u_char)(asyncmap >> (i * 8));\r
+  }\r
+  PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n",\r
+            unit,\r
+            pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3]));\r
+}\r
+\r
+#if 0\r
+/*\r
+ * ccp_test - ask kernel whether a given compression method\r
+ * is acceptable for use.  Returns 1 if the method and parameters\r
+ * are OK, 0 if the method is known but the parameters are not OK\r
+ * (e.g. code size should be reduced), or -1 if the method is unknown.\r
+ */\r
+int\r
+ccp_test( int unit, int opt_len,  int for_transmit, u_char *opt_ptr)\r
+{\r
+  return 0; /* XXX Currently no compression. */\r
+}\r
+\r
+/*\r
+ * ccp_flags_set - inform kernel about the current state of CCP.\r
+ */\r
+void\r
+ccp_flags_set(int unit, int isopen, int isup)\r
+{\r
+  /* XXX */\r
+}\r
+\r
+/*\r
+ * ccp_fatal_error - returns 1 if decompression was disabled as a\r
+ * result of an error detected after decompression of a packet,\r
+ * 0 otherwise.  This is necessary because of patent nonsense.\r
+ */\r
+int\r
+ccp_fatal_error(int unit)\r
+{\r
+  /* XXX */\r
+  return 0;\r
+}\r
+#endif\r
+\r
+/*\r
+ * get_idle_time - return how long the link has been idle.\r
+ */\r
+int\r
+get_idle_time(int u, struct ppp_idle *ip)\r
+{\r
+  /* XXX */\r
+  LWIP_UNUSED_ARG(u);\r
+  LWIP_UNUSED_ARG(ip);\r
+\r
+  return 0;\r
+}\r
+\r
+\r
+/*\r
+ * Return user specified netmask, modified by any mask we might determine\r
+ * for address `addr' (in network byte order).\r
+ * Here we scan through the system's list of interfaces, looking for\r
+ * any non-point-to-point interfaces which might appear to be on the same\r
+ * network as `addr'.  If we find any, we OR in their netmask to the\r
+ * user-specified netmask.\r
+ */\r
+u32_t\r
+GetMask(u32_t addr)\r
+{\r
+  u32_t mask, nmask;\r
+\r
+  htonl(addr);\r
+  if (IN_CLASSA(addr)) { /* determine network mask for address class */\r
+    nmask = IN_CLASSA_NET;\r
+  } else if (IN_CLASSB(addr)) {\r
+    nmask = IN_CLASSB_NET;\r
+  } else { \r
+    nmask = IN_CLASSC_NET;\r
+  }\r
+\r
+  /* class D nets are disallowed by bad_ip_adrs */\r
+  mask = subnetMask | htonl(nmask);\r
+  \r
+  /* XXX\r
+   * Scan through the system's network interfaces.\r
+   * Get each netmask and OR them into our mask.\r
+   */\r
+\r
+  return mask;\r
+}\r
+\r
+/*\r
+ * sifvjcomp - config tcp header compression\r
+ */\r
+int\r
+sifvjcomp( int pd, int vjcomp, int cidcomp, int maxcid)\r
+{\r
+#if PPPOS_SUPPORT && VJ_SUPPORT\r
+  PPPControl *pc = &pppControl[pd];\r
+  \r
+  pc->vjEnabled = vjcomp;\r
+  pc->vjComp.compressSlot = cidcomp;\r
+  pc->vjComp.maxSlotIndex = maxcid;\r
+  PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n",\r
+            vjcomp, cidcomp, maxcid));\r
+#endif /* PPPOS_SUPPORT && VJ_SUPPORT */\r
+\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * pppifNetifInit - netif init callback\r
+ */\r
+static err_t\r
+pppifNetifInit(struct netif *netif)\r
+{\r
+  netif->name[0] = 'p';\r
+  netif->name[1] = 'p';\r
+  netif->output = pppifOutput;\r
+  netif->mtu = pppMTU((int)netif->state);\r
+  return ERR_OK;\r
+}\r
+\r
+\r
+/*\r
+ * sifup - Config the interface up and enable IP packets to pass.\r
+ */\r
+int\r
+sifup(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+  \r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+  } else {\r
+    netif_remove(&pc->netif);\r
+    if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) {\r
+      netif_set_up(&pc->netif);\r
+#if LWIP_DHCP\r
+      /* ugly workaround for storing a reference to the ppp related info*/\r
+      pc->netif.dhcp = (struct dhcp *) &pc->addrs;\r
+#endif /* LWIP_DHCP */\r
+      pc->if_up = 1;\r
+      pc->errCode = PPPERR_NONE;\r
+\r
+      PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+      if(pc->linkStatusCB) {\r
+        pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs);\r
+      }\r
+    } else {\r
+      st = 0;\r
+      PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd));\r
+    }\r
+  }\r
+\r
+  return st;\r
+}\r
+\r
+/*\r
+ * sifnpmode - Set the mode for handling packets for a given NP.\r
+ */\r
+int\r
+sifnpmode(int u, int proto, enum NPmode mode)\r
+{\r
+  LWIP_UNUSED_ARG(u);\r
+  LWIP_UNUSED_ARG(proto);\r
+  LWIP_UNUSED_ARG(mode);\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * sifdown - Config the interface down and disable IP.\r
+ */\r
+int\r
+sifdown(int pd)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+  \r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd));\r
+  } else {\r
+    pc->if_up = 0;\r
+    netif_remove(&pc->netif);\r
+    PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+    if(pc->linkStatusCB) {\r
+      pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL);\r
+    }\r
+  }\r
+  return st;\r
+}\r
+\r
+/**\r
+ * sifaddr - Config the interface IP addresses and netmask.\r
+ * @param pd Interface unit ???\r
+ * @param o Our IP address ???\r
+ * @param h His IP address ???\r
+ * @param m IP subnet mask ???\r
+ * @param ns1 Primary DNS\r
+ * @param ns2 Secondary DNS\r
+ */\r
+int\r
+sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+  \r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+  } else {\r
+    SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o));\r
+    SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h));\r
+    SMEMCPY(&pc->addrs.netmask, &m, sizeof(m));\r
+    SMEMCPY(&pc->addrs.dns1, &ns1, sizeof(ns1));\r
+    SMEMCPY(&pc->addrs.dns2, &ns2, sizeof(ns2));\r
+  }\r
+  return st;\r
+}\r
+\r
+/**\r
+ * cifaddr - Clear the interface IP addresses, and delete routes\r
+ * through the interface if possible.\r
+ * @param pd Interface unit ???\r
+ * @param o Our IP address ???\r
+ * @param h IP broadcast address ???\r
+ */\r
+int\r
+cifaddr( int pd, u32_t o, u32_t h)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+  \r
+  LWIP_UNUSED_ARG(o);\r
+  LWIP_UNUSED_ARG(h);\r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+  } else {\r
+    IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0);\r
+    IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0);\r
+    IP4_ADDR(&pc->addrs.netmask, 255,255,255,0);\r
+    IP4_ADDR(&pc->addrs.dns1, 0,0,0,0);\r
+    IP4_ADDR(&pc->addrs.dns2, 0,0,0,0);\r
+  }\r
+  return st;\r
+}\r
+\r
+/*\r
+ * sifdefaultroute - assign a default route through the address given.\r
+ */\r
+int\r
+sifdefaultroute(int pd, u32_t l, u32_t g)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+\r
+  LWIP_UNUSED_ARG(l);\r
+  LWIP_UNUSED_ARG(g);\r
+\r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+  } else {\r
+    netif_set_default(&pc->netif);\r
+  }\r
+\r
+  /* TODO: check how PPP handled the netMask, previously not set by ipSetDefault */\r
+\r
+  return st;\r
+}\r
+\r
+/*\r
+ * cifdefaultroute - delete a default route through the address given.\r
+ */\r
+int\r
+cifdefaultroute(int pd, u32_t l, u32_t g)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  int st = 1;\r
+\r
+  LWIP_UNUSED_ARG(l);\r
+  LWIP_UNUSED_ARG(g);\r
+\r
+  if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) {\r
+    st = 0;\r
+    PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd));\r
+  } else {\r
+    netif_set_default(NULL);\r
+  }\r
+\r
+  return st;\r
+}\r
+\r
+/**********************************/\r
+/*** LOCAL FUNCTION DEFINITIONS ***/\r
+/**********************************/\r
+\r
+#if PPPOS_SUPPORT\r
+/* The main PPP process function.  This implements the state machine according\r
+ * to section 4 of RFC 1661: The Point-To-Point Protocol. */\r
+static void\r
+pppMain(void *arg)\r
+{\r
+  int pd = (int)arg;\r
+  struct pbuf *p;\r
+  PPPControl* pc;\r
+  int c;\r
+\r
+  pc = &pppControl[pd];\r
+\r
+  p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM);\r
+  if (!p) {\r
+    LWIP_ASSERT("p != NULL", p);\r
+    pc->errCode = PPPERR_ALLOC;\r
+    goto out;\r
+  }\r
+\r
+  /*\r
+   * Start the connection and handle incoming events (packet or timeout).\r
+   */\r
+  PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));\r
+  tcpip_callback(pppStartCB, arg);\r
+  while (lcp_phase[pd] != PHASE_DEAD) {\r
+    if (pc->kill_link) {\r
+      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d kill_link -> pppStopCB\n", pd));\r
+      pc->errCode = PPPERR_USER;\r
+      /* This will leave us at PHASE_DEAD. */\r
+      tcpip_callback(pppStopCB, arg);\r
+      pc->kill_link = 0;\r
+    } else if (pc->sig_hup) {\r
+      PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sig_hup -> pppHupCB\n", pd));\r
+      pc->sig_hup = 0;\r
+      tcpip_callback(pppHupCB, arg);\r
+    } else {\r
+      c = sio_read(pc->fd, p->payload, p->len);\r
+      if(c > 0) {\r
+        pppInProc(pd, p->payload, c);\r
+      } else {\r
+        PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sio_read len=%d returned %d\n", pd, p->len, c));\r
+        sys_msleep(1); /* give other tasks a chance to run */\r
+      }\r
+    }\r
+  }\r
+  PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd));\r
+  pppDrop(pc); /* bug fix #17726 */\r
+  pbuf_free(p);\r
+\r
+out:\r
+  PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode));\r
+  if(pc->linkStatusCB) {\r
+    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);\r
+  }\r
+\r
+  pc->openFlag = 0;\r
+}\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+#if PPPOE_SUPPORT\r
+\r
+void\r
+pppOverEthernetInitFailed(void* arg)\r
+{\r
+  PPPControl* pc;\r
+  int pd = (int)arg;\r
+\r
+  pppHupCB(arg);\r
+  pppStopCB(arg);\r
+\r
+  pc = &pppControl[pd];\r
+  pppoe_destroy(&pc->netif);\r
+  pc->openFlag = 0;\r
+\r
+  if(pc->linkStatusCB) {\r
+    pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL);\r
+  }\r
+}\r
+\r
+static void\r
+pppOverEthernetLinkStatusCB(int pd, int up)\r
+{\r
+  if(up) {\r
+    PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd));\r
+    tcpip_callback(pppStartCB, (void*)pd);\r
+  } else {\r
+    PPPControl* pc;\r
+    pc = &pppControl[pd];\r
+    tcpip_callback(pppOverEthernetInitFailed, (void*)pd);\r
+  }\r
+}\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+struct pbuf *\r
+pppSingleBuf(struct pbuf *p)\r
+{\r
+  struct pbuf *q, *b;\r
+  u_char *pl;\r
+\r
+  if(p->tot_len == p->len) {\r
+    return p;\r
+  }\r
+\r
+  q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);\r
+  if(!q) {\r
+    PPPDEBUG((LOG_ERR,\r
+             "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len));\r
+    return p; /* live dangerously */\r
+  }\r
+\r
+  for(b = p, pl = q->payload; b != NULL; b = b->next) {\r
+    MEMCPY(pl, b->payload, b->len);\r
+    pl += b->len;\r
+  }\r
+\r
+  pbuf_free(p);\r
+\r
+  return q;\r
+}\r
+\r
+struct pppInputHeader {\r
+  int unit;\r
+  u16_t proto;\r
+};\r
+\r
+/*\r
+ * Pass the processed input packet to the appropriate handler.\r
+ * This function and all handlers run in the context of the tcpip_thread\r
+ */\r
+static void\r
+pppInput(void *arg)\r
+{\r
+  struct pbuf *nb = (struct pbuf *)arg;\r
+  u16_t protocol;\r
+  int pd;\r
+\r
+  pd = ((struct pppInputHeader *)nb->payload)->unit;\r
+  protocol = ((struct pppInputHeader *)nb->payload)->proto;\r
+    \r
+  if(pbuf_header(nb, -(int)sizeof(struct pppInputHeader))) {\r
+    LWIP_ASSERT("pbuf_header failed\n", 0);\r
+    goto drop;\r
+  }\r
+\r
+  LINK_STATS_INC(link.recv);\r
+\r
+  /*\r
+   * Toss all non-LCP packets unless LCP is OPEN.\r
+   * Until we get past the authentication phase, toss all packets\r
+   * except LCP, LQR and authentication packets.\r
+   */\r
+  if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) {\r
+    if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) ||\r
+        (lcp_phase[pd] != PHASE_AUTHENTICATE)) {\r
+      PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd]));\r
+      goto drop;\r
+    }\r
+  }\r
+\r
+  switch(protocol) {\r
+    case PPP_VJC_COMP:      /* VJ compressed TCP */\r
+#if VJ_SUPPORT\r
+      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len));\r
+      /*\r
+       * Clip off the VJ header and prepend the rebuilt TCP/IP header and\r
+       * pass the result to IP.\r
+       */\r
+      if ((vj_uncompress_tcp(&nb, &pppControl[pd].vjComp) >= 0) && (pppControl[pd].netif.input)) {\r
+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+        return;\r
+      }\r
+      /* Something's wrong so drop it. */\r
+      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd));\r
+#else  /* VJ_SUPPORT */\r
+      /* No handler for this protocol so drop the packet. */\r
+      PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload));\r
+#endif /* VJ_SUPPORT */\r
+      break;\r
+\r
+    case PPP_VJC_UNCOMP:    /* VJ uncompressed TCP */\r
+#if VJ_SUPPORT\r
+      PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len));\r
+      /*\r
+       * Process the TCP/IP header for VJ header compression and then pass\r
+       * the packet to IP.\r
+       */\r
+      if ((vj_uncompress_uncomp(nb, &pppControl[pd].vjComp) >= 0) && pppControl[pd].netif.input) {\r
+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+        return;\r
+      }\r
+      /* Something's wrong so drop it. */\r
+      PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd));\r
+#else  /* VJ_SUPPORT */\r
+      /* No handler for this protocol so drop the packet. */\r
+      PPPDEBUG((LOG_INFO,\r
+               "pppInput[%d]: drop VJ UnComp in %d:.*H\n", \r
+                pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload));\r
+#endif /* VJ_SUPPORT */\r
+      break;\r
+\r
+    case PPP_IP:            /* Internet Protocol */\r
+      PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len));\r
+      if (pppControl[pd].netif.input) {\r
+        pppControl[pd].netif.input(nb, &pppControl[pd].netif);\r
+        return;\r
+      }\r
+      break;\r
+\r
+    default: {\r
+      struct protent *protp;\r
+      int i;\r
+\r
+      /*\r
+       * Upcall the proper protocol input routine.\r
+       */\r
+      for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) {\r
+        if (protp->protocol == protocol && protp->enabled_flag) {\r
+          PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len));\r
+          nb = pppSingleBuf(nb);\r
+          (*protp->input)(pd, nb->payload, nb->len);\r
+          goto out;\r
+        }\r
+      }\r
+\r
+      /* No handler for this protocol so reject the packet. */\r
+      PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len));\r
+      if (pbuf_header(nb, sizeof(protocol))) {\r
+        LWIP_ASSERT("pbuf_header failed\n", 0);\r
+        goto drop;\r
+      }\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+      protocol = htons(protocol);\r
+      SMEMCPY(nb->payload, &protocol, sizeof(protocol));\r
+#endif /* BYTE_ORDER == LITTLE_ENDIAN */\r
+      lcp_sprotrej(pd, nb->payload, nb->len);\r
+    }\r
+    break;\r
+  }\r
+\r
+drop:\r
+  LINK_STATS_INC(link.drop);\r
+\r
+out:\r
+  pbuf_free(nb);\r
+  return;\r
+}\r
+\r
+#if PPPOS_SUPPORT\r
+/*\r
+ * Drop the input packet.\r
+ */\r
+static void\r
+pppDrop(PPPControl *pc)\r
+{\r
+  if (pc->inHead != NULL) {\r
+#if 0\r
+    PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload));\r
+#endif\r
+    PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len));\r
+    if (pc->inTail && (pc->inTail != pc->inHead)) {\r
+      pbuf_free(pc->inTail);\r
+    }\r
+    pbuf_free(pc->inHead);\r
+    pc->inHead = NULL;\r
+    pc->inTail = NULL;\r
+  }\r
+#if VJ_SUPPORT\r
+  vj_uncompress_err(&pc->vjComp);\r
+#endif /* VJ_SUPPORT */\r
+\r
+  LINK_STATS_INC(link.drop);\r
+}\r
+\r
+/**\r
+ * Process a received octet string.\r
+ */\r
+static void\r
+pppInProc(int pd, u_char *s, int l)\r
+{\r
+  PPPControl *pc = &pppControl[pd];\r
+  struct pbuf *nextNBuf;\r
+  u_char curChar;\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l));\r
+  while (l-- > 0) {\r
+    curChar = *s++;\r
+    \r
+    /* Handle special characters. */\r
+    if (ESCAPE_P(pc->inACCM, curChar)) {\r
+      /* Check for escape sequences. */\r
+      /* XXX Note that this does not handle an escaped 0x5d character which\r
+       * would appear as an escape character.  Since this is an ASCII ']'\r
+       * and there is no reason that I know of to escape it, I won't complicate\r
+       * the code to handle this case. GLL */\r
+      if (curChar == PPP_ESCAPE) {\r
+        pc->inEscaped = 1;\r
+      /* Check for the flag character. */\r
+      } else if (curChar == PPP_FLAG) {\r
+         /* If this is just an extra flag character, ignore it. */\r
+         if (pc->inState <= PDADDRESS) {\r
+           /* ignore it */;\r
+         /* If we haven't received the packet header, drop what has come in. */\r
+         } else if (pc->inState < PDDATA) {\r
+           PPPDEBUG((LOG_WARNING,\r
+                    "pppInProc[%d]: Dropping incomplete packet %d\n", \r
+                     pd, pc->inState));\r
+           LINK_STATS_INC(link.lenerr);\r
+           pppDrop(pc);\r
+         /* If the fcs is invalid, drop the packet. */\r
+         } else if (pc->inFCS != PPP_GOODFCS) {\r
+           PPPDEBUG((LOG_INFO,\r
+                    "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", \r
+                     pd, pc->inFCS, pc->inProtocol));\r
+           LINK_STATS_INC(link.chkerr);\r
+           pppDrop(pc);\r
+         /* Otherwise it's a good packet so pass it on. */\r
+         } else {\r
+           /* Trim off the checksum. */\r
+           if(pc->inTail->len >= 2) {\r
+             pc->inTail->len -= 2;\r
+\r
+             pc->inTail->tot_len = pc->inTail->len;\r
+             if (pc->inTail != pc->inHead) {\r
+               pbuf_cat(pc->inHead, pc->inTail);\r
+             }\r
+           } else {\r
+             pc->inTail->tot_len = pc->inTail->len;\r
+             if (pc->inTail != pc->inHead) {\r
+               pbuf_cat(pc->inHead, pc->inTail);\r
+             }\r
+\r
+             pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2);\r
+           }\r
+\r
+           /* Dispatch the packet thereby consuming it. */\r
+           if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) {\r
+             PPPDEBUG((LOG_ERR, "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd));\r
+             pbuf_free(pc->inHead);\r
+             LINK_STATS_INC(link.drop);\r
+           }\r
+           pc->inHead = NULL;\r
+           pc->inTail = NULL;\r
+         }\r
+\r
+         /* Prepare for a new packet. */\r
+         pc->inFCS = PPP_INITFCS;\r
+         pc->inState = PDADDRESS;\r
+         pc->inEscaped = 0;\r
+      /* Other characters are usually control characters that may have\r
+       * been inserted by the physical layer so here we just drop them. */\r
+      } else {\r
+        PPPDEBUG((LOG_WARNING,\r
+                 "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar));\r
+      }\r
+    /* Process other characters. */\r
+    } else {\r
+      /* Unencode escaped characters. */\r
+      if (pc->inEscaped) {\r
+        pc->inEscaped = 0;\r
+        curChar ^= PPP_TRANS;\r
+      }\r
+\r
+      /* Process character relative to current state. */\r
+      switch(pc->inState) {\r
+        case PDIDLE:                    /* Idle state - waiting. */\r
+          /* Drop the character if it's not 0xff\r
+           * we would have processed a flag character above. */\r
+          if (curChar != PPP_ALLSTATIONS) {\r
+            break;\r
+          }\r
+\r
+        /* Fall through */\r
+        case PDSTART:                   /* Process start flag. */\r
+          /* Prepare for a new packet. */\r
+          pc->inFCS = PPP_INITFCS;\r
+\r
+        /* Fall through */\r
+        case PDADDRESS:                 /* Process address field. */\r
+          if (curChar == PPP_ALLSTATIONS) {\r
+            pc->inState = PDCONTROL;\r
+            break;\r
+          }\r
+          /* Else assume compressed address and control fields so\r
+           * fall through to get the protocol... */\r
+        case PDCONTROL:                 /* Process control field. */\r
+          /* If we don't get a valid control code, restart. */\r
+          if (curChar == PPP_UI) {\r
+            pc->inState = PDPROTOCOL1;\r
+            break;\r
+          }\r
+#if 0\r
+          else {\r
+            PPPDEBUG((LOG_WARNING,\r
+                     "pppInProc[%d]: Invalid control <%d>\n", pd, curChar));\r
+                      pc->inState = PDSTART;\r
+          }\r
+#endif\r
+        case PDPROTOCOL1:               /* Process protocol field 1. */\r
+          /* If the lower bit is set, this is the end of the protocol\r
+           * field. */\r
+          if (curChar & 1) {\r
+            pc->inProtocol = curChar;\r
+            pc->inState = PDDATA;\r
+          } else {\r
+            pc->inProtocol = (u_int)curChar << 8;\r
+            pc->inState = PDPROTOCOL2;\r
+          }\r
+          break;\r
+        case PDPROTOCOL2:               /* Process protocol field 2. */\r
+          pc->inProtocol |= curChar;\r
+          pc->inState = PDDATA;\r
+          break;\r
+        case PDDATA:                    /* Process data byte. */\r
+          /* Make space to receive processed data. */\r
+          if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) {\r
+            if(pc->inTail) {\r
+              pc->inTail->tot_len = pc->inTail->len;\r
+              if (pc->inTail != pc->inHead) {\r
+                pbuf_cat(pc->inHead, pc->inTail);\r
+              }\r
+            }\r
+            /* If we haven't started a packet, we need a packet header. */\r
+            nextNBuf = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL);\r
+            if (nextNBuf == NULL) {\r
+              /* No free buffers.  Drop the input packet and let the\r
+               * higher layers deal with it.  Continue processing\r
+               * the received pbuf chain in case a new packet starts. */\r
+              PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd));\r
+              LINK_STATS_INC(link.memerr);\r
+              pppDrop(pc);\r
+              pc->inState = PDSTART;  /* Wait for flag sequence. */\r
+              break;\r
+            }\r
+            if (pc->inHead == NULL) {\r
+              struct pppInputHeader *pih = nextNBuf->payload;\r
+\r
+              pih->unit = pd;\r
+              pih->proto = pc->inProtocol;\r
+\r
+              nextNBuf->len += sizeof(*pih);\r
+\r
+              pc->inHead = nextNBuf;\r
+            }\r
+            pc->inTail = nextNBuf;\r
+          }\r
+          /* Load character into buffer. */\r
+          ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar;\r
+          break;\r
+      }\r
+\r
+      /* update the frame check sequence number. */\r
+      pc->inFCS = PPP_FCS(pc->inFCS, curChar);\r
+    }\r
+  }\r
+\r
+  avRandomize();\r
+}\r
+#endif /* PPPOS_SUPPORT */\r
+\r
+#if PPPOE_SUPPORT\r
+void\r
+pppInProcOverEthernet(int pd, struct pbuf *pb)\r
+{\r
+  struct pppInputHeader *pih;\r
+  u16_t inProtocol;\r
+\r
+  if(pb->len < sizeof(inProtocol)) {\r
+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: too small for protocol field\n"));\r
+    goto drop;\r
+  }\r
+\r
+  inProtocol = (((u8_t *)pb->payload)[0] << 8) | ((u8_t*)pb->payload)[1];\r
+\r
+  /* make room for pppInputHeader - should not fail */\r
+  if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) {\r
+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: could not allocate room for header\n"));\r
+    goto drop;\r
+  }\r
+\r
+  pih = pb->payload;\r
+\r
+  pih->unit = pd;\r
+  pih->proto = inProtocol;\r
+\r
+  /* Dispatch the packet thereby consuming it. */\r
+  if(tcpip_callback(pppInput, pb) != ERR_OK) {\r
+    PPPDEBUG((LOG_ERR, "pppInProcOverEthernet[%d]: tcpip_callback() failed, dropping packet\n", pd));\r
+    goto drop;\r
+  }\r
+\r
+  return;\r
+\r
+drop:\r
+  LINK_STATS_INC(link.drop);\r
+  pbuf_free(pb);\r
+  return;\r
+}\r
+#endif /* PPPOE_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp.h
new file mode 100644 (file)
index 0000000..d610e4b
--- /dev/null
@@ -0,0 +1,465 @@
+/*****************************************************************************\r
+* ppp.h - Network Point to Point Protocol header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1997 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 97-11-05 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Original derived from BSD codes.\r
+*****************************************************************************/\r
+\r
+#ifndef PPP_H\r
+#define PPP_H\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/sio.h"\r
+#include "lwip/api.h"\r
+#include "lwip/sockets.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/tcpip.h"\r
+#include "lwip/netif.h"\r
+\r
+/*\r
+ * pppd.h - PPP daemon global declarations.\r
+ *\r
+ * Copyright (c) 1989 Carnegie Mellon University.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by Carnegie Mellon University.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ */\r
+/*\r
+ * ppp_defs.h - PPP definitions.\r
+ *\r
+ * Copyright (c) 1994 The Australian National University.\r
+ * All rights reserved.\r
+ *\r
+ * Permission to use, copy, modify, and distribute this software and its\r
+ * documentation is hereby granted, provided that the above copyright\r
+ * notice appears in all copies.  This software is provided without any\r
+ * warranty, express or implied. The Australian National University\r
+ * makes no representations about the suitability of this software for\r
+ * any purpose.\r
+ *\r
+ * IN NO EVENT SHALL THE AUSTRALIAN NATIONAL UNIVERSITY BE LIABLE TO ANY\r
+ * PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES\r
+ * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY HAVE BEEN ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * THE AUSTRALIAN NATIONAL UNIVERSITY SPECIFICALLY DISCLAIMS ANY WARRANTIES,\r
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY\r
+ * AND FITNESS FOR A PARTICULAR PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS\r
+ * ON AN "AS IS" BASIS, AND THE AUSTRALIAN NATIONAL UNIVERSITY HAS NO\r
+ * OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,\r
+ * OR MODIFICATIONS.\r
+ */\r
+\r
+#define TIMEOUT(f, a, t)    sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a))\r
+#define UNTIMEOUT(f, a)     sys_untimeout((f), (a))\r
+\r
+\r
+#ifndef __u_char_defined\r
+\r
+/* Type definitions for BSD code. */\r
+typedef unsigned long  u_long;\r
+typedef unsigned int   u_int;\r
+typedef unsigned short u_short;\r
+typedef unsigned char  u_char;\r
+\r
+#endif\r
+\r
+/*\r
+ * Constants and structures defined by the internet system,\r
+ * Per RFC 790, September 1981, and numerous additions.\r
+ */\r
+\r
+/*\r
+ * The basic PPP frame.\r
+ */\r
+#define PPP_HDRLEN      4       /* octets for standard ppp header */\r
+#define PPP_FCSLEN      2       /* octets for FCS */\r
+\r
+\r
+/*\r
+ * Significant octet values.\r
+ */\r
+#define PPP_ALLSTATIONS 0xff    /* All-Stations broadcast address */\r
+#define PPP_UI          0x03    /* Unnumbered Information */\r
+#define PPP_FLAG        0x7e    /* Flag Sequence */\r
+#define PPP_ESCAPE      0x7d    /* Asynchronous Control Escape */\r
+#define PPP_TRANS       0x20    /* Asynchronous transparency modifier */\r
+\r
+/*\r
+ * Protocol field values.\r
+ */\r
+#define PPP_IP          0x21    /* Internet Protocol */\r
+#define PPP_AT          0x29    /* AppleTalk Protocol */\r
+#define PPP_VJC_COMP    0x2d    /* VJ compressed TCP */\r
+#define PPP_VJC_UNCOMP  0x2f    /* VJ uncompressed TCP */\r
+#define PPP_COMP        0xfd    /* compressed packet */\r
+#define PPP_IPCP        0x8021  /* IP Control Protocol */\r
+#define PPP_ATCP        0x8029  /* AppleTalk Control Protocol */\r
+#define PPP_CCP         0x80fd  /* Compression Control Protocol */\r
+#define PPP_LCP         0xc021  /* Link Control Protocol */\r
+#define PPP_PAP         0xc023  /* Password Authentication Protocol */\r
+#define PPP_LQR         0xc025  /* Link Quality Report protocol */\r
+#define PPP_CHAP        0xc223  /* Cryptographic Handshake Auth. Protocol */\r
+#define PPP_CBCP        0xc029  /* Callback Control Protocol */\r
+\r
+/*\r
+ * Values for FCS calculations.\r
+ */\r
+#define PPP_INITFCS     0xffff  /* Initial FCS value */\r
+#define PPP_GOODFCS     0xf0b8  /* Good final FCS value */\r
+#define PPP_FCS(fcs, c) (((fcs) >> 8) ^ fcstab[((fcs) ^ (c)) & 0xff])\r
+\r
+/*\r
+ * Extended asyncmap - allows any character to be escaped.\r
+ */\r
+typedef u_char  ext_accm[32];\r
+\r
+/*\r
+ * What to do with network protocol (NP) packets.\r
+ */\r
+enum NPmode {\r
+  NPMODE_PASS,        /* pass the packet through */\r
+  NPMODE_DROP,        /* silently drop the packet */\r
+  NPMODE_ERROR,       /* return an error */\r
+  NPMODE_QUEUE        /* save it up for later. */\r
+};\r
+\r
+/*\r
+ * Inline versions of get/put char/short/long.\r
+ * Pointer is advanced; we assume that both arguments\r
+ * are lvalues and will already be in registers.\r
+ * cp MUST be u_char *.\r
+ */\r
+#define GETCHAR(c, cp) { \\r
+    (c) = *(cp)++; \\r
+}\r
+#define PUTCHAR(c, cp) { \\r
+    *(cp)++ = (u_char) (c); \\r
+}\r
+\r
+\r
+#define GETSHORT(s, cp) { \\r
+    (s) = *(cp); (cp)++; (s) <<= 8; \\r
+    (s) |= *(cp); (cp)++; \\r
+}\r
+#define PUTSHORT(s, cp) { \\r
+    *(cp)++ = (u_char) ((s) >> 8); \\r
+    *(cp)++ = (u_char) (s & 0xff); \\r
+}\r
+\r
+#define GETLONG(l, cp) { \\r
+    (l) = *(cp); (cp)++; (l) <<= 8; \\r
+    (l) |= *(cp); (cp)++; (l) <<= 8; \\r
+    (l) |= *(cp); (cp)++; (l) <<= 8; \\r
+    (l) |= *(cp); (cp)++; \\r
+}\r
+#define PUTLONG(l, cp) { \\r
+    *(cp)++ = (u_char) ((l) >> 24); \\r
+    *(cp)++ = (u_char) ((l) >> 16); \\r
+    *(cp)++ = (u_char) ((l) >> 8); \\r
+    *(cp)++ = (u_char) (l); \\r
+}\r
+\r
+\r
+#define INCPTR(n, cp)   ((cp) += (n))\r
+#define DECPTR(n, cp)   ((cp) -= (n))\r
+\r
+#define BCMP(s0, s1, l)     memcmp((u_char *)(s0), (u_char *)(s1), (l))\r
+#define BCOPY(s, d, l)      MEMCPY((d), (s), (l))\r
+#define BZERO(s, n)         memset(s, 0, n)\r
+\r
+#if PPP_DEBUG\r
+#define PRINTMSG(m, l)  { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); }\r
+#else  /* PPP_DEBUG */\r
+#define PRINTMSG(m, l)\r
+#endif /* PPP_DEBUG */\r
+\r
+/*\r
+ * MAKEHEADER - Add PPP Header fields to a packet.\r
+ */\r
+#define MAKEHEADER(p, t) { \\r
+    PUTCHAR(PPP_ALLSTATIONS, p); \\r
+    PUTCHAR(PPP_UI, p); \\r
+    PUTSHORT(t, p); }\r
+\r
+/*************************\r
+*** PUBLIC DEFINITIONS ***\r
+*************************/\r
+\r
+/* Error codes. */\r
+#define PPPERR_NONE      0 /* No error. */\r
+#define PPPERR_PARAM    -1 /* Invalid parameter. */\r
+#define PPPERR_OPEN     -2 /* Unable to open PPP session. */\r
+#define PPPERR_DEVICE   -3 /* Invalid I/O device for PPP. */\r
+#define PPPERR_ALLOC    -4 /* Unable to allocate resources. */\r
+#define PPPERR_USER     -5 /* User interrupt. */\r
+#define PPPERR_CONNECT  -6 /* Connection lost. */\r
+#define PPPERR_AUTHFAIL -7 /* Failed authentication challenge. */\r
+#define PPPERR_PROTOCOL -8 /* Failed to meet protocol. */\r
+\r
+/*\r
+ * PPP IOCTL commands.\r
+ */\r
+/*\r
+ * Get the up status - 0 for down, non-zero for up.  The argument must\r
+ * point to an int.\r
+ */\r
+#define PPPCTLG_UPSTATUS 100 /* Get the up status - 0 down else up */\r
+#define PPPCTLS_ERRCODE  101 /* Set the error code */\r
+#define PPPCTLG_ERRCODE  102 /* Get the error code */\r
+#define PPPCTLG_FD       103 /* Get the fd associated with the ppp */\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+\r
+/*\r
+ * The following struct gives the addresses of procedures to call\r
+ * for a particular protocol.\r
+ */\r
+struct protent {\r
+    u_short protocol;       /* PPP protocol number */\r
+    /* Initialization procedure */\r
+    void (*init) (int unit);\r
+    /* Process a received packet */\r
+    void (*input) (int unit, u_char *pkt, int len);\r
+    /* Process a received protocol-reject */\r
+    void (*protrej) (int unit);\r
+    /* Lower layer has come up */\r
+    void (*lowerup) (int unit);\r
+    /* Lower layer has gone down */\r
+    void (*lowerdown) (int unit);\r
+    /* Open the protocol */\r
+    void (*open) (int unit);\r
+    /* Close the protocol */\r
+    void (*close) (int unit, char *reason);\r
+#if 0\r
+    /* Print a packet in readable form */\r
+    int  (*printpkt) (u_char *pkt, int len,\r
+              void (*printer) (void *, char *, ...),\r
+              void *arg);\r
+    /* Process a received data packet */\r
+    void (*datainput) (int unit, u_char *pkt, int len);\r
+#endif\r
+    int  enabled_flag;      /* 0 iff protocol is disabled */\r
+    char *name;         /* Text name of protocol */\r
+#if 0\r
+    /* Check requested options, assign defaults */\r
+    void (*check_options) (u_long);\r
+    /* Configure interface for demand-dial */\r
+    int  (*demand_conf) (int unit);\r
+    /* Say whether to bring up link for this pkt */\r
+    int  (*active_pkt) (u_char *pkt, int len);\r
+#endif\r
+};\r
+\r
+/*\r
+ * The following structure records the time in seconds since\r
+ * the last NP packet was sent or received.\r
+ */\r
+struct ppp_idle {\r
+  u_short xmit_idle;      /* seconds since last NP packet sent */\r
+  u_short recv_idle;      /* seconds since last NP packet received */\r
+};\r
+\r
+struct ppp_settings {\r
+\r
+  u_int  disable_defaultip : 1;       /* Don't use hostname for default IP addrs */\r
+  u_int  auth_required     : 1;       /* Peer is required to authenticate */\r
+  u_int  explicit_remote   : 1;       /* remote_name specified with remotename opt */\r
+  u_int  refuse_pap        : 1;       /* Don't wanna auth. ourselves with PAP */\r
+  u_int  refuse_chap       : 1;       /* Don't wanna auth. ourselves with CHAP */\r
+  u_int  usehostname       : 1;       /* Use hostname for our_name */\r
+  u_int  usepeerdns        : 1;       /* Ask peer for DNS adds */\r
+\r
+  u_short idle_time_limit;            /* Shut down link if idle for this long */\r
+  int  maxconnect;                    /* Maximum connect time (seconds) */\r
+\r
+  char user       [MAXNAMELEN   + 1]; /* Username for PAP */\r
+  char passwd     [MAXSECRETLEN + 1]; /* Password for PAP, secret for CHAP */\r
+  char our_name   [MAXNAMELEN   + 1]; /* Our name for authentication purposes */\r
+  char remote_name[MAXNAMELEN   + 1]; /* Peer's name for authentication */\r
+};\r
+\r
+struct ppp_addrs {\r
+  struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2;\r
+};\r
+\r
+/*****************************\r
+*** PUBLIC DATA STRUCTURES ***\r
+*****************************/\r
+\r
+/* Buffers for outgoing packets. */\r
+extern u_char *outpacket_buf[NUM_PPP];\r
+\r
+extern struct ppp_settings ppp_settings;\r
+\r
+extern struct protent *ppp_protocols[]; /* Table of pointers to supported protocols */\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+\r
+/* Initialize the PPP subsystem. */\r
+err_t pppInit(void);\r
+\r
+/* Warning: Using PPPAUTHTYPE_ANY might have security consequences.\r
+ * RFC 1994 says:\r
+ *\r
+ * In practice, within or associated with each PPP server, there is a\r
+ * database which associates "user" names with authentication\r
+ * information ("secrets").  It is not anticipated that a particular\r
+ * named user would be authenticated by multiple methods.  This would\r
+ * make the user vulnerable to attacks which negotiate the least secure\r
+ * method from among a set (such as PAP rather than CHAP).  If the same\r
+ * secret was used, PAP would reveal the secret to be used later with\r
+ * CHAP.\r
+ *\r
+ * Instead, for each user name there should be an indication of exactly\r
+ * one method used to authenticate that user name.  If a user needs to\r
+ * make use of different authentication methods under different\r
+ * circumstances, then distinct user names SHOULD be employed, each of\r
+ * which identifies exactly one authentication method.\r
+ *\r
+ */\r
+enum pppAuthType {\r
+    PPPAUTHTYPE_NONE,\r
+    PPPAUTHTYPE_ANY,\r
+    PPPAUTHTYPE_PAP,\r
+    PPPAUTHTYPE_CHAP\r
+};\r
+\r
+void pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd);\r
+\r
+/*\r
+ * Open a new PPP connection using the given serial I/O device.\r
+ * This initializes the PPP control block but does not\r
+ * attempt to negotiate the LCP session.\r
+ * Return a new PPP connection descriptor on success or\r
+ * an error code (negative) on failure. \r
+ */\r
+int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);\r
+\r
+/*\r
+ * Open a new PPP Over Ethernet (PPPOE) connection.\r
+ */\r
+int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const char *concentrator_name, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx);\r
+\r
+/* for source code compatibility */\r
+#define pppOpen(fd,cb,ls) pppOverSerialOpen(fd,cb,ls)\r
+\r
+/*\r
+ * Close a PPP connection and release the descriptor. \r
+ * Any outstanding packets in the queues are dropped.\r
+ * Return 0 on success, an error code on failure. \r
+ */\r
+int pppClose(int pd);\r
+\r
+/*\r
+ * Indicate to the PPP process that the line has disconnected.\r
+ */\r
+void pppSigHUP(int pd);\r
+\r
+/*\r
+ * Get and set parameters for the given connection.\r
+ * Return 0 on success, an error code on failure. \r
+ */\r
+int  pppIOCtl(int pd, int cmd, void *arg);\r
+\r
+/*\r
+ * Return the Maximum Transmission Unit for the given PPP connection.\r
+ */\r
+u_int pppMTU(int pd);\r
+\r
+/*\r
+ * Write n characters to a ppp link.\r
+ * RETURN: >= 0 Number of characters written, -1 Failed to write to device.\r
+ */\r
+int pppWrite(int pd, const u_char *s, int n);\r
+\r
+void pppInProcOverEthernet(int pd, struct pbuf *pb);\r
+\r
+struct pbuf *pppSingleBuf(struct pbuf *p);\r
+\r
+void pppLinkTerminated(int pd);\r
+\r
+void pppLinkDown(int pd);\r
+\r
+void pppMainWakeup(int pd);\r
+\r
+/* Configure i/f transmit parameters */\r
+void ppp_send_config (int, int, u32_t, int, int);\r
+/* Set extended transmit ACCM */\r
+void ppp_set_xaccm (int, ext_accm *);\r
+/* Configure i/f receive parameters */\r
+void ppp_recv_config (int, int, u32_t, int, int);\r
+/* Find out how long link has been idle */\r
+int  get_idle_time (int, struct ppp_idle *);\r
+\r
+/* Configure VJ TCP header compression */\r
+int  sifvjcomp (int, int, int, int);\r
+/* Configure i/f down (for IP) */\r
+int  sifup (int);\r
+/* Set mode for handling packets for proto */\r
+int  sifnpmode (int u, int proto, enum NPmode mode);\r
+/* Configure i/f down (for IP) */\r
+int  sifdown (int);\r
+/* Configure IP addresses for i/f */\r
+int  sifaddr (int, u32_t, u32_t, u32_t, u32_t, u32_t);\r
+/* Reset i/f IP addresses */\r
+int  cifaddr (int, u32_t, u32_t);\r
+/* Create default route through i/f */\r
+int  sifdefaultroute (int, u32_t, u32_t);\r
+/* Delete default route through i/f */\r
+int  cifdefaultroute (int, u32_t, u32_t);\r
+\r
+/* Get appropriate netmask for address */\r
+u32_t GetMask (u32_t); \r
+\r
+#endif /* PPP_SUPPORT */\r
+\r
+#endif /* PPP_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/ppp_oe.c
new file mode 100644 (file)
index 0000000..2fcffdd
--- /dev/null
@@ -0,0 +1,1227 @@
+/*****************************************************************************\r
+* ppp_oe.c - PPP Over Ethernet implementation for lwIP.\r
+*\r
+* Copyright (c) 2006 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 06-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+*****************************************************************************/\r
+\r
+\r
+\r
+/* based on NetBSD: if_pppoe.c,v 1.64 2006/01/31 23:50:15 martin Exp */\r
+\r
+/*-\r
+ * Copyright (c) 2002 The NetBSD Foundation, Inc.\r
+ * All rights reserved.\r
+ *\r
+ * This code is derived from software contributed to The NetBSD Foundation\r
+ * by Martin Husemann <martin@NetBSD.org>.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without\r
+ * modification, are permitted provided that the following conditions\r
+ * are met:\r
+ * 1. Redistributions of source code must retain the above copyright\r
+ *    notice, this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright\r
+ *    notice, this list of conditions and the following disclaimer in the\r
+ *    documentation and/or other materials provided with the distribution.\r
+ * 3. All advertising materials mentioning features or use of this software\r
+ *    must display the following acknowledgement:\r
+ *        This product includes software developed by the NetBSD\r
+ *        Foundation, Inc. and its contributors.\r
+ * 4. Neither the name of The NetBSD Foundation nor the names of its\r
+ *    contributors may be used to endorse or promote products derived\r
+ *    from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS\r
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED\r
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS\r
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\r
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\r
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\r
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\r
+ * POSSIBILITY OF SUCH DAMAGE.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "lwip/sys.h"\r
+\r
+#include "netif/ppp_oe.h"\r
+#include "netif/etharp.h"\r
+\r
+#include <string.h>\r
+#include <stdio.h>\r
+\r
+/** @todo Replace this part with a simple list like other lwIP lists */\r
+#ifndef _SYS_QUEUE_H_\r
+#define _SYS_QUEUE_H_\r
+\r
+/*\r
+ * A list is headed by a single forward pointer (or an array of forward\r
+ * pointers for a hash table header). The elements are doubly linked\r
+ * so that an arbitrary element can be removed without a need to\r
+ * traverse the list. New elements can be added to the list before\r
+ * or after an existing element or at the head of the list. A list\r
+ * may only be traversed in the forward direction.\r
+ *\r
+ * For details on the use of these macros, see the queue(3) manual page.\r
+ */\r
+\r
+/*\r
+ * List declarations.\r
+ */\r
+#define  LIST_HEAD(name, type)                                                 \\r
+struct name {                                                                  \\r
+  struct type *lh_first;  /* first element */                                  \\r
+}\r
+\r
+#define  LIST_HEAD_INITIALIZER(head)                                           \\r
+  { NULL }\r
+\r
+#define  LIST_ENTRY(type)                                                      \\r
+struct {                                                                       \\r
+  struct type *le_next;  /* next element */                                    \\r
+  struct type **le_prev; /* address of previous next element */                \\r
+}\r
+\r
+/*\r
+ * List functions.\r
+ */\r
+\r
+#define  LIST_EMPTY(head)  ((head)->lh_first == NULL)\r
+\r
+#define  LIST_FIRST(head)  ((head)->lh_first)\r
+\r
+#define  LIST_FOREACH(var, head, field)                                        \\r
+  for ((var) = LIST_FIRST((head));                                             \\r
+      (var);                                                                   \\r
+      (var) = LIST_NEXT((var), field))\r
+\r
+#define  LIST_INIT(head) do {                                                  \\r
+  LIST_FIRST((head)) = NULL;                                                   \\r
+} while (0)\r
+\r
+#define  LIST_INSERT_AFTER(listelm, elm, field) do {                           \\r
+  if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL)         \\r
+    LIST_NEXT((listelm), field)->field.le_prev =                               \\r
+        &LIST_NEXT((elm), field);                                              \\r
+  LIST_NEXT((listelm), field) = (elm);                                         \\r
+  (elm)->field.le_prev = &LIST_NEXT((listelm), field);                         \\r
+} while (0)\r
+\r
+#define  LIST_INSERT_BEFORE(listelm, elm, field) do {                          \\r
+  (elm)->field.le_prev = (listelm)->field.le_prev;                             \\r
+  LIST_NEXT((elm), field) = (listelm);                                         \\r
+  *(listelm)->field.le_prev = (elm);                                           \\r
+  (listelm)->field.le_prev = &LIST_NEXT((elm), field);                         \\r
+} while (0)\r
+\r
+#define  LIST_INSERT_HEAD(head, elm, field) do {                               \\r
+  if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL)                  \\r
+    LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field);              \\r
+  LIST_FIRST((head)) = (elm);                                                  \\r
+  (elm)->field.le_prev = &LIST_FIRST((head));                                  \\r
+} while (0)\r
+\r
+#define  LIST_NEXT(elm, field)  ((elm)->field.le_next)\r
+\r
+#define  LIST_REMOVE(elm, field) do {                                          \\r
+  if (LIST_NEXT((elm), field) != NULL)                                         \\r
+    LIST_NEXT((elm), field)->field.le_prev =                                   \\r
+        (elm)->field.le_prev;                                                  \\r
+  *(elm)->field.le_prev = LIST_NEXT((elm), field);                             \\r
+} while (0)\r
+\r
+#endif /* !_SYS_QUEUE_H_ */\r
+\r
+\r
+/* Add a 16 bit unsigned value to a buffer pointed to by PTR */\r
+#define PPPOE_ADD_16(PTR, VAL) \\r
+    *(PTR)++ = (VAL) / 256;    \\r
+    *(PTR)++ = (VAL) % 256\r
+\r
+/* Add a complete PPPoE header to the buffer pointed to by PTR */\r
+#define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN)  \\r
+    *(PTR)++ = PPPOE_VERTYPE;  \\r
+    *(PTR)++ = (CODE);         \\r
+    PPPOE_ADD_16(PTR, SESS);   \\r
+    PPPOE_ADD_16(PTR, LEN)\r
+\r
+#define PPPOE_DISC_TIMEOUT (5*1000)  /* base for quick timeout calculation */\r
+#define PPPOE_SLOW_RETRY   (60*1000) /* persistent retry interval */\r
+#define PPPOE_DISC_MAXPADI  4        /* retry PADI four times (quickly) */\r
+#define PPPOE_DISC_MAXPADR  2        /* retry PADR twice */\r
+\r
+#ifdef PPPOE_SERVER\r
+/* from if_spppsubr.c */\r
+#define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */\r
+#endif\r
+\r
+struct pppoe_softc {\r
+  LIST_ENTRY(pppoe_softc) sc_list;\r
+  struct netif *sc_ethif;      /* ethernet interface we are using */\r
+  int sc_pd;                   /* ppp unit number */\r
+  void (*sc_linkStatusCB)(int pd, int up);\r
+\r
+  int sc_state;                /* discovery phase or session connected */\r
+  struct eth_addr sc_dest;     /* hardware address of concentrator */\r
+  u16_t sc_session;            /* PPPoE session id */\r
+\r
+  char *sc_service_name;       /* if != NULL: requested name of service */\r
+  char *sc_concentrator_name;  /* if != NULL: requested concentrator id */\r
+  u8_t *sc_ac_cookie;          /* content of AC cookie we must echo back */\r
+  size_t sc_ac_cookie_len;     /* length of cookie data */\r
+#ifdef PPPOE_SERVER\r
+  u8_t *sc_hunique;            /* content of host unique we must echo back */\r
+  size_t sc_hunique_len;       /* length of host unique */\r
+#endif\r
+  int sc_padi_retried;         /* number of PADI retries already done */\r
+  int sc_padr_retried;         /* number of PADR retries already done */\r
+};\r
+\r
+/* input routines */\r
+static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *);\r
+\r
+/* management routines */\r
+static int pppoe_do_disconnect(struct pppoe_softc *);\r
+static void pppoe_abort_connect(struct pppoe_softc *);\r
+static void pppoe_clear_softc(struct pppoe_softc *, const char *);\r
+\r
+/* internal timeout handling */\r
+static void pppoe_timeout(void *);\r
+\r
+/* sending actual protocol controll packets */\r
+static err_t pppoe_send_padi(struct pppoe_softc *);\r
+static err_t pppoe_send_padr(struct pppoe_softc *);\r
+#ifdef PPPOE_SERVER\r
+static err_t pppoe_send_pado(struct pppoe_softc *);\r
+static err_t pppoe_send_pads(struct pppoe_softc *);\r
+#endif\r
+static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *);\r
+\r
+/* internal helper functions */\r
+static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *);\r
+static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *);\r
+\r
+static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list;\r
+\r
+int pppoe_hdrlen;\r
+\r
+void\r
+pppoe_init(void)\r
+{\r
+  pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN;\r
+  LIST_INIT(&pppoe_softc_list);\r
+}\r
+\r
+err_t\r
+pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr)\r
+{\r
+  struct pppoe_softc *sc;\r
+\r
+  sc = mem_malloc(sizeof(struct pppoe_softc));\r
+  if(!sc) {\r
+    *scptr = NULL;\r
+    return ERR_MEM;\r
+  }\r
+  memset(sc, 0, sizeof(struct pppoe_softc));\r
+\r
+  /* changed to real address later */\r
+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));\r
+\r
+  sc->sc_pd = pd;\r
+  sc->sc_linkStatusCB = linkStatusCB;\r
+  sc->sc_ethif = ethif;\r
+\r
+  LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list);\r
+\r
+  *scptr = sc;\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+err_t\r
+pppoe_destroy(struct netif *ifp)\r
+{\r
+  struct pppoe_softc * sc;\r
+\r
+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {\r
+    if (sc->sc_ethif == ifp) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if(!(sc && (sc->sc_ethif == ifp))) {\r
+    return ERR_IF;\r
+  }\r
+\r
+  tcpip_untimeout(pppoe_timeout, sc);\r
+  LIST_REMOVE(sc, sc_list);\r
+\r
+  if (sc->sc_concentrator_name) {\r
+    mem_free(sc->sc_concentrator_name);\r
+  }\r
+  if (sc->sc_service_name) {\r
+    mem_free(sc->sc_service_name);\r
+  }\r
+  if (sc->sc_ac_cookie) {\r
+    mem_free(sc->sc_ac_cookie);\r
+  }\r
+  mem_free(sc);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/*\r
+ * Find the interface handling the specified session.\r
+ * Note: O(number of sessions open), this is a client-side only, mean\r
+ * and lean implementation, so number of open sessions typically should\r
+ * be 1.\r
+ */\r
+static struct pppoe_softc *\r
+pppoe_find_softc_by_session(u_int session, struct netif *rcvif)\r
+{\r
+  struct pppoe_softc *sc;\r
+\r
+  if (session == 0) {\r
+    return NULL;\r
+  }\r
+\r
+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {\r
+    if (sc->sc_state == PPPOE_STATE_SESSION\r
+        && sc->sc_session == session) {\r
+      if (sc->sc_ethif == rcvif) {\r
+        return sc;\r
+      } else {\r
+        return NULL;\r
+      }\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+/* Check host unique token passed and return appropriate softc pointer,\r
+ * or NULL if token is bogus. */\r
+static struct pppoe_softc *\r
+pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif)\r
+{\r
+  struct pppoe_softc *sc, *t;\r
+\r
+  if (LIST_EMPTY(&pppoe_softc_list)) {\r
+    return NULL;\r
+  }\r
+\r
+  if (len != sizeof sc) {\r
+    return NULL;\r
+  }\r
+  MEMCPY(&t, token, len);\r
+\r
+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {\r
+    if (sc == t) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (sc == NULL) {\r
+    PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n"));\r
+    return NULL;\r
+  }\r
+\r
+  /* should be safe to access *sc now */\r
+  if (sc->sc_state < PPPOE_STATE_PADI_SENT || sc->sc_state >= PPPOE_STATE_SESSION) {\r
+    printf("%c%c%"U16_F": host unique tag found, but it belongs to a connection in state %d\n",\r
+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_state);\r
+    return NULL;\r
+  }\r
+  if (sc->sc_ethif != rcvif) {\r
+    printf("%c%c%"U16_F": wrong interface, not accepting host unique\n",\r
+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+    return NULL;\r
+  }\r
+  return sc;\r
+}\r
+\r
+static void\r
+pppoe_linkstatus_up(void *arg)\r
+{\r
+  struct pppoe_softc *sc = (struct pppoe_softc*)arg;\r
+\r
+  sc->sc_linkStatusCB(sc->sc_pd, 1);\r
+}\r
+\r
+/* analyze and handle a single received packet while not in session state */\r
+static void\r
+pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb)\r
+{\r
+  u16_t tag, len;\r
+  u16_t session, plen;\r
+  struct pppoe_softc *sc;\r
+  const char *err_msg;\r
+  char devname[6];\r
+  char *error;\r
+  u8_t *ac_cookie;\r
+  size_t ac_cookie_len;\r
+#ifdef PPPOE_SERVER\r
+  u8_t *hunique;\r
+  size_t hunique_len;\r
+#endif\r
+  struct pppoehdr *ph;\r
+  struct pppoetag pt;\r
+  int off = 0, err, errortag;\r
+  struct eth_hdr *ethhdr;\r
+\r
+  pb = pppSingleBuf(pb);\r
+\r
+  strcpy(devname, "pppoe");  /* as long as we don't know which instance */\r
+  err_msg = NULL;\r
+  errortag = 0;\r
+  if (pb->len < sizeof(*ethhdr)) {\r
+    goto done;\r
+  }\r
+  ethhdr = (struct eth_hdr *)pb->payload;\r
+  off += sizeof(*ethhdr);\r
+\r
+  ac_cookie = NULL;\r
+  ac_cookie_len = 0;\r
+#ifdef PPPOE_SERVER\r
+  hunique = NULL;\r
+  hunique_len = 0;\r
+#endif\r
+  session = 0;\r
+  if (pb->len - off <= PPPOE_HEADERLEN) {\r
+    printf("pppoe: packet too short: %d\n", pb->len);\r
+    goto done;\r
+  }\r
+\r
+  ph = (struct pppoehdr *) (ethhdr + 1);\r
+  if (ph->vertype != PPPOE_VERTYPE) {\r
+    printf("pppoe: unknown version/type packet: 0x%x\n", ph->vertype);\r
+    goto done;\r
+  }\r
+  session = ntohs(ph->session);\r
+  plen = ntohs(ph->plen);\r
+  off += sizeof(*ph);\r
+\r
+  if (plen + off > pb->len) {\r
+    printf("pppoe: packet content does not fit: data available = %d, packet size = %u\n",\r
+        pb->len - off, plen);\r
+    goto done;\r
+  }\r
+  if(pb->tot_len == pb->len) {\r
+    pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */\r
+  }\r
+  tag = 0;\r
+  len = 0;\r
+  sc = NULL;\r
+  while (off + sizeof(pt) <= pb->len) {\r
+    MEMCPY(&pt, (u8_t*)pb->payload + off, sizeof(pt));\r
+    tag = ntohs(pt.tag);\r
+    len = ntohs(pt.len);\r
+    if (off + sizeof(pt) + len > pb->len) {\r
+      printf("pppoe: tag 0x%x len 0x%x is too long\n", tag, len);\r
+      goto done;\r
+    }\r
+    switch (tag) {\r
+      case PPPOE_TAG_EOL:\r
+        goto breakbreak;\r
+      case PPPOE_TAG_SNAME:\r
+        break;  /* ignored */\r
+      case PPPOE_TAG_ACNAME:\r
+        break;  /* ignored */\r
+      case PPPOE_TAG_HUNIQUE:\r
+        if (sc != NULL) {\r
+          break;\r
+        }\r
+#ifdef PPPOE_SERVER\r
+        hunique = (u8_t*)pb->payload + off + sizeof(pt);\r
+        hunique_len = len;\r
+#endif\r
+        sc = pppoe_find_softc_by_hunique((u8_t*)pb->payload + off + sizeof(pt), len, netif);\r
+        if (sc != NULL) {\r
+          snprintf(devname, sizeof(devname), "%c%c%"U16_F, sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+        }\r
+        break;\r
+      case PPPOE_TAG_ACCOOKIE:\r
+        if (ac_cookie == NULL) {\r
+          ac_cookie = (u8_t*)pb->payload + off + sizeof(pt);\r
+          ac_cookie_len = len;\r
+        }\r
+        break;\r
+      case PPPOE_TAG_SNAME_ERR:\r
+        err_msg = "SERVICE NAME ERROR";\r
+        errortag = 1;\r
+        break;\r
+      case PPPOE_TAG_ACSYS_ERR:\r
+        err_msg = "AC SYSTEM ERROR";\r
+        errortag = 1;\r
+        break;\r
+      case PPPOE_TAG_GENERIC_ERR:\r
+        err_msg = "GENERIC ERROR";\r
+        errortag = 1;\r
+        break;\r
+    }\r
+    if (err_msg) {\r
+      error = NULL;\r
+      if (errortag && len) {\r
+        error = mem_malloc(len+1);\r
+        if (error) {\r
+          strncpy(error, (char*)pb->payload + off + sizeof(pt), len);\r
+          error[len-1] = '\0';\r
+        }\r
+      }\r
+      if (error) {\r
+        printf("%s: %s: %s\n", devname, err_msg, error);\r
+        mem_free(error);\r
+      } else {\r
+        printf("%s: %s\n", devname, err_msg);\r
+      }\r
+      if (errortag) {\r
+        goto done;\r
+      }\r
+    }\r
+    off += sizeof(pt) + len;\r
+  }\r
+\r
+breakbreak:;\r
+  switch (ph->code) {\r
+    case PPPOE_CODE_PADI:\r
+#ifdef PPPOE_SERVER\r
+      /*\r
+       * got service name, concentrator name, and/or host unique.\r
+       * ignore if we have no interfaces with IFF_PASSIVE|IFF_UP.\r
+       */\r
+      if (LIST_EMPTY(&pppoe_softc_list)) {\r
+        goto done;\r
+      }\r
+      LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {\r
+        if (!(sc->sc_sppp.pp_if.if_flags & IFF_UP)) {\r
+          continue;\r
+        }\r
+        if (!(sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {\r
+          continue;\r
+        }\r
+        if (sc->sc_state == PPPOE_STATE_INITIAL) {\r
+          break;\r
+        }\r
+      }\r
+      if (sc == NULL) {\r
+        /* printf("pppoe: free passive interface is not found\n"); */\r
+        goto done;\r
+      }\r
+      if (hunique) {\r
+        if (sc->sc_hunique) {\r
+          mem_free(sc->sc_hunique);\r
+        }\r
+        sc->sc_hunique = mem_malloc(hunique_len);\r
+        if (sc->sc_hunique == NULL) {\r
+          goto done;\r
+        }\r
+        sc->sc_hunique_len = hunique_len;\r
+        MEMCPY(sc->sc_hunique, hunique, hunique_len);\r
+      }\r
+      MEMCPY(&sc->sc_dest, eh->ether_shost, sizeof sc->sc_dest);\r
+      sc->sc_state = PPPOE_STATE_PADO_SENT;\r
+      pppoe_send_pado(sc);\r
+      break;\r
+  #endif /* PPPOE_SERVER */\r
+    case PPPOE_CODE_PADR:\r
+  #ifdef PPPOE_SERVER\r
+      /*\r
+       * get sc from ac_cookie if IFF_PASSIVE\r
+       */\r
+      if (ac_cookie == NULL) {\r
+        /* be quiet if there is not a single pppoe instance */\r
+        printf("pppoe: received PADR but not includes ac_cookie\n");\r
+        goto done;\r
+      }\r
+      sc = pppoe_find_softc_by_hunique(ac_cookie, ac_cookie_len, netif);\r
+      if (sc == NULL) {\r
+        /* be quiet if there is not a single pppoe instance */\r
+        if (!LIST_EMPTY(&pppoe_softc_list)) {\r
+          printf("pppoe: received PADR but could not find request for it\n");\r
+        }\r
+        goto done;\r
+      }\r
+      if (sc->sc_state != PPPOE_STATE_PADO_SENT) {\r
+        printf("%c%c%"U16_F": received unexpected PADR\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+        goto done;\r
+      }\r
+      if (hunique) {\r
+        if (sc->sc_hunique) {\r
+          mem_free(sc->sc_hunique);\r
+        }\r
+        sc->sc_hunique = mem_malloc(hunique_len);\r
+        if (sc->sc_hunique == NULL) {\r
+          goto done;\r
+        }\r
+        sc->sc_hunique_len = hunique_len;\r
+        MEMCPY(sc->sc_hunique, hunique, hunique_len);\r
+      }\r
+      pppoe_send_pads(sc);\r
+      sc->sc_state = PPPOE_STATE_SESSION;\r
+      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */\r
+      break;\r
+  #else\r
+      /* ignore, we are no access concentrator */\r
+      goto done;\r
+  #endif /* PPPOE_SERVER */\r
+    case PPPOE_CODE_PADO:\r
+      if (sc == NULL) {\r
+        /* be quiet if there is not a single pppoe instance */\r
+        if (!LIST_EMPTY(&pppoe_softc_list)) {\r
+          printf("pppoe: received PADO but could not find request for it\n");\r
+        }\r
+        goto done;\r
+      }\r
+      if (sc->sc_state != PPPOE_STATE_PADI_SENT) {\r
+        printf("%c%c%"U16_F": received unexpected PADO\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+        goto done;\r
+      }\r
+      if (ac_cookie) {\r
+        if (sc->sc_ac_cookie) {\r
+          mem_free(sc->sc_ac_cookie);\r
+        }\r
+        sc->sc_ac_cookie = mem_malloc(ac_cookie_len);\r
+        if (sc->sc_ac_cookie == NULL) {\r
+          goto done;\r
+        }\r
+        sc->sc_ac_cookie_len = ac_cookie_len;\r
+        MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len);\r
+      }\r
+      MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr));\r
+      tcpip_untimeout(pppoe_timeout, sc);\r
+      sc->sc_padr_retried = 0;\r
+      sc->sc_state = PPPOE_STATE_PADR_SENT;\r
+      if ((err = pppoe_send_padr(sc)) != 0) {\r
+        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));\r
+      }\r
+      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);\r
+      break;\r
+    case PPPOE_CODE_PADS:\r
+      if (sc == NULL) {\r
+        goto done;\r
+      }\r
+      sc->sc_session = session;\r
+      tcpip_untimeout(pppoe_timeout, sc);\r
+      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));\r
+      sc->sc_state = PPPOE_STATE_SESSION;\r
+      tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */\r
+      break;\r
+    case PPPOE_CODE_PADT:\r
+      if (sc == NULL) {\r
+        goto done;\r
+      }\r
+      pppoe_clear_softc(sc, "received PADT");\r
+      break;\r
+    default:\r
+      if(sc) {\r
+        printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n",\r
+            sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,\r
+            ph->code, session);\r
+      } else {\r
+        printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session);\r
+      }\r
+      break;\r
+  }\r
+\r
+done:\r
+  pbuf_free(pb);\r
+  return;\r
+}\r
+\r
+void\r
+pppoe_disc_input(struct netif *netif, struct pbuf *p)\r
+{\r
+  /* avoid error messages if there is not a single pppoe instance */\r
+  if (!LIST_EMPTY(&pppoe_softc_list)) {\r
+    pppoe_dispatch_disc_pkt(netif, p);\r
+  } else {\r
+    pbuf_free(p);\r
+  }\r
+}\r
+\r
+void\r
+pppoe_data_input(struct netif *netif, struct pbuf *pb)\r
+{\r
+  u16_t session, plen;\r
+  struct pppoe_softc *sc;\r
+  struct pppoehdr *ph;\r
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS\r
+  u8_t shost[ETHER_ADDR_LEN];\r
+#endif\r
+\r
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS\r
+  MEMCPY(shost, ((struct eth_hdr *)pb->payload)->src.addr, sizeof(shost));\r
+#endif\r
+  if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) {\r
+    /* bail out */\r
+    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n"));\r
+    LINK_STATS_INC(link.lenerr);\r
+    goto drop;\r
+  } \r
+\r
+  pb = pppSingleBuf (pb);\r
+\r
+  if (pb->len <= PPPOE_HEADERLEN) {\r
+    printf("pppoe (data): dropping too short packet: %d bytes\n", pb->len);\r
+    goto drop;\r
+  }\r
+\r
+  if (pb->len < sizeof(*ph)) {\r
+    printf("pppoe_data_input: could not get PPPoE header\n");\r
+    goto drop;\r
+  }\r
+  ph = (struct pppoehdr *)pb->payload;\r
+\r
+  if (ph->vertype != PPPOE_VERTYPE) {\r
+    printf("pppoe (data): unknown version/type packet: 0x%x\n", ph->vertype);\r
+    goto drop;\r
+  }\r
+  if (ph->code != 0) {\r
+    goto drop;\r
+  }\r
+\r
+  session = ntohs(ph->session);\r
+  sc = pppoe_find_softc_by_session(session, netif);\r
+  if (sc == NULL) {\r
+#ifdef PPPOE_TERM_UNKNOWN_SESSIONS\r
+    printf("pppoe: input for unknown session 0x%x, sending PADT\n", session);\r
+    pppoe_send_padt(netif, session, shost);\r
+#endif\r
+    goto drop;\r
+  }\r
+\r
+  plen = ntohs(ph->plen);\r
+\r
+  if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) {\r
+    /* bail out */\r
+    PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n"));\r
+    LINK_STATS_INC(link.lenerr);\r
+    goto drop;\r
+  } \r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n",\r
+        sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num,\r
+        pb->len, plen));\r
+\r
+  if (pb->len < plen) {\r
+    goto drop;\r
+  }\r
+\r
+  pppInProcOverEthernet(sc->sc_pd, pb);\r
+\r
+  return;\r
+\r
+drop:\r
+  pbuf_free(pb);\r
+}\r
+\r
+static err_t\r
+pppoe_output(struct pppoe_softc *sc, struct pbuf *pb)\r
+{\r
+  struct eth_hdr *ethhdr;\r
+  u16_t etype;\r
+  err_t res;\r
+\r
+  if (!sc->sc_ethif) {\r
+    pbuf_free(pb);\r
+    return ERR_IF;\r
+  }\r
+\r
+  ethhdr = (struct eth_hdr *)pb->payload;\r
+  etype = sc->sc_state == PPPOE_STATE_SESSION ? ETHTYPE_PPPOE : ETHTYPE_PPPOEDISC;\r
+  ethhdr->type = htons(etype);\r
+  MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr));\r
+  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr));\r
+\r
+  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",\r
+      sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype,\r
+      sc->sc_state, sc->sc_session,\r
+      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],\r
+      pb->tot_len));\r
+\r
+  res = sc->sc_ethif->linkoutput(sc->sc_ethif, pb);\r
+\r
+  pbuf_free(pb);\r
+\r
+  return res;\r
+}\r
+\r
+static err_t\r
+pppoe_send_padi(struct pppoe_softc *sc)\r
+{\r
+  struct pbuf *pb;\r
+  u8_t *p;\r
+  int len, l1 = 0, l2 = 0; /* XXX: gcc */\r
+\r
+  if (sc->sc_state >PPPOE_STATE_PADI_SENT) {\r
+    PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state));\r
+  }\r
+\r
+  /* calculate length of frame (excluding ethernet header + pppoe header) */\r
+  len = 2 + 2 + 2 + 2 + sizeof sc;  /* service name tag is required, host unique is send too */\r
+  if (sc->sc_service_name != NULL) {\r
+    l1 = strlen(sc->sc_service_name);\r
+    len += l1;\r
+  }\r
+  if (sc->sc_concentrator_name != NULL) {\r
+    l2 = strlen(sc->sc_concentrator_name);\r
+    len += 2 + 2 + l2;\r
+  }\r
+\r
+  /* allocate a buffer */\r
+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);\r
+  if (!pb) {\r
+    return ERR_MEM;\r
+  }\r
+\r
+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);\r
+  /* fill in pkt */\r
+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len);\r
+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);\r
+  if (sc->sc_service_name != NULL) {\r
+    PPPOE_ADD_16(p, l1);\r
+    MEMCPY(p, sc->sc_service_name, l1);\r
+    p += l1;\r
+  } else {\r
+    PPPOE_ADD_16(p, 0);\r
+  }\r
+  if (sc->sc_concentrator_name != NULL) {\r
+    PPPOE_ADD_16(p, PPPOE_TAG_ACNAME);\r
+    PPPOE_ADD_16(p, l2);\r
+    MEMCPY(p, sc->sc_concentrator_name, l2);\r
+    p += l2;\r
+  }\r
+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);\r
+  PPPOE_ADD_16(p, sizeof(sc));\r
+  MEMCPY(p, &sc, sizeof sc);\r
+\r
+  /* send pkt */\r
+  return pppoe_output(sc, pb);\r
+}\r
+\r
+static void\r
+pppoe_timeout(void *arg)\r
+{\r
+  int retry_wait, err;\r
+  struct pppoe_softc *sc = (struct pppoe_softc*)arg;\r
+\r
+  PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));\r
+\r
+  switch (sc->sc_state) {\r
+    case PPPOE_STATE_PADI_SENT:\r
+      /*\r
+       * We have two basic ways of retrying:\r
+       *  - Quick retry mode: try a few times in short sequence\r
+       *  - Slow retry mode: we already had a connection successfully\r
+       *    established and will try infinitely (without user\r
+       *    intervention)\r
+       * We only enter slow retry mode if IFF_LINK1 (aka autodial)\r
+       * is not set.\r
+       */\r
+\r
+      /* initialize for quick retry mode */\r
+      retry_wait = PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried);\r
+\r
+      sc->sc_padi_retried++;\r
+      if (sc->sc_padi_retried >= PPPOE_DISC_MAXPADI) {\r
+#if 0\r
+        if ((sc->sc_sppp.pp_if.if_flags & IFF_LINK1) == 0) {\r
+          /* slow retry mode */\r
+          retry_wait = PPPOE_SLOW_RETRY;\r
+        } else\r
+#endif\r
+        {\r
+          pppoe_abort_connect(sc);\r
+          return;\r
+        }\r
+      }\r
+      if ((err = pppoe_send_padi(sc)) != 0) {\r
+        sc->sc_padi_retried--;\r
+        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));\r
+      }\r
+      tcpip_timeout(retry_wait, pppoe_timeout, sc);\r
+      break;\r
+\r
+    case PPPOE_STATE_PADR_SENT:\r
+      sc->sc_padr_retried++;\r
+      if (sc->sc_padr_retried >= PPPOE_DISC_MAXPADR) {\r
+        MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));\r
+        sc->sc_state = PPPOE_STATE_PADI_SENT;\r
+        sc->sc_padr_retried = 0;\r
+        if ((err = pppoe_send_padi(sc)) != 0) {\r
+          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));\r
+        }\r
+        tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc);\r
+        return;\r
+      }\r
+      if ((err = pppoe_send_padr(sc)) != 0) {\r
+        sc->sc_padr_retried--;\r
+        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));\r
+      }\r
+      tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc);\r
+      break;\r
+    case PPPOE_STATE_CLOSING:\r
+      pppoe_do_disconnect(sc);\r
+      break;\r
+    default:\r
+      return;  /* all done, work in peace */\r
+  }\r
+}\r
+\r
+/* Start a connection (i.e. initiate discovery phase) */\r
+int\r
+pppoe_connect(struct pppoe_softc *sc)\r
+{\r
+  int err;\r
+\r
+  if (sc->sc_state != PPPOE_STATE_INITIAL) {\r
+    return EBUSY;\r
+  }\r
+\r
+#ifdef PPPOE_SERVER\r
+  /* wait PADI if IFF_PASSIVE */\r
+  if ((sc->sc_sppp.pp_if.if_flags & IFF_PASSIVE)) {\r
+    return 0;\r
+  }\r
+#endif\r
+  /* save state, in case we fail to send PADI */\r
+  sc->sc_state = PPPOE_STATE_PADI_SENT;\r
+  sc->sc_padr_retried = 0;\r
+  err = pppoe_send_padi(sc);\r
+  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));\r
+  tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc);\r
+  return err;\r
+}\r
+\r
+/* disconnect */\r
+void\r
+pppoe_disconnect(struct pppoe_softc *sc)\r
+{\r
+  if (sc->sc_state < PPPOE_STATE_SESSION) {\r
+    return;\r
+  }\r
+  /*\r
+   * Do not call pppoe_disconnect here, the upper layer state\r
+   * machine gets confused by this. We must return from this\r
+   * function and defer disconnecting to the timeout handler.\r
+   */\r
+  sc->sc_state = PPPOE_STATE_CLOSING;\r
+  tcpip_timeout(20, pppoe_timeout, sc);\r
+}\r
+\r
+static int\r
+pppoe_do_disconnect(struct pppoe_softc *sc)\r
+{\r
+  int err;\r
+\r
+  if (sc->sc_state < PPPOE_STATE_SESSION) {\r
+    err = EBUSY;\r
+  } else {\r
+    PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num));\r
+    err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest);\r
+  }\r
+\r
+  /* cleanup softc */\r
+  sc->sc_state = PPPOE_STATE_INITIAL;\r
+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));\r
+  if (sc->sc_ac_cookie) {\r
+    mem_free(sc->sc_ac_cookie);\r
+    sc->sc_ac_cookie = NULL;\r
+  }\r
+  sc->sc_ac_cookie_len = 0;\r
+#ifdef PPPOE_SERVER\r
+  if (sc->sc_hunique) {\r
+    mem_free(sc->sc_hunique);\r
+    sc->sc_hunique = NULL;\r
+  }\r
+  sc->sc_hunique_len = 0;\r
+#endif\r
+  sc->sc_session = 0;\r
+\r
+  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */\r
+\r
+  return err;\r
+}\r
+\r
+/* Connection attempt aborted */\r
+static void\r
+pppoe_abort_connect(struct pppoe_softc *sc)\r
+{\r
+  printf("%c%c%"U16_F": could not establish connection\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+  sc->sc_state = PPPOE_STATE_CLOSING;\r
+\r
+  sc->sc_linkStatusCB(sc->sc_pd, 0); /* notify upper layers */\r
+\r
+  /* clear connection state */\r
+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));\r
+  sc->sc_state = PPPOE_STATE_INITIAL;\r
+}\r
+\r
+/* Send a PADR packet */\r
+static err_t\r
+pppoe_send_padr(struct pppoe_softc *sc)\r
+{\r
+  struct pbuf *pb;\r
+  u8_t *p;\r
+  size_t len, l1 = 0; /* XXX: gcc */\r
+\r
+  if (sc->sc_state != PPPOE_STATE_PADR_SENT) {\r
+    return ERR_CONN;\r
+  }\r
+\r
+  len = 2 + 2 + 2 + 2 + sizeof(sc);    /* service name, host unique */\r
+  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */\r
+    l1 = strlen(sc->sc_service_name);\r
+    len += l1;\r
+  }\r
+  if (sc->sc_ac_cookie_len > 0) {\r
+    len += 2 + 2 + sc->sc_ac_cookie_len;  /* AC cookie */\r
+  }\r
+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);\r
+  if (!pb) {\r
+    return ERR_MEM;\r
+  }\r
+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);\r
+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len);\r
+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);\r
+  if (sc->sc_service_name != NULL) {\r
+    PPPOE_ADD_16(p, l1);\r
+    MEMCPY(p, sc->sc_service_name, l1);\r
+    p += l1;\r
+  } else {\r
+    PPPOE_ADD_16(p, 0);\r
+  }\r
+  if (sc->sc_ac_cookie_len > 0) {\r
+    PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);\r
+    PPPOE_ADD_16(p, sc->sc_ac_cookie_len);\r
+    MEMCPY(p, sc->sc_ac_cookie, sc->sc_ac_cookie_len);\r
+    p += sc->sc_ac_cookie_len;\r
+  }\r
+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);\r
+  PPPOE_ADD_16(p, sizeof(sc));\r
+  MEMCPY(p, &sc, sizeof sc);\r
+\r
+  return pppoe_output(sc, pb);\r
+}\r
+\r
+/* send a PADT packet */\r
+static err_t\r
+pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest)\r
+{\r
+  struct pbuf *pb;\r
+  struct eth_hdr *ethhdr;\r
+  err_t res;\r
+  u8_t *p;\r
+\r
+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN, PBUF_RAM);\r
+  if (!pb) {\r
+    return ERR_MEM;\r
+  }\r
+\r
+  ethhdr = (struct eth_hdr *)pb->payload;\r
+  ethhdr->type = htons(ETHTYPE_PPPOEDISC);\r
+  MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr));\r
+  MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr));\r
+\r
+  p = (u8_t*)(ethhdr + 1);\r
+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADT, session, 0);\r
+\r
+  res = outgoing_if->linkoutput(outgoing_if, pb);\r
+\r
+  pbuf_free(pb);\r
+\r
+  return res;\r
+}\r
+\r
+#ifdef PPPOE_SERVER\r
+static err_t\r
+pppoe_send_pado(struct pppoe_softc *sc)\r
+{\r
+  struct pbuf *pb;\r
+  u8_t *p;\r
+  size_t len;\r
+\r
+  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {\r
+    return ERR_CONN;\r
+  }\r
+\r
+  /* calc length */\r
+  len = 0;\r
+  /* include ac_cookie */\r
+  len += 2 + 2 + sizeof(sc);\r
+  /* include hunique */\r
+  len += 2 + 2 + sc->sc_hunique_len;\r
+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);\r
+  if (!pb) {\r
+    return ERR_MEM;\r
+  }\r
+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);\r
+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len);\r
+  PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE);\r
+  PPPOE_ADD_16(p, sizeof(sc));\r
+  MEMCPY(p, &sc, sizeof(sc));\r
+  p += sizeof(sc);\r
+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);\r
+  PPPOE_ADD_16(p, sc->sc_hunique_len);\r
+  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);\r
+  return pppoe_output(sc, pb);\r
+}\r
+\r
+static err_t\r
+pppoe_send_pads(struct pppoe_softc *sc)\r
+{\r
+  struct pbuf *pb;\r
+  u8_t *p;\r
+  size_t len, l1 = 0;  /* XXX: gcc */\r
+\r
+  if (sc->sc_state != PPPOE_STATE_PADO_SENT) {\r
+    return ERR_CONN;\r
+  }\r
+\r
+  sc->sc_session = mono_time.tv_sec % 0xff + 1;\r
+  /* calc length */\r
+  len = 0;\r
+  /* include hunique */\r
+  len += 2 + 2 + 2 + 2 + sc->sc_hunique_len;  /* service name, host unique*/\r
+  if (sc->sc_service_name != NULL) {    /* service name tag maybe empty */\r
+    l1 = strlen(sc->sc_service_name);\r
+    len += l1;\r
+  }\r
+  pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM);\r
+  if (!pb) {\r
+    return ERR_MEM;\r
+  }\r
+  p = (u8_t*)pb->payload + sizeof (struct eth_hdr);\r
+  PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len);\r
+  PPPOE_ADD_16(p, PPPOE_TAG_SNAME);\r
+  if (sc->sc_service_name != NULL) {\r
+    PPPOE_ADD_16(p, l1);\r
+    MEMCPY(p, sc->sc_service_name, l1);\r
+    p += l1;\r
+  } else {\r
+    PPPOE_ADD_16(p, 0);\r
+  }\r
+  PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE);\r
+  PPPOE_ADD_16(p, sc->sc_hunique_len);\r
+  MEMCPY(p, sc->sc_hunique, sc->sc_hunique_len);\r
+  return pppoe_output(sc, pb);\r
+}\r
+#endif\r
+\r
+err_t\r
+pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb)\r
+{\r
+  u8_t *p;\r
+  size_t len;\r
+\r
+  /* are we ready to process data yet? */\r
+  if (sc->sc_state < PPPOE_STATE_SESSION) {\r
+    /*sppp_flush(&sc->sc_sppp.pp_if);*/\r
+    pbuf_free(pb);\r
+    return ERR_CONN;\r
+  }\r
+\r
+  len = pb->tot_len;\r
+\r
+  /* make room for Ethernet header - should not fail */\r
+  if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) {\r
+    /* bail out */\r
+    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));\r
+    LINK_STATS_INC(link.lenerr);\r
+    pbuf_free(pb);\r
+    return ERR_BUF;\r
+  } \r
+\r
+  p = (u8_t*)pb->payload + sizeof(struct eth_hdr);\r
+  PPPOE_ADD_HEADER(p, 0, sc->sc_session, len);\r
+\r
+  return pppoe_output(sc, pb);\r
+}\r
+\r
+#if 0 /*def PFIL_HOOKS*/\r
+static int\r
+pppoe_ifattach_hook(void *arg, struct pbuf **mp, struct netif *ifp, int dir)\r
+{\r
+  struct pppoe_softc *sc;\r
+  int s;\r
+\r
+  if (mp != (struct pbuf **)PFIL_IFNET_DETACH) {\r
+    return 0;\r
+  }\r
+\r
+  LIST_FOREACH(sc, &pppoe_softc_list, sc_list) {\r
+    if (sc->sc_ethif != ifp) {\r
+      continue;\r
+    }\r
+    if (sc->sc_sppp.pp_if.if_flags & IFF_UP) {\r
+      sc->sc_sppp.pp_if.if_flags &= ~(IFF_UP|IFF_RUNNING);\r
+      printf("%c%c%"U16_F": ethernet interface detached, going down\n",\r
+          sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num);\r
+    }\r
+    sc->sc_ethif = NULL;\r
+    pppoe_clear_softc(sc, "ethernet interface detached");\r
+  }\r
+\r
+  return 0;\r
+}\r
+#endif\r
+\r
+static void\r
+pppoe_clear_softc(struct pppoe_softc *sc, const char *message)\r
+{\r
+  LWIP_UNUSED_ARG(message);\r
+\r
+  /* stop timer */\r
+  tcpip_untimeout(pppoe_timeout, sc);\r
+  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));\r
+\r
+  /* fix our state */\r
+  sc->sc_state = PPPOE_STATE_INITIAL;\r
+\r
+  /* notify upper layers */\r
+  sc->sc_linkStatusCB(sc->sc_pd, 0);\r
+\r
+  /* clean up softc */\r
+  MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest));\r
+  if (sc->sc_ac_cookie) {\r
+    mem_free(sc->sc_ac_cookie);\r
+    sc->sc_ac_cookie = NULL;\r
+  }\r
+  sc->sc_ac_cookie_len = 0;\r
+  sc->sc_session = 0;\r
+}\r
+\r
+#endif /* PPPOE_SUPPORT */\r
+\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/pppdebug.h
new file mode 100644 (file)
index 0000000..77b8d1f
--- /dev/null
@@ -0,0 +1,86 @@
+/*****************************************************************************\r
+* pppdebug.h - System debugging utilities.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* portions Copyright (c) 1998 Global Election Systems Inc.\r
+* portions Copyright (c) 2001 by Cognizant Pty Ltd.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY (please don't use tabs!)\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-07-29 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Original.\r
+*\r
+*****************************************************************************\r
+*/\r
+#ifndef PPPDEBUG_H\r
+#define PPPDEBUG_H\r
+\r
+/************************\r
+*** PUBLIC DATA TYPES ***\r
+************************/\r
+/* Trace levels. */\r
+typedef enum {\r
+LOG_CRITICAL = 0,\r
+LOG_ERR      = 1,\r
+LOG_NOTICE   = 2,\r
+LOG_WARNING  = 3,\r
+LOG_INFO     = 5,\r
+LOG_DETAIL   = 6,\r
+LOG_DEBUG    = 7\r
+} LogCodes;\r
+\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+/*\r
+ * ppp_trace - a form of printf to send tracing information to stderr\r
+ */\r
+void ppp_trace(int level, const char *format,...);\r
+\r
+#define TRACELCP PPP_DEBUG\r
+\r
+#if PPP_DEBUG\r
+\r
+#define AUTHDEBUG(a) ppp_trace a\r
+#define IPCPDEBUG(a) ppp_trace a\r
+#define UPAPDEBUG(a) ppp_trace a\r
+#define LCPDEBUG(a)  ppp_trace a\r
+#define FSMDEBUG(a)  ppp_trace a\r
+#define CHAPDEBUG(a) ppp_trace a\r
+#define PPPDEBUG(a)  ppp_trace a\r
+\r
+#else /* PPP_DEBUG */\r
+\r
+#define AUTHDEBUG(a)\r
+#define IPCPDEBUG(a)\r
+#define UPAPDEBUG(a)\r
+#define LCPDEBUG(a)\r
+#define FSMDEBUG(a)\r
+#define CHAPDEBUG(a)\r
+#define PPPDEBUG(a)\r
+\r
+#endif /* PPP_DEBUG */\r
+\r
+#endif /* PPPDEBUG_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.c
new file mode 100644 (file)
index 0000000..b6c974c
--- /dev/null
@@ -0,0 +1,248 @@
+/*****************************************************************************\r
+* randm.c - Random number generator program file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1998 by Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-06-03 Guy Lancaster <lancasterg@acm.org>, Global Election Systems Inc.\r
+*   Extracted from avos.\r
+*****************************************************************************/\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "md5.h"\r
+#include "randm.h"\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+\r
+#if MD5_SUPPORT /* this module depends on MD5 */\r
+#define RANDPOOLSZ 16   /* Bytes stored in the pool of randomness. */\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static char randPool[RANDPOOLSZ];   /* Pool of randomness. */\r
+static long randCount = 0;      /* Pseudo-random incrementer */\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * Initialize the random number generator.\r
+ *\r
+ * Since this is to be called on power up, we don't have much\r
+ *  system randomess to work with.  Here all we use is the\r
+ *  real-time clock.  We'll accumulate more randomness as soon\r
+ *  as things start happening.\r
+ */\r
+void\r
+avRandomInit()\r
+{\r
+  avChurnRand(NULL, 0);\r
+}\r
+\r
+/*\r
+ * Churn the randomness pool on a random event.  Call this early and often\r
+ *  on random and semi-random system events to build randomness in time for\r
+ *  usage.  For randomly timed events, pass a null pointer and a zero length\r
+ *  and this will use the system timer and other sources to add randomness.\r
+ *  If new random data is available, pass a pointer to that and it will be\r
+ *  included.\r
+ *\r
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427\r
+ */\r
+void\r
+avChurnRand(char *randData, u32_t randLen)\r
+{\r
+  MD5_CTX md5;\r
+\r
+  /* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */\r
+  MD5Init(&md5);\r
+  MD5Update(&md5, (u_char *)randPool, sizeof(randPool));\r
+  if (randData) {\r
+    MD5Update(&md5, (u_char *)randData, randLen);\r
+  } else {\r
+    struct {\r
+      /* INCLUDE fields for any system sources of randomness */\r
+      char foobar;\r
+    } sysData;\r
+\r
+    /* Load sysData fields here. */\r
+    MD5Update(&md5, (u_char *)&sysData, sizeof(sysData));\r
+  }\r
+  MD5Final((u_char *)randPool, &md5);\r
+/*  ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */\r
+}\r
+\r
+/*\r
+ * Use the random pool to generate random data.  This degrades to pseudo\r
+ *  random when used faster than randomness is supplied using churnRand().\r
+ * Note: It's important that there be sufficient randomness in randPool\r
+ *  before this is called for otherwise the range of the result may be\r
+ *  narrow enough to make a search feasible.\r
+ *\r
+ * Ref: Applied Cryptography 2nd Ed. by Bruce Schneier p. 427\r
+ *\r
+ * XXX Why does he not just call churnRand() for each block?  Probably\r
+ *  so that you don't ever publish the seed which could possibly help\r
+ *  predict future values.\r
+ * XXX Why don't we preserve md5 between blocks and just update it with\r
+ *  randCount each time?  Probably there is a weakness but I wish that\r
+ *  it was documented.\r
+ */\r
+void\r
+avGenRand(char *buf, u32_t bufLen)\r
+{\r
+  MD5_CTX md5;\r
+  u_char tmp[16];\r
+  u32_t n;\r
+\r
+  while (bufLen > 0) {\r
+    n = LWIP_MIN(bufLen, RANDPOOLSZ);\r
+    MD5Init(&md5);\r
+    MD5Update(&md5, (u_char *)randPool, sizeof(randPool));\r
+    MD5Update(&md5, (u_char *)&randCount, sizeof(randCount));\r
+    MD5Final(tmp, &md5);\r
+    randCount++;\r
+    MEMCPY(buf, tmp, n);\r
+    buf += n;\r
+    bufLen -= n;\r
+  }\r
+}\r
+\r
+/*\r
+ * Return a new random number.\r
+ */\r
+u32_t\r
+avRandom()\r
+{\r
+  u32_t newRand;\r
+\r
+  avGenRand((char *)&newRand, sizeof(newRand));\r
+\r
+  return newRand;\r
+}\r
+\r
+#else /* MD5_SUPPORT */\r
+\r
+/*****************************/\r
+/*** LOCAL DATA STRUCTURES ***/\r
+/*****************************/\r
+static int  avRandomized = 0;       /* Set when truely randomized. */\r
+static u32_t avRandomSeed = 0;      /* Seed used for random number generation. */\r
+\r
+\r
+/***********************************/\r
+/*** PUBLIC FUNCTION DEFINITIONS ***/\r
+/***********************************/\r
+/*\r
+ * Initialize the random number generator.\r
+ *\r
+ * Here we attempt to compute a random number seed but even if\r
+ * it isn't random, we'll randomize it later.\r
+ *\r
+ * The current method uses the fields from the real time clock,\r
+ * the idle process counter, the millisecond counter, and the\r
+ * hardware timer tick counter.  When this is invoked\r
+ * in startup(), then the idle counter and timer values may\r
+ * repeat after each boot and the real time clock may not be\r
+ * operational.  Thus we call it again on the first random\r
+ * event.\r
+ */\r
+void\r
+avRandomInit()\r
+{\r
+#if 0\r
+  /* Get a pointer into the last 4 bytes of clockBuf. */\r
+  u32_t *lptr1 = (u32_t *)((char *)&clockBuf[3]);\r
+\r
+  /*\r
+   * Initialize our seed using the real-time clock, the idle\r
+   * counter, the millisecond timer, and the hardware timer\r
+   * tick counter.  The real-time clock and the hardware\r
+   * tick counter are the best sources of randomness but\r
+   * since the tick counter is only 16 bit (and truncated\r
+   * at that), the idle counter and millisecond timer\r
+   * (which may be small values) are added to help\r
+   * randomize the lower 16 bits of the seed.\r
+   */\r
+  readClk();\r
+  avRandomSeed += *(u32_t *)clockBuf + *lptr1 + OSIdleCtr\r
+           + ppp_mtime() + ((u32_t)TM1 << 16) + TM1;\r
+#else\r
+  avRandomSeed += sys_jiffies(); /* XXX */\r
+#endif\r
+\r
+  /* Initialize the Borland random number generator. */\r
+  srand((unsigned)avRandomSeed);\r
+}\r
+\r
+/*\r
+ * Randomize our random seed value.  Here we use the fact that\r
+ * this function is called at *truely random* times by the polling\r
+ * and network functions.  Here we only get 16 bits of new random\r
+ * value but we use the previous value to randomize the other 16\r
+ * bits.\r
+ */\r
+void\r
+avRandomize(void)\r
+{\r
+  static u32_t last_jiffies;\r
+\r
+  if (!avRandomized) {\r
+    avRandomized = !0;\r
+    avRandomInit();\r
+    /* The initialization function also updates the seed. */\r
+  } else {\r
+    /* avRandomSeed += (avRandomSeed << 16) + TM1; */\r
+    avRandomSeed += (sys_jiffies() - last_jiffies); /* XXX */\r
+  }\r
+  last_jiffies = sys_jiffies();\r
+}\r
+\r
+/*\r
+ * Return a new random number.\r
+ * Here we use the Borland rand() function to supply a pseudo random\r
+ * number which we make truely random by combining it with our own\r
+ * seed which is randomized by truely random events. \r
+ * Thus the numbers will be truely random unless there have been no\r
+ * operator or network events in which case it will be pseudo random\r
+ * seeded by the real time clock.\r
+ */\r
+u32_t\r
+avRandom()\r
+{\r
+  return ((((u32_t)rand() << 16) + rand()) + avRandomSeed);\r
+}\r
+\r
+#endif /* MD5_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/randm.h
new file mode 100644 (file)
index 0000000..5fb99ef
--- /dev/null
@@ -0,0 +1,81 @@
+/*****************************************************************************\r
+* randm.h - Random number generator header file.\r
+*\r
+* Copyright (c) 2003 by Marc Boucher, Services Informatiques (MBSI) inc.\r
+* Copyright (c) 1998 Global Election Systems Inc.\r
+*\r
+* The authors hereby grant permission to use, copy, modify, distribute,\r
+* and license this software and its documentation for any purpose, provided\r
+* that existing copyright notices are retained in all copies and that this\r
+* notice and the following disclaimer are included verbatim in any \r
+* distributions. No written agreement, license, or royalty fee is required\r
+* for any of the authorized uses.\r
+*\r
+* THIS SOFTWARE IS PROVIDED BY THE CONTRIBUTORS *AS IS* AND ANY EXPRESS OR\r
+* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\r
+* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. \r
+* IN NO EVENT SHALL THE CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,\r
+* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\r
+* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\r
+* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY\r
+* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\r
+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF\r
+* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+*\r
+******************************************************************************\r
+* REVISION HISTORY\r
+*\r
+* 03-01-01 Marc Boucher <marc@mbsi.ca>\r
+*   Ported to lwIP.\r
+* 98-05-29 Guy Lancaster <glanca@gesn.com>, Global Election Systems Inc.\r
+*   Extracted from avos.\r
+*****************************************************************************/\r
+\r
+#ifndef RANDM_H\r
+#define RANDM_H\r
+\r
+/***********************\r
+*** PUBLIC FUNCTIONS ***\r
+***********************/\r
+/*\r
+ * Initialize the random number generator.\r
+ */\r
+void avRandomInit(void);\r
+\r
+/*\r
+ * Churn the randomness pool on a random event.  Call this early and often\r
+ * on random and semi-random system events to build randomness in time for\r
+ * usage.  For randomly timed events, pass a null pointer and a zero length\r
+ * and this will use the system timer and other sources to add randomness.\r
+ * If new random data is available, pass a pointer to that and it will be\r
+ * included.\r
+ */\r
+void avChurnRand(char *randData, u32_t randLen);\r
+\r
+/*\r
+ * Randomize our random seed value.  To be called for truely random events\r
+ * such as user operations and network traffic.\r
+ */\r
+#if MD5_SUPPORT\r
+#define avRandomize() avChurnRand(NULL, 0)\r
+#else  /* MD5_SUPPORT */\r
+void avRandomize(void);\r
+#endif /* MD5_SUPPORT */\r
+\r
+/*\r
+ * Use the random pool to generate random data.  This degrades to pseudo\r
+ * random when used faster than randomness is supplied using churnRand().\r
+ * Thus it's important to make sure that the results of this are not\r
+ * published directly because one could predict the next result to at\r
+ * least some degree.  Also, it's important to get a good seed before\r
+ * the first use.\r
+ */\r
+void avGenRand(char *buf, u32_t bufLen);\r
+\r
+/*\r
+ * Return a new random number.\r
+ */\r
+u32_t avRandom(void);\r
+\r
+\r
+#endif /* RANDM_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.c
new file mode 100644 (file)
index 0000000..eba7da9
--- /dev/null
@@ -0,0 +1,660 @@
+/*\r
+ * Routines to compress and uncompess tcp packets (for transmission\r
+ * over low speed serial lines.\r
+ *\r
+ * Copyright (c) 1989 Regents of the University of California.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the University of California, Berkeley.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:\r
+ *   Initial distribution.\r
+ *\r
+ * Modified June 1993 by Paul Mackerras, paulus@cs.anu.edu.au,\r
+ * so that the entire packet being decompressed doesn't have\r
+ * to be in contiguous memory (just the compressed header).\r
+ *\r
+ * Modified March 1998 by Guy Lancaster, glanca@gesn.com,\r
+ * for a 16 bit processor.\r
+ */\r
+\r
+#include "lwip/opt.h"\r
+\r
+#if PPP_SUPPORT /* don't build if not configured for use in lwipopts.h */\r
+\r
+#include "ppp.h"\r
+#include "pppdebug.h"\r
+\r
+#include "vj.h"\r
+\r
+#include <string.h>\r
+\r
+#if VJ_SUPPORT\r
+\r
+#if LINK_STATS\r
+#define INCR(counter) ++comp->stats.counter\r
+#else\r
+#define INCR(counter)\r
+#endif\r
+\r
+#if defined(NO_CHAR_BITFIELDS)\r
+#define getip_hl(base)  ((base).ip_hl_v&0xf)\r
+#define getth_off(base) (((base).th_x2_off&0xf0)>>4)\r
+#else\r
+#define getip_hl(base)  ((base).ip_hl)\r
+#define getth_off(base) ((base).th_off)\r
+#endif\r
+\r
+void\r
+vj_compress_init(struct vjcompress *comp)\r
+{\r
+  register u_int i;\r
+  register struct cstate *tstate = comp->tstate;\r
+  \r
+#if MAX_SLOTS == 0\r
+  memset((char *)comp, 0, sizeof(*comp));\r
+#endif\r
+  comp->maxSlotIndex = MAX_SLOTS - 1;\r
+  comp->compressSlot = 0;    /* Disable slot ID compression by default. */\r
+  for (i = MAX_SLOTS - 1; i > 0; --i) {\r
+    tstate[i].cs_id = i;\r
+    tstate[i].cs_next = &tstate[i - 1];\r
+  }\r
+  tstate[0].cs_next = &tstate[MAX_SLOTS - 1];\r
+  tstate[0].cs_id = 0;\r
+  comp->last_cs = &tstate[0];\r
+  comp->last_recv = 255;\r
+  comp->last_xmit = 255;\r
+  comp->flags = VJF_TOSS;\r
+}\r
+\r
+\r
+/* ENCODE encodes a number that is known to be non-zero.  ENCODEZ\r
+ * checks for zero (since zero has to be encoded in the long, 3 byte\r
+ * form).\r
+ */\r
+#define ENCODE(n) { \\r
+  if ((u_short)(n) >= 256) { \\r
+    *cp++ = 0; \\r
+    cp[1] = (n); \\r
+    cp[0] = (n) >> 8; \\r
+    cp += 2; \\r
+  } else { \\r
+    *cp++ = (n); \\r
+  } \\r
+}\r
+#define ENCODEZ(n) { \\r
+  if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \\r
+    *cp++ = 0; \\r
+    cp[1] = (n); \\r
+    cp[0] = (n) >> 8; \\r
+    cp += 2; \\r
+  } else { \\r
+    *cp++ = (n); \\r
+  } \\r
+}\r
+\r
+#define DECODEL(f) { \\r
+  if (*cp == 0) {\\r
+    u32_t tmp = ntohl(f) + ((cp[1] << 8) | cp[2]); \\r
+    (f) = htonl(tmp); \\r
+    cp += 3; \\r
+  } else { \\r
+    u32_t tmp = ntohl(f) + (u32_t)*cp++; \\r
+    (f) = htonl(tmp); \\r
+  } \\r
+}\r
+\r
+#define DECODES(f) { \\r
+  if (*cp == 0) {\\r
+    u_short tmp = ntohs(f) + (((u_short)cp[1] << 8) | cp[2]); \\r
+    (f) = htons(tmp); \\r
+    cp += 3; \\r
+  } else { \\r
+    u_short tmp = ntohs(f) + (u_short)*cp++; \\r
+    (f) = htons(tmp); \\r
+  } \\r
+}\r
+\r
+#define DECODEU(f) { \\r
+  if (*cp == 0) {\\r
+    (f) = htons(((u_short)cp[1] << 8) | cp[2]); \\r
+    cp += 3; \\r
+  } else { \\r
+    (f) = htons((u_short)*cp++); \\r
+  } \\r
+}\r
+\r
+/*\r
+ * vj_compress_tcp - Attempt to do Van Jacobsen header compression on a\r
+ * packet.  This assumes that nb and comp are not null and that the first\r
+ * buffer of the chain contains a valid IP header.\r
+ * Return the VJ type code indicating whether or not the packet was\r
+ * compressed.\r
+ */\r
+u_int\r
+vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb)\r
+{\r
+  register struct ip *ip = (struct ip *)pb->payload;\r
+  register struct cstate *cs = comp->last_cs->cs_next;\r
+  register u_short hlen = getip_hl(*ip);\r
+  register struct tcphdr *oth;\r
+  register struct tcphdr *th;\r
+  register u_short deltaS, deltaA;\r
+  register u_long deltaL;\r
+  register u_int changes = 0;\r
+  u_char new_seq[16];\r
+  register u_char *cp = new_seq;\r
+\r
+  /*  \r
+   * Check that the packet is IP proto TCP.\r
+   */\r
+  if (ip->ip_p != IPPROTO_TCP) {\r
+    return (TYPE_IP);\r
+  }\r
+\r
+  /*\r
+   * Bail if this is an IP fragment or if the TCP packet isn't\r
+   * `compressible' (i.e., ACK isn't set or some other control bit is\r
+   * set).  \r
+   */\r
+  if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) {\r
+    return (TYPE_IP);\r
+  }\r
+  th = (struct tcphdr *)&((long *)ip)[hlen];\r
+  if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) {\r
+    return (TYPE_IP);\r
+  }\r
+  /*\r
+   * Packet is compressible -- we're going to send either a\r
+   * COMPRESSED_TCP or UNCOMPRESSED_TCP packet.  Either way we need\r
+   * to locate (or create) the connection state.  Special case the\r
+   * most recently used connection since it's most likely to be used\r
+   * again & we don't have to do any reordering if it's used.\r
+   */\r
+  INCR(vjs_packets);\r
+  if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr \r
+      || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr \r
+      || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {\r
+    /*\r
+     * Wasn't the first -- search for it.\r
+     *\r
+     * States are kept in a circularly linked list with\r
+     * last_cs pointing to the end of the list.  The\r
+     * list is kept in lru order by moving a state to the\r
+     * head of the list whenever it is referenced.  Since\r
+     * the list is short and, empirically, the connection\r
+     * we want is almost always near the front, we locate\r
+     * states via linear search.  If we don't find a state\r
+     * for the datagram, the oldest state is (re-)used.\r
+     */\r
+    register struct cstate *lcs;\r
+    register struct cstate *lastcs = comp->last_cs;\r
+    \r
+    do {\r
+      lcs = cs; cs = cs->cs_next;\r
+      INCR(vjs_searches);\r
+      if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr\r
+          && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr\r
+          && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) {\r
+        goto found;\r
+      }\r
+    } while (cs != lastcs);\r
+\r
+    /*\r
+     * Didn't find it -- re-use oldest cstate.  Send an\r
+     * uncompressed packet that tells the other side what\r
+     * connection number we're using for this conversation.\r
+     * Note that since the state list is circular, the oldest\r
+     * state points to the newest and we only need to set\r
+     * last_cs to update the lru linkage.\r
+     */\r
+    INCR(vjs_misses);\r
+    comp->last_cs = lcs;\r
+    hlen += getth_off(*th);\r
+    hlen <<= 2;\r
+    /* Check that the IP/TCP headers are contained in the first buffer. */\r
+    if (hlen > pb->len) {\r
+      return (TYPE_IP);\r
+    }\r
+    goto uncompressed;\r
+\r
+    found:\r
+    /*\r
+     * Found it -- move to the front on the connection list.\r
+     */\r
+    if (cs == lastcs) {\r
+      comp->last_cs = lcs;\r
+    } else {\r
+      lcs->cs_next = cs->cs_next;\r
+      cs->cs_next = lastcs->cs_next;\r
+      lastcs->cs_next = cs;\r
+    }\r
+  }\r
+\r
+  oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen];\r
+  deltaS = hlen;\r
+  hlen += getth_off(*th);\r
+  hlen <<= 2;\r
+  /* Check that the IP/TCP headers are contained in the first buffer. */\r
+  if (hlen > pb->len) {\r
+    PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen));\r
+    return (TYPE_IP);\r
+  }\r
+\r
+  /*\r
+   * Make sure that only what we expect to change changed. The first\r
+   * line of the `if' checks the IP protocol version, header length &\r
+   * type of service.  The 2nd line checks the "Don't fragment" bit.\r
+   * The 3rd line checks the time-to-live and protocol (the protocol\r
+   * check is unnecessary but costless).  The 4th line checks the TCP\r
+   * header length.  The 5th line checks IP options, if any.  The 6th\r
+   * line checks TCP options, if any.  If any of these things are\r
+   * different between the previous & current datagram, we send the\r
+   * current datagram `uncompressed'.\r
+   */\r
+  if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] \r
+      || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] \r
+      || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] \r
+      || getth_off(*th) != getth_off(*oth) \r
+      || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) \r
+      || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) {\r
+    goto uncompressed;\r
+  }\r
+\r
+  /*\r
+   * Figure out which of the changing fields changed.  The\r
+   * receiver expects changes in the order: urgent, window,\r
+   * ack, seq (the order minimizes the number of temporaries\r
+   * needed in this section of code).\r
+   */\r
+  if (th->th_flags & TCP_URG) {\r
+    deltaS = ntohs(th->th_urp);\r
+    ENCODEZ(deltaS);\r
+    changes |= NEW_U;\r
+  } else if (th->th_urp != oth->th_urp) {\r
+    /* argh! URG not set but urp changed -- a sensible\r
+     * implementation should never do this but RFC793\r
+     * doesn't prohibit the change so we have to deal\r
+     * with it. */\r
+    goto uncompressed;\r
+  }\r
+\r
+  if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) {\r
+    ENCODE(deltaS);\r
+    changes |= NEW_W;\r
+  }\r
+\r
+  if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) {\r
+    if (deltaL > 0xffff) {\r
+      goto uncompressed;\r
+    }\r
+    deltaA = (u_short)deltaL;\r
+    ENCODE(deltaA);\r
+    changes |= NEW_A;\r
+  }\r
+\r
+  if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) {\r
+    if (deltaL > 0xffff) {\r
+      goto uncompressed;\r
+    }\r
+    deltaS = (u_short)deltaL;\r
+    ENCODE(deltaS);\r
+    changes |= NEW_S;\r
+  }\r
+\r
+  switch(changes) {\r
+  case 0:\r
+    /*\r
+     * Nothing changed. If this packet contains data and the\r
+     * last one didn't, this is probably a data packet following\r
+     * an ack (normal on an interactive connection) and we send\r
+     * it compressed.  Otherwise it's probably a retransmit,\r
+     * retransmitted ack or window probe.  Send it uncompressed\r
+     * in case the other side missed the compressed version.\r
+     */\r
+    if (ip->ip_len != cs->cs_ip.ip_len &&\r
+      ntohs(cs->cs_ip.ip_len) == hlen) {\r
+      break;\r
+    }\r
+\r
+  /* (fall through) */\r
+\r
+  case SPECIAL_I:\r
+  case SPECIAL_D:\r
+    /*\r
+     * actual changes match one of our special case encodings --\r
+     * send packet uncompressed.\r
+     */\r
+    goto uncompressed;\r
+\r
+  case NEW_S|NEW_A:\r
+    if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {\r
+      /* special case for echoed terminal traffic */\r
+      changes = SPECIAL_I;\r
+      cp = new_seq;\r
+    }\r
+    break;\r
+\r
+  case NEW_S:\r
+    if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) {\r
+      /* special case for data xfer */\r
+      changes = SPECIAL_D;\r
+      cp = new_seq;\r
+    }\r
+    break;\r
+  }\r
+\r
+  deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id));\r
+  if (deltaS != 1) {\r
+    ENCODEZ(deltaS);\r
+    changes |= NEW_I;\r
+  }\r
+  if (th->th_flags & TCP_PSH) {\r
+    changes |= TCP_PUSH_BIT;\r
+  }\r
+  /*\r
+   * Grab the cksum before we overwrite it below.  Then update our\r
+   * state with this packet's header.\r
+   */\r
+  deltaA = ntohs(th->th_sum);\r
+  BCOPY(ip, &cs->cs_ip, hlen);\r
+\r
+  /*\r
+   * We want to use the original packet as our compressed packet.\r
+   * (cp - new_seq) is the number of bytes we need for compressed\r
+   * sequence numbers.  In addition we need one byte for the change\r
+   * mask, one for the connection id and two for the tcp checksum.\r
+   * So, (cp - new_seq) + 4 bytes of header are needed.  hlen is how\r
+   * many bytes of the original packet to toss so subtract the two to\r
+   * get the new packet size.\r
+   */\r
+  deltaS = (u_short)(cp - new_seq);\r
+  if (!comp->compressSlot || comp->last_xmit != cs->cs_id) {\r
+    comp->last_xmit = cs->cs_id;\r
+    hlen -= deltaS + 4;\r
+    if(pbuf_header(pb, -hlen)){\r
+      /* Can we cope with this failing?  Just assert for now */\r
+      LWIP_ASSERT("pbuf_header failed\n", 0);\r
+    }\r
+    cp = (u_char *)pb->payload;\r
+    *cp++ = changes | NEW_C;\r
+    *cp++ = cs->cs_id;\r
+  } else {\r
+    hlen -= deltaS + 3;\r
+    if(pbuf_header(pb, -hlen)) {\r
+      /* Can we cope with this failing?  Just assert for now */\r
+      LWIP_ASSERT("pbuf_header failed\n", 0);\r
+    }\r
+    cp = (u_char *)pb->payload;\r
+    *cp++ = changes;\r
+  }\r
+  *cp++ = deltaA >> 8;\r
+  *cp++ = deltaA;\r
+  BCOPY(new_seq, cp, deltaS);\r
+  INCR(vjs_compressed);\r
+  return (TYPE_COMPRESSED_TCP);\r
+\r
+  /*\r
+   * Update connection state cs & send uncompressed packet (that is,\r
+   * a regular ip/tcp packet but with the 'conversation id' we hope\r
+   * to use on future compressed packets in the protocol field).\r
+   */\r
+uncompressed:\r
+  BCOPY(ip, &cs->cs_ip, hlen);\r
+  ip->ip_p = cs->cs_id;\r
+  comp->last_xmit = cs->cs_id;\r
+  return (TYPE_UNCOMPRESSED_TCP);\r
+}\r
+\r
+/*\r
+ * Called when we may have missed a packet.\r
+ */\r
+void\r
+vj_uncompress_err(struct vjcompress *comp)\r
+{\r
+  comp->flags |= VJF_TOSS;\r
+  INCR(vjs_errorin);\r
+}\r
+\r
+/*\r
+ * "Uncompress" a packet of type TYPE_UNCOMPRESSED_TCP.\r
+ * Return 0 on success, -1 on failure.\r
+ */\r
+int\r
+vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp)\r
+{\r
+  register u_int hlen;\r
+  register struct cstate *cs;\r
+  register struct ip *ip;\r
+  \r
+  ip = (struct ip *)nb->payload;\r
+  hlen = getip_hl(*ip) << 2;\r
+  if (ip->ip_p >= MAX_SLOTS\r
+      || hlen + sizeof(struct tcphdr) > nb->len\r
+      || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2)\r
+          > nb->len\r
+      || hlen > MAX_HDR) {\r
+    PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", \r
+          ip->ip_p, hlen, nb->len));\r
+    comp->flags |= VJF_TOSS;\r
+    INCR(vjs_errorin);\r
+    return -1;\r
+  }\r
+  cs = &comp->rstate[comp->last_recv = ip->ip_p];\r
+  comp->flags &=~ VJF_TOSS;\r
+  ip->ip_p = IPPROTO_TCP;\r
+  BCOPY(ip, &cs->cs_ip, hlen);\r
+  cs->cs_hlen = hlen;\r
+  INCR(vjs_uncompressedin);\r
+  return 0;\r
+}\r
+\r
+/*\r
+ * Uncompress a packet of type TYPE_COMPRESSED_TCP.\r
+ * The packet is composed of a buffer chain and the first buffer\r
+ * must contain an accurate chain length.\r
+ * The first buffer must include the entire compressed TCP/IP header. \r
+ * This procedure replaces the compressed header with the uncompressed\r
+ * header and returns the length of the VJ header.\r
+ */\r
+int\r
+vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp)\r
+{\r
+  u_char *cp;\r
+  struct tcphdr *th;\r
+  struct cstate *cs;\r
+  u_short *bp;\r
+  struct pbuf *n0 = *nb;\r
+  u32_t tmp;\r
+  u_int vjlen, hlen, changes;\r
+\r
+  INCR(vjs_compressedin);\r
+  cp = (u_char *)n0->payload;\r
+  changes = *cp++;\r
+  if (changes & NEW_C) {\r
+    /* \r
+     * Make sure the state index is in range, then grab the state.\r
+     * If we have a good state index, clear the 'discard' flag. \r
+     */\r
+    if (*cp >= MAX_SLOTS) {\r
+      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp));\r
+      goto bad;\r
+    }\r
+\r
+    comp->flags &=~ VJF_TOSS;\r
+    comp->last_recv = *cp++;\r
+  } else {\r
+    /* \r
+     * this packet has an implicit state index.  If we've\r
+     * had a line error since the last time we got an\r
+     * explicit state index, we have to toss the packet. \r
+     */\r
+    if (comp->flags & VJF_TOSS) {\r
+      PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n"));\r
+      INCR(vjs_tossed);\r
+      return (-1);\r
+    }\r
+  }\r
+  cs = &comp->rstate[comp->last_recv];\r
+  hlen = getip_hl(cs->cs_ip) << 2;\r
+  th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen];\r
+  th->th_sum = htons((*cp << 8) | cp[1]);\r
+  cp += 2;\r
+  if (changes & TCP_PUSH_BIT) {\r
+    th->th_flags |= TCP_PSH;\r
+  } else {\r
+    th->th_flags &=~ TCP_PSH;\r
+  }\r
+\r
+  switch (changes & SPECIALS_MASK) {\r
+  case SPECIAL_I:\r
+    {\r
+      register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;\r
+      /* some compilers can't nest inline assembler.. */\r
+      tmp = ntohl(th->th_ack) + i;\r
+      th->th_ack = htonl(tmp);\r
+      tmp = ntohl(th->th_seq) + i;\r
+      th->th_seq = htonl(tmp);\r
+    }\r
+    break;\r
+\r
+  case SPECIAL_D:\r
+    /* some compilers can't nest inline assembler.. */\r
+    tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen;\r
+    th->th_seq = htonl(tmp);\r
+    break;\r
+\r
+  default:\r
+    if (changes & NEW_U) {\r
+      th->th_flags |= TCP_URG;\r
+      DECODEU(th->th_urp);\r
+    } else {\r
+      th->th_flags &=~ TCP_URG;\r
+    }\r
+    if (changes & NEW_W) {\r
+      DECODES(th->th_win);\r
+    }\r
+    if (changes & NEW_A) {\r
+      DECODEL(th->th_ack);\r
+    }\r
+    if (changes & NEW_S) {\r
+      DECODEL(th->th_seq);\r
+    }\r
+    break;\r
+  }\r
+  if (changes & NEW_I) {\r
+    DECODES(cs->cs_ip.ip_id);\r
+  } else {\r
+    cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1;\r
+    cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id);\r
+  }\r
+\r
+  /*\r
+   * At this point, cp points to the first byte of data in the\r
+   * packet.  Fill in the IP total length and update the IP\r
+   * header checksum.\r
+   */\r
+  vjlen = (u_short)(cp - (u_char*)n0->payload);\r
+  if (n0->len < vjlen) {\r
+    /* \r
+     * We must have dropped some characters (crc should detect\r
+     * this but the old slip framing won't) \r
+     */\r
+    PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n", \r
+          n0->len, vjlen));\r
+    goto bad;\r
+  }\r
+\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+  tmp = n0->tot_len - vjlen + cs->cs_hlen;\r
+  cs->cs_ip.ip_len = htons(tmp);\r
+#else\r
+  cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen);\r
+#endif\r
+\r
+  /* recompute the ip header checksum */\r
+  bp = (u_short *) &cs->cs_ip;\r
+  cs->cs_ip.ip_sum = 0;\r
+  for (tmp = 0; hlen > 0; hlen -= 2) {\r
+    tmp += *bp++;\r
+  }\r
+  tmp = (tmp & 0xffff) + (tmp >> 16);\r
+  tmp = (tmp & 0xffff) + (tmp >> 16);\r
+  cs->cs_ip.ip_sum = (u_short)(~tmp);\r
+  \r
+  /* Remove the compressed header and prepend the uncompressed header. */\r
+  if(pbuf_header(n0, -((s16_t)(vjlen)))) {\r
+    /* Can we cope with this failing?  Just assert for now */\r
+    LWIP_ASSERT("pbuf_header failed\n", 0);\r
+    goto bad;\r
+  }\r
+\r
+  if(LWIP_MEM_ALIGN(n0->payload) != n0->payload) {\r
+    struct pbuf *np, *q;\r
+    u8_t *bufptr;\r
+\r
+    np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL);\r
+    if(!np) {\r
+      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n"));\r
+      goto bad;\r
+    }\r
+\r
+    if(pbuf_header(np, -cs->cs_hlen)) {\r
+      /* Can we cope with this failing?  Just assert for now */\r
+      LWIP_ASSERT("pbuf_header failed\n", 0);\r
+      goto bad;\r
+    }\r
+\r
+    bufptr = n0->payload;\r
+    for(q = np; q != NULL; q = q->next) {\r
+      MEMCPY(q->payload, bufptr, q->len);\r
+      bufptr += q->len;\r
+    }\r
+\r
+    if(n0->next) {\r
+      pbuf_chain(np, n0->next);\r
+      pbuf_dechain(n0);\r
+    }\r
+    pbuf_free(n0);\r
+    n0 = np;\r
+  }\r
+\r
+  if(pbuf_header(n0, cs->cs_hlen)) {\r
+    struct pbuf *np;\r
+\r
+    LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE);\r
+    np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL);\r
+    if(!np) {\r
+      PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n"));\r
+      goto bad;\r
+    }\r
+    pbuf_cat(np, n0);\r
+    n0 = np;\r
+  }\r
+  LWIP_ASSERT("n0->len >= cs->cs_hlen", n0->len >= cs->cs_hlen);\r
+  MEMCPY(n0->payload, &cs->cs_ip, cs->cs_hlen);\r
+\r
+  *nb = n0;\r
+\r
+  return vjlen;\r
+\r
+bad:\r
+  comp->flags |= VJF_TOSS;\r
+  INCR(vjs_errorin);\r
+  return (-1);\r
+}\r
+\r
+#endif /* VJ_SUPPORT */\r
+\r
+#endif /* PPP_SUPPORT */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vj.h
new file mode 100644 (file)
index 0000000..bc02442
--- /dev/null
@@ -0,0 +1,155 @@
+/*\r
+ * Definitions for tcp compression routines.\r
+ *\r
+ * $Id: vj.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $\r
+ *\r
+ * Copyright (c) 1989 Regents of the University of California.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms are permitted\r
+ * provided that the above copyright notice and this paragraph are\r
+ * duplicated in all such forms and that any documentation,\r
+ * advertising materials, and other materials related to such\r
+ * distribution and use acknowledge that the software was developed\r
+ * by the University of California, Berkeley.  The name of the\r
+ * University may not be used to endorse or promote products derived\r
+ * from this software without specific prior written permission.\r
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR\r
+ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED\r
+ * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.\r
+ *\r
+ * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989:\r
+ * - Initial distribution.\r
+ */\r
+\r
+#ifndef VJ_H\r
+#define VJ_H\r
+\r
+#include "vjbsdhdr.h"\r
+\r
+#define MAX_SLOTS 16 /* must be > 2 and < 256 */\r
+#define MAX_HDR   128\r
+\r
+/*\r
+ * Compressed packet format:\r
+ *\r
+ * The first octet contains the packet type (top 3 bits), TCP\r
+ * 'push' bit, and flags that indicate which of the 4 TCP sequence\r
+ * numbers have changed (bottom 5 bits).  The next octet is a\r
+ * conversation number that associates a saved IP/TCP header with\r
+ * the compressed packet.  The next two octets are the TCP checksum\r
+ * from the original datagram.  The next 0 to 15 octets are\r
+ * sequence number changes, one change per bit set in the header\r
+ * (there may be no changes and there are two special cases where\r
+ * the receiver implicitly knows what changed -- see below).\r
+ * \r
+ * There are 5 numbers which can change (they are always inserted\r
+ * in the following order): TCP urgent pointer, window,\r
+ * acknowlegement, sequence number and IP ID.  (The urgent pointer\r
+ * is different from the others in that its value is sent, not the\r
+ * change in value.)  Since typical use of SLIP links is biased\r
+ * toward small packets (see comments on MTU/MSS below), changes\r
+ * use a variable length coding with one octet for numbers in the\r
+ * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the\r
+ * range 256 - 65535 or 0.  (If the change in sequence number or\r
+ * ack is more than 65535, an uncompressed packet is sent.)\r
+ */\r
+\r
+/*\r
+ * Packet types (must not conflict with IP protocol version)\r
+ *\r
+ * The top nibble of the first octet is the packet type.  There are\r
+ * three possible types: IP (not proto TCP or tcp with one of the\r
+ * control flags set); uncompressed TCP (a normal IP/TCP packet but\r
+ * with the 8-bit protocol field replaced by an 8-bit connection id --\r
+ * this type of packet syncs the sender & receiver); and compressed\r
+ * TCP (described above).\r
+ *\r
+ * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and\r
+ * is logically part of the 4-bit "changes" field that follows.  Top\r
+ * three bits are actual packet type.  For backward compatibility\r
+ * and in the interest of conserving bits, numbers are chosen so the\r
+ * IP protocol version number (4) which normally appears in this nibble\r
+ * means "IP packet".\r
+ */\r
+\r
+/* packet types */\r
+#define TYPE_IP               0x40\r
+#define TYPE_UNCOMPRESSED_TCP 0x70\r
+#define TYPE_COMPRESSED_TCP   0x80\r
+#define TYPE_ERROR            0x00\r
+\r
+/* Bits in first octet of compressed packet */\r
+#define NEW_C 0x40 /* flag bits for what changed in a packet */\r
+#define NEW_I 0x20\r
+#define NEW_S 0x08\r
+#define NEW_A 0x04\r
+#define NEW_W 0x02\r
+#define NEW_U 0x01\r
+\r
+/* reserved, special-case values of above */\r
+#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */\r
+#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */\r
+#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U)\r
+\r
+#define TCP_PUSH_BIT 0x10\r
+\r
+\r
+/*\r
+ * "state" data for each active tcp conversation on the wire.  This is\r
+ * basically a copy of the entire IP/TCP header from the last packet\r
+ * we saw from the conversation together with a small identifier\r
+ * the transmit & receive ends of the line use to locate saved header.\r
+ */\r
+struct cstate {\r
+  struct cstate *cs_next; /* next most recently used state (xmit only) */\r
+  u_short cs_hlen;        /* size of hdr (receive only) */\r
+  u_char cs_id;           /* connection # associated with this state */\r
+  u_char cs_filler;\r
+  union {\r
+    char csu_hdr[MAX_HDR];\r
+    struct ip csu_ip;     /* ip/tcp hdr from most recent packet */\r
+  } vjcs_u;\r
+};\r
+#define cs_ip vjcs_u.csu_ip\r
+#define cs_hdr vjcs_u.csu_hdr\r
+\r
+\r
+struct vjstat {\r
+  unsigned long vjs_packets;        /* outbound packets */\r
+  unsigned long vjs_compressed;     /* outbound compressed packets */\r
+  unsigned long vjs_searches;       /* searches for connection state */\r
+  unsigned long vjs_misses;         /* times couldn't find conn. state */\r
+  unsigned long vjs_uncompressedin; /* inbound uncompressed packets */\r
+  unsigned long vjs_compressedin;   /* inbound compressed packets */\r
+  unsigned long vjs_errorin;        /* inbound unknown type packets */\r
+  unsigned long vjs_tossed;         /* inbound packets tossed because of error */\r
+};\r
+\r
+/*\r
+ * all the state data for one serial line (we need one of these per line).\r
+ */\r
+struct vjcompress {\r
+  struct cstate *last_cs;          /* most recently used tstate */\r
+  u_char last_recv;                /* last rcvd conn. id */\r
+  u_char last_xmit;                /* last sent conn. id */\r
+  u_short flags;\r
+  u_char maxSlotIndex;\r
+  u_char compressSlot;             /* Flag indicating OK to compress slot ID. */\r
+#if LINK_STATS\r
+  struct vjstat stats;\r
+#endif\r
+  struct cstate tstate[MAX_SLOTS]; /* xmit connection states */\r
+  struct cstate rstate[MAX_SLOTS]; /* receive connection states */\r
+};\r
+\r
+/* flag values */\r
+#define VJF_TOSS 1U /* tossing rcvd frames because of input err */\r
+\r
+extern void  vj_compress_init    (struct vjcompress *comp);\r
+extern u_int vj_compress_tcp     (struct vjcompress *comp, struct pbuf *pb);\r
+extern void  vj_uncompress_err   (struct vjcompress *comp);\r
+extern int   vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp);\r
+extern int   vj_uncompress_tcp   (struct pbuf **nb, struct vjcompress *comp);\r
+\r
+#endif /* VJ_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h b/Demo/Common/ethernet/lwIP_130/src/netif/ppp/vjbsdhdr.h
new file mode 100644 (file)
index 0000000..c641ee4
--- /dev/null
@@ -0,0 +1,75 @@
+#ifndef VJBSDHDR_H\r
+#define VJBSDHDR_H\r
+\r
+#include "lwip/tcp.h"\r
+\r
+/*\r
+ * Structure of an internet header, naked of options.\r
+ *\r
+ * We declare ip_len and ip_off to be short, rather than u_short\r
+ * pragmatically since otherwise unsigned comparisons can result\r
+ * against negative integers quite easily, and fail in subtle ways.\r
+ */\r
+PACK_STRUCT_BEGIN\r
+struct ip\r
+{\r
+#if defined(NO_CHAR_BITFIELDS)\r
+  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... */\r
+#else\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+  unsigned ip_hl:4,              /* header length */\r
+           ip_v :4;              /* version */\r
+#elif BYTE_ORDER == BIG_ENDIAN \r
+  unsigned ip_v :4,              /* version */\r
+           ip_hl:4;              /* header length */\r
+#else\r
+  COMPLAIN - NO BYTE ORDER SELECTED!\r
+#endif\r
+#endif\r
+  u_char  ip_tos;                /* type of service */\r
+  u_short ip_len;                /* total length */\r
+  u_short ip_id;                 /* identification */\r
+  u_short ip_off;                /* fragment offset field */\r
+#define  IP_DF 0x4000            /* dont fragment flag */\r
+#define  IP_MF 0x2000            /* more fragments flag */\r
+#define  IP_OFFMASK 0x1fff       /* mask for fragmenting bits */\r
+  u_char  ip_ttl;                /* time to live */\r
+  u_char  ip_p;                  /* protocol */\r
+  u_short ip_sum;                /* checksum */\r
+  struct  in_addr ip_src,ip_dst; /* source and dest address */\r
+};\r
+PACK_STRUCT_END\r
+\r
+typedef u32_t tcp_seq;\r
+\r
+/*\r
+ * TCP header.\r
+ * Per RFC 793, September, 1981.\r
+ */\r
+PACK_STRUCT_BEGIN\r
+struct tcphdr  \r
+{\r
+  u_short  th_sport;    /* source port */\r
+  u_short  th_dport;    /* destination port */\r
+  tcp_seq  th_seq;      /* sequence number */\r
+  tcp_seq  th_ack;      /* acknowledgement number */\r
+#if defined(NO_CHAR_BITFIELDS)\r
+  u_char   th_x2_off;\r
+#else\r
+#if BYTE_ORDER == LITTLE_ENDIAN\r
+  unsigned th_x2 :4,    /* (unused) */\r
+           th_off:4;    /* data offset */\r
+#endif\r
+#if BYTE_ORDER == BIG_ENDIAN \r
+  unsigned th_off:4,    /* data offset */\r
+           th_x2 :4;    /* (unused) */\r
+#endif\r
+#endif\r
+  u_char   th_flags;\r
+  u_short  th_win;      /* window */\r
+  u_short  th_sum;      /* checksum */\r
+  u_short  th_urp;      /* urgent pointer */\r
+};\r
+PACK_STRUCT_END\r
+\r
+#endif /* VJBSDHDR_H */\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/slipif.c b/Demo/Common/ethernet/lwIP_130/src/netif/slipif.c
new file mode 100644 (file)
index 0000000..7839da4
--- /dev/null
@@ -0,0 +1,275 @@
+/**\r
+ * @file\r
+ * SLIP Interface\r
+ *\r
+ */\r
+\r
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved. \r
+ *\r
+ * Redistribution and use in source and binary forms, with or without \r
+ * modification, are permitted provided that the following conditions \r
+ * are met: \r
+ * 1. Redistributions of source code must retain the above copyright \r
+ *    notice, this list of conditions and the following disclaimer. \r
+ * 2. Redistributions in binary form must reproduce the above copyright \r
+ *    notice, this list of conditions and the following disclaimer in the \r
+ *    documentation and/or other materials provided with the distribution. \r
+ * 3. Neither the name of the Institute nor the names of its contributors \r
+ *    may be used to endorse or promote products derived from this software \r
+ *    without specific prior written permission. \r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND \r
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE \r
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE \r
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE \r
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL \r
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS \r
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) \r
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT \r
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY \r
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF \r
+ * SUCH DAMAGE. \r
+ *\r
+ * This file is built upon the file: src/arch/rtxc/netif/sioslip.c\r
+ *\r
+ * Author: Magnus Ivarsson <magnus.ivarsson(at)volvo.com> \r
+ */\r
+\r
+/* \r
+ * This is an arch independent SLIP netif. The specific serial hooks must be\r
+ * provided by another file. They are sio_open, sio_recv and sio_send\r
+ */\r
+\r
+#include "netif/slipif.h"\r
+#include "lwip/opt.h"\r
+#include "lwip/def.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include "lwip/stats.h"\r
+#include "lwip/snmp.h"\r
+#include "lwip/sio.h"\r
+\r
+#define SLIP_END     0300 /* 0xC0 */\r
+#define SLIP_ESC     0333 /* 0xDB */\r
+#define SLIP_ESC_END 0334 /* 0xDC */\r
+#define SLIP_ESC_ESC 0335 /* 0xDD */\r
+\r
+#define MAX_SIZE     1500\r
+\r
+/**\r
+ * Send a pbuf doing the necessary SLIP encapsulation\r
+ *\r
+ * Uses the serial layer's sio_send()\r
+ *\r
+ * @param netif the lwip network interface structure for this slipif\r
+ * @param p the pbuf chaing packet to send\r
+ * @param ipaddr the ip address to send the packet to (not used for slipif)\r
+ * @return always returns ERR_OK since the serial layer does not provide return values\r
+ */\r
+err_t\r
+slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr)\r
+{\r
+  struct pbuf *q;\r
+  u16_t i;\r
+  u8_t c;\r
+\r
+  LWIP_ASSERT("netif != NULL", (netif != NULL));\r
+  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));\r
+  LWIP_ASSERT("p != NULL", (p != NULL));\r
+\r
+  LWIP_UNUSED_ARG(ipaddr);\r
+\r
+  /* Send pbuf out on the serial I/O device. */\r
+  sio_send(SLIP_END, netif->state);\r
+\r
+  for (q = p; q != NULL; q = q->next) {\r
+    for (i = 0; i < q->len; i++) {\r
+      c = ((u8_t *)q->payload)[i];\r
+      switch (c) {\r
+      case SLIP_END:\r
+        sio_send(SLIP_ESC, netif->state);\r
+        sio_send(SLIP_ESC_END, netif->state);\r
+        break;\r
+      case SLIP_ESC:\r
+        sio_send(SLIP_ESC, netif->state);\r
+        sio_send(SLIP_ESC_ESC, netif->state);\r
+        break;\r
+      default:\r
+        sio_send(c, netif->state);\r
+        break;\r
+      }\r
+    }\r
+  }\r
+  sio_send(SLIP_END, netif->state);\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Handle the incoming SLIP stream character by character\r
+ *\r
+ * Poll the serial layer by calling sio_recv()\r
+ *\r
+ * @param netif the lwip network interface structure for this slipif\r
+ * @return The IP packet when SLIP_END is received \r
+ */\r
+static struct pbuf *\r
+slipif_input(struct netif *netif)\r
+{\r
+  u8_t c;\r
+  /* q is the whole pbuf chain for a packet, p is the current pbuf in the chain */\r
+  struct pbuf *p, *q;\r
+  u16_t recved;\r
+  u16_t i;\r
+\r
+  LWIP_ASSERT("netif != NULL", (netif != NULL));\r
+  LWIP_ASSERT("netif->state != NULL", (netif->state != NULL));\r
+\r
+  q = p = NULL;\r
+  recved = i = 0;\r
+  c = 0;\r
+\r
+  while (1) {\r
+    c = sio_recv(netif->state);\r
+    switch (c) {\r
+    case SLIP_END:\r
+      if (recved > 0) {\r
+        /* Received whole packet. */\r
+        /* Trim the pbuf to the size of the received packet. */\r
+        pbuf_realloc(q, recved);\r
+        \r
+        LINK_STATS_INC(link.recv);\r
+        \r
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif: Got packet\n"));\r
+        return q;\r
+      }\r
+      break;\r
+\r
+    case SLIP_ESC:\r
+      c = sio_recv(netif->state);\r
+      switch (c) {\r
+      case SLIP_ESC_END:\r
+        c = SLIP_END;\r
+        break;\r
+      case SLIP_ESC_ESC:\r
+        c = SLIP_ESC;\r
+        break;\r
+      }\r
+      /* FALLTHROUGH */\r
+\r
+    default:\r
+      /* byte received, packet not yet completely received */\r
+      if (p == NULL) {\r
+        /* allocate a new pbuf */\r
+        LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: alloc\n"));\r
+        p = pbuf_alloc(PBUF_LINK, PBUF_POOL_BUFSIZE, PBUF_POOL);\r
+\r
+        if (p == NULL) {\r
+          LINK_STATS_INC(link.drop);\r
+          LWIP_DEBUGF(SLIP_DEBUG, ("slipif_input: no new pbuf! (DROP)\n"));\r
+          /* don't process any further since we got no pbuf to receive to */\r
+          break;\r
+        }\r
+\r
+        if (q != NULL) {\r
+          /* 'chain' the pbuf to the existing chain */\r
+          pbuf_cat(q, p);\r
+        } else {\r
+          /* p is the first pbuf in the chain */\r
+          q = p;\r
+        }\r
+      }\r
+\r
+      /* this automatically drops bytes if > MAX_SIZE */\r
+      if ((p != NULL) && (recved <= MAX_SIZE)) {\r
+        ((u8_t *)p->payload)[i] = c;\r
+        recved++;\r
+        i++;\r
+        if (i >= p->len) {\r
+          /* on to the next pbuf */\r
+          i = 0;\r
+          if (p->next != NULL && p->next->len > 0) {\r
+            /* p is a chain, on to the next in the chain */\r
+            p = p->next;\r
+          } else {\r
+            /* p is a single pbuf, set it to NULL so next time a new\r
+             * pbuf is allocated */\r
+            p = NULL;\r
+          }\r
+        }\r
+      }\r
+      break;\r
+    }\r
+  }\r
+  return NULL;\r
+}\r
+\r
+#if !NO_SYS\r
+/**\r
+ * The SLIP input thread.\r
+ *\r
+ * Feed the IP layer with incoming packets\r
+ *\r
+ * @param nf the lwip network interface structure for this slipif\r
+ */\r
+static void\r
+slipif_loop(void *nf)\r
+{\r
+  struct pbuf *p;\r
+  struct netif *netif = (struct netif *)nf;\r
+\r
+  while (1) {\r
+    p = slipif_input(netif);\r
+    if (p != NULL) {\r
+      if (netif->input(p, netif) != ERR_OK) {\r
+        pbuf_free(p);\r
+        p = NULL;\r
+      }\r
+    }\r
+  }\r
+}\r
+#endif /* !NO_SYS */\r
+\r
+/**\r
+ * SLIP netif initialization\r
+ *\r
+ * Call the arch specific sio_open and remember\r
+ * the opened device in the state field of the netif.\r
+ *\r
+ * @param netif the lwip network interface structure for this slipif\r
+ * @return ERR_OK if serial line could be opened,\r
+ *         ERR_IF is serial line couldn't be opened\r
+ *\r
+ * @note netif->num must contain the number of the serial port to open\r
+ *       (0 by default)\r
+ */\r
+err_t\r
+slipif_init(struct netif *netif)\r
+{\r
+\r
+  LWIP_DEBUGF(SLIP_DEBUG, ("slipif_init: netif->num=%"U16_F"\n", (u16_t)netif->num));\r
+\r
+  netif->name[0] = 's';\r
+  netif->name[1] = 'l';\r
+  netif->output = slipif_output;\r
+  netif->mtu = MAX_SIZE;\r
+  netif->flags = NETIF_FLAG_POINTTOPOINT;\r
+\r
+  /* Try to open the serial port (netif->num contains the port number). */\r
+  netif->state = sio_open(netif->num);\r
+  if (!netif->state) {\r
+    /* Opening the serial port failed. */\r
+    return ERR_IF;\r
+  }\r
+\r
+  /* initialize the snmp variables and counters inside the struct netif\r
+   * ifSpeed: no assumption can be made without knowing more about the\r
+   * serial line!\r
+   */\r
+  NETIF_INIT_SNMP(netif, snmp_ifType_slip, 0);\r
+\r
+  /* Create a thread to poll the serial line. */\r
+  sys_thread_new(SLIPIF_THREAD_NAME, slipif_loop, netif, SLIPIF_THREAD_STACKSIZE, SLIPIF_THREAD_PRIO);\r
+  return ERR_OK;\r
+}\r
diff --git a/Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c b/Demo/Common/ethernet/lwIP_130/src/netif/stf91x_ethernetif.c
new file mode 100644 (file)
index 0000000..1b58aac
--- /dev/null
@@ -0,0 +1,416 @@
+/*\r
+ * Copyright (c) 2001-2004 Swedish Institute of Computer Science.\r
+ * All rights reserved.\r
+ *\r
+ * Redistribution and use in source and binary forms, with or without modification,\r
+ * are permitted provided that the following conditions are met:\r
+ *\r
+ * 1. Redistributions of source code must retain the above copyright notice,\r
+ *    this list of conditions and the following disclaimer.\r
+ * 2. Redistributions in binary form must reproduce the above copyright notice,\r
+ *    this list of conditions and the following disclaimer in the documentation\r
+ *    and/or other materials provided with the distribution.\r
+ * 3. The name of the author may not be used to endorse or promote products\r
+ *    derived from this software without specific prior written permission.\r
+ *\r
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED\r
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\r
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT\r
+ * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT\r
+ * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\r
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\r
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING\r
+ * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY\r
+ * OF SUCH DAMAGE.\r
+ *\r
+ * This file is part of the lwIP TCP/IP stack.\r
+ *\r
+ * Author: Adam Dunkels <adam@sics.se>\r
+ *\r
+ */\r
+\r
+/*\r
+ * This file is a skeleton for developing Ethernet network interface\r
+ * drivers for lwIP. Add code to the low_level functions and do a\r
+ * search-and-replace for the word "ethernetif" to replace it with\r
+ * something that better describes your network interface.\r
+ */\r
+\r
+#include "lwip/def.h"\r
+#include "lwip/mem.h"\r
+#include "lwip/pbuf.h"\r
+#include "lwip/sys.h"\r
+#include <lwip/stats.h>\r
+#include <lwip/snmp.h>\r
+#include "netif/etharp.h"\r
+#include "91x_enet.h"\r
+\r
+// Standard library include\r
+#include <stdio.h>\r
+#include <string.h>\r
+\r
+#define netifMTU                                                                                                       ( 1500 )\r
+#define netifINTERFACE_TASK_STACK_SIZE         ( 350 )\r
+#define netifINTERFACE_TASK_PRIORITY                   ( configMAX_PRIORITIES - 1 )\r
+#define netifBUFFER_WAIT_ATTEMPTS                                      10\r
+#define netifBUFFER_WAIT_DELAY                                         (10 / portTICK_RATE_MS)\r
+#define IFNAME0 'e'\r
+#define IFNAME1 'n'\r
+\r
+/* The time to block waiting for input. */\r
+#define emacBLOCK_TIME_WAITING_FOR_INPUT       ( ( portTickType ) 100 )\r
+\r
+/* Interrupt status bit definition. */\r
+#define DMI_RX_CURRENT_DONE 0x8000\r
+\r
+static u8_t s_rxBuff[1520];\r
+\r
+/* The semaphore used by the ISR to wake the lwIP task. */\r
+static xSemaphoreHandle s_xSemaphore = NULL;\r
+\r
+struct ethernetif {\r
+  struct eth_addr *ethaddr;\r
+  /* Add whatever per-interface state that is needed here. */\r
+};\r
+\r
+/* Forward declarations. */\r
+static void ethernetif_input( void *pParams );\r
+u8 *pcGetNextBuffer( void );\r
+\r
+/**\r
+ * In this function, the hardware should be initialized.\r
+ * Called from ethernetif_init().\r
+ *\r
+ * @param netif the already initialized lwip network interface structure\r
+ *        for this ethernetif\r
+ */\r
+static void low_level_init(struct netif *netif)\r
+{\r
+  /* set MAC hardware address length */\r
+  netif->hwaddr_len = ETHARP_HWADDR_LEN;\r
+\r
+  /* set MAC hardware address */\r
+  netif->hwaddr[0] = MAC_ADDR0;\r
+  netif->hwaddr[1] = MAC_ADDR1;\r
+  netif->hwaddr[2] = MAC_ADDR2;\r
+  netif->hwaddr[3] = MAC_ADDR3;\r
+  netif->hwaddr[4] = MAC_ADDR4;\r
+  netif->hwaddr[5] = MAC_ADDR5;\r
+\r
+  /* maximum transfer unit */\r
+  netif->mtu = netifMTU;\r
+\r
+  // device capabilities.\r
+       // don't set NETIF_FLAG_ETHARP if this device is not an ethernet one\r
+  netif->flags |= NETIF_FLAG_BROADCAST | NETIF_FLAG_ETHARP;\r
+\r
+  /* Do whatever else is needed to initialize interface. */\r
+       \r
+  if( s_xSemaphore == NULL )\r
+  {\r
+      vSemaphoreCreateBinary( s_xSemaphore );\r
+      xSemaphoreTake( s_xSemaphore,  0);\r
+  }\r
+\r
+  /* Initialise the MAC. */\r
+  ENET_InitClocksGPIO();\r
+  ENET_Init(PHY_AUTO_NEGOTIATION);\r
+  ENET_Start();\r
+       \r
+  portENTER_CRITICAL();\r
+  {\r
+      /*set MAC physical*/\r
+      ENET_MAC->MAH = (MAC_ADDR5<<8) + MAC_ADDR4;\r
+      ENET_MAC->MAL = (MAC_ADDR3<<24) + (MAC_ADDR2<<16) + (MAC_ADDR1<<8) + MAC_ADDR0;\r
+       \r
+      VIC_Config( ENET_ITLine, VIC_IRQ, 1 );\r
+      VIC_ITCmd( ENET_ITLine, ENABLE );        \r
+      ENET_DMA->ISR = DMI_RX_CURRENT_DONE;\r
+      ENET_DMA->IER = DMI_RX_CURRENT_DONE;\r
+  }\r
+  portEXIT_CRITICAL();\r
+       \r
+  netif->flags |= NETIF_FLAG_LINK_UP;\r
+\r
+  /* Create the task that handles the EMAC. */\r
+  xTaskCreate( ethernetif_input, ( signed portCHAR * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, (void *)netif, netifINTERFACE_TASK_PRIORITY, NULL );\r
+}      \r
+\r
+\r
+/**\r
+ * This function should do the actual transmission of the packet. The packet is\r
+ * contained in the pbuf that is passed to the function. This pbuf\r
+ * might be chained.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @param p the MAC packet to send (e.g. IP packet including MAC addresses and type)\r
+ * @return ERR_OK if the packet could be sent\r
+ *         an err_t value if the packet couldn't be sent\r
+ *\r
+ * @note Returning ERR_MEM here if a DMA queue of your MAC is full can lead to\r
+ *       strange results. You might consider waiting for space in the DMA queue\r
+ *       to become availale since the stack doesn't retry to send a packet\r
+ *       dropped because of memory failure (except for the TCP timers).\r
+ */\r
+static err_t low_level_output(struct netif *netif, struct pbuf *p)\r
+{\r
+  struct pbuf *q;\r
+  u32_t l = 0;\r
+       unsigned portCHAR *pcTxData;\r
+\r
+#if ETH_PAD_SIZE\r
+  pbuf_header(p, -ETH_PAD_SIZE);                       /* drop the padding word */\r
+#endif\r
+       \r
+       /* Get a DMA buffer into which we can write the data to send. */\r
+       for( int i = 0; i < netifBUFFER_WAIT_ATTEMPTS; i++ )\r
+       {\r
+               pcTxData = pcGetNextBuffer();\r
+\r
+               if( pcTxData ){\r
+                       break;\r
+               } else {\r
+                       vTaskDelay( netifBUFFER_WAIT_DELAY );\r
+               }\r
+       }\r
+       \r
+       if (pcTxData == NULL) {\r
+               portNOP();              \r
+               \r
+               return ERR_BUF;\r
+       }\r
+       else {\r
+\r
+               for(q = p; q != NULL; q = q->next) {\r
+                       /* Send the data from the pbuf to the interface, one pbuf at a\r
+                                time. The size of the data in each pbuf is kept in the ->len\r
+                                variable. */\r
+                       \r
+                       vTaskSuspendAll();\r
+                       memcpy(&pcTxData[l], (u8_t*)q->payload, q->len);\r
+                       xTaskResumeAll();\r
+                       l += q->len;\r
+               }\r
+       }\r
+\r
+       ENET_TxPkt( &pcTxData, l );\r
+                       \r
+       #if ETH_PAD_SIZE\r
+               pbuf_header(p, ETH_PAD_SIZE);                   /* reclaim the padding word */\r
+       #endif\r
+\r
+               LINK_STATS_INC(link.xmit);\r
+\r
+  return ERR_OK;\r
+}\r
+\r
+/**\r
+ * Should allocate a pbuf and transfer the bytes of the incoming\r
+ * packet from the interface into the pbuf.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @return a pbuf filled with the received packet (including MAC header)\r
+ *         NULL on memory error\r
+ */\r
+static struct pbuf *low_level_input(struct netif *netif)\r
+{\r
+  struct pbuf *p, *q;\r
+  u16_t len, l;\r
+\r
+  l = 0;\r
+  p = NULL;\r
+       \r
+\r
+       /* Obtain the size of the packet and put it into the "len"\r
+                variable. */\r
+       len = ENET_HandleRxPkt(s_rxBuff);\r
+\r
+       if(len)\r
+       {\r
+       #if ETH_PAD_SIZE\r
+               len += ETH_PAD_SIZE;                                            /* allow room for Ethernet padding */\r
+       #endif\r
+\r
+               /* We allocate a pbuf chain of pbufs from the pool. */\r
+               p = pbuf_alloc(PBUF_RAW, len, PBUF_POOL);\r
+\r
+               if (p != NULL) {\r
+\r
+       #if ETH_PAD_SIZE\r
+                       pbuf_header(p, -ETH_PAD_SIZE);                  /* drop the padding word */\r
+       #endif\r
+\r
+                       /* We iterate over the pbuf chain until we have read the entire\r
+                        * packet into the pbuf. */\r
+                       for(q = p; q != NULL; q = q->next) {\r
+                               /* Read enough bytes to fill this pbuf in the chain. The\r
+                                * available data in the pbuf is given by the q->len\r
+                                * variable. */\r
+                               vTaskSuspendAll();\r
+                               memcpy((u8_t*)q->payload, &s_rxBuff[l], q->len);\r
+                               xTaskResumeAll();\r
+                               l = l + q->len;\r
+                       }\r
+\r
+\r
+       #if ETH_PAD_SIZE\r
+                       pbuf_header(p, ETH_PAD_SIZE);                   /* reclaim the padding word */\r
+       #endif\r
+\r
+                       LINK_STATS_INC(link.recv);\r
+\r
+               } else {\r
+\r
+                       LINK_STATS_INC(link.memerr);\r
+                       LINK_STATS_INC(link.drop);\r
+\r
+               } /* End else */\r
+       } /* End if */\r
+                       \r
+  return p;\r
+}\r
+\r
+/**\r
+ * This function should be called when a packet is ready to be read\r
+ * from the interface. It uses the function low_level_input() that\r
+ * should handle the actual reception of bytes from the network\r
+ * interface.Then the type of the received packet is determined and\r
+ * the appropriate input function is called.\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ */\r
+\r
+static void ethernetif_input( void *pParams )\r
+{\r
+       struct netif *netif;\r
+  struct ethernetif *ethernetif;\r
+  struct eth_hdr *ethhdr;\r
+  struct pbuf *p;\r
+\r
+       netif = (struct netif*) pParams;\r
+       ethernetif = netif->state;\r
+       \r
+       for( ;; )\r
+       {\r
+               do\r
+               {\r
+                       \r
+                       /* move received packet into a new pbuf */\r
+                       p = low_level_input( netif );\r
+                       \r
+                       if( p == NULL )\r
+                       {\r
+                               /* No packet could be read.  Wait a for an interrupt to tell us\r
+                               there is more data available. */\r
+                               xSemaphoreTake( s_xSemaphore, emacBLOCK_TIME_WAITING_FOR_INPUT );\r
+                       }\r
+               \r
+               } while( p == NULL );\r
+\r
+               /* points to packet payload, which starts with an Ethernet header */\r
+               ethhdr = p->payload;\r
+\r
+               switch (htons(ethhdr->type)) {\r
+                       /* IP or ARP packet? */\r
+       \r
+               case ETHTYPE_IP:\r
+       \r
+                       /* full packet send to tcpip_thread to process */\r
+                       if (netif->input(p, netif) != ERR_OK)\r
+                       {\r
+                               LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_input: IP input error\n"));\r
+                               pbuf_free(p);\r
+                               p = NULL;\r
+                       }\r
+                       break;\r
+                               \r
+               case ETHTYPE_ARP:\r
+                               \r
+#if ETHARP_TRUST_IP_MAC\r
+                       etharp_ip_input(netif, p);\r
+#endif\r
+                               \r
+                       etharp_arp_input(netif, ethernetif->ethaddr, p);\r
+                       break;\r
+               \r
+               default:\r
+                       pbuf_free(p);\r
+                       p = NULL;\r
+                       break;\r
+               }\r
+       }\r
+}\r
+\r
+/**\r
+ * Should be called at the beginning of the program to set up the\r
+ * network interface. It calls the function low_level_init() to do the\r
+ * actual setup of the hardware.\r
+ *\r
+ * This function should be passed as a parameter to netif_add().\r
+ *\r
+ * @param netif the lwip network interface structure for this ethernetif\r
+ * @return ERR_OK if the loopif is initialized\r
+ *         ERR_MEM if private data couldn't be allocated\r
+ *         any other err_t on error\r
+ */\r
+err_t\r
+ethernetif_init(struct netif *netif)\r
+{\r
+  struct ethernetif *ethernetif;\r
+       \r
+       LWIP_ASSERT("netif != NULL", (netif != NULL));\r
+\r
+  ethernetif = mem_malloc(sizeof(struct ethernetif));\r
+\r
+  if (ethernetif == NULL)\r
+  {\r
+       LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));\r
+       return ERR_MEM;\r
+  }\r
+\r
+#if LWIP_NETIF_HOSTNAME\r
+  /* Initialize interface hostname */\r
+  netif->hostname = "lwip";\r
+#endif /* LWIP_NETIF_HOSTNAME */\r
+       \r
+  /*\r
+        * Initialize the snmp variables and counters inside the struct netif.\r
+        * The last argument should be replaced with your link speed, in units\r
+        * of bits per second.\r
+        */\r
+       NETIF_INIT_SNMP(netif, snmp_ifType_ethernet_csmacd, 100);       \r
+\r
+  netif->state = ethernetif;\r
+  netif->name[0] = IFNAME0;\r
+  netif->name[1] = IFNAME1;\r
+  /* We directly use etharp_output() here to save a function call.\r
+        * You can instead declare your own function an call etharp_output()\r
+        * from it if you have to do some checks before sending (e.g. if link\r
+        * is available...)\r
+        */     \r
+  netif->output = etharp_output;\r
+  netif->linkoutput = low_level_output;\r
+\r
+  ethernetif->ethaddr = (struct eth_addr *)&(netif->hwaddr[0]);\r
+\r
+  low_level_init(netif);\r
+\r
+  return ERR_OK;\r
+}\r
+/*-----------------------------------------------------------*/\r
+\r
+void ENET_IRQHandler(void)\r
+{\r
+portBASE_TYPE xSwitchRequired;\r
+\r
+       /* Give the semaphore in case the lwIP task needs waking. */\r
+       xSwitchRequired = xSemaphoreGiveFromISR( s_xSemaphore, &xSwitchRequired );\r
+       \r
+       /* Clear the interrupt. */\r
+       ENET_DMA->ISR = DMI_RX_CURRENT_DONE;\r
+       \r
+       /* Switch tasks if necessary. */        \r
+       portEND_SWITCHING_ISR( xSwitchRequired );\r
+}\r
+/*-----------------------------------------------------------*/\r
diff --git a/Demo/Common/ethernet/lwIP_130/sys b/Demo/Common/ethernet/lwIP_130/sys
new file mode 100644 (file)
index 0000000..e69de29