--- /dev/null
+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
--- /dev/null
+/*\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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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, ðbroadcast,\r
+ (struct eth_addr *)netif->hwaddr, &netif->autoip->llipaddr, ðzero,\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+IPv6 support in lwIP is very experimental.\r
--- /dev/null
+/*\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
--- /dev/null
+/**\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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, ðaddr_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, ðaddr_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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/** @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
--- /dev/null
+/**\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/**\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*\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
--- /dev/null
+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
--- /dev/null
+/**\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 *)ðbroadcast;\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, ðbroadcast,\r
+ (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero,\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
--- /dev/null
+/**\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
--- /dev/null
+/**\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*** 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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*** 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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*****************************************************************************\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
--- /dev/null
+/*\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
--- /dev/null
+/*\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
--- /dev/null
+#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
--- /dev/null
+/**\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
--- /dev/null
+/*\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