diff options
author | H. Peter Anvin <hpa@linux.intel.com> | 2012-05-29 10:31:38 -0700 |
---|---|---|
committer | H. Peter Anvin <hpa@linux.intel.com> | 2012-05-29 10:31:38 -0700 |
commit | d493d0416f038f80d73b897e317e6d2c251c1775 (patch) | |
tree | 6a1f4aa39149c6093ec4ab7c8a93dd1252d7ec4e /core/lwip | |
parent | c135aeebe08d857548a3a56b6fc3a0125ec8972c (diff) | |
parent | 930e929b202ed292077fb14981e5c6bd4c55651e (diff) | |
download | syslinux-d493d0416f038f80d73b897e317e6d2c251c1775.tar.gz |
Merge remote-tracking branch 'genec/lwip-1.4.0-test-2' into lwip
Diffstat (limited to 'core/lwip')
112 files changed, 12478 insertions, 7883 deletions
diff --git a/core/lwip/CHANGELOG b/core/lwip/CHANGELOG index 860d1c47..6e27a66b 100644 --- a/core/lwip/CHANGELOG +++ b/core/lwip/CHANGELOG @@ -1,27 +1,658 @@ -FUTURE - - * TODO: The lwIP source code makes some invalid assumptions on processor - word-length, storage sizes and alignment. See the mailing lists for - problems with exoteric (/DSP) architectures showing these problems. - We still have to fix some of these issues neatly. - - * TODO: the PPP code is broken in a few ways. There are namespace - collisions on BSD systems and many assumptions on word-length - (sizeof(int)). In ppp.c an assumption is made on the availability of - a thread subsystem. Either PPP needs to be moved to contrib/ports/??? - or rearranged to be more generic. - HISTORY (CVS HEAD) * [Enter new changes just after this line - do not remove this line] + ++ New features: + + + ++ Bugfixes: + + + + +(STABLE-1.4.0) + ++ New features: + 2011-03-27: Simon Goldschmidt + * tcp_impl.h, tcp_in.c, tcp_out.c: Removed 'dataptr' from 'struct tcp_seg' and + calculate it in tcp_zero_window_probe (the only place where it was used). + + 2010-11-21: Simon Goldschmidt + * dhcp.c/.h: Added a function to deallocate the struct dhcp from a netif + (fixes bug #31525). + + 2010-07-12: Simon Goldschmidt (patch by Stephane Lesage) + * ip.c, udp.c/.h, pbuf.h, sockets.c: task #10495: Added support for + IP_MULTICAST_LOOP at socket- and raw-API level. + + 2010-06-16: Simon Goldschmidt + * ip.c: Added an optional define (LWIP_IP_ACCEPT_UDP_PORT) that can allow + link-layer-addressed UDP traffic to be received while a netif is down (just + like DHCP during configuration) + + 2010-05-22: Simon Goldschmidt + * many many files: bug #27352: removed packing from ip_addr_t, the packed + version is now only used in protocol headers. Added global storage for + current src/dest IP address while in input functions. + + 2010-05-16: Simon Goldschmidt + * def.h: task #10391: Add preprocessor-macros for compile-time htonl + calculation (and use them throughout the stack where applicable) + + 2010-05-16: Simon Goldschmidt + * opt.h, memp_std.h, memp.c, ppp_oe.h/.c: PPPoE now uses its own MEMP pool + instead of the heap (moved struct pppoe_softc from ppp_oe.c to ppp_oe.h) + + 2010-05-16: Simon Goldschmidt + * opt.h, memp_std.h, dns.h/.c: DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own + MEMP pool instead of the heap + + 2010-05-13: Simon Goldschmidt + * tcp.c, udp.c: task #6995: Implement SO_REUSEADDR (correctly), added + new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast + packets to more than one pcb. + + 2010-05-02: Simon Goldschmidt + * netbuf.h/.c, sockets.c, api_msg.c: use checksum-on-copy for sending + UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 + + 2010-04-30: Simon Goldschmidt + * udp.h/.c, pbuf.h/.c: task #6849: added udp_send(_to/_if) functions that + take a precalculated checksum, added pbuf_fill_chksum() to copy data + into a pbuf and at the same time calculating the checksum for that data + + 2010-04-29: Simon Goldschmidt + * ip_addr.h, etharp.h/.c, autoip.c: Create overridable macros for copying + 2-byte-aligned IP addresses and MAC addresses + + 2010-04-28: Patch by Bill Auerbach + * ip.c: Inline generating IP checksum to save a function call + + 2010-04-14: Simon Goldschmidt + * tcpip.h/.c, timers.c: Added an overridable define to get informed when the + tcpip_thread processes messages or timeouts to implement a watchdog. + + 2010-03-28: Simon Goldschmidt + * ip_frag.c: create a new (contiguous) PBUF_RAM for every outgoing + fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 + + 2010-03-27: Simon Goldschmidt + * etharp.c: Speedup TX by moving code from find_entry to etharp_output/ + etharp_query to prevent unnecessary function calls (inspired by + patch #7135). + + 2010-03-20: Simon Goldschmidt + * opt.h, tcpip.c/.h: Added an option to disable tcpip_(un)timeout code + since the linker cannot do this automatically to save space. + + 2010-03-20: Simon Goldschmidt + * opt.h, etharp.c/.h: Added support for static ARP table entries + + 2010-03-14: Simon Goldschmidt + * tcp_impl.h, tcp_out.c, inet_chksum.h/.c: task #6849: Calculate checksum + when creating TCP segments, not when (re-)transmitting them. + + 2010-03-07: Simon Goldschmidt + * sockets.c: bug #28775 (select/event_callback: only check select_cb_list + on change) plus use SYS_LIGHTWEIGHT_PROT to protect the select code. + This should speed up receiving data on sockets as the select code in + event_callback is only executed when select is waiting. + + 2010-03-06: Simon Goldschmidt + * tcp_out.c: task #7013 (Create option to have all packets delivered to + netif->output in one piece): Always copy to try to create single pbufs + in tcp_write. + + 2010-03-06: Simon Goldschmidt + * api.h, api_lib.c, sockets.c: task #10167 (sockets: speed up TCP recv + by not allocating a netbuf): added function netconn_recv_tcp_pbuf() + for tcp netconns to receive pbufs, not netbufs; use that function + for tcp sockets. + + 2010-03-05: Jakob Ole Stoklundsen / Simon Goldschmidt + * opt.h, tcp.h, tcp_impl.h, tcp.c, tcp_in.c, tcp_out.c: task #7040: + Work on tcp_enqueue: Don't waste memory when chaining segments, + added option TCP_OVERSIZE to prevent creating many small pbufs when + calling tcp_write with many small blocks of data. Instead, pbufs are + allocated larger than needed and the space is used for later calls to + tcp_write. + + 2010-02-21: Simon Goldschmidt + * stats.c/.h: Added const char* name to mem- and memp-stats for easier + debugging. + + 2010-02-21: Simon Goldschmidt + * tcp.h (and usages), added tcp_impl.h: Splitted API and internal + implementation of tcp to make API usage cleare to application programmers + + 2010-02-14: Simon Goldschmidt/Stephane Lesage + * ip_addr.h: Improved some defines working on ip addresses, added faster + macro to copy addresses that cannot be NULL + + 2010-02-13: Simon Goldschmidt + * api.h, api_lib.c, api_msg.c, sockets.c: task #7865 (implement non- + blocking send operation) + + 2010-02-12: Simon Goldschmidt + * sockets.c/.h: Added a minimal version of posix fctl() to have a + standardised way to set O_NONBLOCK for nonblocking sockets. + + 2010-02-12: Simon Goldschmidt + * dhcp.c/.h, autoip.c/.h: task #10139 (Prefer statically allocated + memory): added autoip_set_struct() and dhcp_set_struct() to let autoip + and dhcp work with user-allocated structs instead of callin mem_malloc + + 2010-02-12: Simon Goldschmidt/Jeff Barber + * tcp.c/h: patch #6865 (SO_REUSEADDR for TCP): if pcb.so_options has + SOF_REUSEADDR set, allow binding to endpoint in TIME_WAIT + + 2010-02-12: Simon Goldschmidt + * sys layer: task #10139 (Prefer statically allocated memory): converted + mbox and semaphore functions to take pointers to sys_mbox_t/sys_sem_t; + converted sys_mbox_new/sys_sem_new to take pointers and return err_t; + task #7212: Add Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX + to let sys.h use binary semaphores instead of mutexes - as before) + + 2010-02-09: Simon Goldschmidt (Simon Kallweit) + * timers.c/.h: Added function sys_restart_timeouts() from patch #7085 + (Restart system timeout handling) + + 2010-02-09: Simon Goldschmidt + * netif.c/.h, removed loopif.c/.h: task #10153 (Integrate loopif into + netif.c) - loopif does not have to be created by the port any more, + just define LWIP_HAVE_LOOPIF to 1. + + 2010-02-08: Simon Goldschmidt + * inet.h, ip_addr.c/.h: Added reentrant versions of inet_ntoa/ipaddr_ntoa + inet_ntoa_r/ipaddr_ntoa_r + + 2010-02-08: Simon Goldschmidt + * netif.h: Added netif_s/get_igmp_mac_filter() macros + + 2010-02-05: Simon Goldschmidt + * netif.h: Added function-like macros to get/set the hostname on a netif + + 2010-02-04: Simon Goldschmidt + * nearly every file: Replaced struct ip_addr by typedef ip_addr_t to + make changing the actual implementation behind the typedef easier. + + 2010-02-01: Simon Goldschmidt + * opt.h, memp_std.h, dns.h, netdb.c, memp.c: Let netdb use a memp pool + for allocating memory when getaddrinfo() is called. + + 2010-01-31: Simon Goldschmidt + * dhcp.h, dhcp.c: Reworked the code that parses DHCP options: parse + them once instead of parsing for every option. This also removes + the need for mem_malloc from dhcp_recv and makes it possible to + correctly retrieve the BOOTP file. + + 2010-01-30: simon Goldschmidt + * sockets.c: Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect + the sockets array. + + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) + * api.h, api_msg.c, sockets.c: Added except set support in select + (patch #6860) + + 2010-01-29: Simon Goldschmidt (patch by Laura Garrett) + * api.h, sockets.h, err.h, api_lib.c, api_msg.c, sockets.c, err.c: + Add non-blocking support for connect (partly from patch #6860), + plus many cleanups in socket & netconn API. + + 2010-01-27: Simon Goldschmidt + * opt.h, tcp.h, init.c, api_msg.c: Added TCP_SNDQUEUELOWAT corresponding + to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 + + 2010-01-26: Simon Goldschmidt + * snmp: Use memp pools for snmp instead of the heap; added 4 new pools. + + 2010-01-14: Simon Goldschmidt + * ppp.c/.h: Fixed bug #27856: PPP: Set netif link- and status-callback + by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() + + 2010-01-13: Simon Goldschmidt + * mem.c: The heap now may be moved to user-defined memory by defining + LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address + (patch #6966 and bug #26133) + + 2010-01-10: Simon Goldschmidt (Bill Auerbach) + * opt.h, memp.c: patch #6822 (Add option to place memory pools in + separate arrays) + + 2010-01-10: Simon Goldschmidt + * init.c, igmp.c: patch #6463 (IGMP - Adding Random Delay): added define + LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) + + 2009-12-31: Simon Goldschmidt + * tcpip.c, init.c, memp.c, sys.c, memp_std.h, sys.h, tcpip.h + added timers.c/.h: Separated timer implementation from semaphore/mbox + implementation, moved timer implementation to timers.c/.h, timers are + now only called from tcpip_thread or by explicitly checking them. + (TASK#7235) + + 2009-12-27: Simon Goldschmidt + * opt.h, etharp.h/.c, init.c, tcpip.c: Added an additional option + LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) + ++ Bugfixes: + 2011-04-20: Simon Goldschmidt + * sys_arch.txt: sys_arch_timeouts() is not needed any more. + + 2011-04-13: Simon Goldschmidt + * tcp.c, udp.c: Fixed bug #33048 (Bad range for IP source port numbers) by + using ports in the IANA private/dynamic range (49152 through 65535). + + 2011-03-29: Simon Goldschmidt, patch by Emil Lhungdahl: + * etharp.h/.c: Fixed broken VLAN support. + + 2011-03-27: Simon Goldschmidt + * tcp.c: Fixed bug #32926 (TCP_RMV(&tcp_bound_pcbs) is called on unbound tcp + pcbs) by checking if the pcb was bound (local_port != 0). + + 2011-03-27: Simon Goldschmidt + * ppp.c: Fixed bug #32280 (ppp: a pbuf is freed twice) + + 2011-03-27: Simon Goldschmidt + * sockets.c: Fixed bug #32906: lwip_connect+lwip_send did not work for udp and + raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. + + 2011-03-27: Simon Goldschmidt + * tcp_out.c: Fixed bug #32820 (Outgoing TCP connections created before route + is present never times out) by starting retransmission timer before checking + route. + + 2011-03-22: Simon Goldschmidt + * ppp.c: Fixed bug #32648 (PPP code crashes when terminating a link) by only + calling sio_read_abort() if the file descriptor is valid. + + 2011-03-14: Simon Goldschmidt + * err.h/.c, sockets.c, api_msg.c: fixed bug #31748 (Calling non-blocking connect + more than once can render a socket useless) since it mainly involves changing + "FATAL" classification of error codes: ERR_USE and ERR_ISCONN just aren't fatal. + + 2011-03-13: Simon Goldschmidt + * sockets.c: fixed bug #32769 (ESHUTDOWN is linux-specific) by fixing + err_to_errno_table (ERR_CLSD: ENOTCONN instead of ESHUTDOWN), ERR_ISCONN: + use EALRADY instead of -1 + + 2011-03-13: Simon Goldschmidt + * api_lib.c: netconn_accept: return ERR_ABRT instead of ERR_CLSD if the + connection has been aborted by err_tcp (since this is not a normal closing + procedure). + + 2011-03-13: Simon Goldschmidt + * tcp.c: tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind + with pcb->state != CLOSED + + 2011-02-17: Simon Goldschmidt + * rawapi.txt: Fixed bug #32561 tcp_poll argument definition out-of-order in + documentation + + 2011-02-17: Simon Goldschmidt + * many files: Added missing U/UL modifiers to fix 16-bit-arch portability. + + 2011-01-24: Simon Goldschmidt + * sockets.c: Fixed bug #31741: lwip_select seems to have threading problems + + 2010-12-02: Simon Goldschmidt + * err.h: Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. + + 2010-11-23: Simon Goldschmidt + * api.h, api_lib.c, api_msg.c, sockets.c: netconn.recv_avail is only used for + LWIP_SO_RCVBUF and ioctl/FIONREAD. + + 2010-11-23: Simon Goldschmidt + * etharp.c: Fixed bug #31720: ARP-queueing: RFC 1122 recommends to queue at + least 1 packet -> ARP_QUEUEING==0 now queues the most recent packet. + + 2010-11-23: Simon Goldschmidt + * tcp_in.c: Fixed bug #30577: tcp_input: don't discard ACK-only packets after + refusing 'refused_data' again. + + 2010-11-22: Simon Goldschmidt + * sockets.c: Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS + after a successful nonblocking connection. + + 2010-11-22: Simon Goldschmidt + * etharp.c: Fixed bug #31722: IP packets sent with an AutoIP source addr + must be sent link-local + + 2010-11-22: Simon Goldschmidt + * timers.c: patch #7329: tcp_timer_needed prototype was ifdef'ed out for + LWIP_TIMERS==0 + + 2010-11-20: Simon Goldschmidt + * sockets.c: Fixed bug #31170: lwip_setsockopt() does not set socket number + + 2010-11-20: Simon Goldschmidt + * sockets.h: Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to + resemble other stacks. + + 2010-11-20: Simon Goldschmidt + * dns.c: Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else + no-copy TCP writes will never succeed. + + 2010-11-20: Simon Goldschmidt + * dns.c: Fixed bug #31701: Error return value from dns_gethostbyname() does + not match documentation: return ERR_ARG instead of ERR_VAL if not + initialized or wrong argument. + + 2010-10-20: Simon Goldschmidt + * sockets.h: Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 + + 2010-10-05: Simon Goldschmidt + * dhcp.c: Once again fixed #30038: DHCP/AutoIP cooperation failed when + replugging the network cable after an AutoIP address was assigned. + + 2010-08-10: Simon Goldschmidt + * tcp.c: Fixed bug #30728: tcp_new_port() did not check listen pcbs + + 2010-08-03: Simon Goldschmidt + * udp.c, raw.c: Don't chain empty pbufs when sending them (fixes bug #30625) + + 2010-08-01: Simon Goldschmidt (patch by Greg Renda) + * ppp.c: Applied patch #7264 (PPP protocols are rejected incorrectly on big + endian architectures) + + 2010-07-28: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, mib2.c: Fixed compilation with TCP or UDP + disabled. + + 2010-07-27: Simon Goldschmidt + * tcp.c: Fixed bug #30565 (tcp_connect() check bound list): that check did no + harm but never did anything + + 2010-07-21: Simon Goldschmidt + * ip.c: Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not + add IP options) + + 2010-07-16: Kieran Mansley + * msg_in.c: Fixed SNMP ASN constant defines to not use ! operator + + 2010-07-10: Simon Goldschmidt + * ip.c: Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options + + 2010-06-30: Simon Goldschmidt + * api_msg.c: fixed bug #30300 (shutdown parameter was not initialized in + netconn_delete) + + 2010-06-28: Kieran Mansley + * timers.c remove unportable printing of C function pointers + + 2010-06-24: Simon Goldschmidt + * init.c, timers.c/.h, opt.h, memp_std.h: From patch #7221: added flag + NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading + + 2010-06-24: Simon Goldschmidt + * api(_lib).c/.h, api_msg.c/.h, sockets.c/.h: Fixed bug #10088: Correctly + implemented shutdown at socket level. + + 2010-06-21: Simon Goldschmidt + * pbuf.c/.h, ip_frag.c/.h, opt.h, memp_std.h: Fixed bug #29361 (ip_frag has + problems with zero-copy DMA MACs) by adding custom pbufs and implementing + custom pbufs that reference other (original) pbufs. Additionally set + IP_FRAG_USES_STATIC_BUF=0 as default to be on the safe side. + + 2010-06-15: Simon Goldschmidt + * dhcp.c: Fixed bug #29970: DHCP endian issue parsing option responses + + 2010-06-14: Simon Goldschmidt + * autoip.c: Fixed bug #30039: AutoIP does not reuse previous addresses + + 2010-06-12: Simon Goldschmidt + * dhcp.c: Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop + state + + 2010-05-17: Simon Goldschmidt + * netdb.c: Correctly NULL-terminate h_addr_list + + 2010-05-16: Simon Goldschmidt + * def.h/.c: changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent + "symbol already defined" i.e. when linking to winsock + + 2010-05-05: Simon Goldschmidt + * def.h, timers.c: Fixed bug #29769 (sys_check_timeouts: sys_now() may + overflow) + + 2010-04-21: Simon Goldschmidt + * api_msg.c: Fixed bug #29617 (sometime cause stall on delete listening + connection) + + 2010-03-28: Luca Ceresoli + * ip_addr.c/.h: patch #7143: Add a few missing const qualifiers + + 2010-03-27: Luca Ceresoli + * mib2.c: patch #7130: remove meaningless const qualifiers + + 2010-03-26: Simon Goldschmidt + * tcp_out.c: Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too + + 2010-03-26: Simon Goldschmidt + * various files: Fixed compiling with different options disabled (TCP/UDP), + triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled + + 2010-03-25: Simon Goldschmidt + * sockets.c: Fixed bug #29332: lwip_select() processes readset incorrectly + + 2010-03-25: Simon Goldschmidt + * tcp_in.c, test_tcp_oos.c: Fixed bug #29080: Correctly handle remote side + overrunning our rcv_wnd in ooseq case. + + 2010-03-22: Simon Goldschmidt + * tcp.c: tcp_listen() did not copy the pcb's prio. + + 2010-03-19: Simon Goldschmidt + * snmp_msg.c: Fixed bug #29256: SNMP Trap address was not correctly set + + 2010-03-14: Simon Goldschmidt + * opt.h, etharp.h: Fixed bug #29148 (Incorrect PBUF_POOL_BUFSIZE for ports + where ETH_PAD_SIZE > 0) by moving definition of ETH_PAD_SIZE to opt.h + and basing PBUF_LINK_HLEN on it. + + 2010-03-08: Simon Goldschmidt + * netif.c, ipv4/ip.c: task #10241 (AutoIP: don't break existing connections + when assiging routable address): when checking incoming packets and + aborting existing connection on address change, filter out link-local + addresses. + + 2010-03-06: Simon Goldschmidt + * sockets.c: Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING + + 2010-03-06: Simon Goldschmidt + * ipv4/ip.c: Don't try to forward link-local addresses + + 2010-03-06: Simon Goldschmidt + * etharp.c: Fixed bug #29087: etharp: don't send packets for LinkLocal- + addresses to gw + + 2010-03-05: Simon Goldschmidt + * dhcp.c: Fixed bug #29072: Correctly set ciaddr based on message-type + and state. + + 2010-03-05: Simon Goldschmidt + * api_msg.c: Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split + into multiple calls to tcp_write. + + 2010-02-21: Simon Goldschmidt + * opt.h, mem.h, dns.c: task #10140: Remove DNS_USES_STATIC_BUF (keep + the implementation of DNS_USES_STATIC_BUF==1) + + 2010-02-20: Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c, tcp_out.c: Task #10088: Correctly implement + close() vs. shutdown(). Now the application does not get any more + recv callbacks after calling tcp_close(). Added tcp_shutdown(). + + 2010-02-19: Simon Goldschmidt + * mem.c/.h, pbuf.c: Renamed mem_realloc() to mem_trim() to prevent + confusion with realloc() + + 2010-02-15: Simon Goldschmidt/Stephane Lesage + * netif.c/.h: Link status does not depend on LWIP_NETIF_LINK_CALLBACK + (fixes bug #28899) + + 2010-02-14: Simon Goldschmidt + * netif.c: Fixed bug #28877 (Duplicate ARP gratuitous packet with + LWIP_NETIF_LINK_CALLBACK set on) by only sending if both link- and + admin-status of a netif are up + + 2010-02-14: Simon Goldschmidt + * opt.h: Disable ETHARP_TRUST_IP_MAC by default since it slows down packet + reception and is not really necessary + + 2010-02-14: Simon Goldschmidt + * etharp.c/.h: Fixed ARP input processing: only add a new entry if a + request was directed as us (RFC 826, Packet Reception), otherwise + only update existing entries; internalized some functions + + 2010-02-14: Simon Goldschmidt + * netif.h, etharp.c, tcpip.c: Fixed bug #28183 (ARP and TCP/IP cannot be + disabled on netif used for PPPoE) by adding a new netif flag + (NETIF_FLAG_ETHERNET) that tells the stack the device is an ethernet + device but prevents usage of ARP (so that ethernet_input can be used + for PPPoE). + + 2010-02-12: Simon Goldschmidt + * netif.c: netif_set_link_up/down: only do something if the link state + actually changes + + 2010-02-12: Simon Goldschmidt/Stephane Lesage + * api_msg.c: Fixed bug #28865 (Cannot close socket/netconn in non-blocking + connect) + + 2010-02-12: Simon Goldschmidt + * mem.h: Fixed bug #28866 (mem_realloc function defined in mem.h) + + 2010-02-09: Simon Goldschmidt + * api_lib.c, api_msg.c, sockets.c, api.h, api_msg.h: Fixed bug #22110 + (recv() makes receive window update for data that wasn't received by + application) + + 2010-02-09: Simon Goldschmidt/Stephane Lesage + * sockets.c: Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out + or any netconn_recv() error) + + 2010-02-09: Simon Goldschmidt + * ppp.c: task #10154 (PPP: Update snmp in/out counters for tx/rx packets) + + 2010-02-09: Simon Goldschmidt + * netif.c: For loopback packets, adjust the stats- and snmp-counters + for the loopback netif. + + 2010-02-08: Simon Goldschmidt + * igmp.c/.h, ip.h: Moved most defines from igmp.h to igmp.c for clarity + since they are not used anywhere else. + + 2010-02-08: Simon Goldschmidt (Stéphane Lesage) + * igmp.c, igmp.h, stats.c, stats.h: Improved IGMP stats + (patch from bug #28798) + + 2010-02-08: Simon Goldschmidt (Stéphane Lesage) + * igmp.c: Fixed bug #28798 (Error in "Max Response Time" processing) and + another bug when LWIP_RAND() returns zero. + + 2010-02-04: Simon Goldschmidt + * nearly every file: Use macros defined in ip_addr.h (some of them new) + to work with IP addresses (preparation for bug #27352 - Change ip_addr + from struct to typedef (u32_t) - and better code). + + 2010-01-31: Simon Goldschmidt + * netif.c: Don't call the link-callback from netif_set_up/down() since + this invalidly retriggers DHCP. + + 2010-01-29: Simon Goldschmidt + * ip_addr.h, inet.h, def.h, inet.c, def.c, more: Cleanly separate the + portability file inet.h and its contents from the stack: moved htonX- + functions to def.h (and the new def.c - they are not ipv4 dependent), + let inet.h depend on ip_addr.h and not the other way round. + This fixes bug #28732. + + 2010-01-28: Kieran Mansley + * tcp.c: Ensure ssthresh >= 2*MSS + + 2010-01-27: Simon Goldschmidt + * tcp.h, tcp.c, tcp_in.c: Fixed bug #27871: Calling tcp_abort() in recv + callback can lead to accessing unallocated memory. As a consequence, + ERR_ABRT means the application has called tcp_abort()! + + 2010-01-25: Simon Goldschmidt + * snmp_structs.h, msg_in.c: Partly fixed bug #22070 (MIB_OBJECT_WRITE_ONLY + not implemented in SNMP): write-only or not-accessible are still + returned by getnext (though not by get) + + 2010-01-24: Simon Goldschmidt + * snmp: Renamed the private mib node from 'private' to 'mib_private' to + not use reserved C/C++ keywords + + 2010-01-23: Simon Goldschmidt + * sockets.c: Fixed bug #28716: select() returns 0 after waiting for less + than 1 ms + + 2010-01-21: Simon Goldschmidt + * tcp.c, api_msg.c: Fixed bug #28651 (tcp_connect: no callbacks called + if tcp_enqueue fails) both in raw- and netconn-API + + 2010-01-19: Simon Goldschmidt + * api_msg.c: Fixed bug #27316: netconn: Possible deadlock in err_tcp + + 2010-01-18: Iordan Neshev/Simon Goldschmidt + * src/netif/ppp: reorganised PPP sourcecode to 2.3.11 including some + bugfix backports from 2.4.x. + + 2010-01-18: Simon Goldschmidt + * mem.c: Fixed bug #28679: mem_realloc calculates mem_stats wrong + + 2010-01-17: Simon Goldschmidt + * api_lib.c, api_msg.c, (api_msg.h, api.h, sockets.c, tcpip.c): + task #10102: "netconn: clean up conn->err threading issues" by adding + error return value to struct api_msg_msg + + 2010-01-17: Simon Goldschmidt + * api.h, api_lib.c, sockets.c: Changed netconn_recv() and netconn_accept() + to return err_t (bugs #27709 and #28087) + + 2010-01-14: Simon Goldschmidt + * ...: Use typedef for function prototypes throughout the stack. + + 2010-01-13: Simon Goldschmidt + * api_msg.h/.c, api_lib.c: Fixed bug #26672 (close connection when receive + window = 0) by correctly draining recvmbox/acceptmbox + + 2010-01-11: Simon Goldschmidt + * pap.c: Fixed bug #13315 (PPP PAP authentication can result in + erroneous callbacks) by copying the code from recent pppd + + 2010-01-10: Simon Goldschmidt + * raw.c: Fixed bug #28506 (raw_bind should filter received packets) + + 2010-01-10: Simon Goldschmidt + * tcp.h/.c: bug #28127 (remove call to tcp_output() from tcp_ack(_now)()) + + 2010-01-08: Simon Goldschmidt + * sockets.c: Fixed bug #28519 (lwip_recvfrom bug with len > 65535) + + 2010-01-08: Simon Goldschmidt + * dns.c: Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string + passed to dns_local_addhost() might be volatile + + 2010-01-07: Simon Goldschmidt + * timers.c, tcp.h: Call tcp_timer_needed() with NO_SYS==1, too + + 2010-01-06: Simon Goldschmidt + * netdb.h: Fixed bug #28496: missing include guards in netdb.h + + 2009-12-31: Simon Goldschmidt + * many ppp files: Reorganised PPP source code from ucip structure to pppd + structure to easily compare our code against the pppd code (around v2.3.1) + + 2009-12-27: Simon Goldschmidt + * tcp_in.c: Another fix for bug #28241 (ooseq processing) and adapted + unit test + (STABLE-1.3.2) diff --git a/core/lwip/UPGRADING b/core/lwip/UPGRADING new file mode 100644 index 00000000..6501107a --- /dev/null +++ b/core/lwip/UPGRADING @@ -0,0 +1,144 @@ +This file lists major changes between release versions that require +ports or applications to be changed. Use it to update a port or an +application written for an older version of lwIP to correctly work +with newer versions. + + +(CVS HEAD) + + * [Enter new changes just after this line - do not remove this line] + + ++ Application changes: + + * Replaced struct ip_addr by typedef ip_addr_t (struct ip_addr is kept for + compatibility to old applications, but will be removed in the future). + + * Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() + + +++ Raw API: + * Changed the semantics of tcp_close() (since it was rather a + shutdown before): Now the application does *NOT* get any calls to the recv + callback (aside from NULL/closed) after calling tcp_close() + + * When calling tcp_abort() from a raw API TCP callback function, + make sure you return ERR_ABRT to prevent accessing unallocated memory. + (ERR_ABRT now means the applicaiton has called tcp_abort!) + + +++ Netconn API: + * Changed netconn_receive() and netconn_accept() to return + err_t, not a pointer to new data/netconn. + + +++ Socket API: + * LWIP_SO_RCVTIMEO: when accept() or recv() time out, they + now set errno to EWOULDBLOCK/EAGAIN, not ETIMEDOUT. + + * Added a minimal version of posix fctl() to have a + standardised way to set O_NONBLOCK for nonblocking sockets. + + +++ all APIs: + * correctly implemented SO(F)_REUSEADDR + + ++ Port changes + + +++ new files: + + * Added 4 new files: def.c, timers.c, timers.h, tcp_impl.h: + + * Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains + the actual application programmer's API + + * Separated timer implementation from sys.h/.c, moved to timers.h/.c; + Added timer implementation for NO_SYS==1, set NO_SYS_NO_TIMERS==1 if you + still want to use your own timer implementation for NO_SYS==0 (as before). + + +++ sys layer: + + * Converted mbox- and semaphore-functions to take pointers to sys_mbox_t/ + sys_sem_t; + + * Converted sys_mbox_new/sys_sem_new to take pointers and return err_t; + + * Added Mutex concept in sys_arch (define LWIP_COMPAT_MUTEX to let sys.h use + binary semaphores instead of mutexes - as before) + + +++ new options: + + * Don't waste memory when chaining segments, added option TCP_OVERSIZE to + prevent creating many small pbufs when calling tcp_write with many small + blocks of data. Instead, pbufs are allocated larger than needed and the + space is used for later calls to tcp_write. + + * Added LWIP_NETIF_TX_SINGLE_PBUF to always copy to try to create single pbufs + in tcp_write/udp_send. + + * Added an additional option LWIP_ETHERNET to support ethernet without ARP + (necessary for pure PPPoE) + + * Add MEMP_SEPARATE_POOLS to place memory pools in separate arrays. This may + be used to place these pools into user-defined memory by using external + declaration. + + * Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT + + +++ new pools: + + * Netdb uses a memp pool for allocating memory when getaddrinfo() is called, + so MEMP_NUM_NETDB has to be set accordingly. + + * DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses a memp pool instead of the heap, so + MEMP_NUM_LOCALHOSTLIST has to be set accordingly. + + * Snmp-agent uses a memp pools instead of the heap, so MEMP_NUM_SNMP_* have + to be set accordingly. + + * PPPoE uses a MEMP pool instead of the heap, so MEMP_NUM_PPPOE_INTERFACES + has to be set accordingly + + * Integrated loopif into netif.c - loopif does not have to be created by the + port any more, just define LWIP_HAVE_LOOPIF to 1. + + * Added define LWIP_RAND() for lwip-wide randomization (needs to be defined + in cc.h, e.g. used by igmp) + + * Added printf-formatter X8_F to printf u8_t as hex + + * The heap now may be moved to user-defined memory by defining + LWIP_RAM_HEAP_POINTER as a void pointer to that memory's address + + * added autoip_set_struct() and dhcp_set_struct() to let autoip and dhcp work + with user-allocated structs instead of calling mem_malloc + + * Added const char* name to mem- and memp-stats for easier debugging. + + * Calculate the TCP/UDP checksum while copying to only fetch data once: + Define LWIP_CHKSUM_COPY to a memcpy-like function that returns the checksum + + * Added SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to + more than one pcb. + + * Changed the semantics of ARP_QUEUEING==0: ARP_QUEUEING now cannot be turned + off any more, if this is set to 0, only one packet (the most recent one) is + queued (like demanded by RFC 1122). + + + ++ Major bugfixes/improvements + + * Implemented tcp_shutdown() to only shut down one end of a connection + * Implemented shutdown() at socket- and netconn-level + * Added errorset support to select() + improved select speed overhead + * Merged pppd to v2.3.11 (including some backported bugfixes from 2.4.x) + * Added timer implementation for NO_SYS==1 (may be disabled with NO_SYS_NO_TIMERS==1 + * Use macros defined in ip_addr.h to work with IP addresses + * Implemented many nonblocking socket/netconn functions + * Fixed ARP input processing: only add a new entry if a request was directed as us + * mem_realloc() to mem_trim() to prevent confusion with realloc() + * Some improvements for AutoIP (don't route/forward link-local addresses, don't break + existing connections when assigning a routable address) + * Correctly handle remote side overrunning our rcv_wnd in ooseq case + * Removed packing from ip_addr_t, the packed version is now only used in protocol headers + * Corrected PBUF_POOL_BUFSIZE for ports where ETH_PAD_SIZE > 0 + * Added support for static ARP table entries + +(STABLE-1.3.2) + + * initial version of this file diff --git a/core/lwip/doc/rawapi.txt b/core/lwip/doc/rawapi.txt index 25fdc2e8..c727da99 100644 --- a/core/lwip/doc/rawapi.txt +++ b/core/lwip/doc/rawapi.txt @@ -251,8 +251,9 @@ if a call to tcp_write() has failed because memory wasn't available, the application may use the polling functionality to call tcp_write() again when the connection has been idle for a while. -- void tcp_poll(struct tcp_pcb *pcb, u8_t interval, - err_t (* poll)(void *arg, struct tcp_pcb *tpcb)) +- void tcp_poll(struct tcp_pcb *pcb, + err_t (* poll)(void *arg, struct tcp_pcb *tpcb), + u8_t interval) Specifies the polling interval and the callback function that should be called to poll the application. The interval is specified in @@ -278,6 +279,11 @@ again when the connection has been idle for a while. Aborts the connection by sending a RST (reset) segment to the remote host. The pcb is deallocated. This function never fails. + ATTENTION: When calling this from one of the TCP callbacks, make + sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + or you will risk accessing deallocated memory or memory leaks! + + If a connection is aborted because of an error, the application is alerted of this event by the err callback. Errors that might abort a connection are when there is a shortage of memory. The callback @@ -476,3 +482,24 @@ to match your application and network. For a production release it is recommended to set LWIP_STATS to 0. Note that speed performance isn't influenced much by simply setting high values to the memory options. + +For more optimization hints take a look at the lwIP wiki. + +--- Zero-copy MACs + +To achieve zero-copy on transmit, the data passed to the raw API must +remain unchanged until sent. Because the send- (or write-)functions return +when the packets have been enqueued for sending, data must be kept stable +after that, too. + +This implies that PBUF_RAM/PBUF_POOL pbufs passed to raw-API send functions +must *not* be reused by the application unless their ref-count is 1. + +For no-copy pbufs (PBUF_ROM/PBUF_REF), data must be kept unchanged, too, +but the stack/driver will/must copy PBUF_REF'ed data when enqueueing, while +PBUF_ROM-pbufs are just enqueued (as ROM-data is expected to never change). + +Also, data passed to tcp_write without the copy-flag must not be changed! + +Therefore, be careful which type of PBUF you use and if you copy TCP data +or not! diff --git a/core/lwip/doc/snmp_agent.txt b/core/lwip/doc/snmp_agent.txt index 9b58616a..2653230f 100644 --- a/core/lwip/doc/snmp_agent.txt +++ b/core/lwip/doc/snmp_agent.txt @@ -46,7 +46,7 @@ Loading additional MIBs Large SNMP message support The packet decoding and encoding routines are designed - to use pbuf-chains. Larger payloads then the minimum + to use pbuf-chains. Larger payloads than the minimum SNMP requirement of 484 octets are supported if the PBUF_POOL_SIZE and IP_REASS_BUFSIZE are set to match your local requirement. @@ -170,7 +170,7 @@ resembles the "auto-completion" operation) The middle part is usually located in ROM (const) to preserve precious RAM on small microcontrollers. -However RAM location is possible for an dynamically +However RAM location is possible for a dynamically changing private tree. The index part is handled by functions which in diff --git a/core/lwip/doc/sys_arch.txt b/core/lwip/doc/sys_arch.txt index cac4c626..4eb93078 100644 --- a/core/lwip/doc/sys_arch.txt +++ b/core/lwip/doc/sys_arch.txt @@ -123,18 +123,6 @@ The following functions must be implemented by the sys_arch: sys_arch_mbox_fetch(mbox,msg,1) although this would introduce unnecessary delays. -- struct sys_timeouts *sys_arch_timeouts(void) - - Returns a pointer to the per-thread sys_timeouts structure. In lwIP, - each thread has a list of timeouts which is repressented as a linked - list of sys_timeout structures. The sys_timeouts structure holds a - pointer to a linked list of timeouts. This function is called by - the lwIP timeout scheduler and must not return a NULL value. - - In a single thread sys_arch implementation, this function will - simply return a pointer to a global sys_timeouts variable stored in - the sys_arch module. - If threads are supported by the underlying operating system and if such functionality is needed in lwIP, the following function will have to be implemented as well: diff --git a/core/lwip/src/api/api_lib.c b/core/lwip/src/api/api_lib.c index 195a9a52..b1a9e525 100644 --- a/core/lwip/src/api/api_lib.c +++ b/core/lwip/src/api/api_lib.c @@ -71,19 +71,19 @@ netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, netconn_cal struct api_msg msg; conn = netconn_alloc(t, callback); - if (conn != NULL ) { + if (conn != NULL) { msg.function = do_newconn; msg.msg.msg.n.proto = proto; msg.msg.conn = conn; - TCPIP_APIMSG(&msg); - - if (conn->err != ERR_OK) { + if (TCPIP_APIMSG(&msg) != ERR_OK) { LWIP_ASSERT("freeing conn without freeing pcb", conn->pcb.tcp == NULL); - LWIP_ASSERT("conn has no op_completed", conn->op_completed != SYS_SEM_NULL); - LWIP_ASSERT("conn has no recvmbox", conn->recvmbox != SYS_MBOX_NULL); - LWIP_ASSERT("conn->acceptmbox shouldn't exist", conn->acceptmbox == SYS_MBOX_NULL); - sys_sem_free(conn->op_completed); - sys_mbox_free(conn->recvmbox); + LWIP_ASSERT("conn has no op_completed", sys_sem_valid(&conn->op_completed)); + LWIP_ASSERT("conn has no recvmbox", sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("conn->acceptmbox shouldn't exist", !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + sys_sem_free(&conn->op_completed); + sys_mbox_free(&conn->recvmbox); memp_free(MEMP_NETCONN, conn); return NULL; } @@ -113,9 +113,10 @@ netconn_delete(struct netconn *conn) msg.msg.conn = conn; tcpip_apimsg(&msg); - conn->pcb.tcp = NULL; netconn_free(conn); + /* don't care for return value of do_delconn since it only calls void functions */ + return ERR_OK; } @@ -131,9 +132,10 @@ netconn_delete(struct netconn *conn) * ERR_OK if the information was retrieved */ err_t -netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t local) +netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;); @@ -144,9 +146,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo msg.msg.msg.ad.ipaddr = addr; msg.msg.msg.ad.port = port; msg.msg.msg.ad.local = local; - TCPIP_APIMSG(&msg); + err = TCPIP_APIMSG(&msg); - return conn->err; + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** @@ -160,9 +163,10 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo * @return ERR_OK if bound, any other err_t on failure */ err_t -netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) +netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_bind: invalid conn", (conn != NULL), return ERR_ARG;); @@ -170,8 +174,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) msg.msg.conn = conn; msg.msg.msg.bc.ipaddr = addr; msg.msg.msg.bc.port = port; - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** @@ -183,9 +189,10 @@ netconn_bind(struct netconn *conn, struct ip_addr *addr, u16_t port) * @return ERR_OK if connected, return value of tcp_/udp_/raw_connect otherwise */ err_t -netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) +netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_connect: invalid conn", (conn != NULL), return ERR_ARG;); @@ -194,8 +201,10 @@ netconn_connect(struct netconn *conn, struct ip_addr *addr, u16_t port) msg.msg.msg.bc.ipaddr = addr; msg.msg.msg.bc.port = port; /* This is the only function which need to not block tcpip_thread */ - tcpip_apimsg(&msg); - return conn->err; + err = tcpip_apimsg(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** @@ -208,13 +217,16 @@ err_t netconn_disconnect(struct netconn *conn) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_disconnect: invalid conn", (conn != NULL), return ERR_ARG;); msg.function = do_disconnect; msg.msg.conn = conn; - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** @@ -228,7 +240,9 @@ netconn_disconnect(struct netconn *conn) err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) { +#if LWIP_TCP struct api_msg msg; + err_t err; /* This does no harm. If TCP_LISTEN_BACKLOG is off, backlog is unused. */ LWIP_UNUSED_ARG(backlog); @@ -240,156 +254,276 @@ netconn_listen_with_backlog(struct netconn *conn, u8_t backlog) #if TCP_LISTEN_BACKLOG msg.msg.msg.lb.backlog = backlog; #endif /* TCP_LISTEN_BACKLOG */ - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(backlog); + return ERR_ARG; +#endif /* LWIP_TCP */ } /** * Accept a new connection on a TCP listening netconn. * * @param conn the TCP listen netconn - * @return the newly accepted netconn or NULL on timeout + * @param new_conn pointer where the new connection is stored + * @return ERR_OK if a new connection has been received or an error + * code otherwise */ -struct netconn * -netconn_accept(struct netconn *conn) +err_t +netconn_accept(struct netconn *conn, struct netconn **new_conn) { +#if LWIP_TCP struct netconn *newconn; + err_t err; +#if TCP_LISTEN_BACKLOG + struct api_msg msg; +#endif /* TCP_LISTEN_BACKLOG */ + + LWIP_ERROR("netconn_accept: invalid pointer", (new_conn != NULL), return ERR_ARG;); + *new_conn = NULL; + LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid acceptmbox", sys_mbox_valid(&conn->acceptmbox), return ERR_ARG;); - LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;); - LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;); + err = conn->last_err; + if (ERR_IS_FATAL(err)) { + /* don't recv on fatal errors: this might block the application task + waiting on acceptmbox forever! */ + return err; + } #if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { - newconn = NULL; - } else + if (sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); + return ERR_TIMEOUT; + } #else - sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0); + sys_arch_mbox_fetch(&conn->acceptmbox, (void **)&newconn, 0); #endif /* LWIP_SO_RCVTIMEO*/ - { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + if (newconn == NULL) { + /* connection has been aborted */ + NETCONN_SET_SAFE_ERR(conn, ERR_ABRT); + return ERR_ABRT; + } #if TCP_LISTEN_BACKLOG - if (newconn != NULL) { - /* Let the stack know that we have accepted the connection. */ - struct api_msg msg; - msg.function = do_recv; - msg.msg.conn = conn; - TCPIP_APIMSG(&msg); - } + /* Let the stack know that we have accepted the connection. */ + msg.function = do_recv; + msg.msg.conn = conn; + /* don't care for the return value of do_recv */ + TCPIP_APIMSG(&msg); #endif /* TCP_LISTEN_BACKLOG */ - } - return newconn; + *new_conn = newconn; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(new_conn); + return ERR_ARG; +#endif /* LWIP_TCP */ } /** - * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * Receive data: actual implementation that doesn't care whether pbuf or netbuf + * is received * * @param conn the netconn from which to receive data - * @return a new netbuf containing received data or NULL on memory error or timeout + * @param new_buf pointer where a new pbuf/netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) */ -struct netbuf * -netconn_recv(struct netconn *conn) +static err_t +netconn_recv_data(struct netconn *conn, void **new_buf) { - struct api_msg msg; - struct netbuf *buf = NULL; - struct pbuf *p; + void *buf = NULL; u16_t len; + err_t err; +#if LWIP_TCP + struct api_msg msg; +#endif /* LWIP_TCP */ - LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;); - - if (conn->recvmbox == SYS_MBOX_NULL) { - /* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */ - /* TCP listen conns don't have a recvmbox! */ - conn->err = ERR_CONN; - return NULL; + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); + + err = conn->last_err; + if (ERR_IS_FATAL(err)) { + /* don't recv on fatal errors: this might block the application task + waiting on recvmbox forever! */ + /* @todo: this does not allow us to fetch data that has been put into recvmbox + before the fatal error occurred - is that a problem? */ + return err; } - if (ERR_IS_FATAL(conn->err)) { - return NULL; +#if LWIP_SO_RCVTIMEO + if (sys_arch_mbox_fetch(&conn->recvmbox, &buf, conn->recv_timeout) == SYS_ARCH_TIMEOUT) { + NETCONN_SET_SAFE_ERR(conn, ERR_TIMEOUT); + return ERR_TIMEOUT; } +#else + sys_arch_mbox_fetch(&conn->recvmbox, &buf, 0); +#endif /* LWIP_SO_RCVTIMEO*/ - if (conn->type == NETCONN_TCP) { #if LWIP_TCP - if (conn->state == NETCONN_LISTEN) { - /* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */ - conn->err = ERR_CONN; - return NULL; + if (conn->type == NETCONN_TCP) { + if (!netconn_get_noautorecved(conn) || (buf == NULL)) { + /* Let the stack know that we have taken the data. */ + /* TODO: Speedup: Don't block and wait for the answer here + (to prevent multiple thread-switches). */ + msg.function = do_recv; + msg.msg.conn = conn; + if (buf != NULL) { + msg.msg.msg.r.len = ((struct pbuf *)buf)->tot_len; + } else { + msg.msg.msg.r.len = 1; + } + /* don't care for the return value of do_recv */ + TCPIP_APIMSG(&msg); } - buf = memp_malloc(MEMP_NETBUF); - + /* If we are closed, we indicate that we no longer wish to use the socket */ if (buf == NULL) { - conn->err = ERR_MEM; - return NULL; + API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0); + /* Avoid to lose any previous error code */ + NETCONN_SET_SAFE_ERR(conn, ERR_CLSD); + return ERR_CLSD; } + len = ((struct pbuf *)buf)->tot_len; + } +#endif /* LWIP_TCP */ +#if LWIP_TCP && (LWIP_UDP || LWIP_RAW) + else +#endif /* LWIP_TCP && (LWIP_UDP || LWIP_RAW) */ +#if (LWIP_UDP || LWIP_RAW) + { + LWIP_ASSERT("buf != NULL", buf != NULL); + len = netbuf_len((struct netbuf *)buf); + } +#endif /* (LWIP_UDP || LWIP_RAW) */ -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { - memp_free(MEMP_NETBUF, buf); - conn->err = ERR_TIMEOUT; - return NULL; - } -#else - sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0); -#endif /* LWIP_SO_RCVTIMEO*/ +#if LWIP_SO_RCVBUF + SYS_ARCH_DEC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ + /* Register event with callback */ + API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); - if (p != NULL) { - len = p->tot_len; - SYS_ARCH_DEC(conn->recv_avail, len); - } else { - len = 0; - } + LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len)); - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, len); + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; +} - /* If we are closed, we indicate that we no longer wish to use the socket */ - if (p == NULL) { +/** + * Receive data (in form of a pbuf) from a TCP netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new pbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + * ERR_ARG if conn is not a TCP netconn + */ +err_t +netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf) +{ + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL) && + netconn_type(conn) == NETCONN_TCP, return ERR_ARG;); + + return netconn_recv_data(conn, (void **)new_buf); +} + +/** + * Receive data (in form of a netbuf containing a packet buffer) from a netconn + * + * @param conn the netconn from which to receive data + * @param new_buf pointer where a new netbuf is stored when received data + * @return ERR_OK if data has been received, an error code otherwise (timeout, + * memory error or another error) + */ +err_t +netconn_recv(struct netconn *conn, struct netbuf **new_buf) +{ +#if LWIP_TCP + struct netbuf *buf = NULL; + err_t err; +#endif /* LWIP_TCP */ + + LWIP_ERROR("netconn_recv: invalid pointer", (new_buf != NULL), return ERR_ARG;); + *new_buf = NULL; + LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return ERR_ARG;); + LWIP_ERROR("netconn_accept: invalid recvmbox", sys_mbox_valid(&conn->recvmbox), return ERR_CONN;); + +#if LWIP_TCP + if (conn->type == NETCONN_TCP) { + struct pbuf *p = NULL; + /* This is not a listening netconn, since recvmbox is set */ + + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); + if (buf == NULL) { + NETCONN_SET_SAFE_ERR(conn, ERR_MEM); + return ERR_MEM; + } + + err = netconn_recv_data(conn, (void **)&p); + if (err != ERR_OK) { memp_free(MEMP_NETBUF, buf); - /* Avoid to lose any previous error code */ - if (conn->err == ERR_OK) { - conn->err = ERR_CLSD; - } - return NULL; + return err; } + LWIP_ASSERT("p != NULL", p != NULL); buf->p = p; buf->ptr = p; buf->port = 0; - buf->addr = NULL; + ip_addr_set_any(&buf->addr); + *new_buf = buf; + /* don't set conn->last_err: it's only ERR_OK, anyway */ + return ERR_OK; + } else +#endif /* LWIP_TCP */ + { +#if (LWIP_UDP || LWIP_RAW) + return netconn_recv_data(conn, (void **)new_buf); +#endif /* (LWIP_UDP || LWIP_RAW) */ + } +} +/** + * TCP: update the receive window: by calling this, the application + * tells the stack that it has processed data and is able to accept + * new data. + * ATTENTION: use with care, this is mainly used for sockets! + * Can only be used when calling netconn_set_noautorecved(conn, 1) before. + * + * @param conn the netconn for which to update the receive window + * @param length amount of data processed (ATTENTION: this must be accurate!) + */ +void +netconn_recved(struct netconn *conn, u32_t length) +{ +#if LWIP_TCP + if ((conn != NULL) && (conn->type == NETCONN_TCP) && + (netconn_get_noautorecved(conn))) { + struct api_msg msg; /* Let the stack know that we have taken the data. */ + /* TODO: Speedup: Don't block and wait for the answer here + (to prevent multiple thread-switches). */ msg.function = do_recv; msg.msg.conn = conn; - if (buf != NULL) { - msg.msg.msg.r.len = buf->p->tot_len; - } else { - msg.msg.msg.r.len = 1; - } + msg.msg.msg.r.len = length; + /* don't care for the return value of do_recv */ TCPIP_APIMSG(&msg); -#endif /* LWIP_TCP */ - } else { -#if (LWIP_UDP || LWIP_RAW) -#if LWIP_SO_RCVTIMEO - if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, conn->recv_timeout)==SYS_ARCH_TIMEOUT) { - buf = NULL; - } -#else - sys_arch_mbox_fetch(conn->recvmbox, (void *)&buf, 0); -#endif /* LWIP_SO_RCVTIMEO*/ - if (buf!=NULL) { - SYS_ARCH_DEC(conn->recv_avail, buf->p->tot_len); - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVMINUS, buf->p->tot_len); - } -#endif /* (LWIP_UDP || LWIP_RAW) */ } - - LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err)); - - return buf; +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(conn); + LWIP_UNUSED_ARG(length); +#endif /* LWIP_TCP */ } /** @@ -403,10 +537,10 @@ netconn_recv(struct netconn *conn) * @return ERR_OK if data was sent, any other err_t on error */ err_t -netconn_sendto(struct netconn *conn, struct netbuf *buf, struct ip_addr *addr, u16_t port) +netconn_sendto(struct netconn *conn, struct netbuf *buf, ip_addr_t *addr, u16_t port) { if (buf != NULL) { - buf->addr = addr; + ip_addr_set(&buf->addr, addr); buf->port = port; return netconn_send(conn, buf); } @@ -424,6 +558,7 @@ err_t netconn_send(struct netconn *conn, struct netbuf *buf) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_send: invalid conn", (conn != NULL), return ERR_ARG;); @@ -431,8 +566,10 @@ netconn_send(struct netconn *conn, struct netbuf *buf) msg.function = do_send; msg.msg.conn = conn; msg.msg.msg.b = buf; - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** @@ -442,18 +579,25 @@ netconn_send(struct netconn *conn, struct netbuf *buf) * @param dataptr pointer to the application buffer that contains the data to send * @param size size of the application data to send * @param apiflags combination of following flags : - * - NETCONN_COPY (0x01) data will be copied into memory belonging to the stack - * - NETCONN_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_COPY: data will be copied into memory belonging to the stack + * - NETCONN_MORE: for TCP connection, PSH flag will be set on last segment sent + * - NETCONN_DONTBLOCK: only write the data if all dat can be written at once * @return ERR_OK if data was sent, any other err_t on error */ err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apiflags) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_write: invalid conn", (conn != NULL), return ERR_ARG;); LWIP_ERROR("netconn_write: invalid conn->type", (conn->type == NETCONN_TCP), return ERR_VAL;); + if (size == 0) { + return ERR_OK; + } + /* @todo: for non-blocking write, check if 'size' would ever fit into + snd_queue or snd_buf */ msg.function = do_write; msg.msg.conn = conn; msg.msg.msg.w.dataptr = dataptr; @@ -462,27 +606,62 @@ netconn_write(struct netconn *conn, const void *dataptr, size_t size, u8_t apifl /* For locking the core: this _can_ be delayed on low memory/low send buffer, but if it is, this is done inside api_msg.c:do_write(), so we can use the non-blocking version here. */ - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } /** - * Close a TCP netconn (doesn't delete it). + * Close ot shutdown a TCP netconn (doesn't delete it). * - * @param conn the TCP netconn to close + * @param conn the TCP netconn to close or shutdown + * @param how fully close or only shutdown one side? * @return ERR_OK if the netconn was closed, any other err_t on error */ -err_t -netconn_close(struct netconn *conn) +static err_t +netconn_close_shutdown(struct netconn *conn, u8_t how) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;); msg.function = do_close; msg.msg.conn = conn; - tcpip_apimsg(&msg); - return conn->err; + /* shutting down both ends is the same as closing */ + msg.msg.msg.sd.shut = how; + /* because of the LWIP_TCPIP_CORE_LOCKING implementation of do_close, + don't use TCPIP_APIMSG here */ + err = tcpip_apimsg(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; +} + +/** + * Close a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to close + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_close(struct netconn *conn) +{ + /* shutting down both ends is the same as closing */ + return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR); +} + +/** + * Shut down one or both sides of a TCP netconn (doesn't delete it). + * + * @param conn the TCP netconn to shut down + * @return ERR_OK if the netconn was closed, any other err_t on error + */ +err_t +netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx) +{ + return netconn_close_shutdown(conn, (shut_rx ? NETCONN_SHUT_RD : 0) | (shut_tx ? NETCONN_SHUT_WR : 0)); } #if LWIP_IGMP @@ -491,28 +670,31 @@ netconn_close(struct netconn *conn) * * @param conn the UDP netconn for which to change multicast addresses * @param multiaddr IP address of the multicast group to join or leave - * @param interface the IP address of the network interface on which to send + * @param netif_addr the IP address of the network interface on which to send * the igmp message * @param join_or_leave flag whether to send a join- or leave-message * @return ERR_OK if the action was taken, any err_t on error */ err_t netconn_join_leave_group(struct netconn *conn, - struct ip_addr *multiaddr, - struct ip_addr *interface, + ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave) { struct api_msg msg; + err_t err; LWIP_ERROR("netconn_join_leave_group: invalid conn", (conn != NULL), return ERR_ARG;); msg.function = do_join_leave_group; msg.msg.conn = conn; msg.msg.msg.jl.multiaddr = multiaddr; - msg.msg.msg.jl.interface = interface; + msg.msg.msg.jl.netif_addr = netif_addr; msg.msg.msg.jl.join_or_leave = join_or_leave; - TCPIP_APIMSG(&msg); - return conn->err; + err = TCPIP_APIMSG(&msg); + + NETCONN_SET_SAFE_ERR(conn, err); + return err; } #endif /* LWIP_IGMP */ @@ -521,14 +703,14 @@ netconn_join_leave_group(struct netconn *conn, * Execute a DNS query, only one IP address is returned * * @param name a string representation of the DNS host name to query - * @param addr a preallocated struct ip_addr where to store the resolved IP address + * @param addr a preallocated ip_addr_t where to store the resolved IP address * @return ERR_OK: resolving succeeded * ERR_MEM: memory error, try again later * ERR_ARG: dns client not initialized or invalid hostname * ERR_VAL: dns server response was invalid */ err_t -netconn_gethostbyname(const char *name, struct ip_addr *addr) +netconn_gethostbyname(const char *name, ip_addr_t *addr) { struct dns_api_msg msg; err_t err; @@ -537,19 +719,19 @@ netconn_gethostbyname(const char *name, struct ip_addr *addr) LWIP_ERROR("netconn_gethostbyname: invalid name", (name != NULL), return ERR_ARG;); LWIP_ERROR("netconn_gethostbyname: invalid addr", (addr != NULL), return ERR_ARG;); - sem = sys_sem_new(0); - if (sem == SYS_SEM_NULL) { - return ERR_MEM; + err = sys_sem_new(&sem, 0); + if (err != ERR_OK) { + return err; } msg.name = name; msg.addr = addr; msg.err = &err; - msg.sem = sem; + msg.sem = &sem; tcpip_callback(do_gethostbyname, &msg); - sys_sem_wait(sem); - sys_sem_free(sem); + sys_sem_wait(&sem); + sys_sem_free(&sem); return err; } diff --git a/core/lwip/src/api/api_msg.c b/core/lwip/src/api/api_msg.c index 46c9abf2..448f96dd 100644 --- a/core/lwip/src/api/api_msg.c +++ b/core/lwip/src/api/api_msg.c @@ -54,6 +54,12 @@ #include <string.h> +#define SET_NONBLOCKING_CONNECT(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_IN_NONBLOCKING_CONNECT; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_IN_NONBLOCKING_CONNECT; }} while(0) +#define IN_NONBLOCKING_CONNECT(conn) (((conn)->flags & NETCONN_FLAG_IN_NONBLOCKING_CONNECT) != 0) + /* forward declarations */ #if LWIP_TCP static err_t do_writemore(struct netconn *conn); @@ -70,24 +76,22 @@ static void do_close_internal(struct netconn *conn); */ static u8_t recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, - struct ip_addr *addr) + ip_addr_t *addr) { struct pbuf *q; struct netbuf *buf; struct netconn *conn; -#if LWIP_SO_RCVBUF - int recv_avail; -#endif /* LWIP_SO_RCVBUF */ LWIP_UNUSED_ARG(addr); - conn = arg; + conn = (struct netconn *)arg; + if ((conn != NULL) && sys_mbox_valid(&conn->recvmbox)) { #if LWIP_SO_RCVBUF - SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL) && - ((recv_avail + (int)(p->tot_len)) <= conn->recv_bufsize)) { -#else /* LWIP_SO_RCVBUF */ - if ((conn != NULL) && (conn->recvmbox != SYS_MBOX_NULL)) { + int recv_avail; + SYS_ARCH_GET(conn->recv_avail, recv_avail); + if ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize) { + return 0; + } #endif /* LWIP_SO_RCVBUF */ /* copy the whole packet into new pbufs */ q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); @@ -98,8 +102,9 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, } } - if(q != NULL) { - buf = memp_malloc(MEMP_NETBUF); + if (q != NULL) { + u16_t len; + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { pbuf_free(q); return 0; @@ -107,16 +112,19 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, buf->p = q; buf->ptr = q; - buf->addr = &(((struct ip_hdr*)(q->payload))->src); + ip_addr_copy(buf->addr, *ip_current_src_addr()); buf->port = pcb->protocol; - if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { + len = q->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return 0; } else { - SYS_ARCH_INC(conn->recv_avail, q->tot_len); +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, q->tot_len); + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } } } @@ -134,10 +142,11 @@ recv_raw(void *arg, struct raw_pcb *pcb, struct pbuf *p, */ static void recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *addr, u16_t port) + ip_addr_t *addr, u16_t port) { struct netbuf *buf; struct netconn *conn; + u16_t len; #if LWIP_SO_RCVBUF int recv_avail; #endif /* LWIP_SO_RCVBUF */ @@ -145,47 +154,53 @@ recv_udp(void *arg, struct udp_pcb *pcb, struct pbuf *p, LWIP_UNUSED_ARG(pcb); /* only used for asserts... */ LWIP_ASSERT("recv_udp must have a pcb argument", pcb != NULL); LWIP_ASSERT("recv_udp must have an argument", arg != NULL); - conn = arg; + conn = (struct netconn *)arg; LWIP_ASSERT("recv_udp: recv for wrong pcb!", conn->pcb.udp == pcb); #if LWIP_SO_RCVBUF SYS_ARCH_GET(conn->recv_avail, recv_avail); - if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL) || + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox) || ((recv_avail + (int)(p->tot_len)) > conn->recv_bufsize)) { #else /* LWIP_SO_RCVBUF */ - if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { + if ((conn == NULL) || !sys_mbox_valid(&conn->recvmbox)) { #endif /* LWIP_SO_RCVBUF */ pbuf_free(p); return; } - buf = memp_malloc(MEMP_NETBUF); + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf == NULL) { pbuf_free(p); return; } else { buf->p = p; buf->ptr = p; - buf->addr = addr; + ip_addr_set(&buf->addr, addr); buf->port = port; #if LWIP_NETBUF_RECVINFO { const struct ip_hdr* iphdr = ip_current_header(); /* get the UDP header - always in the first pbuf, ensured by udp_input */ const struct udp_hdr* udphdr = (void*)(((char*)iphdr) + IPH_LEN(iphdr)); - buf->toaddr = (struct ip_addr*)&iphdr->dest; - buf->toport = udphdr->dest; +#if LWIP_CHECKSUM_ON_COPY + buf->flags = NETBUF_FLAG_DESTADDR; +#endif /* LWIP_CHECKSUM_ON_COPY */ + ip_addr_set(&buf->toaddr, ip_current_dest_addr()); + buf->toport_chksum = udphdr->dest; } #endif /* LWIP_NETBUF_RECVINFO */ } - if (sys_mbox_trypost(conn->recvmbox, buf) != ERR_OK) { + len = p->tot_len; + if (sys_mbox_trypost(&conn->recvmbox, buf) != ERR_OK) { netbuf_delete(buf); return; } else { - SYS_ARCH_INC(conn->recv_avail, p->tot_len); +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, p->tot_len); + API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } } #endif /* LWIP_UDP */ @@ -206,24 +221,40 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("recv_tcp must have a pcb argument", pcb != NULL); LWIP_ASSERT("recv_tcp must have an argument", arg != NULL); - conn = arg; + conn = (struct netconn *)arg; LWIP_ASSERT("recv_tcp: recv for wrong pcb!", conn->pcb.tcp == pcb); - if ((conn == NULL) || (conn->recvmbox == SYS_MBOX_NULL)) { + if (conn == NULL) { return ERR_VAL; } + if (!sys_mbox_valid(&conn->recvmbox)) { + /* recvmbox already deleted */ + if (p != NULL) { + tcp_recved(pcb, p->tot_len); + pbuf_free(p); + } + return ERR_OK; + } + /* Unlike for UDP or RAW pcbs, don't check for available space + using recv_avail since that could break the connection + (data is already ACKed) */ + + /* don't overwrite fatal errors! */ + NETCONN_SET_SAFE_ERR(conn, err); - conn->err = err; if (p != NULL) { len = p->tot_len; - SYS_ARCH_INC(conn->recv_avail, len); } else { len = 0; } - if (sys_mbox_trypost(conn->recvmbox, p) != ERR_OK) { + if (sys_mbox_trypost(&conn->recvmbox, p) != ERR_OK) { + /* don't deallocate p: it is presented to us later again from tcp_fasttmr! */ return ERR_MEM; } else { +#if LWIP_SO_RCVBUF + SYS_ARCH_INC(conn->recv_avail, len); +#endif /* LWIP_SO_RCVBUF */ /* Register event with callback */ API_EVENT(conn, NETCONN_EVT_RCVPLUS, len); } @@ -245,7 +276,7 @@ recv_tcp(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err) static err_t poll_tcp(void *arg, struct tcp_pcb *pcb) { - struct netconn *conn = arg; + struct netconn *conn = (struct netconn *)arg; LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("conn != NULL", (conn != NULL)); @@ -255,6 +286,18 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) } else if (conn->state == NETCONN_CLOSE) { do_close_internal(conn); } + /* @todo: implement connect timeout here? */ + + /* Did a nonblocking write fail before? Then check available write-space. */ + if (conn->flags & NETCONN_FLAG_CHECK_WRITESPACE) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } + } return ERR_OK; } @@ -269,20 +312,23 @@ poll_tcp(void *arg, struct tcp_pcb *pcb) static err_t sent_tcp(void *arg, struct tcp_pcb *pcb, u16_t len) { - struct netconn *conn = arg; + struct netconn *conn = (struct netconn *)arg; LWIP_UNUSED_ARG(pcb); LWIP_ASSERT("conn != NULL", (conn != NULL)); if (conn->state == NETCONN_WRITE) { - LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); do_writemore(conn); } else if (conn->state == NETCONN_CLOSE) { do_close_internal(conn); } if (conn) { - if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT)) { + /* If the queued byte- or pbuf-count drops below the configured low-water limit, + let select mark this pcb as writable again. */ + if ((conn->pcb.tcp != NULL) && (tcp_sndbuf(conn->pcb.tcp) > TCP_SNDLOWAT) && + (tcp_sndqueuelen(conn->pcb.tcp) < TCP_SNDQUEUELOWAT)) { + conn->flags &= ~NETCONN_FLAG_CHECK_WRITESPACE; API_EVENT(conn, NETCONN_EVT_SENDPLUS, len); } } @@ -301,33 +347,59 @@ static void err_tcp(void *arg, err_t err) { struct netconn *conn; + enum netconn_state old_state; + SYS_ARCH_DECL_PROTECT(lev); - conn = arg; + conn = (struct netconn *)arg; LWIP_ASSERT("conn != NULL", (conn != NULL)); conn->pcb.tcp = NULL; - conn->err = err; - if (conn->recvmbox != SYS_MBOX_NULL) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - sys_mbox_post(conn->recvmbox, NULL); - } - if (conn->op_completed != SYS_SEM_NULL && conn->state == NETCONN_CONNECT) { - conn->state = NETCONN_NONE; - sys_sem_signal(conn->op_completed); + /* no check since this is always fatal! */ + SYS_ARCH_PROTECT(lev); + conn->last_err = err; + SYS_ARCH_UNPROTECT(lev); + + /* reset conn->state now before waking up other threads */ + old_state = conn->state; + conn->state = NETCONN_NONE; + + /* Notify the user layer about a connection error. Used to signal + select. */ + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + /* Try to release selects pending on 'read' or 'write', too. + They will get an error if they actually try to read or write. */ + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + /* pass NULL-message to recvmbox to wake up pending recv */ + if (sys_mbox_valid(&conn->recvmbox)) { + /* use trypost to prevent deadlock */ + sys_mbox_trypost(&conn->recvmbox, NULL); } - if (conn->acceptmbox != SYS_MBOX_NULL) { - /* Register event with callback */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - sys_mbox_post(conn->acceptmbox, NULL); + /* pass NULL-message to acceptmbox to wake up pending accept */ + if (sys_mbox_valid(&conn->acceptmbox)) { + /* use trypost to preven deadlock */ + sys_mbox_trypost(&conn->acceptmbox, NULL); } - if ((conn->state == NETCONN_WRITE) || (conn->state == NETCONN_CLOSE)) { + + if ((old_state == NETCONN_WRITE) || (old_state == NETCONN_CLOSE) || + (old_state == NETCONN_CONNECT)) { /* calling do_writemore/do_close_internal is not necessary since the pcb has already been deleted! */ - conn->state = NETCONN_NONE; - /* wake up the waiting task */ - sys_sem_signal(conn->op_completed); + int was_nonblocking_connect = IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + + if (!was_nonblocking_connect) { + /* set error return code */ + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + conn->current_msg->err = err; + conn->current_msg = NULL; + /* wake up the waiting task */ + sys_sem_signal(&conn->op_completed); + } + } else { + LWIP_ASSERT("conn->current_msg == NULL", conn->current_msg == NULL); } } @@ -360,17 +432,14 @@ static err_t accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) { struct netconn *newconn; - struct netconn *conn; + struct netconn *conn = (struct netconn *)arg; -#if API_MSG_DEBUG -#if TCP_DEBUG - tcp_debug_print_state(newpcb->state); -#endif /* TCP_DEBUG */ -#endif /* API_MSG_DEBUG */ - conn = (struct netconn *)arg; + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: newpcb->tate: %s\n", tcp_debug_state_str(newpcb->state))); - LWIP_ERROR("accept_function: invalid conn->acceptmbox", - conn->acceptmbox != SYS_MBOX_NULL, return ERR_VAL;); + if (!sys_mbox_valid(&conn->acceptmbox)) { + LWIP_DEBUGF(API_MSG_DEBUG, ("accept_function: acceptmbox already deleted\n")); + return ERR_VAL; + } /* We have to set the callback here even though * the new socket is unknown. conn->socket is marked as -1. */ @@ -380,12 +449,17 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) } newconn->pcb.tcp = newpcb; setup_tcp(newconn); - newconn->err = err; + /* no protection: when creating the pcb, the netconn is not yet known + to the application thread */ + newconn->last_err = err; - if (sys_mbox_trypost(conn->acceptmbox, newconn) != ERR_OK) { - /* When returning != ERR_OK, the connection is aborted in tcp_process(), + if (sys_mbox_trypost(&conn->acceptmbox, newconn) != ERR_OK) { + /* When returning != ERR_OK, the pcb is aborted in tcp_process(), so do nothing here! */ newconn->pcb.tcp = NULL; + /* no need to drain since we know the recvmbox is empty. */ + sys_mbox_free(&newconn->recvmbox); + sys_mbox_set_invalid(&newconn->recvmbox); netconn_free(newconn); return ERR_MEM; } else { @@ -404,60 +478,56 @@ accept_function(void *arg, struct tcp_pcb *newpcb, err_t err) * @param msg the api_msg_msg describing the connection type * @return msg->conn->err, but the return value is currently ignored */ -static err_t +static void pcb_new(struct api_msg_msg *msg) { - msg->conn->err = ERR_OK; - - LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); + LWIP_ASSERT("pcb_new: pcb already allocated", msg->conn->pcb.tcp == NULL); - /* Allocate a PCB for this connection */ - switch(NETCONNTYPE_GROUP(msg->conn->type)) { + /* Allocate a PCB for this connection */ + switch(NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW - case NETCONN_RAW: - msg->conn->pcb.raw = raw_new(msg->msg.n.proto); - if(msg->conn->pcb.raw == NULL) { - msg->conn->err = ERR_MEM; - break; - } - raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); - break; + case NETCONN_RAW: + msg->conn->pcb.raw = raw_new(msg->msg.n.proto); + if(msg->conn->pcb.raw == NULL) { + msg->err = ERR_MEM; + break; + } + raw_recv(msg->conn->pcb.raw, recv_raw, msg->conn); + break; #endif /* LWIP_RAW */ #if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp = udp_new(); - if(msg->conn->pcb.udp == NULL) { - msg->conn->err = ERR_MEM; - break; - } + case NETCONN_UDP: + msg->conn->pcb.udp = udp_new(); + if(msg->conn->pcb.udp == NULL) { + msg->err = ERR_MEM; + break; + } #if LWIP_UDPLITE - if (msg->conn->type==NETCONN_UDPLITE) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); - } + if (msg->conn->type==NETCONN_UDPLITE) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_UDPLITE); + } #endif /* LWIP_UDPLITE */ - if (msg->conn->type==NETCONN_UDPNOCHKSUM) { - udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); - } - udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); - break; + if (msg->conn->type==NETCONN_UDPNOCHKSUM) { + udp_setflags(msg->conn->pcb.udp, UDP_FLAGS_NOCHKSUM); + } + udp_recv(msg->conn->pcb.udp, recv_udp, msg->conn); + break; #endif /* LWIP_UDP */ #if LWIP_TCP - case NETCONN_TCP: - msg->conn->pcb.tcp = tcp_new(); - if(msg->conn->pcb.tcp == NULL) { - msg->conn->err = ERR_MEM; - break; - } - setup_tcp(msg->conn); - break; + case NETCONN_TCP: + msg->conn->pcb.tcp = tcp_new(); + if(msg->conn->pcb.tcp == NULL) { + msg->err = ERR_MEM; + break; + } + setup_tcp(msg->conn); + break; #endif /* LWIP_TCP */ - default: - /* Unsupported netconn type, e.g. protocol disabled */ - msg->conn->err = ERR_VAL; - break; - } - - return msg->conn->err; + default: + /* Unsupported netconn type, e.g. protocol disabled */ + msg->err = ERR_VAL; + break; + } } /** @@ -469,14 +539,15 @@ pcb_new(struct api_msg_msg *msg) void do_newconn(struct api_msg_msg *msg) { - if(msg->conn->pcb.tcp == NULL) { - pcb_new(msg); - } - /* Else? This "new" connection already has a PCB allocated. */ - /* Is this an error condition? Should it be deleted? */ - /* We currently just are happy and return. */ - - TCPIP_APIMSG_ACK(msg); + msg->err = ERR_OK; + if(msg->conn->pcb.tcp == NULL) { + pcb_new(msg); + } + /* Else? This "new" connection already has a PCB allocated. */ + /* Is this an error condition? Should it be deleted? */ + /* We currently just are happy and return. */ + + TCPIP_APIMSG_ACK(msg); } /** @@ -495,12 +566,12 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) struct netconn *conn; int size; - conn = memp_malloc(MEMP_NETCONN); + conn = (struct netconn *)memp_malloc(MEMP_NETCONN); if (conn == NULL) { return NULL; } - conn->err = ERR_OK; + conn->last_err = ERR_OK; conn->type = t; conn->pcb.tcp = NULL; @@ -530,35 +601,37 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) } #endif - if ((conn->op_completed = sys_sem_new(0)) == SYS_SEM_NULL) { + if (sys_sem_new(&conn->op_completed, 0) != ERR_OK) { memp_free(MEMP_NETCONN, conn); return NULL; } - if ((conn->recvmbox = sys_mbox_new(size)) == SYS_MBOX_NULL) { - sys_sem_free(conn->op_completed); + if (sys_mbox_new(&conn->recvmbox, size) != ERR_OK) { + sys_sem_free(&conn->op_completed); memp_free(MEMP_NETCONN, conn); return NULL; } - conn->acceptmbox = SYS_MBOX_NULL; +#if LWIP_TCP + sys_mbox_set_invalid(&conn->acceptmbox); +#endif conn->state = NETCONN_NONE; +#if LWIP_SOCKET /* initialize socket to -1 since 0 is a valid socket */ conn->socket = -1; +#endif /* LWIP_SOCKET */ conn->callback = callback; - conn->recv_avail = 0; #if LWIP_TCP - conn->write_msg = NULL; + conn->current_msg = NULL; conn->write_offset = 0; -#if LWIP_TCPIP_CORE_LOCKING - conn->write_delayed = 0; -#endif /* LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_TCP */ #if LWIP_SO_RCVTIMEO conn->recv_timeout = 0; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF conn->recv_bufsize = RECV_BUFSIZE_DEFAULT; + conn->recv_avail = 0; #endif /* LWIP_SO_RCVBUF */ + conn->flags = 0; return conn; } @@ -571,37 +644,83 @@ netconn_alloc(enum netconn_type t, netconn_callback callback) void netconn_free(struct netconn *conn) { - void *mem; LWIP_ASSERT("PCB must be deallocated outside this function", conn->pcb.tcp == NULL); + LWIP_ASSERT("recvmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->recvmbox)); +#if LWIP_TCP + LWIP_ASSERT("acceptmbox must be deallocated before calling this function", + !sys_mbox_valid(&conn->acceptmbox)); +#endif /* LWIP_TCP */ + + sys_sem_free(&conn->op_completed); + sys_sem_set_invalid(&conn->op_completed); + + memp_free(MEMP_NETCONN, conn); +} - /* Drain the recvmbox. */ - if (conn->recvmbox != SYS_MBOX_NULL) { - while (sys_mbox_tryfetch(conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +/** + * Delete rcvmbox and acceptmbox of a netconn and free the left-over data in + * these mboxes + * + * @param conn the netconn to free + * @bytes_drained bytes drained from recvmbox + * @accepts_drained pending connections drained from acceptmbox + */ +static void +netconn_drain(struct netconn *conn) +{ + void *mem; +#if LWIP_TCP + struct pbuf *p; +#endif /* LWIP_TCP */ + + /* This runs in tcpip_thread, so we don't need to lock against rx packets */ + + /* Delete and drain the recvmbox. */ + if (sys_mbox_valid(&conn->recvmbox)) { + while (sys_mbox_tryfetch(&conn->recvmbox, &mem) != SYS_MBOX_EMPTY) { +#if LWIP_TCP if (conn->type == NETCONN_TCP) { if(mem != NULL) { - pbuf_free((struct pbuf *)mem); + p = (struct pbuf*)mem; + /* pcb might be set to NULL already by err_tcp() */ + if (conn->pcb.tcp != NULL) { + tcp_recved(conn->pcb.tcp, p->tot_len); + } + pbuf_free(p); } - } else { + } else +#endif /* LWIP_TCP */ + { netbuf_delete((struct netbuf *)mem); } } - sys_mbox_free(conn->recvmbox); - conn->recvmbox = SYS_MBOX_NULL; + sys_mbox_free(&conn->recvmbox); + sys_mbox_set_invalid(&conn->recvmbox); } - /* Drain the acceptmbox. */ - if (conn->acceptmbox != SYS_MBOX_NULL) { - while (sys_mbox_tryfetch(conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { - netconn_delete((struct netconn *)mem); + /* Delete and drain the acceptmbox. */ +#if LWIP_TCP + if (sys_mbox_valid(&conn->acceptmbox)) { + while (sys_mbox_tryfetch(&conn->acceptmbox, &mem) != SYS_MBOX_EMPTY) { + struct netconn *newconn = (struct netconn *)mem; + /* Only tcp pcbs have an acceptmbox, so no need to check conn->type */ + /* pcb might be set to NULL already by err_tcp() */ + if (conn->pcb.tcp != NULL) { + tcp_accepted(conn->pcb.tcp); + } + /* drain recvmbox */ + netconn_drain(newconn); + if (newconn->pcb.tcp != NULL) { + tcp_abort(newconn->pcb.tcp); + newconn->pcb.tcp = NULL; + } + netconn_free(newconn); } - sys_mbox_free(conn->acceptmbox); - conn->acceptmbox = SYS_MBOX_NULL; + sys_mbox_free(&conn->acceptmbox); + sys_mbox_set_invalid(&conn->acceptmbox); } - - sys_sem_free(conn->op_completed); - conn->op_completed = SYS_SEM_NULL; - - memp_free(MEMP_NETCONN, conn); +#endif /* LWIP_TCP */ } #if LWIP_TCP @@ -616,38 +735,66 @@ static void do_close_internal(struct netconn *conn) { err_t err; + u8_t shut, shut_rx, shut_tx, close; LWIP_ASSERT("invalid conn", (conn != NULL)); LWIP_ASSERT("this is for tcp netconns only", (conn->type == NETCONN_TCP)); LWIP_ASSERT("conn must be in state NETCONN_CLOSE", (conn->state == NETCONN_CLOSE)); LWIP_ASSERT("pcb already closed", (conn->pcb.tcp != NULL)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + + shut = conn->current_msg->msg.sd.shut; + shut_rx = shut & NETCONN_SHUT_RD; + shut_tx = shut & NETCONN_SHUT_WR; + /* shutting down both ends is the same as closing */ + close = shut == NETCONN_SHUT_RDWR; /* Set back some callback pointers */ - tcp_arg(conn->pcb.tcp, NULL); + if (close) { + tcp_arg(conn->pcb.tcp, NULL); + } if (conn->pcb.tcp->state == LISTEN) { tcp_accept(conn->pcb.tcp, NULL); } else { - tcp_recv(conn->pcb.tcp, NULL); - tcp_accept(conn->pcb.tcp, NULL); /* some callbacks have to be reset if tcp_close is not successful */ - tcp_sent(conn->pcb.tcp, NULL); - tcp_poll(conn->pcb.tcp, NULL, 4); - tcp_err(conn->pcb.tcp, NULL); + if (shut_rx) { + tcp_recv(conn->pcb.tcp, NULL); + tcp_accept(conn->pcb.tcp, NULL); + } + if (shut_tx) { + tcp_sent(conn->pcb.tcp, NULL); + } + if (close) { + tcp_poll(conn->pcb.tcp, NULL, 4); + tcp_err(conn->pcb.tcp, NULL); + } } /* Try to close the connection */ - err = tcp_close(conn->pcb.tcp); + if (shut == NETCONN_SHUT_RDWR) { + err = tcp_close(conn->pcb.tcp); + } else { + err = tcp_shutdown(conn->pcb.tcp, shut & NETCONN_SHUT_RD, shut & NETCONN_SHUT_WR); + } if (err == ERR_OK) { /* Closing succeeded */ + conn->current_msg->err = ERR_OK; + conn->current_msg = NULL; conn->state = NETCONN_NONE; /* Set back some callback pointers as conn is going away */ conn->pcb.tcp = NULL; - conn->err = ERR_OK; - /* Trigger select() in socket layer. This send should something else so the - errorfd is set, not the read and write fd! */ - API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + /* Trigger select() in socket layer. Make sure everybody notices activity + on the connection, error first! */ + if (close) { + API_EVENT(conn, NETCONN_EVT_ERROR, 0); + } + if (shut_rx) { + API_EVENT(conn, NETCONN_EVT_RCVPLUS, 0); + } + if (shut_tx) { + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + } /* wake up the application task */ - sys_sem_signal(conn->op_completed); + sys_sem_signal(&conn->op_completed); } else { /* Closing failed, restore some of the callbacks */ /* Closing of listen pcb will never fail! */ @@ -656,6 +803,7 @@ do_close_internal(struct netconn *conn) tcp_poll(conn->pcb.tcp, poll_tcp, 4); tcp_err(conn->pcb.tcp, err_tcp); tcp_arg(conn->pcb.tcp, conn); + /* don't restore recv callback: we don't want to receive any more data */ } /* If closing didn't succeed, we get called again either from poll_tcp or from sent_tcp */ @@ -671,40 +819,59 @@ do_close_internal(struct netconn *conn) void do_delconn(struct api_msg_msg *msg) { - if (msg->conn->pcb.tcp != NULL) { - switch (NETCONNTYPE_GROUP(msg->conn->type)) { + /* @todo TCP: abort running write/connect? */ + if ((msg->conn->state != NETCONN_NONE) && + (msg->conn->state != NETCONN_LISTEN) && + (msg->conn->state != NETCONN_CONNECT)) { + /* this only happens for TCP netconns */ + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else { + LWIP_ASSERT("blocking connect in progress", + (msg->conn->state != NETCONN_CONNECT) || IN_NONBLOCKING_CONNECT(msg->conn)); + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + + if (msg->conn->pcb.tcp != NULL) { + + switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW - case NETCONN_RAW: - raw_remove(msg->conn->pcb.raw); - break; + case NETCONN_RAW: + raw_remove(msg->conn->pcb.raw); + break; #endif /* LWIP_RAW */ #if LWIP_UDP - case NETCONN_UDP: - msg->conn->pcb.udp->recv_arg = NULL; - udp_remove(msg->conn->pcb.udp); - break; + case NETCONN_UDP: + msg->conn->pcb.udp->recv_arg = NULL; + udp_remove(msg->conn->pcb.udp); + break; #endif /* LWIP_UDP */ #if LWIP_TCP - case NETCONN_TCP: - msg->conn->state = NETCONN_CLOSE; - do_close_internal(msg->conn); - /* API_EVENT is called inside do_close_internal, before releasing - the application thread, so we can return at this point! */ - return; + case NETCONN_TCP: + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + msg->conn->state = NETCONN_CLOSE; + msg->msg.sd.shut = NETCONN_SHUT_RDWR; + msg->conn->current_msg = msg; + do_close_internal(msg->conn); + /* API_EVENT is called inside do_close_internal, before releasing + the application thread, so we can return at this point! */ + return; #endif /* LWIP_TCP */ - default: - break; + default: + break; + } + msg->conn->pcb.tcp = NULL; } - } - /* tcp netconns don't come here! */ - - /* Trigger select() in socket layer. This send should something else so the - errorfd is set, not the read and write fd! */ - API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); - API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + /* tcp netconns don't come here! */ - if (msg->conn->op_completed != SYS_SEM_NULL) { - sys_sem_signal(msg->conn->op_completed); + /* @todo: this lets select make the socket readable and writable, + which is wrong! errfd instead? */ + API_EVENT(msg->conn, NETCONN_EVT_RCVPLUS, 0); + API_EVENT(msg->conn, NETCONN_EVT_SENDPLUS, 0); + } + if (sys_sem_valid(&msg->conn->op_completed)) { + sys_sem_signal(&msg->conn->op_completed); } } @@ -718,30 +885,30 @@ do_delconn(struct api_msg_msg *msg) void do_bind(struct api_msg_msg *msg) { - if (!ERR_IS_FATAL(msg->conn->err)) { + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_VAL; if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->conn->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); + msg->err = raw_bind(msg->conn->pcb.raw, msg->msg.bc.ipaddr); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->conn->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); + msg->err = udp_bind(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->conn->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); + msg->err = tcp_bind(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port); break; #endif /* LWIP_TCP */ default: break; } - } else { - /* msg->conn->pcb is NULL */ - msg->conn->err = ERR_VAL; } } TCPIP_APIMSG_ACK(msg); @@ -758,21 +925,38 @@ static err_t do_connected(void *arg, struct tcp_pcb *pcb, err_t err) { struct netconn *conn; + int was_blocking; LWIP_UNUSED_ARG(pcb); - conn = arg; + conn = (struct netconn *)arg; if (conn == NULL) { return ERR_VAL; } - conn->err = err; + LWIP_ASSERT("conn->state == NETCONN_CONNECT", conn->state == NETCONN_CONNECT); + LWIP_ASSERT("(conn->current_msg != NULL) || conn->in_non_blocking_connect", + (conn->current_msg != NULL) || IN_NONBLOCKING_CONNECT(conn)); + + if (conn->current_msg != NULL) { + conn->current_msg->err = err; + } if ((conn->type == NETCONN_TCP) && (err == ERR_OK)) { setup_tcp(conn); } + was_blocking = !IN_NONBLOCKING_CONNECT(conn); + SET_NONBLOCKING_CONNECT(conn, 0); + conn->current_msg = NULL; conn->state = NETCONN_NONE; - sys_sem_signal(conn->op_completed); + if (!was_blocking) { + NETCONN_SET_SAFE_ERR(conn, ERR_OK); + } + API_EVENT(conn, NETCONN_EVT_SENDPLUS, 0); + + if (was_blocking) { + sys_sem_signal(&conn->op_completed); + } return ERR_OK; } #endif /* LWIP_TCP */ @@ -788,38 +972,51 @@ void do_connect(struct api_msg_msg *msg) { if (msg->conn->pcb.tcp == NULL) { - sys_sem_signal(msg->conn->op_completed); - return; - } - - switch (NETCONNTYPE_GROUP(msg->conn->type)) { + /* This may happen when calling netconn_connect() a second time */ + msg->err = ERR_CLSD; + } else { + switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - msg->conn->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); - sys_sem_signal(msg->conn->op_completed); + msg->err = raw_connect(msg->conn->pcb.raw, msg->msg.bc.ipaddr); break; #endif /* LWIP_RAW */ #if LWIP_UDP case NETCONN_UDP: - msg->conn->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); - sys_sem_signal(msg->conn->op_completed); + msg->err = udp_connect(msg->conn->pcb.udp, msg->msg.bc.ipaddr, msg->msg.bc.port); break; #endif /* LWIP_UDP */ #if LWIP_TCP case NETCONN_TCP: - msg->conn->state = NETCONN_CONNECT; - setup_tcp(msg->conn); - msg->conn->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, msg->msg.bc.port, - do_connected); - /* sys_sem_signal() is called from do_connected (or err_tcp()), - * when the connection is established! */ + /* Prevent connect while doing any other action. */ + if (msg->conn->state != NETCONN_NONE) { + msg->err = ERR_ISCONN; + } else { + setup_tcp(msg->conn); + msg->err = tcp_connect(msg->conn->pcb.tcp, msg->msg.bc.ipaddr, + msg->msg.bc.port, do_connected); + if (msg->err == ERR_OK) { + u8_t non_blocking = netconn_is_nonblocking(msg->conn); + msg->conn->state = NETCONN_CONNECT; + SET_NONBLOCKING_CONNECT(msg->conn, non_blocking); + if (non_blocking) { + msg->err = ERR_INPROGRESS; + } else { + msg->conn->current_msg = msg; + /* sys_sem_signal() is called from do_connected (or err_tcp()), + * when the connection is established! */ + return; + } + } + } break; #endif /* LWIP_TCP */ default: - LWIP_ERROR("Invalid netconn type", 0, do{ msg->conn->err = ERR_VAL; - sys_sem_signal(msg->conn->op_completed); }while(0)); + LWIP_ERROR("Invalid netconn type", 0, do{ msg->err = ERR_VAL; }while(0)); break; + } } + sys_sem_signal(&msg->conn->op_completed); } /** @@ -835,11 +1032,16 @@ do_disconnect(struct api_msg_msg *msg) #if LWIP_UDP if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { udp_disconnect(msg->conn->pcb.udp); - } + msg->err = ERR_OK; + } else #endif /* LWIP_UDP */ + { + msg->err = ERR_VAL; + } TCPIP_APIMSG_ACK(msg); } +#if LWIP_TCP /** * Set a TCP pcb contained in a netconn into listen mode * Called from netconn_listen. @@ -849,46 +1051,50 @@ do_disconnect(struct api_msg_msg *msg) void do_listen(struct api_msg_msg *msg) { -#if LWIP_TCP - if (!ERR_IS_FATAL(msg->conn->err)) { + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { if (msg->conn->type == NETCONN_TCP) { - if (msg->conn->pcb.tcp->state == CLOSED) { + if (msg->conn->state == NETCONN_NONE) { #if TCP_LISTEN_BACKLOG struct tcp_pcb* lpcb = tcp_listen_with_backlog(msg->conn->pcb.tcp, msg->msg.lb.backlog); #else /* TCP_LISTEN_BACKLOG */ struct tcp_pcb* lpcb = tcp_listen(msg->conn->pcb.tcp); #endif /* TCP_LISTEN_BACKLOG */ if (lpcb == NULL) { - msg->conn->err = ERR_MEM; + /* in this case, the old pcb is still allocated */ + msg->err = ERR_MEM; } else { /* delete the recvmbox and allocate the acceptmbox */ - if (msg->conn->recvmbox != SYS_MBOX_NULL) { + if (sys_mbox_valid(&msg->conn->recvmbox)) { /** @todo: should we drain the recvmbox here? */ - sys_mbox_free(msg->conn->recvmbox); - msg->conn->recvmbox = SYS_MBOX_NULL; + sys_mbox_free(&msg->conn->recvmbox); + sys_mbox_set_invalid(&msg->conn->recvmbox); } - if (msg->conn->acceptmbox == SYS_MBOX_NULL) { - if ((msg->conn->acceptmbox = sys_mbox_new(DEFAULT_ACCEPTMBOX_SIZE)) == SYS_MBOX_NULL) { - msg->conn->err = ERR_MEM; - } + msg->err = ERR_OK; + if (!sys_mbox_valid(&msg->conn->acceptmbox)) { + msg->err = sys_mbox_new(&msg->conn->acceptmbox, DEFAULT_ACCEPTMBOX_SIZE); } - if (msg->conn->err == ERR_OK) { + if (msg->err == ERR_OK) { msg->conn->state = NETCONN_LISTEN; msg->conn->pcb.tcp = lpcb; tcp_arg(msg->conn->pcb.tcp, msg->conn); tcp_accept(msg->conn->pcb.tcp, accept_function); + } else { + /* since the old pcb is already deallocated, free lpcb now */ + tcp_close(lpcb); + msg->conn->pcb.tcp = NULL; } } - } else { - msg->conn->err = ERR_CONN; } } } } -#endif /* LWIP_TCP */ TCPIP_APIMSG_ACK(msg); } +#endif /* LWIP_TCP */ /** * Send some data on a RAW or UDP pcb contained in a netconn @@ -899,25 +1105,39 @@ do_listen(struct api_msg_msg *msg) void do_send(struct api_msg_msg *msg) { - if (!ERR_IS_FATAL(msg->conn->err)) { + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + msg->err = ERR_CONN; if (msg->conn->pcb.tcp != NULL) { switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: - if (msg->msg.b->addr == NULL) { - msg->conn->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = raw_send(msg->conn->pcb.raw, msg->msg.b->p); } else { - msg->conn->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, msg->msg.b->addr); + msg->err = raw_sendto(msg->conn->pcb.raw, msg->msg.b->p, &msg->msg.b->addr); } break; #endif #if LWIP_UDP case NETCONN_UDP: - if (msg->msg.b->addr == NULL) { - msg->conn->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); +#if LWIP_CHECKSUM_ON_COPY + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = udp_send_chksum(msg->conn->pcb.udp, msg->msg.b->p, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } else { - msg->conn->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, msg->msg.b->addr, msg->msg.b->port); + msg->err = udp_sendto_chksum(msg->conn->pcb.udp, msg->msg.b->p, + &msg->msg.b->addr, msg->msg.b->port, + msg->msg.b->flags & NETBUF_FLAG_CHKSUM, msg->msg.b->toport_chksum); } +#else /* LWIP_CHECKSUM_ON_COPY */ + if (ip_addr_isany(&msg->msg.b->addr)) { + msg->err = udp_send(msg->conn->pcb.udp, msg->msg.b->p); + } else { + msg->err = udp_sendto(msg->conn->pcb.udp, msg->msg.b->p, &msg->msg.b->addr, msg->msg.b->port); + } +#endif /* LWIP_CHECKSUM_ON_COPY */ break; #endif /* LWIP_UDP */ default: @@ -928,6 +1148,7 @@ do_send(struct api_msg_msg *msg) TCPIP_APIMSG_ACK(msg); } +#if LWIP_TCP /** * Indicate data has been received from a TCP pcb contained in a netconn * Called from netconn_recv @@ -937,26 +1158,27 @@ do_send(struct api_msg_msg *msg) void do_recv(struct api_msg_msg *msg) { -#if LWIP_TCP - if (!ERR_IS_FATAL(msg->conn->err)) { - if (msg->conn->pcb.tcp != NULL) { - if (msg->conn->type == NETCONN_TCP) { + msg->err = ERR_OK; + if (msg->conn->pcb.tcp != NULL) { + if (msg->conn->type == NETCONN_TCP) { #if TCP_LISTEN_BACKLOG - if (msg->conn->pcb.tcp->state == LISTEN) { - tcp_accepted(msg->conn->pcb.tcp); - } else + if (msg->conn->pcb.tcp->state == LISTEN) { + tcp_accepted(msg->conn->pcb.tcp); + } else #endif /* TCP_LISTEN_BACKLOG */ - { - tcp_recved(msg->conn->pcb.tcp, msg->msg.r.len); - } + { + u32_t remaining = msg->msg.r.len; + do { + u16_t recved = (remaining > 0xffff) ? 0xffff : (u16_t)remaining; + tcp_recved(msg->conn->pcb.tcp, recved); + remaining -= recved; + }while(remaining != 0); } } } -#endif /* LWIP_TCP */ TCPIP_APIMSG_ACK(msg); } -#if LWIP_TCP /** * See if more data needs to be written from a previous call to netconn_write. * Called initially from do_write. If the first call can't send all data @@ -971,21 +1193,30 @@ do_recv(struct api_msg_msg *msg) static err_t do_writemore(struct netconn *conn) { - err_t err; + err_t err = ERR_OK; void *dataptr; u16_t len, available; u8_t write_finished = 0; size_t diff; + u8_t dontblock = netconn_is_nonblocking(conn) || + (conn->current_msg->msg.w.apiflags & NETCONN_DONTBLOCK); + u8_t apiflags = conn->current_msg->msg.w.apiflags; + LWIP_ASSERT("conn != NULL", conn != NULL); LWIP_ASSERT("conn->state == NETCONN_WRITE", (conn->state == NETCONN_WRITE)); + LWIP_ASSERT("conn->current_msg != NULL", conn->current_msg != NULL); + LWIP_ASSERT("conn->pcb.tcp != NULL", conn->pcb.tcp != NULL); + LWIP_ASSERT("conn->write_offset < conn->current_msg->msg.w.len", + conn->write_offset < conn->current_msg->msg.w.len); - dataptr = (u8_t*)conn->write_msg->msg.w.dataptr + conn->write_offset; - diff = conn->write_msg->msg.w.len - conn->write_offset; + dataptr = (u8_t*)conn->current_msg->msg.w.dataptr + conn->write_offset; + diff = conn->current_msg->msg.w.len - conn->write_offset; if (diff > 0xffffUL) { /* max_u16_t */ len = 0xffff; #if LWIP_TCPIP_CORE_LOCKING - conn->write_delayed = 1; + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif + apiflags |= TCP_WRITE_FLAG_MORE; } else { len = (u16_t)diff; } @@ -994,54 +1225,74 @@ do_writemore(struct netconn *conn) /* don't try to write more than sendbuf */ len = available; #if LWIP_TCPIP_CORE_LOCKING - conn->write_delayed = 1; + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; #endif + apiflags |= TCP_WRITE_FLAG_MORE; + } + if (dontblock && (len < conn->current_msg->msg.w.len)) { + /* failed to send all data at once -> nonblocking write not possible */ + err = ERR_MEM; } - - err = tcp_write(conn->pcb.tcp, dataptr, len, conn->write_msg->msg.w.apiflags); - LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->write_msg->msg.w.len)); if (err == ERR_OK) { - conn->write_offset += len; - if (conn->write_offset == conn->write_msg->msg.w.len) { - /* everything was written */ - write_finished = 1; - conn->write_msg = NULL; - conn->write_offset = 0; - /* API_EVENT might call tcp_tmr, so reset conn->state now */ - conn->state = NETCONN_NONE; - } - err = tcp_output_nagle(conn->pcb.tcp); - conn->err = err; - if ((err == ERR_OK) && (tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT)) { + LWIP_ASSERT("do_writemore: invalid length!", ((conn->write_offset + len) <= conn->current_msg->msg.w.len)); + err = tcp_write(conn->pcb.tcp, dataptr, len, apiflags); + } + if (dontblock && (err == ERR_MEM)) { + /* nonblocking write failed */ + write_finished = 1; + err = ERR_WOULDBLOCK; + /* let poll_tcp check writable space to mark the pcb + writable again */ + conn->flags |= NETCONN_FLAG_CHECK_WRITESPACE; + /* let select mark this pcb as non-writable. */ + API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); + } else { + /* if OK or memory error, check available space */ + if (((err == ERR_OK) || (err == ERR_MEM)) && + ((tcp_sndbuf(conn->pcb.tcp) <= TCP_SNDLOWAT) || + (tcp_sndqueuelen(conn->pcb.tcp) >= TCP_SNDQUEUELOWAT))) { + /* The queued byte- or pbuf-count exceeds the configured low-water limit, + let select mark this pcb as non-writable. */ API_EVENT(conn, NETCONN_EVT_SENDMINUS, len); } - } else if (err == ERR_MEM) { - /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called - we do NOT return to the application thread, since ERR_MEM is - only a temporary error! */ - /* tcp_enqueue returned ERR_MEM, try tcp_output anyway */ - err = tcp_output(conn->pcb.tcp); - -#if LWIP_TCPIP_CORE_LOCKING - conn->write_delayed = 1; -#endif - } else { - /* On errors != ERR_MEM, we don't try writing any more but return - the error to the application thread. */ - conn->err = err; - write_finished = 1; + if (err == ERR_OK) { + conn->write_offset += len; + if (conn->write_offset == conn->current_msg->msg.w.len) { + /* everything was written */ + write_finished = 1; + conn->write_offset = 0; + } + tcp_output(conn->pcb.tcp); + } else if (err == ERR_MEM) { + /* If ERR_MEM, we wait for sent_tcp or poll_tcp to be called + we do NOT return to the application thread, since ERR_MEM is + only a temporary error! */ + + /* tcp_write returned ERR_MEM, try tcp_output anyway */ + tcp_output(conn->pcb.tcp); + + #if LWIP_TCPIP_CORE_LOCKING + conn->flags |= NETCONN_FLAG_WRITE_DELAYED; + #endif + } else { + /* On errors != ERR_MEM, we don't try writing any more but return + the error to the application thread. */ + write_finished = 1; + } } if (write_finished) { /* everything was written: set back connection state and back to application task */ + conn->current_msg->err = err; + conn->current_msg = NULL; conn->state = NETCONN_NONE; #if LWIP_TCPIP_CORE_LOCKING - if (conn->write_delayed != 0) + if ((conn->flags & NETCONN_FLAG_WRITE_DELAYED) != 0) #endif { - sys_sem_signal(conn->op_completed); + sys_sem_signal(&conn->op_completed); } } #if LWIP_TCPIP_CORE_LOCKING @@ -1061,33 +1312,46 @@ do_writemore(struct netconn *conn) void do_write(struct api_msg_msg *msg) { - if (!ERR_IS_FATAL(msg->conn->err)) { - if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { + if (msg->conn->type == NETCONN_TCP) { #if LWIP_TCP - msg->conn->state = NETCONN_WRITE; - /* set all the variables used by do_writemore */ - LWIP_ASSERT("already writing", msg->conn->write_msg == NULL && - msg->conn->write_offset == 0); - msg->conn->write_msg = msg; - msg->conn->write_offset = 0; + if (msg->conn->state != NETCONN_NONE) { + /* netconn is connecting, closing or in blocking write */ + msg->err = ERR_INPROGRESS; + } else if (msg->conn->pcb.tcp != NULL) { + msg->conn->state = NETCONN_WRITE; + /* set all the variables used by do_writemore */ + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); + LWIP_ASSERT("msg->msg.w.len != 0", msg->msg.w.len != 0); + msg->conn->current_msg = msg; + msg->conn->write_offset = 0; #if LWIP_TCPIP_CORE_LOCKING - msg->conn->write_delayed = 0; - if (do_writemore(msg->conn) != ERR_OK) { - LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); - UNLOCK_TCPIP_CORE(); - sys_arch_sem_wait(msg->conn->op_completed, 0); - LOCK_TCPIP_CORE(); - LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + msg->conn->flags &= ~NETCONN_FLAG_WRITE_DELAYED; + if (do_writemore(msg->conn) != ERR_OK) { + LWIP_ASSERT("state!", msg->conn->state == NETCONN_WRITE); + UNLOCK_TCPIP_CORE(); + sys_arch_sem_wait(&msg->conn->op_completed, 0); + LOCK_TCPIP_CORE(); + LWIP_ASSERT("state!", msg->conn->state == NETCONN_NONE); + } +#else /* LWIP_TCPIP_CORE_LOCKING */ + do_writemore(msg->conn); +#endif /* LWIP_TCPIP_CORE_LOCKING */ + /* for both cases: if do_writemore was called, don't ACK the APIMSG + since do_writemore ACKs it! */ + return; + } else { + msg->err = ERR_CONN; } -#else - do_writemore(msg->conn); -#endif - /* for both cases: if do_writemore was called, don't ACK the APIMSG! */ - return; +#else /* LWIP_TCP */ + msg->err = ERR_VAL; #endif /* LWIP_TCP */ #if (LWIP_UDP || LWIP_RAW) } else { - msg->conn->err = ERR_VAL; + msg->err = ERR_VAL; #endif /* (LWIP_UDP || LWIP_RAW) */ } } @@ -1104,8 +1368,10 @@ void do_getaddr(struct api_msg_msg *msg) { if (msg->conn->pcb.ip != NULL) { - *(msg->msg.ad.ipaddr) = (msg->msg.ad.local?msg->conn->pcb.ip->local_ip:msg->conn->pcb.ip->remote_ip); - + *(msg->msg.ad.ipaddr) = (msg->msg.ad.local ? msg->conn->pcb.ip->local_ip : + msg->conn->pcb.ip->remote_ip); + + msg->err = ERR_OK; switch (NETCONNTYPE_GROUP(msg->conn->type)) { #if LWIP_RAW case NETCONN_RAW: @@ -1113,7 +1379,7 @@ do_getaddr(struct api_msg_msg *msg) *(msg->msg.ad.port) = msg->conn->pcb.raw->protocol; } else { /* return an error as connecting is only a helper for upper layers */ - msg->conn->err = ERR_CONN; + msg->err = ERR_CONN; } break; #endif /* LWIP_RAW */ @@ -1123,7 +1389,7 @@ do_getaddr(struct api_msg_msg *msg) *(msg->msg.ad.port) = msg->conn->pcb.udp->local_port; } else { if ((msg->conn->pcb.udp->flags & UDP_FLAGS_CONNECTED) == 0) { - msg->conn->err = ERR_CONN; + msg->err = ERR_CONN; } else { *(msg->msg.ad.port) = msg->conn->pcb.udp->remote_port; } @@ -1135,9 +1401,12 @@ do_getaddr(struct api_msg_msg *msg) *(msg->msg.ad.port) = (msg->msg.ad.local?msg->conn->pcb.tcp->local_port:msg->conn->pcb.tcp->remote_port); break; #endif /* LWIP_TCP */ + default: + LWIP_ASSERT("invalid netconn_type", 0); + break; } } else { - msg->conn->err = ERR_CONN; + msg->err = ERR_CONN; } TCPIP_APIMSG_ACK(msg); } @@ -1152,16 +1421,34 @@ void do_close(struct api_msg_msg *msg) { #if LWIP_TCP - if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { + /* @todo: abort running write/connect? */ + if ((msg->conn->state != NETCONN_NONE) && (msg->conn->state != NETCONN_LISTEN)) { + /* this only happens for TCP netconns */ + LWIP_ASSERT("msg->conn->type == NETCONN_TCP", msg->conn->type == NETCONN_TCP); + msg->err = ERR_INPROGRESS; + } else if ((msg->conn->pcb.tcp != NULL) && (msg->conn->type == NETCONN_TCP)) { + if ((msg->msg.sd.shut != NETCONN_SHUT_RDWR) && (msg->conn->state == NETCONN_LISTEN)) { + /* LISTEN doesn't support half shutdown */ + msg->err = ERR_CONN; + } else { + if (msg->msg.sd.shut & NETCONN_SHUT_RD) { + /* Drain and delete mboxes */ + netconn_drain(msg->conn); + } + LWIP_ASSERT("already writing or closing", msg->conn->current_msg == NULL && + msg->conn->write_offset == 0); msg->conn->state = NETCONN_CLOSE; + msg->conn->current_msg = msg; do_close_internal(msg->conn); /* for tcp netconns, do_close_internal ACKs the message */ + return; + } } else #endif /* LWIP_TCP */ { - msg->conn->err = ERR_VAL; - sys_sem_signal(msg->conn->op_completed); + msg->err = ERR_VAL; } + sys_sem_signal(&msg->conn->op_completed); } #if LWIP_IGMP @@ -1174,21 +1461,25 @@ do_close(struct api_msg_msg *msg) void do_join_leave_group(struct api_msg_msg *msg) { - if (!ERR_IS_FATAL(msg->conn->err)) { + if (ERR_IS_FATAL(msg->conn->last_err)) { + msg->err = msg->conn->last_err; + } else { if (msg->conn->pcb.tcp != NULL) { if (NETCONNTYPE_GROUP(msg->conn->type) == NETCONN_UDP) { #if LWIP_UDP if (msg->msg.jl.join_or_leave == NETCONN_JOIN) { - msg->conn->err = igmp_joingroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); + msg->err = igmp_joingroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); } else { - msg->conn->err = igmp_leavegroup(msg->msg.jl.interface, msg->msg.jl.multiaddr); + msg->err = igmp_leavegroup(msg->msg.jl.netif_addr, msg->msg.jl.multiaddr); } #endif /* LWIP_UDP */ #if (LWIP_TCP || LWIP_RAW) } else { - msg->conn->err = ERR_VAL; + msg->err = ERR_VAL; #endif /* (LWIP_TCP || LWIP_RAW) */ } + } else { + msg->err = ERR_CONN; } } TCPIP_APIMSG_ACK(msg); @@ -1202,11 +1493,12 @@ do_join_leave_group(struct api_msg_msg *msg) * signaling the semaphore. */ static void -do_dns_found(const char *name, struct ip_addr *ipaddr, void *arg) +do_dns_found(const char *name, ip_addr_t *ipaddr, void *arg) { struct dns_api_msg *msg = (struct dns_api_msg*)arg; LWIP_ASSERT("DNS response for wrong host name", strcmp(msg->name, name) == 0); + LWIP_UNUSED_ARG(name); if (ipaddr == NULL) { /* timeout or memory error */ diff --git a/core/lwip/src/api/err.c b/core/lwip/src/api/err.c index a90cb98c..92fa8b7d 100644 --- a/core/lwip/src/api/err.c +++ b/core/lwip/src/api/err.c @@ -44,18 +44,19 @@ static const char *err_strerr[] = { "Ok.", /* ERR_OK 0 */ "Out of memory error.", /* ERR_MEM -1 */ "Buffer error.", /* ERR_BUF -2 */ - "Timeout.", /* ERR_TIMEOUT -3 */ + "Timeout.", /* ERR_TIMEOUT -3 */ "Routing problem.", /* ERR_RTE -4 */ - "Connection aborted.", /* ERR_ABRT -5 */ - "Connection reset.", /* ERR_RST -6 */ - "Connection closed.", /* ERR_CLSD -7 */ - "Not connected.", /* ERR_CONN -8 */ - "Illegal value.", /* ERR_VAL -9 */ - "Illegal argument.", /* ERR_ARG -10 */ - "Address in use.", /* ERR_USE -11 */ - "Low-level netif error.", /* ERR_IF -12 */ - "Already connected.", /* ERR_ISCONN -13 */ - "Operation in progress." /* ERR_INPROGRESS -14 */ + "Operation in progress.", /* ERR_INPROGRESS -5 */ + "Illegal value.", /* ERR_VAL -6 */ + "Operation would block.", /* ERR_WOULDBLOCK -7 */ + "Address in use.", /* ERR_USE -8 */ + "Already connected.", /* ERR_ISCONN -9 */ + "Connection aborted.", /* ERR_ABRT -10 */ + "Connection reset.", /* ERR_RST -11 */ + "Connection closed.", /* ERR_CLSD -12 */ + "Not connected.", /* ERR_CONN -13 */ + "Illegal argument.", /* ERR_ARG -14 */ + "Low-level netif error.", /* ERR_IF -15 */ }; /** diff --git a/core/lwip/src/api/netbuf.c b/core/lwip/src/api/netbuf.c index 57efc4f9..9390c9ee 100644 --- a/core/lwip/src/api/netbuf.c +++ b/core/lwip/src/api/netbuf.c @@ -57,16 +57,21 @@ netbuf *netbuf_new(void) { struct netbuf *buf; - buf = memp_malloc(MEMP_NETBUF); + buf = (struct netbuf *)memp_malloc(MEMP_NETBUF); if (buf != NULL) { buf->p = NULL; buf->ptr = NULL; - buf->addr = NULL; + ip_addr_set_any(&buf->addr); buf->port = 0; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + buf->flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ + buf->toport_chksum = 0; #if LWIP_NETBUF_RECVINFO - buf->toaddr = NULL; - buf->toport = 0; + ip_addr_set_any(&buf->toaddr); #endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ return buf; } else { return NULL; diff --git a/core/lwip/src/api/netdb.c b/core/lwip/src/api/netdb.c index 69a331be..a7e4e06b 100644 --- a/core/lwip/src/api/netdb.c +++ b/core/lwip/src/api/netdb.c @@ -39,16 +39,18 @@ #include "lwip/err.h" #include "lwip/mem.h" +#include "lwip/memp.h" #include "lwip/ip_addr.h" #include "lwip/api.h" +#include "lwip/dns.h" #include <string.h> #include <stdlib.h> /** helper struct for gethostbyname_r to access the char* buffer */ struct gethostbyname_r_helper { - struct ip_addr *addrs; - struct ip_addr addr; + ip_addr_t *addrs; + ip_addr_t addr; char *aliases; }; @@ -83,13 +85,13 @@ struct hostent* lwip_gethostbyname(const char *name) { err_t err; - struct ip_addr addr; + ip_addr_t addr; /* buffer variables for lwip_gethostbyname() */ HOSTENT_STORAGE struct hostent s_hostent; HOSTENT_STORAGE char *s_aliases; - HOSTENT_STORAGE struct ip_addr s_hostent_addr; - HOSTENT_STORAGE struct ip_addr *s_phostent_addr; + HOSTENT_STORAGE ip_addr_t s_hostent_addr; + HOSTENT_STORAGE ip_addr_t *s_phostent_addr[2]; /* query host IP address */ err = netconn_gethostbyname(name, &addr); @@ -101,11 +103,12 @@ lwip_gethostbyname(const char *name) /* fill hostent */ s_hostent_addr = addr; - s_phostent_addr = &s_hostent_addr; + s_phostent_addr[0] = &s_hostent_addr; + s_phostent_addr[1] = NULL; s_hostent.h_name = (char*)name; s_hostent.h_aliases = &s_aliases; s_hostent.h_addrtype = AF_INET; - s_hostent.h_length = sizeof(struct ip_addr); + s_hostent.h_length = sizeof(ip_addr_t); s_hostent.h_addr_list = (char**)&s_phostent_addr; #if DNS_DEBUG @@ -126,7 +129,7 @@ lwip_gethostbyname(const char *name) u8_t idx; for ( idx=0; s_hostent.h_addr_list[idx]; idx++) { LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == %p\n", idx, s_hostent.h_addr_list[idx])); - LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa(s_hostent.h_addr_list[idx]))); + LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, ip_ntoa((ip_addr_t*)s_hostent.h_addr_list[idx]))); } } #endif /* DNS_DEBUG */ @@ -211,7 +214,7 @@ lwip_gethostbyname_r(const char *name, struct hostent *ret, char *buf, ret->h_name = (char*)hostname; ret->h_aliases = &(h->aliases); ret->h_addrtype = AF_INET; - ret->h_length = sizeof(struct ip_addr); + ret->h_length = sizeof(ip_addr_t); ret->h_addr_list = (char**)&(h->addrs); /* set result != NULL */ @@ -235,7 +238,7 @@ lwip_freeaddrinfo(struct addrinfo *ai) while (ai != NULL) { next = ai->ai_next; - mem_free(ai); + memp_free(MEMP_NETDB, ai); ai = next; } } @@ -264,7 +267,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, const struct addrinfo *hints, struct addrinfo **res) { err_t err; - struct ip_addr addr; + ip_addr_t addr; struct addrinfo *ai; struct sockaddr_in *sa = NULL; int port_nr = 0; @@ -296,7 +299,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, } } else { /* service location specified, use loopback address */ - addr.addr = htonl(INADDR_LOOPBACK); + ip_addr_set_loopback(&addr); } total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in); @@ -305,17 +308,20 @@ lwip_getaddrinfo(const char *nodename, const char *servname, LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1); total_size += namelen + 1; } - ai = mem_malloc(total_size); + /* If this fails, please report to lwip-devel! :-) */ + LWIP_ASSERT("total_size <= NETDB_ELEM_SIZE: please report this!", + total_size <= NETDB_ELEM_SIZE); + ai = (struct addrinfo *)memp_malloc(MEMP_NETDB); if (ai == NULL) { goto memerr; } memset(ai, 0, total_size); sa = (struct sockaddr_in*)((u8_t*)ai + sizeof(struct addrinfo)); /* set up sockaddr */ - sa->sin_addr.s_addr = addr.addr; + inet_addr_from_ipaddr(&sa->sin_addr, &addr); sa->sin_family = AF_INET; sa->sin_len = sizeof(struct sockaddr_in); - sa->sin_port = htons(port_nr); + sa->sin_port = htons((u16_t)port_nr); /* set up addrinfo */ ai->ai_family = AF_INET; @@ -338,7 +344,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname, return 0; memerr: if (ai != NULL) { - mem_free(ai); + memp_free(MEMP_NETDB, ai); } return EAI_MEMORY; } diff --git a/core/lwip/src/api/netifapi.c b/core/lwip/src/api/netifapi.c index 57089864..43e47203 100644 --- a/core/lwip/src/api/netifapi.c +++ b/core/lwip/src/api/netifapi.c @@ -42,7 +42,7 @@ * Call netif_add() inside the tcpip_thread context. */ void -do_netifapi_netif_add( struct netifapi_msg_msg *msg) +do_netifapi_netif_add(struct netifapi_msg_msg *msg) { if (!netif_add( msg->netif, msg->msg.add.ipaddr, @@ -62,7 +62,7 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg) * Call netif_set_addr() inside the tcpip_thread context. */ void -do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg) +do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg) { netif_set_addr( msg->netif, msg->msg.add.ipaddr, @@ -77,11 +77,10 @@ do_netifapi_netif_set_addr( struct netifapi_msg_msg *msg) * tcpip_thread context. */ void -do_netifapi_netif_common( struct netifapi_msg_msg *msg) +do_netifapi_netif_common(struct netifapi_msg_msg *msg) { - if (msg->msg.common.errtfunc!=NULL) { - msg->err = - msg->msg.common.errtfunc(msg->netif); + if (msg->msg.common.errtfunc != NULL) { + msg->err = msg->msg.common.errtfunc(msg->netif); } else { msg->err = ERR_OK; msg->msg.common.voidfunc(msg->netif); @@ -97,12 +96,12 @@ do_netifapi_netif_common( struct netifapi_msg_msg *msg) */ err_t netifapi_netif_add(struct netif *netif, - struct ip_addr *ipaddr, - struct ip_addr *netmask, - struct ip_addr *gw, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, void *state, - err_t (* init)(struct netif *netif), - err_t (* input)(struct pbuf *p, struct netif *netif)) + netif_init_fn init, + netif_input_fn input) { struct netifapi_msg msg; msg.function = do_netifapi_netif_add; @@ -125,9 +124,9 @@ netifapi_netif_add(struct netif *netif, */ err_t netifapi_netif_set_addr(struct netif *netif, - struct ip_addr *ipaddr, - struct ip_addr *netmask, - struct ip_addr *gw) + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw) { struct netifapi_msg msg; msg.function = do_netifapi_netif_set_addr; @@ -146,9 +145,8 @@ netifapi_netif_set_addr(struct netif *netif, * @note use only for functions where there is only "netif" parameter. */ err_t -netifapi_netif_common( struct netif *netif, - void (* voidfunc)(struct netif *netif), - err_t (* errtfunc)(struct netif *netif) ) +netifapi_netif_common(struct netif *netif, netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc) { struct netifapi_msg msg; msg.function = do_netifapi_netif_common; diff --git a/core/lwip/src/api/sockets.c b/core/lwip/src/api/sockets.c index 340c6dcf..e36012ce 100644 --- a/core/lwip/src/api/sockets.c +++ b/core/lwip/src/api/sockets.c @@ -51,35 +51,43 @@ #include "lwip/raw.h" #include "lwip/udp.h" #include "lwip/tcpip.h" +#include "lwip/pbuf.h" +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" +#endif #include <string.h> #define NUM_SOCKETS MEMP_NUM_NETCONN /** Contains all internal pointers and states used for a socket */ -struct lwip_socket { +struct lwip_sock { /** sockets currently are built on netconns, each socket has one netconn */ struct netconn *conn; /** data that was left from the previous read */ - struct netbuf *lastdata; + void *lastdata; /** offset in the data that was left from the previous read */ u16_t lastoffset; /** number of times data was received, set by event_callback(), tested by the receive and select functions */ s16_t rcvevent; - /** number of times data was received, set by event_callback(), + /** number of times data was ACKed (free send buffer), set by event_callback(), tested by select */ u16_t sendevent; - /** socket flags (currently, only used for O_NONBLOCK) */ - u16_t flags; + /** error happened for this socket, set by event_callback(), tested by select */ + u16_t errevent; /** last error that occurred on this socket */ int err; + /** counter of how many threads are waiting for this socket using select */ + int select_waiting; }; /** Description for a task waiting in select */ struct lwip_select_cb { /** Pointer to the next waiting task */ struct lwip_select_cb *next; + /** Pointer to the previous waiting task */ + struct lwip_select_cb *prev; /** readset passed to select */ fd_set *readset; /** writeset passed to select */ @@ -96,9 +104,11 @@ struct lwip_select_cb { * functions running in tcpip_thread context (only a void* is allowed) */ struct lwip_setgetsockopt_data { /** socket struct for which to change options */ - struct lwip_socket *sock; + struct lwip_sock *sock; +#ifdef LWIP_DEBUG /** socket index for which to change options */ int s; +#endif /* LWIP_DEBUG */ /** level of the option to process */ int level; /** name of the option to process */ @@ -113,14 +123,12 @@ struct lwip_setgetsockopt_data { }; /** The global array of available sockets */ -static struct lwip_socket sockets[NUM_SOCKETS]; +static struct lwip_sock sockets[NUM_SOCKETS]; /** The global list of tasks waiting for select */ static struct lwip_select_cb *select_cb_list; - -/** Semaphore protecting the sockets array */ -static sys_sem_t socksem; -/** Semaphore protecting select_cb_list */ -static sys_sem_t selectsem; +/** This counter is increased from lwip_select when the list is chagned + and checked in event_callback to see if it has changed. */ +static volatile int select_cb_ctr; /** Table to quickly map an lwIP error (err_t) to a socket error * by using -err as an index */ @@ -128,18 +136,19 @@ static const int err_to_errno_table[] = { 0, /* ERR_OK 0 No error, everything OK. */ ENOMEM, /* ERR_MEM -1 Out of memory error. */ ENOBUFS, /* ERR_BUF -2 Buffer error. */ - ETIMEDOUT, /* ERR_TIMEOUT -3 Timeout */ + EWOULDBLOCK, /* ERR_TIMEOUT -3 Timeout */ EHOSTUNREACH, /* ERR_RTE -4 Routing problem. */ - ECONNABORTED, /* ERR_ABRT -5 Connection aborted. */ - ECONNRESET, /* ERR_RST -6 Connection reset. */ - ESHUTDOWN, /* ERR_CLSD -7 Connection closed. */ - ENOTCONN, /* ERR_CONN -8 Not connected. */ - EINVAL, /* ERR_VAL -9 Illegal value. */ - EIO, /* ERR_ARG -10 Illegal argument. */ - EADDRINUSE, /* ERR_USE -11 Address in use. */ - -1, /* ERR_IF -12 Low-level netif error */ - -1, /* ERR_ISCONN -13 Already connected. */ - EINPROGRESS /* ERR_INPROGRESS -14 Operation in progress */ + EINPROGRESS, /* ERR_INPROGRESS -5 Operation in progress */ + EINVAL, /* ERR_VAL -6 Illegal value. */ + EWOULDBLOCK, /* ERR_WOULDBLOCK -7 Operation would block. */ + EADDRINUSE, /* ERR_USE -8 Address in use. */ + EALREADY, /* ERR_ISCONN -9 Already connected. */ + ECONNABORTED, /* ERR_ABRT -10 Connection aborted. */ + ECONNRESET, /* ERR_RST -11 Connection reset. */ + ENOTCONN, /* ERR_CLSD -12 Connection closed. */ + ENOTCONN, /* ERR_CONN -13 Not connected. */ + EIO, /* ERR_ARG -14 Illegal argument. */ + -1, /* ERR_IF -15 Low-level netif error */ }; #define ERR_TO_ERRNO_TABLE_SIZE \ @@ -153,9 +162,9 @@ static const int err_to_errno_table[] = { #ifndef set_errno #define set_errno(err) errno = (err) #endif -#else +#else /* ERRNO */ #define set_errno(err) -#endif +#endif /* ERRNO */ #define sock_set_errno(sk, e) do { \ sk->err = (e); \ @@ -174,20 +183,18 @@ static void lwip_setsockopt_internal(void *arg); void lwip_socket_init(void) { - socksem = sys_sem_new(1); - selectsem = sys_sem_new(1); } /** * Map a externally used socket index to the internal socket representation. * * @param s externally used socket index - * @return struct lwip_socket for the socket or NULL if not found + * @return struct lwip_sock for the socket or NULL if not found */ -static struct lwip_socket * +static struct lwip_sock * get_socket(int s) { - struct lwip_socket *sock; + struct lwip_sock *sock; if ((s < 0) || (s >= NUM_SOCKETS)) { LWIP_DEBUGF(SOCKETS_DEBUG, ("get_socket(%d): invalid\n", s)); @@ -207,37 +214,94 @@ get_socket(int s) } /** + * Same as get_socket but doesn't set errno + * + * @param s externally used socket index + * @return struct lwip_sock for the socket or NULL if not found + */ +static struct lwip_sock * +tryget_socket(int s) +{ + if ((s < 0) || (s >= NUM_SOCKETS)) { + return NULL; + } + if (!sockets[s].conn) { + return NULL; + } + return &sockets[s]; +} + +/** * Allocate a new socket for a given netconn. * * @param newconn the netconn for which to allocate a socket + * @param accepted 1 if socket has been created by accept(), + * 0 if socket has been created by socket() * @return the index of the new socket; -1 on error */ static int -alloc_socket(struct netconn *newconn) +alloc_socket(struct netconn *newconn, int accepted) { int i; - - /* Protect socket array */ - sys_sem_wait(socksem); + SYS_ARCH_DECL_PROTECT(lev); /* allocate a new socket identifier */ for (i = 0; i < NUM_SOCKETS; ++i) { + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); if (!sockets[i].conn) { sockets[i].conn = newconn; + /* The socket is not yet known to anyone, so no need to protect + after having marked it as used. */ + SYS_ARCH_UNPROTECT(lev); sockets[i].lastdata = NULL; sockets[i].lastoffset = 0; sockets[i].rcvevent = 0; - sockets[i].sendevent = 1; /* TCP send buf is empty */ - sockets[i].flags = 0; + /* TCP sendbuf is empty, but the socket is not yet writable until connected + * (unless it has been created by accept()). */ + sockets[i].sendevent = (newconn->type == NETCONN_TCP ? (accepted != 0) : 1); + sockets[i].errevent = 0; sockets[i].err = 0; - sys_sem_signal(socksem); + sockets[i].select_waiting = 0; return i; } + SYS_ARCH_UNPROTECT(lev); } - sys_sem_signal(socksem); return -1; } +/** Free a socket. The socket's netconn must have been + * delete before! + * + * @param sock the socket to free + * @param is_tcp != 0 for TCP sockets, used to free lastdata + */ +static void +free_socket(struct lwip_sock *sock, int is_tcp) +{ + void *lastdata; + SYS_ARCH_DECL_PROTECT(lev); + + lastdata = sock->lastdata; + sock->lastdata = NULL; + sock->lastoffset = 0; + sock->err = 0; + + /* Protect socket array */ + SYS_ARCH_PROTECT(lev); + sock->conn = NULL; + SYS_ARCH_UNPROTECT(lev); + /* don't use 'sock' after this line, as another task might have allocated it */ + + if (lastdata != NULL) { + if (is_tcp) { + pbuf_free((struct pbuf *)lastdata); + } else { + netbuf_delete((struct netbuf *)lastdata); + } + } +} + /* Below this, the well-known socket functions are implemented. * Use google.com or opengroup.org to get a good description :-) * @@ -247,35 +311,42 @@ alloc_socket(struct netconn *newconn) int lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) { - struct lwip_socket *sock, *nsock; + struct lwip_sock *sock, *nsock; struct netconn *newconn; - struct ip_addr naddr; + ip_addr_t naddr; u16_t port; int newsock; struct sockaddr_in sin; err_t err; + SYS_ARCH_DECL_PROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d)...\n", s)); sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } - if ((sock->flags & O_NONBLOCK) && (sock->rcvevent <= 0)) { + if (netconn_is_nonblocking(sock->conn) && (sock->rcvevent <= 0)) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): returning EWOULDBLOCK\n", s)); sock_set_errno(sock, EWOULDBLOCK); return -1; } - newconn = netconn_accept(sock->conn); - if (!newconn) { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) failed, err=%d\n", s, sock->conn->err)); - sock_set_errno(sock, err_to_errno(sock->conn->err)); + /* wait for a new connection */ + err = netconn_accept(sock->conn, &newconn); + if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_acept failed, err=%d\n", s, err)); + sock_set_errno(sock, err_to_errno(err)); return -1; } + LWIP_ASSERT("newconn != NULL", newconn != NULL); + /* Prevent automatic window updates, we do this on our own! */ + netconn_set_noautorecved(newconn, 1); /* get the IP address and port of the remote host */ err = netconn_peer(newconn, &naddr, &port); if (err != ERR_OK) { + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d): netconn_peer failed, err=%d\n", s, err)); netconn_delete(newconn); sock_set_errno(sock, err_to_errno(err)); return -1; @@ -290,7 +361,7 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(port); - sin.sin_addr.s_addr = naddr.addr; + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); if (*addrlen > sizeof(sin)) *addrlen = sizeof(sin); @@ -298,26 +369,25 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) MEMCPY(addr, &sin, *addrlen); } - newsock = alloc_socket(newconn); + newsock = alloc_socket(newconn, 1); if (newsock == -1) { netconn_delete(newconn); sock_set_errno(sock, ENFILE); return -1; } LWIP_ASSERT("invalid socket index", (newsock >= 0) && (newsock < NUM_SOCKETS)); - newconn->callback = event_callback; + LWIP_ASSERT("newconn->callback == event_callback", newconn->callback == event_callback); nsock = &sockets[newsock]; - LWIP_ASSERT("invalid socket pointer", nsock != NULL); - sys_sem_wait(socksem); /* See event_callback: If data comes in right away after an accept, even * though the server task might not have created a new socket yet. * In that case, newconn->socket is counted down (newconn->socket--), * so nsock->rcvevent is >= 1 here! */ - nsock->rcvevent += -1 - newconn->socket; + SYS_ARCH_PROTECT(lev); + nsock->rcvevent += (s16_t)(-1 - newconn->socket); newconn->socket = newsock; - sys_sem_signal(socksem); + SYS_ARCH_UNPROTECT(lev); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_accept(%d) returning new sock=%d addr=", s, newsock)); ip_addr_debug_print(SOCKETS_DEBUG, &naddr); @@ -330,21 +400,25 @@ lwip_accept(int s, struct sockaddr *addr, socklen_t *addrlen) int lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) { - struct lwip_socket *sock; - struct ip_addr local_addr; + struct lwip_sock *sock; + ip_addr_t local_addr; u16_t local_port; err_t err; + const struct sockaddr_in *name_in; sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } + /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_bind: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), + ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + name_in = (const struct sockaddr_in *)(void*)name; - local_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; - local_port = ((const struct sockaddr_in *)name)->sin_port; + inet_addr_to_ipaddr(&local_addr, &name_in->sin_addr); + local_port = name_in->sin_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_bind(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &local_addr); @@ -366,7 +440,8 @@ lwip_bind(int s, const struct sockaddr *name, socklen_t namelen) int lwip_close(int s) { - struct lwip_socket *sock; + struct lwip_sock *sock; + int is_tcp = 0; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_close(%d)\n", s)); @@ -375,43 +450,46 @@ lwip_close(int s) return -1; } + if(sock->conn != NULL) { + is_tcp = netconn_type(sock->conn) == NETCONN_TCP; + } else { + LWIP_ASSERT("sock->lastdata == NULL", sock->lastdata == NULL); + } + netconn_delete(sock->conn); - sys_sem_wait(socksem); - if (sock->lastdata) { - netbuf_delete(sock->lastdata); - } - sock->lastdata = NULL; - sock->lastoffset = 0; - sock->conn = NULL; - sock_set_errno(sock, 0); - sys_sem_signal(socksem); + free_socket(sock, is_tcp); + set_errno(0); return 0; } int lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) { - struct lwip_socket *sock; + struct lwip_sock *sock; err_t err; + const struct sockaddr_in *name_in; sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } + /* check size, familiy and alignment of 'name' */ LWIP_ERROR("lwip_connect: invalid address", ((namelen == sizeof(struct sockaddr_in)) && - ((((const struct sockaddr_in *)name)->sin_family) == AF_INET)), + ((name->sa_family) == AF_INET) && ((((mem_ptr_t)name) % 4) == 0)), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + name_in = (const struct sockaddr_in *)(void*)name; - if (((const struct sockaddr_in *)name)->sin_family == AF_UNSPEC) { + if (name_in->sin_family == AF_UNSPEC) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, AF_UNSPEC)\n", s)); err = netconn_disconnect(sock->conn); } else { - struct ip_addr remote_addr; + ip_addr_t remote_addr; u16_t remote_port; - remote_addr.addr = ((const struct sockaddr_in *)name)->sin_addr.s_addr; - remote_port = ((const struct sockaddr_in *)name)->sin_port; + inet_addr_to_ipaddr(&remote_addr, &name_in->sin_addr); + remote_port = name_in->sin_port; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_connect(%d, addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); @@ -436,30 +514,26 @@ lwip_connect(int s, const struct sockaddr *name, socklen_t namelen) * The socket may not have been used for another connection previously. * * @param s the socket to set to listening mode - * @param backlog (ATTENTION: need TCP_LISTEN_BACKLOG=1) + * @param backlog (ATTENTION: needs TCP_LISTEN_BACKLOG=1) * @return 0 on success, non-zero on failure */ int lwip_listen(int s, int backlog) { - struct lwip_socket *sock; + struct lwip_sock *sock; err_t err; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d, backlog=%d)\n", s, backlog)); sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } /* limit the "backlog" parameter to fit in an u8_t */ - if (backlog < 0) { - backlog = 0; - } - if (backlog > 0xff) { - backlog = 0xff; - } + backlog = LWIP_MIN(LWIP_MAX(backlog, 0), 0xff); - err = netconn_listen_with_backlog(sock->conn, backlog); + err = netconn_listen_with_backlog(sock->conn, (u8_t)backlog); if (err != ERR_OK) { LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_listen(%d) failed, err=%d\n", s, err)); @@ -475,28 +549,34 @@ int lwip_recvfrom(int s, void *mem, size_t len, int flags, struct sockaddr *from, socklen_t *fromlen) { - struct lwip_socket *sock; - struct netbuf *buf; - u16_t buflen, copylen, off = 0; - struct ip_addr *addr; - u16_t port; - u8_t done = 0; + struct lwip_sock *sock; + void *buf = NULL; + struct pbuf *p; + u16_t buflen, copylen; + int off = 0; + ip_addr_t *addr; + u16_t port; + u8_t done = 0; + err_t err; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d, %p, %"SZT_F", 0x%x, ..)\n", s, mem, len, flags)); sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } do { - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", (void*)sock->lastdata)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: top while sock->lastdata=%p\n", sock->lastdata)); /* Check if there is data left from the last recv operation. */ if (sock->lastdata) { buf = sock->lastdata; } else { /* If this is non-blocking call, then check first */ - if (((flags & MSG_DONTWAIT) || (sock->flags & O_NONBLOCK)) && + if (((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) && (sock->rcvevent <= 0)) { if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); /* already received data, return that */ sock_set_errno(sock, 0); return off; @@ -507,26 +587,44 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, } /* No data was left from the previous operation, so we try to get - some from the network. */ - sock->lastdata = buf = netconn_recv(sock->conn); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv netbuf=%p\n", (void*)buf)); + some from the network. */ + if (netconn_type(sock->conn) == NETCONN_TCP) { + err = netconn_recv_tcp_pbuf(sock->conn, (struct pbuf **)&buf); + } else { + err = netconn_recv(sock->conn, (struct netbuf **)&buf); + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: netconn_recv err=%d, netbuf=%p\n", + err, buf)); - if (!buf) { + if (err != ERR_OK) { if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); /* already received data, return that */ sock_set_errno(sock, 0); return off; } /* We should really do some error checking here. */ - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL!\n", s)); - sock_set_errno(sock, (((sock->conn->pcb.ip != NULL) && (sock->conn->err == ERR_OK)) - ? ETIMEDOUT : err_to_errno(sock->conn->err))); - return 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): buf == NULL, error is \"%s\"!\n", + s, lwip_strerr(err))); + sock_set_errno(sock, err_to_errno(err)); + if (err == ERR_CLSD) { + return 0; + } else { + return -1; + } } + LWIP_ASSERT("buf != NULL", buf != NULL); + sock->lastdata = buf; } - buflen = netbuf_len(buf); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%"U16_F" sock->lastoffset=%"U16_F"\n", + if (netconn_type(sock->conn) == NETCONN_TCP) { + p = (struct pbuf *)buf; + } else { + p = ((struct netbuf *)buf)->p; + } + buflen = p->tot_len; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: buflen=%"U16_F" len=%"SZT_F" off=%d sock->lastoffset=%"U16_F"\n", buflen, len, off, sock->lastoffset)); buflen -= sock->lastoffset; @@ -539,7 +637,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, /* copy the contents of the received buffer into the supplied memory pointer mem */ - netbuf_copy_partial(buf, (u8_t*)mem + off, copylen, sock->lastoffset); + pbuf_copy_partial(p, (u8_t*)mem + off, copylen, sock->lastoffset); off += copylen; @@ -547,7 +645,7 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, LWIP_ASSERT("invalid copylen, len would underflow", len >= copylen); len -= copylen; if ( (len <= 0) || - (buf->p->flags & PBUF_FLAG_PUSH) || + (p->flags & PBUF_FLAG_PUSH) || (sock->rcvevent <= 0) || ((flags & MSG_PEEK)!=0)) { done = 1; @@ -558,22 +656,23 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, /* Check to see from where the data was.*/ if (done) { + ip_addr_t fromaddr; if (from && fromlen) { struct sockaddr_in sin; if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = (struct ip_addr*)&(sin.sin_addr.s_addr); + addr = &fromaddr; netconn_getaddr(sock->conn, addr, &port, 0); } else { - addr = netbuf_fromaddr(buf); - port = netbuf_fromport(buf); + addr = netbuf_fromaddr((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); } memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); sin.sin_family = AF_INET; sin.sin_port = htons(port); - sin.sin_addr.s_addr = addr->addr; + inet_addr_from_ipaddr(&sin.sin_addr, addr); if (*fromlen > sizeof(sin)) { *fromlen = sizeof(sin); @@ -583,44 +682,50 @@ lwip_recvfrom(int s, void *mem, size_t len, int flags, LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); } else { - #if SOCKETS_DEBUG - struct sockaddr_in sin; - +#if SOCKETS_DEBUG if (netconn_type(sock->conn) == NETCONN_TCP) { - addr = (struct ip_addr*)&(sin.sin_addr.s_addr); + addr = &fromaddr; netconn_getaddr(sock->conn, addr, &port, 0); } else { - addr = netbuf_fromaddr(buf); - port = netbuf_fromport(buf); + addr = netbuf_fromaddr((struct netbuf *)buf); + port = netbuf_fromport((struct netbuf *)buf); } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom(%d): addr=", s)); ip_addr_debug_print(SOCKETS_DEBUG, addr); - LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%"U16_F"\n", port, off)); - #endif /* SOCKETS_DEBUG */ + LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F" len=%d\n", port, off)); +#endif /* SOCKETS_DEBUG */ } } /* If we don't peek the incoming message... */ - if ((flags & MSG_PEEK)==0) { + if ((flags & MSG_PEEK) == 0) { /* If this is a TCP socket, check if there is data left in the buffer. If so, it should be saved in the sock structure for next time around. */ if ((netconn_type(sock->conn) == NETCONN_TCP) && (buflen - copylen > 0)) { sock->lastdata = buf; sock->lastoffset += copylen; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", (void*)buf)); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: lastdata now netbuf=%p\n", buf)); } else { sock->lastdata = NULL; sock->lastoffset = 0; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", (void*)buf)); - netbuf_delete(buf); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_recvfrom: deleting netbuf=%p\n", buf)); + if (netconn_type(sock->conn) == NETCONN_TCP) { + pbuf_free((struct pbuf *)buf); + } else { + netbuf_delete((struct netbuf *)buf); + } } } } while (!done); + if (off > 0) { + /* update receive window */ + netconn_recved(sock->conn, (u32_t)off); + } sock_set_errno(sock, 0); return off; } @@ -640,26 +745,39 @@ lwip_recv(int s, void *mem, size_t len, int flags) int lwip_send(int s, const void *data, size_t size, int flags) { - struct lwip_socket *sock; + struct lwip_sock *sock; err_t err; + u8_t write_flags; LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d, data=%p, size=%"SZT_F", flags=0x%x)\n", s, data, size, flags)); sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } if (sock->conn->type != NETCONN_TCP) { #if (LWIP_UDP || LWIP_RAW) return lwip_sendto(s, data, size, flags, NULL, 0); -#else +#else /* (LWIP_UDP || LWIP_RAW) */ sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1; #endif /* (LWIP_UDP || LWIP_RAW) */ } - err = netconn_write(sock->conn, data, size, NETCONN_COPY | ((flags & MSG_MORE)?NETCONN_MORE:0)); + if ((flags & MSG_DONTWAIT) || netconn_is_nonblocking(sock->conn)) { + if ((size > TCP_SND_BUF) || ((size / TCP_MSS) > TCP_SND_QUEUELEN)) { + /* too much data to ever send nonblocking! */ + sock_set_errno(sock, EMSGSIZE); + return -1; + } + } + + write_flags = NETCONN_COPY | + ((flags & MSG_MORE) ? NETCONN_MORE : 0) | + ((flags & MSG_DONTWAIT) ? NETCONN_DONTBLOCK : 0); + err = netconn_write(sock->conn, data, size, write_flags); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_send(%d) err=%d size=%"SZT_F"\n", s, err, size)); sock_set_errno(sock, err_to_errno(err)); @@ -670,77 +788,115 @@ int lwip_sendto(int s, const void *data, size_t size, int flags, const struct sockaddr *to, socklen_t tolen) { - struct lwip_socket *sock; - struct ip_addr remote_addr; + struct lwip_sock *sock; err_t err; u16_t short_size; + const struct sockaddr_in *to_in; + u16_t remote_port; #if !LWIP_TCPIP_CORE_LOCKING struct netbuf buf; - u16_t remote_port; #endif sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } if (sock->conn->type == NETCONN_TCP) { #if LWIP_TCP return lwip_send(s, data, size, flags); -#else +#else /* LWIP_TCP */ + LWIP_UNUSED_ARG(flags); sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1; #endif /* LWIP_TCP */ } + /* @todo: split into multiple sendto's? */ LWIP_ASSERT("lwip_sendto: size must fit in u16_t", size <= 0xffff); short_size = (u16_t)size; LWIP_ERROR("lwip_sendto: invalid address", (((to == NULL) && (tolen == 0)) || ((tolen == sizeof(struct sockaddr_in)) && - ((((const struct sockaddr_in *)to)->sin_family) == AF_INET))), + ((to->sa_family) == AF_INET) && ((((mem_ptr_t)to) % 4) == 0))), sock_set_errno(sock, err_to_errno(ERR_ARG)); return -1;); + to_in = (const struct sockaddr_in *)(void*)to; #if LWIP_TCPIP_CORE_LOCKING /* Should only be consider like a sample or a simple way to experiment this option (no check of "to" field...) */ - { struct pbuf* p; - - p = pbuf_alloc(PBUF_TRANSPORT, 0, PBUF_REF); - if (p == NULL) { - err = ERR_MEM; - } else { + { + struct pbuf* p; + ip_addr_t *remote_addr; + +#if LWIP_NETIF_TX_SINGLE_PBUF + p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_RAM); + if (p != NULL) { +#if LWIP_CHECKSUM_ON_COPY + u16_t chksum = 0; + if (sock->conn->type != NETCONN_RAW) { + chksum = LWIP_CHKSUM_COPY(p->payload, data, short_size); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + MEMCPY(p->payload, data, size); +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(PBUF_TRANSPORT, short_size, PBUF_REF); + if (p != NULL) { p->payload = (void*)data; - p->len = p->tot_len = short_size; - - remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; - +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + if (to_in != NULL) { + inet_addr_to_ipaddr_p(remote_addr, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + } else { + remote_addr = &sock->conn->pcb.raw->remote_ip; + if (sock->conn->type == NETCONN_RAW) { + remote_port = 0; + } else { + remote_port = sock->conn->pcb.udp->remote_port; + } + } + LOCK_TCPIP_CORE(); - if (sock->conn->type==NETCONN_RAW) { - err = sock->conn->err = raw_sendto(sock->conn->pcb.raw, p, &remote_addr); + if (sock->conn->type == NETCONN_RAW) { + err = sock->conn->last_err = raw_sendto(sock->conn->pcb.raw, p, remote_addr); } else { - err = sock->conn->err = udp_sendto(sock->conn->pcb.udp, p, &remote_addr, ntohs(((const struct sockaddr_in *)to)->sin_port)); +#if LWIP_UDP +#if LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF + err = sock->conn->last_err = udp_sendto_chksum(sock->conn->pcb.udp, p, + remote_addr, remote_port, 1, chksum); +#else /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ + err = sock->conn->last_err = udp_sendto(sock->conn->pcb.udp, p, + remote_addr, remote_port); +#endif /* LWIP_CHECKSUM_ON_COPY && LWIP_NETIF_TX_SINGLE_PBUF */ +#else /* LWIP_UDP */ + err = ERR_ARG; +#endif /* LWIP_UDP */ } UNLOCK_TCPIP_CORE(); pbuf_free(p); + } else { + err = ERR_MEM; } } -#else +#else /* LWIP_TCPIP_CORE_LOCKING */ /* initialize a buffer */ buf.p = buf.ptr = NULL; +#if LWIP_CHECKSUM_ON_COPY + buf.flags = 0; +#endif /* LWIP_CHECKSUM_ON_COPY */ if (to) { - remote_addr.addr = ((const struct sockaddr_in *)to)->sin_addr.s_addr; - remote_port = ntohs(((const struct sockaddr_in *)to)->sin_port); - buf.addr = &remote_addr; - buf.port = remote_port; + inet_addr_to_ipaddr(&buf.addr, &to_in->sin_addr); + remote_port = ntohs(to_in->sin_port); + netbuf_fromport(&buf) = remote_port; } else { - remote_addr.addr = 0; - remote_port = 0; - buf.addr = NULL; - buf.port = 0; + remote_port = 0; + ip_addr_set_any(&buf.addr); + netbuf_fromport(&buf) = 0; } - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%d"U16_F", flags=0x%x to=", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_sendto(%d, data=%p, short_size=%"U16_F", flags=0x%x to=", s, data, short_size, flags)); - ip_addr_debug_print(SOCKETS_DEBUG, &remote_addr); + ip_addr_debug_print(SOCKETS_DEBUG, &buf.addr); LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F"\n", remote_port)); /* make the buffer point to the data that should be sent */ @@ -749,7 +905,16 @@ lwip_sendto(int s, const void *data, size_t size, int flags, if (netbuf_alloc(&buf, short_size) == NULL) { err = ERR_MEM; } else { - err = netbuf_take(&buf, data, short_size); +#if LWIP_CHECKSUM_ON_COPY + if (sock->conn->type != NETCONN_RAW) { + u16_t chksum = LWIP_CHKSUM_COPY(buf.p->payload, data, short_size); + netbuf_set_chksum(&buf, chksum); + err = ERR_OK; + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + err = netbuf_take(&buf, data, short_size); + } } #else /* LWIP_NETIF_TX_SINGLE_PBUF */ err = netbuf_ref(&buf, data, short_size); @@ -791,6 +956,10 @@ lwip_socket(int domain, int type, int protocol) conn = netconn_new_with_callback(NETCONN_TCP, event_callback); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%s, SOCK_STREAM, %d) = ", domain == PF_INET ? "PF_INET" : "UNKNOWN", protocol)); + if (conn != NULL) { + /* Prevent automatic window updates, we do this on our own! */ + netconn_set_noautorecved(conn, 1); + } break; default: LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_socket(%d, %d/UNKNOWN, %d) = -1\n", @@ -805,7 +974,7 @@ lwip_socket(int domain, int type, int protocol) return -1; } - i = alloc_socket(conn); + i = alloc_socket(conn, 0); if (i == -1) { netconn_delete(conn); @@ -832,200 +1001,228 @@ lwip_write(int s, const void *data, size_t size) * exceptset is not used for now!!! * * @param maxfdp1 the highest socket index in the sets - * @param readset in: set of sockets to check for read events; - * out: set of sockets that had read events - * @param writeset in: set of sockets to check for write events; - * out: set of sockets that had write events - * @param exceptset not yet implemented - * @return number of sockets that had events (read+write) + * @param readset_in: set of sockets to check for read events + * @param writeset_in: set of sockets to check for write events + * @param exceptset_in: set of sockets to check for error events + * @param readset_out: set of sockets that had read events + * @param writeset_out: set of sockets that had write events + * @param exceptset_out: set os sockets that had error events + * @return number of sockets that had events (read/write/exception) (>= 0) */ static int -lwip_selscan(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset) +lwip_selscan(int maxfdp1, fd_set *readset_in, fd_set *writeset_in, fd_set *exceptset_in, + fd_set *readset_out, fd_set *writeset_out, fd_set *exceptset_out) { int i, nready = 0; fd_set lreadset, lwriteset, lexceptset; - struct lwip_socket *p_sock; - + struct lwip_sock *sock; + SYS_ARCH_DECL_PROTECT(lev); + FD_ZERO(&lreadset); FD_ZERO(&lwriteset); FD_ZERO(&lexceptset); - + /* Go through each socket in each list to count number of sockets which - currently match */ + currently match */ for(i = 0; i < maxfdp1; i++) { - if (FD_ISSET(i, readset)) { - /* See if netconn of this socket is ready for read */ - p_sock = get_socket(i); - if (p_sock && (p_sock->lastdata || (p_sock->rcvevent > 0))) { - FD_SET(i, &lreadset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); - nready++; - } + void* lastdata = NULL; + s16_t rcvevent = 0; + u16_t sendevent = 0; + u16_t errevent = 0; + /* First get the socket's status (protected)... */ + SYS_ARCH_PROTECT(lev); + sock = tryget_socket(i); + if (sock != NULL) { + lastdata = sock->lastdata; + rcvevent = sock->rcvevent; + sendevent = sock->sendevent; + errevent = sock->errevent; } - if (FD_ISSET(i, writeset)) { - /* See if netconn of this socket is ready for write */ - p_sock = get_socket(i); - if (p_sock && p_sock->sendevent) { - FD_SET(i, &lwriteset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); - nready++; - } + SYS_ARCH_UNPROTECT(lev); + /* ... then examine it: */ + /* See if netconn of this socket is ready for read */ + if (readset_in && FD_ISSET(i, readset_in) && ((lastdata != NULL) || (rcvevent > 0))) { + FD_SET(i, &lreadset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for reading\n", i)); + nready++; + } + /* See if netconn of this socket is ready for write */ + if (writeset_in && FD_ISSET(i, writeset_in) && (sendevent != 0)) { + FD_SET(i, &lwriteset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for writing\n", i)); + nready++; + } + /* See if netconn of this socket had an error */ + if (exceptset_in && FD_ISSET(i, exceptset_in) && (errevent != 0)) { + FD_SET(i, &lexceptset); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_selscan: fd=%d ready for exception\n", i)); + nready++; } } - *readset = lreadset; - *writeset = lwriteset; - FD_ZERO(exceptset); - + /* copy local sets to the ones provided as arguments */ + *readset_out = lreadset; + *writeset_out = lwriteset; + *exceptset_out = lexceptset; + + LWIP_ASSERT("nready >= 0", nready >= 0); return nready; } - /** * Processing exceptset is not yet implemented. */ int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, - struct timeval *timeout) + struct timeval *timeout) { - int i; + u32_t waitres = 0; int nready; fd_set lreadset, lwriteset, lexceptset; u32_t msectimeout; struct lwip_select_cb select_cb; - struct lwip_select_cb *p_selcb; + err_t err; + int i; + SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%ld tvusec=%ld)\n", + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select(%d, %p, %p, %p, tvsec=%"S32_F" tvusec=%"S32_F")\n", maxfdp1, (void *)readset, (void *) writeset, (void *) exceptset, - timeout ? (long)timeout->tv_sec : (long)-1, - timeout ? (long)timeout->tv_usec : (long)-1)); - - select_cb.next = 0; - select_cb.readset = readset; - select_cb.writeset = writeset; - select_cb.exceptset = exceptset; - select_cb.sem_signalled = 0; - - /* Protect ourselves searching through the list */ - sys_sem_wait(selectsem); - - if (readset) - lreadset = *readset; - else - FD_ZERO(&lreadset); - if (writeset) - lwriteset = *writeset; - else - FD_ZERO(&lwriteset); - if (exceptset) - lexceptset = *exceptset; - else - FD_ZERO(&lexceptset); + timeout ? (s32_t)timeout->tv_sec : (s32_t)-1, + timeout ? (s32_t)timeout->tv_usec : (s32_t)-1)); /* Go through each socket in each list to count number of sockets which currently match */ - nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); /* If we don't have any current events, then suspend if we are supposed to */ if (!nready) { if (timeout && timeout->tv_sec == 0 && timeout->tv_usec == 0) { - sys_sem_signal(selectsem); - if (readset) - FD_ZERO(readset); - if (writeset) - FD_ZERO(writeset); - if (exceptset) - FD_ZERO(exceptset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: no timeout, returning 0\n")); - set_errno(0); - - return 0; + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; } - - /* add our semaphore to list */ - /* We don't actually need any dynamic memory. Our entry on the - * list is only valid while we are in this function, so it's ok - * to use local variables */ - - select_cb.sem = sys_sem_new(0); - /* Note that we are still protected */ + + /* None ready: add our semaphore to list: + We don't actually need any dynamic memory. Our entry on the + list is only valid while we are in this function, so it's ok + to use local variables. */ + + select_cb.next = NULL; + select_cb.prev = NULL; + select_cb.readset = readset; + select_cb.writeset = writeset; + select_cb.exceptset = exceptset; + select_cb.sem_signalled = 0; + err = sys_sem_new(&select_cb.sem, 0); + if (err != ERR_OK) { + /* failed to create semaphore */ + set_errno(ENOMEM); + return -1; + } + + /* Protect the select_cb_list */ + SYS_ARCH_PROTECT(lev); + /* Put this select_cb on top of list */ select_cb.next = select_cb_list; + if (select_cb_list != NULL) { + select_cb_list->prev = &select_cb; + } select_cb_list = &select_cb; - + /* Increasing this counter tells even_callback that the list has changed. */ + select_cb_ctr++; + /* Now we can safely unprotect */ - sys_sem_signal(selectsem); - - /* Now just wait to be woken */ - if (timeout == 0) - /* Wait forever */ - msectimeout = 0; - else { - msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); - if(msectimeout == 0) - msectimeout = 1; + SYS_ARCH_UNPROTECT(lev); + + /* Increase select_waiting for each socket we are interested in */ + for(i = 0; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock = tryget_socket(i); + LWIP_ASSERT("sock != NULL", sock != NULL); + SYS_ARCH_PROTECT(lev); + sock->select_waiting++; + LWIP_ASSERT("sock->select_waiting > 0", sock->select_waiting > 0); + SYS_ARCH_UNPROTECT(lev); + } } - - i = sys_sem_wait_timeout(select_cb.sem, msectimeout); - - /* Take us off the list */ - sys_sem_wait(selectsem); - if (select_cb_list == &select_cb) - select_cb_list = select_cb.next; - else - for (p_selcb = select_cb_list; p_selcb; p_selcb = p_selcb->next) { - if (p_selcb->next == &select_cb) { - p_selcb->next = select_cb.next; - break; + + /* Call lwip_selscan again: there could have been events between + the last scan (whithout us on the list) and putting us on the list! */ + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + if (!nready) { + /* Still none ready, just wait to be woken */ + if (timeout == 0) { + /* Wait forever */ + msectimeout = 0; + } else { + msectimeout = ((timeout->tv_sec * 1000) + ((timeout->tv_usec + 500)/1000)); + if (msectimeout == 0) { + /* Wait 1ms at least (0 means wait forever) */ + msectimeout = 1; } } - - sys_sem_signal(selectsem); - - sys_sem_free(select_cb.sem); - if (i == 0) { + + waitres = sys_arch_sem_wait(&select_cb.sem, msectimeout); + } + /* Increase select_waiting for each socket we are interested in */ + for(i = 0; i < maxfdp1; i++) { + if ((readset && FD_ISSET(i, readset)) || + (writeset && FD_ISSET(i, writeset)) || + (exceptset && FD_ISSET(i, exceptset))) { + struct lwip_sock *sock = tryget_socket(i); + LWIP_ASSERT("sock != NULL", sock != NULL); + SYS_ARCH_PROTECT(lev); + sock->select_waiting--; + LWIP_ASSERT("sock->select_waiting >= 0", sock->select_waiting >= 0); + SYS_ARCH_UNPROTECT(lev); + } + } + /* Take us off the list */ + SYS_ARCH_PROTECT(lev); + if (select_cb.next != NULL) { + select_cb.next->prev = select_cb.prev; + } + if (select_cb_list == &select_cb) { + LWIP_ASSERT("select_cb.prev == NULL", select_cb.prev == NULL); + select_cb_list = select_cb.next; + } else { + LWIP_ASSERT("select_cb.prev != NULL", select_cb.prev != NULL); + select_cb.prev->next = select_cb.next; + } + /* Increasing this counter tells even_callback that the list has changed. */ + select_cb_ctr++; + SYS_ARCH_UNPROTECT(lev); + + sys_sem_free(&select_cb.sem); + if (waitres == SYS_ARCH_TIMEOUT) { /* Timeout */ - if (readset) - FD_ZERO(readset); - if (writeset) - FD_ZERO(writeset); - if (exceptset) - FD_ZERO(exceptset); - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: timeout expired\n")); - set_errno(0); - - return 0; + /* This is OK as the local fdsets are empty and nready is zero, + or we would have returned earlier. */ + goto return_copy_fdsets; } - - if (readset) - lreadset = *readset; - else - FD_ZERO(&lreadset); - if (writeset) - lwriteset = *writeset; - else - FD_ZERO(&lwriteset); - if (exceptset) - lexceptset = *exceptset; - else - FD_ZERO(&lexceptset); - + /* See what's set */ - nready = lwip_selscan(maxfdp1, &lreadset, &lwriteset, &lexceptset); - } else - sys_sem_signal(selectsem); - - if (readset) + nready = lwip_selscan(maxfdp1, readset, writeset, exceptset, &lreadset, &lwriteset, &lexceptset); + } + + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); +return_copy_fdsets: + set_errno(0); + if (readset) { *readset = lreadset; - if (writeset) + } + if (writeset) { *writeset = lwriteset; - if (exceptset) + } + if (exceptset) { *exceptset = lexceptset; - - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_select: nready=%d\n", nready)); - set_errno(0); - + } + + return nready; } @@ -1037,8 +1234,10 @@ static void event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) { int s; - struct lwip_socket *sock; + struct lwip_sock *sock; struct lwip_select_cb *scb; + int last_select_cb_ctr; + SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(len); @@ -1051,16 +1250,16 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) * Just count down (or up) if that's the case and we * will use the data later. Note that only receive events * can happen before the new socket is set up. */ - sys_sem_wait(socksem); + SYS_ARCH_PROTECT(lev); if (conn->socket < 0) { if (evt == NETCONN_EVT_RCVPLUS) { conn->socket--; } - sys_sem_signal(socksem); + SYS_ARCH_UNPROTECT(lev); return; } s = conn->socket; - sys_sem_signal(socksem); + SYS_ARCH_UNPROTECT(lev); } sock = get_socket(s); @@ -1071,7 +1270,7 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) return; } - sys_sem_wait(selectsem); + SYS_ARCH_PROTECT(lev); /* Set event as required */ switch (evt) { case NETCONN_EVT_RCVPLUS: @@ -1086,41 +1285,65 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) case NETCONN_EVT_SENDMINUS: sock->sendevent = 0; break; + case NETCONN_EVT_ERROR: + sock->errevent = 1; + break; default: LWIP_ASSERT("unknown event", 0); break; } - sys_sem_signal(selectsem); + + if (sock->select_waiting == 0) { + /* noone is waiting for this socket, no need to check select_cb_list */ + SYS_ARCH_UNPROTECT(lev); + return; + } /* Now decide if anyone is waiting for this socket */ - /* NOTE: This code is written this way to protect the select link list - but to avoid a deadlock situation by releasing socksem before - signalling for the select. This means we need to go through the list - multiple times ONLY IF a select was actually waiting. We go through - the list the number of waiting select calls + 1. This list is - expected to be small. */ - while (1) { - sys_sem_wait(selectsem); - for (scb = select_cb_list; scb; scb = scb->next) { - if (scb->sem_signalled == 0) { - /* Test this select call for our socket */ - if (scb->readset && FD_ISSET(s, scb->readset)) - if (sock->rcvevent > 0) - break; - if (scb->writeset && FD_ISSET(s, scb->writeset)) - if (sock->sendevent) - break; + /* NOTE: This code goes through the select_cb_list list multiple times + ONLY IF a select was actually waiting. We go through the list the number + of waiting select calls + 1. This list is expected to be small. */ + + /* At this point, SYS_ARCH is still protected! */ +again: + for (scb = select_cb_list; scb != NULL; scb = scb->next) { + if (scb->sem_signalled == 0) { + /* semaphore not signalled yet */ + int do_signal = 0; + /* Test this select call for our socket */ + if (sock->rcvevent > 0) { + if (scb->readset && FD_ISSET(s, scb->readset)) { + do_signal = 1; + } + } + if (sock->sendevent != 0) { + if (!do_signal && scb->writeset && FD_ISSET(s, scb->writeset)) { + do_signal = 1; + } + } + if (sock->errevent != 0) { + if (!do_signal && scb->exceptset && FD_ISSET(s, scb->exceptset)) { + do_signal = 1; + } + } + if (do_signal) { + scb->sem_signalled = 1; + /* Don't call SYS_ARCH_UNPROTECT() before signaling the semaphore, as this might + lead to the select thread taking itself off the list, invalidagin the semaphore. */ + sys_sem_signal(&scb->sem); } } - if (scb) { - scb->sem_signalled = 1; - sys_sem_signal(scb->sem); - sys_sem_signal(selectsem); - } else { - sys_sem_signal(selectsem); - break; + /* unlock interrupts with each step */ + last_select_cb_ctr = select_cb_ctr; + SYS_ARCH_UNPROTECT(lev); + /* this makes sure interrupt protection time is short */ + SYS_ARCH_PROTECT(lev); + if (last_select_cb_ctr != select_cb_ctr) { + /* someone has changed select_cb_list, restart at the beginning */ + goto again; } } + SYS_ARCH_UNPROTECT(lev); } /** @@ -1130,21 +1353,55 @@ event_callback(struct netconn *conn, enum netconn_evt evt, u16_t len) int lwip_shutdown(int s, int how) { - LWIP_UNUSED_ARG(how); + struct lwip_sock *sock; + err_t err; + u8_t shut_rx = 0, shut_tx = 0; + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_shutdown(%d, how=%d)\n", s, how)); - return lwip_close(s); /* XXX temporary hack until proper implementation */ + + sock = get_socket(s); + if (!sock) { + return -1; + } + + if (sock->conn != NULL) { + if (netconn_type(sock->conn) != NETCONN_TCP) { + sock_set_errno(sock, EOPNOTSUPP); + return EOPNOTSUPP; + } + } else { + sock_set_errno(sock, ENOTCONN); + return ENOTCONN; + } + + if (how == SHUT_RD) { + shut_rx = 1; + } else if (how == SHUT_WR) { + shut_tx = 1; + } else if(how == SHUT_RDWR) { + shut_rx = 1; + shut_tx = 1; + } else { + sock_set_errno(sock, EINVAL); + return EINVAL; + } + err = netconn_shutdown(sock->conn, shut_rx, shut_tx); + + sock_set_errno(sock, err_to_errno(err)); + return (err == ERR_OK ? 0 : -1); } static int lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) { - struct lwip_socket *sock; + struct lwip_sock *sock; struct sockaddr_in sin; - struct ip_addr naddr; + ip_addr_t naddr; sock = get_socket(s); - if (!sock) + if (!sock) { return -1; + } memset(&sin, 0, sizeof(sin)); sin.sin_len = sizeof(sin); @@ -1158,10 +1415,11 @@ lwip_getaddrname(int s, struct sockaddr *name, socklen_t *namelen, u8_t local) LWIP_DEBUGF(SOCKETS_DEBUG, (" port=%"U16_F")\n", sin.sin_port)); sin.sin_port = htons(sin.sin_port); - sin.sin_addr.s_addr = naddr.addr; + inet_addr_from_ipaddr(&sin.sin_addr, &naddr); - if (*namelen > sizeof(sin)) + if (*namelen > sizeof(sin)) { *namelen = sizeof(sin); + } MEMCPY(name, &sin, *namelen); sock_set_errno(sock, 0); @@ -1184,11 +1442,12 @@ int lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) { err_t err = ERR_OK; - struct lwip_socket *sock = get_socket(s); + struct lwip_sock *sock = get_socket(s); struct lwip_setgetsockopt_data data; - if (!sock) + if (!sock) { return -1; + } if ((NULL == optval) || (NULL == optlen)) { sock_set_errno(sock, EFAULT); @@ -1274,6 +1533,14 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) err = EINVAL; } break; + case IP_MULTICAST_LOOP: + if (*optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; #endif /* LWIP_IGMP */ default: @@ -1321,8 +1588,9 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) } /* If this is no UDP lite socket, ignore any options. */ - if (sock->conn->type != NETCONN_UDPLITE) + if (sock->conn->type != NETCONN_UDPLITE) { return 0; + } switch (optname) { case UDPLITE_SEND_CSCOV: @@ -1351,13 +1619,16 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) /* Now do the actual option processing */ data.sock = sock; +#ifdef LWIP_DEBUG + data.s = s; +#endif /* LWIP_DEBUG */ data.level = level; data.optname = optname; data.optval = optval; data.optlen = optlen; data.err = err; tcpip_callback(lwip_getsockopt_internal, &data); - sys_arch_sem_wait(sock->conn->op_completed, 0); + sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_getsockopt_internal has changed err */ err = data.err; @@ -1368,7 +1639,7 @@ lwip_getsockopt(int s, int level, int optname, void *optval, socklen_t *optlen) static void lwip_getsockopt_internal(void *arg) { - struct lwip_socket *sock; + struct lwip_sock *sock; #ifdef LWIP_DEBUG int s; #endif /* LWIP_DEBUG */ @@ -1388,7 +1659,7 @@ lwip_getsockopt_internal(void *arg) optval = data->optval; switch (level) { - + /* Level: SOL_SOCKET */ case SOL_SOCKET: switch (optname) { @@ -1432,8 +1703,9 @@ lwip_getsockopt_internal(void *arg) break; case SO_ERROR: - if (sock->err == 0) { - sock_set_errno(sock, err_to_errno(sock->conn->err)); + /* only overwrite ERR_OK or tempoary errors */ + if ((sock->err == 0) || (sock->err == EINPROGRESS)) { + sock_set_errno(sock, err_to_errno(sock->conn->last_err)); } *(int *)optval = sock->err; sock->err = 0; @@ -1443,12 +1715,12 @@ lwip_getsockopt_internal(void *arg) #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: - *(int *)optval = sock->conn->recv_timeout; + *(int *)optval = netconn_get_recvtimeout(sock->conn); break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: - *(int *)optval = sock->conn->recv_bufsize; + *(int *)optval = netconn_get_recvbufsize(sock->conn); break; #endif /* LWIP_SO_RCVBUF */ #if LWIP_UDP @@ -1456,6 +1728,9 @@ lwip_getsockopt_internal(void *arg) *(int*)optval = (udp_flags(sock->conn->pcb.udp) & UDP_FLAGS_NOCHKSUM) ? 1 : 0; break; #endif /* LWIP_UDP*/ + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; @@ -1479,11 +1754,23 @@ lwip_getsockopt_internal(void *arg) s, *(int *)optval)); break; case IP_MULTICAST_IF: - ((struct in_addr*) optval)->s_addr = sock->conn->pcb.udp->multicast_ip.addr; + inet_addr_from_ipaddr((struct in_addr*)optval, &sock->conn->pcb.udp->multicast_ip); LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_IF) = 0x%"X32_F"\n", s, *(u32_t *)optval)); break; + case IP_MULTICAST_LOOP: + if ((sock->conn->pcb.udp->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) { + *(u8_t*)optval = 1; + } else { + *(u8_t*)optval = 0; + } + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_IP, IP_MULTICAST_LOOP) = %d\n", + s, *(int *)optval)); + break; #endif /* LWIP_IGMP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; @@ -1519,7 +1806,9 @@ lwip_getsockopt_internal(void *arg) s, *(int *)optval)); break; #endif /* LWIP_TCP_KEEPALIVE */ - + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; #endif /* LWIP_TCP */ @@ -1537,22 +1826,29 @@ lwip_getsockopt_internal(void *arg) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_getsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) = %d\n", s, (*(int*)optval)) ); break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; #endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled level", 0); + break; } /* switch (level) */ - sys_sem_signal(sock->conn->op_completed); + sys_sem_signal(&sock->conn->op_completed); } int lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t optlen) { - struct lwip_socket *sock = get_socket(s); - int err = ERR_OK; + struct lwip_sock *sock = get_socket(s); + err_t err = ERR_OK; struct lwip_setgetsockopt_data data; - if (!sock) + if (!sock) { return -1; + } if (NULL == optval) { sock_set_errno(sock, EFAULT); @@ -1639,6 +1935,14 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt err = EAFNOSUPPORT; } break; + case IP_MULTICAST_LOOP: + if (optlen < sizeof(u8_t)) { + err = EINVAL; + } + if (NETCONNTYPE_GROUP(sock->conn->type) != NETCONN_UDP) { + err = EAFNOSUPPORT; + } + break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: if (optlen < sizeof(struct ip_mreq)) { @@ -1725,13 +2029,16 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt /* Now do the actual option processing */ data.sock = sock; +#ifdef LWIP_DEBUG + data.s = s; +#endif /* LWIP_DEBUG */ data.level = level; data.optname = optname; data.optval = (void*)optval; data.optlen = &optlen; data.err = err; tcpip_callback(lwip_setsockopt_internal, &data); - sys_arch_sem_wait(sock->conn->op_completed, 0); + sys_arch_sem_wait(&sock->conn->op_completed, 0); /* maybe lwip_setsockopt_internal has changed err */ err = data.err; @@ -1742,7 +2049,7 @@ lwip_setsockopt(int s, int level, int optname, const void *optval, socklen_t opt static void lwip_setsockopt_internal(void *arg) { - struct lwip_socket *sock; + struct lwip_sock *sock; #ifdef LWIP_DEBUG int s; #endif /* LWIP_DEBUG */ @@ -1788,12 +2095,12 @@ lwip_setsockopt_internal(void *arg) break; #if LWIP_SO_RCVTIMEO case SO_RCVTIMEO: - sock->conn->recv_timeout = ( *(int*)optval ); + netconn_set_recvtimeout(sock->conn, *(int*)optval); break; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF case SO_RCVBUF: - sock->conn->recv_bufsize = ( *(int*)optval ); + netconn_set_recvbufsize(sock->conn, *(int*)optval); break; #endif /* LWIP_SO_RCVBUF */ #if LWIP_UDP @@ -1805,6 +2112,9 @@ lwip_setsockopt_internal(void *arg) } break; #endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; @@ -1826,17 +2136,28 @@ lwip_setsockopt_internal(void *arg) sock->conn->pcb.udp->ttl = (u8_t)(*(u8_t*)optval); break; case IP_MULTICAST_IF: - sock->conn->pcb.udp->multicast_ip.addr = ((struct in_addr*) optval)->s_addr; + inet_addr_to_ipaddr(&sock->conn->pcb.udp->multicast_ip, (struct in_addr*)optval); + break; + case IP_MULTICAST_LOOP: + if (*(u8_t*)optval) { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) | UDP_FLAGS_MULTICAST_LOOP); + } else { + udp_setflags(sock->conn->pcb.udp, udp_flags(sock->conn->pcb.udp) & ~UDP_FLAGS_MULTICAST_LOOP); + } break; case IP_ADD_MEMBERSHIP: case IP_DROP_MEMBERSHIP: { /* If this is a TCP or a RAW socket, ignore these options. */ struct ip_mreq *imr = (struct ip_mreq *)optval; + ip_addr_t if_addr; + ip_addr_t multi_addr; + inet_addr_to_ipaddr(&if_addr, &imr->imr_interface); + inet_addr_to_ipaddr(&multi_addr, &imr->imr_multiaddr); if(optname == IP_ADD_MEMBERSHIP){ - data->err = igmp_joingroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); + data->err = igmp_joingroup(&if_addr, &multi_addr); } else { - data->err = igmp_leavegroup((struct ip_addr*)&(imr->imr_interface.s_addr), (struct ip_addr*)&(imr->imr_multiaddr.s_addr)); + data->err = igmp_leavegroup(&if_addr, &multi_addr); } if(data->err != ERR_OK) { data->err = EADDRNOTAVAIL; @@ -1844,6 +2165,9 @@ lwip_setsockopt_internal(void *arg) } break; #endif /* LWIP_IGMP */ + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; @@ -1883,7 +2207,9 @@ lwip_setsockopt_internal(void *arg) s, sock->conn->pcb.tcp->keep_cnt)); break; #endif /* LWIP_TCP_KEEPALIVE */ - + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; #endif /* LWIP_TCP*/ @@ -1892,43 +2218,54 @@ lwip_setsockopt_internal(void *arg) case IPPROTO_UDPLITE: switch (optname) { case UDPLITE_SEND_CSCOV: - if ((*(int*)optval != 0) && (*(int*)optval < 8)) { + if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_tx = 8; } else { - sock->conn->pcb.udp->chksum_len_tx = *(int*)optval; + sock->conn->pcb.udp->chksum_len_tx = (u16_t)*(int*)optval; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_SEND_CSCOV) -> %d\n", s, (*(int*)optval)) ); break; case UDPLITE_RECV_CSCOV: - if ((*(int*)optval != 0) && (*(int*)optval < 8)) { + if ((*(int*)optval != 0) && ((*(int*)optval < 8)) || (*(int*)optval > 0xffff)) { /* don't allow illegal values! */ sock->conn->pcb.udp->chksum_len_rx = 8; } else { - sock->conn->pcb.udp->chksum_len_rx = *(int*)optval; + sock->conn->pcb.udp->chksum_len_rx = (u16_t)*(int*)optval; } LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_setsockopt(%d, IPPROTO_UDPLITE, UDPLITE_RECV_CSCOV) -> %d\n", s, (*(int*)optval)) ); break; + default: + LWIP_ASSERT("unhandled optname", 0); + break; } /* switch (optname) */ break; #endif /* LWIP_UDP */ + default: + LWIP_ASSERT("unhandled level", 0); + break; } /* switch (level) */ - sys_sem_signal(sock->conn->op_completed); + sys_sem_signal(&sock->conn->op_completed); } int lwip_ioctl(int s, long cmd, void *argp) { - struct lwip_socket *sock = get_socket(s); + struct lwip_sock *sock = get_socket(s); + u8_t val; +#if LWIP_SO_RCVBUF u16_t buflen = 0; s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ - if (!sock) + if (!sock) { return -1; + } switch (cmd) { +#if LWIP_SO_RCVBUF case FIONREAD: if (!argp) { sock_set_errno(sock, EINVAL); @@ -1936,13 +2273,18 @@ lwip_ioctl(int s, long cmd, void *argp) } SYS_ARCH_GET(sock->conn->recv_avail, recv_avail); - if (recv_avail < 0) + if (recv_avail < 0) { recv_avail = 0; + } *((u16_t*)argp) = (u16_t)recv_avail; /* Check if there is data left from the last recv operation. /maq 041215 */ if (sock->lastdata) { - buflen = netbuf_len(sock->lastdata); + struct pbuf *p = (struct pbuf *)sock->lastdata; + if (netconn_type(sock->conn) != NETCONN_TCP) { + p = ((struct netbuf *)p)->p; + } + buflen = p->tot_len; buflen -= sock->lastoffset; *((u16_t*)argp) += buflen; @@ -1951,13 +2293,15 @@ lwip_ioctl(int s, long cmd, void *argp) LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONREAD, %p) = %"U16_F"\n", s, argp, *((u16_t*)argp))); sock_set_errno(sock, 0); return 0; +#endif /* LWIP_SO_RCVBUF */ case FIONBIO: - if (argp && *(u32_t*)argp) - sock->flags |= O_NONBLOCK; - else - sock->flags &= ~O_NONBLOCK; - LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, !!(sock->flags & O_NONBLOCK))); + val = 0; + if (argp && *(u32_t*)argp) { + val = 1; + } + netconn_set_nonblocking(sock->conn, val); + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_ioctl(%d, FIONBIO, %d)\n", s, val)); sock_set_errno(sock, 0); return 0; @@ -1968,4 +2312,36 @@ lwip_ioctl(int s, long cmd, void *argp) } /* switch (cmd) */ } +/** A minimal implementation of fcntl. + * Currently only the commands F_GETFL and F_SETFL are implemented. + * Only the flag O_NONBLOCK is implemented. + */ +int +lwip_fcntl(int s, int cmd, int val) +{ + struct lwip_sock *sock = get_socket(s); + int ret = -1; + + if (!sock || !sock->conn) { + return -1; + } + + switch (cmd) { + case F_GETFL: + ret = netconn_is_nonblocking(sock->conn) ? O_NONBLOCK : 0; + break; + case F_SETFL: + if ((val & ~O_NONBLOCK) == 0) { + /* only O_NONBLOCK, all other bits are zero */ + netconn_set_nonblocking(sock->conn, val & O_NONBLOCK); + ret = 0; + } + break; + default: + LWIP_DEBUGF(SOCKETS_DEBUG, ("lwip_fcntl(%d, UNIMPL: %d, %d)\n", s, cmd, val)); + break; + } + return ret; +} + #endif /* LWIP_SOCKET */ diff --git a/core/lwip/src/api/tcpip.c b/core/lwip/src/api/tcpip.c index 9c0ba5b6..857e7d9b 100644 --- a/core/lwip/src/api/tcpip.c +++ b/core/lwip/src/api/tcpip.c @@ -42,183 +42,23 @@ #include "lwip/sys.h" #include "lwip/memp.h" +#include "lwip/mem.h" #include "lwip/pbuf.h" -#include "lwip/ip_frag.h" -#include "lwip/tcp.h" -#include "lwip/autoip.h" -#include "lwip/dhcp.h" -#include "lwip/igmp.h" -#include "lwip/dns.h" #include "lwip/tcpip.h" #include "lwip/init.h" #include "netif/etharp.h" #include "netif/ppp_oe.h" /* global variables */ -static void (* tcpip_init_done)(void *arg); +static tcpip_init_done_fn tcpip_init_done; static void *tcpip_init_done_arg; -static sys_mbox_t mbox = SYS_MBOX_NULL; +static sys_mbox_t mbox; #if LWIP_TCPIP_CORE_LOCKING /** The global semaphore to lock the stack. */ -sys_sem_t lock_tcpip_core; +sys_mutex_t lock_tcpip_core; #endif /* LWIP_TCPIP_CORE_LOCKING */ -#if LWIP_TCP -/* global variable that shows if the tcp timer is currently scheduled or not */ -static int tcpip_tcp_timer_active; - -/** - * Timer callback function that calls tcp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -tcpip_tcp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - - /* call TCP timer handler */ - tcp_tmr(); - /* timer still needed? */ - if (tcp_active_pcbs || tcp_tw_pcbs) { - /* restart timer */ - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } else { - /* disable timer */ - tcpip_tcp_timer_active = 0; - } -} - -#if !NO_SYS -/** - * Called from TCP_REG when registering a new PCB: - * the reason is to have the TCP timer only running when - * there are active (or time-wait) PCBs. - */ -void -tcp_timer_needed(void) -{ - /* timer is off but needed again? */ - if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { - /* enable and start timer */ - tcpip_tcp_timer_active = 1; - sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); - } -} -#endif /* !NO_SYS */ -#endif /* LWIP_TCP */ - -#if IP_REASSEMBLY -/** - * Timer callback function that calls ip_reass_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -ip_reass_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: ip_reass_tmr()\n")); - ip_reass_tmr(); - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -} -#endif /* IP_REASSEMBLY */ - -#if LWIP_ARP -/** - * Timer callback function that calls etharp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -arp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: etharp_tmr()\n")); - etharp_tmr(); - undiarp_tmr(); - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -} -#endif /* LWIP_ARP */ - -#if LWIP_DHCP -/** - * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dhcp_timer_coarse(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); - dhcp_coarse_tmr(); - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); -} - -/** - * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dhcp_timer_fine(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); - dhcp_fine_tmr(); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -} -#endif /* LWIP_DHCP */ - -#if LWIP_AUTOIP -/** - * Timer callback function that calls autoip_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -autoip_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: autoip_tmr()\n")); - autoip_tmr(); - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -} -#endif /* LWIP_AUTOIP */ - -#if LWIP_IGMP -/** - * Timer callback function that calls igmp_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -igmp_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: igmp_tmr()\n")); - igmp_tmr(); - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -} -#endif /* LWIP_IGMP */ - -#if LWIP_DNS -/** - * Timer callback function that calls dns_tmr() and reschedules itself. - * - * @param arg unused argument - */ -static void -dns_timer(void *arg) -{ - LWIP_UNUSED_ARG(arg); - LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip: dns_tmr()\n")); - dns_tmr(); - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -} -#endif /* LWIP_DNS */ /** * The main lwIP thread. This thread has exclusive access to lwIP core functions @@ -236,33 +76,17 @@ tcpip_thread(void *arg) struct tcpip_msg *msg; LWIP_UNUSED_ARG(arg); -#if IP_REASSEMBLY - sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); -#endif /* IP_REASSEMBLY */ -#if LWIP_ARP - sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); -#endif /* LWIP_ARP */ -#if LWIP_DHCP - sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); - sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); -#endif /* LWIP_DHCP */ -#if LWIP_AUTOIP - sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); -#endif /* LWIP_AUTOIP */ -#if LWIP_IGMP - sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); -#endif /* LWIP_IGMP */ -#if LWIP_DNS - sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); -#endif /* LWIP_DNS */ - if (tcpip_init_done != NULL) { tcpip_init_done(tcpip_init_done_arg); } LOCK_TCPIP_CORE(); while (1) { /* MAIN Loop */ - sys_mbox_fetch(mbox, (void *)&msg); + UNLOCK_TCPIP_CORE(); + LWIP_TCPIP_THREAD_ALIVE(); + /* wait for a message, timeouts are processed while waiting */ + sys_timeouts_mbox_fetch(&mbox, (void **)&msg); + LOCK_TCPIP_CORE(); switch (msg->type) { #if LWIP_NETCONN case TCPIP_MSG_API: @@ -271,17 +95,20 @@ tcpip_thread(void *arg) break; #endif /* LWIP_NETCONN */ +#if !LWIP_TCPIP_CORE_LOCKING_INPUT case TCPIP_MSG_INPKT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: PACKET %p\n", (void *)msg)); -#if LWIP_ARP - if (msg->msg.inp.netif->flags & NETIF_FLAG_ETHARP) { +#if LWIP_ETHERNET + if (msg->msg.inp.netif->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { ethernet_input(msg->msg.inp.p, msg->msg.inp.netif); } else -#endif /* LWIP_ARP */ - { ip_input(msg->msg.inp.p, msg->msg.inp.netif); +#endif /* LWIP_ETHERNET */ + { + ip_input(msg->msg.inp.p, msg->msg.inp.netif); } memp_free(MEMP_TCPIP_MSG_INPKT, msg); break; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ #if LWIP_NETIF_API case TCPIP_MSG_NETIFAPI: @@ -292,10 +119,11 @@ tcpip_thread(void *arg) case TCPIP_MSG_CALLBACK: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK %p\n", (void *)msg)); - msg->msg.cb.f(msg->msg.cb.ctx); + msg->msg.cb.function(msg->msg.cb.ctx); memp_free(MEMP_TCPIP_MSG_API, msg); break; +#if LWIP_TCPIP_TIMEOUT case TCPIP_MSG_TIMEOUT: LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg)); sys_timeout(msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg); @@ -306,8 +134,11 @@ tcpip_thread(void *arg) sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg); memp_free(MEMP_TCPIP_MSG_API, msg); break; +#endif /* LWIP_TCPIP_TIMEOUT */ default: + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type)); + LWIP_ASSERT("tcpip_thread: invalid message", 0); break; } } @@ -317,16 +148,32 @@ tcpip_thread(void *arg) * Pass a received packet to tcpip_thread for input processing * * @param p the received packet, p->payload pointing to the Ethernet header or - * to an IP header (if netif doesn't got NETIF_FLAG_ETHARP flag) + * to an IP header (if inp doesn't have NETIF_FLAG_ETHARP or + * NETIF_FLAG_ETHERNET flags) * @param inp the network interface on which the packet was received */ err_t tcpip_input(struct pbuf *p, struct netif *inp) { +#if LWIP_TCPIP_CORE_LOCKING_INPUT + err_t ret; + LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_input: PACKET %p/%p\n", (void *)p, (void *)inp)); + LOCK_TCPIP_CORE(); +#if LWIP_ETHERNET + if (inp->flags & (NETIF_FLAG_ETHARP | NETIF_FLAG_ETHERNET)) { + ret = ethernet_input(p, inp); + } else +#endif /* LWIP_ETHERNET */ + { + ret = ip_input(p, inp); + } + UNLOCK_TCPIP_CORE(); + return ret; +#else /* LWIP_TCPIP_CORE_LOCKING_INPUT */ struct tcpip_msg *msg; - if (mbox != SYS_MBOX_NULL) { - msg = memp_malloc(MEMP_TCPIP_MSG_INPKT); + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT); if (msg == NULL) { return ERR_MEM; } @@ -334,13 +181,14 @@ tcpip_input(struct pbuf *p, struct netif *inp) msg->type = TCPIP_MSG_INPKT; msg->msg.inp.p = p; msg->msg.inp.netif = inp; - if (sys_mbox_trypost(mbox, msg) != ERR_OK) { + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { memp_free(MEMP_TCPIP_MSG_INPKT, msg); return ERR_MEM; } return ERR_OK; } return ERR_VAL; +#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */ } /** @@ -355,23 +203,23 @@ tcpip_input(struct pbuf *p, struct netif *inp) * @return ERR_OK if the function was called, another err_t if not */ err_t -tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block) +tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block) { struct tcpip_msg *msg; - if (mbox != SYS_MBOX_NULL) { - msg = memp_malloc(MEMP_TCPIP_MSG_API); + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } msg->type = TCPIP_MSG_CALLBACK; - msg->msg.cb.f = f; + msg->msg.cb.function = function; msg->msg.cb.ctx = ctx; if (block) { - sys_mbox_post(mbox, msg); + sys_mbox_post(&mbox, msg); } else { - if (sys_mbox_trypost(mbox, msg) != ERR_OK) { + if (sys_mbox_trypost(&mbox, msg) != ERR_OK) { memp_free(MEMP_TCPIP_MSG_API, msg); return ERR_MEM; } @@ -381,10 +229,11 @@ tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block) return ERR_VAL; } +#if LWIP_TCPIP_TIMEOUT /** * call sys_timeout in tcpip_thread * - * @param msec time in miliseconds for timeout + * @param msec time in milliseconds for timeout * @param h function to be called on timeout * @param arg argument to pass to timeout function h * @return ERR_MEM on memory error, ERR_OK otherwise @@ -394,8 +243,8 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) { struct tcpip_msg *msg; - if (mbox != SYS_MBOX_NULL) { - msg = memp_malloc(MEMP_TCPIP_MSG_API); + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } @@ -404,7 +253,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) msg->msg.tmo.msecs = msecs; msg->msg.tmo.h = h; msg->msg.tmo.arg = arg; - sys_mbox_post(mbox, msg); + sys_mbox_post(&mbox, msg); return ERR_OK; } return ERR_VAL; @@ -413,7 +262,7 @@ tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg) /** * call sys_untimeout in tcpip_thread * - * @param msec time in miliseconds for timeout + * @param msec time in milliseconds for timeout * @param h function to be called on timeout * @param arg argument to pass to timeout function h * @return ERR_MEM on memory error, ERR_OK otherwise @@ -423,8 +272,8 @@ tcpip_untimeout(sys_timeout_handler h, void *arg) { struct tcpip_msg *msg; - if (mbox != SYS_MBOX_NULL) { - msg = memp_malloc(MEMP_TCPIP_MSG_API); + if (sys_mbox_valid(&mbox)) { + msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API); if (msg == NULL) { return ERR_MEM; } @@ -432,11 +281,12 @@ tcpip_untimeout(sys_timeout_handler h, void *arg) msg->type = TCPIP_MSG_UNTIMEOUT; msg->msg.tmo.h = h; msg->msg.tmo.arg = arg; - sys_mbox_post(mbox, msg); + sys_mbox_post(&mbox, msg); return ERR_OK; } return ERR_VAL; } +#endif /* LWIP_TCPIP_TIMEOUT */ #if LWIP_NETCONN /** @@ -451,13 +301,17 @@ err_t tcpip_apimsg(struct api_msg *apimsg) { struct tcpip_msg msg; +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->msg.err = ERR_VAL; +#endif - if (mbox != SYS_MBOX_NULL) { + if (sys_mbox_valid(&mbox)) { msg.type = TCPIP_MSG_API; msg.msg.apimsg = apimsg; - sys_mbox_post(mbox, &msg); - sys_arch_sem_wait(apimsg->msg.conn->op_completed, 0); - return ERR_OK; + sys_mbox_post(&mbox, &msg); + sys_arch_sem_wait(&apimsg->msg.conn->op_completed, 0); + return apimsg->msg.err; } return ERR_VAL; } @@ -474,10 +328,15 @@ tcpip_apimsg(struct api_msg *apimsg) err_t tcpip_apimsg_lock(struct api_msg *apimsg) { +#ifdef LWIP_DEBUG + /* catch functions that don't set err */ + apimsg->msg.err = ERR_VAL; +#endif + LOCK_TCPIP_CORE(); apimsg->function(&(apimsg->msg)); UNLOCK_TCPIP_CORE(); - return ERR_OK; + return apimsg->msg.err; } #endif /* LWIP_TCPIP_CORE_LOCKING */ @@ -497,18 +356,18 @@ tcpip_netifapi(struct netifapi_msg* netifapimsg) { struct tcpip_msg msg; - if (mbox != SYS_MBOX_NULL) { - netifapimsg->msg.sem = sys_sem_new(0); - if (netifapimsg->msg.sem == SYS_SEM_NULL) { - netifapimsg->msg.err = ERR_MEM; - return netifapimsg->msg.err; + if (sys_mbox_valid(&mbox)) { + err_t err = sys_sem_new(&netifapimsg->msg.sem, 0); + if (err != ERR_OK) { + netifapimsg->msg.err = err; + return err; } msg.type = TCPIP_MSG_NETIFAPI; msg.msg.netifapimsg = netifapimsg; - sys_mbox_post(mbox, &msg); - sys_sem_wait(netifapimsg->msg.sem); - sys_sem_free(netifapimsg->msg.sem); + sys_mbox_post(&mbox, &msg); + sys_sem_wait(&netifapimsg->msg.sem); + sys_sem_free(&netifapimsg->msg.sem); return netifapimsg->msg.err; } return ERR_VAL; @@ -542,15 +401,19 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg) * @param arg argument to pass to initfunc */ void -tcpip_init(void (* initfunc)(void *), void *arg) +tcpip_init(tcpip_init_done_fn initfunc, void *arg) { lwip_init(); tcpip_init_done = initfunc; tcpip_init_done_arg = arg; - mbox = sys_mbox_new(TCPIP_MBOX_SIZE); + if(sys_mbox_new(&mbox, TCPIP_MBOX_SIZE) != ERR_OK) { + LWIP_ASSERT("failed to create tcpip_thread mbox", 0); + } #if LWIP_TCPIP_CORE_LOCKING - lock_tcpip_core = sys_sem_new(1); + if(sys_mutex_new(&lock_tcpip_core) != ERR_OK) { + LWIP_ASSERT("failed to create lock_tcpip_core", 0); + } #endif /* LWIP_TCPIP_CORE_LOCKING */ sys_thread_new(TCPIP_THREAD_NAME, tcpip_thread, NULL, TCPIP_THREAD_STACKSIZE, TCPIP_THREAD_PRIO); @@ -565,7 +428,7 @@ tcpip_init(void (* initfunc)(void *), void *arg) static void pbuf_free_int(void *p) { - struct pbuf *q = p; + struct pbuf *q = (struct pbuf *)p; pbuf_free(q); } diff --git a/core/lwip/src/arch/sys_arch.c b/core/lwip/src/arch/sys_arch.c index 65be3874..5f8437e8 100644 --- a/core/lwip/src/arch/sys_arch.c +++ b/core/lwip/src/arch/sys_arch.c @@ -8,77 +8,119 @@ void sys_init(void) { } -sys_sem_t sys_sem_new(u8_t count) +err_t sys_sem_new(sys_sem_t *sem, u8_t count) { - sys_sem_t sem = malloc(sizeof(struct semaphore)); if (!sem) - return NULL; + return EINVAL; + *sem = malloc(sizeof(struct semaphore)); + if (!*sem) + return ENOMEM; - sem_init(sem, count); - return sem; + sem_init(*sem, count); + return 0; } -void sys_sem_free(sys_sem_t sem) +void sys_sem_free(sys_sem_t *sem) { - free(sem); + if (!!sem && !!*sem) { + sys_sem_set_invalid(sem); + free(*sem); + } } -u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout) +void sys_sem_set_invalid(sys_sem_t *sem) +{ + if (!sem || !*sem) + return; + sem_set_invalid(*sem); +} + + +int sys_sem_valid(sys_sem_t *sem) +{ + if (!sem || !*sem) + return 0; + return sem_is_valid(*sem); +} + +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout) { mstime_t rv; - rv = sem_down(sem, timeout); + if (!!sem) + return SYS_ARCH_TIMEOUT; + rv = sem_down(*sem, timeout); if (rv == (mstime_t)-1) return SYS_ARCH_TIMEOUT; else return rv; } -sys_mbox_t sys_mbox_new(int size) +err_t sys_mbox_new(sys_mbox_t *mbox, int size) { - struct mailbox *mbox; - - mbox = malloc(MBOX_BYTES(size)); if (!mbox) - return NULL; + return EINVAL; + *mbox = malloc(MBOX_BYTES(size)); + if (!(*mbox)) + return ENOMEM; - mbox_init(mbox, size); - return mbox; + mbox_init(*mbox, size); + return 0; } -void sys_mbox_free(sys_mbox_t mbox) +void sys_mbox_free(sys_mbox_t *mbox) { - free(mbox); + if (!!mbox && !!*mbox) + free(*mbox); } -void sys_mbox_post(sys_mbox_t mbox, void *msg) +void sys_mbox_post(sys_mbox_t *mbox, void *msg) { - mbox_post(mbox, msg, 0); + if (!!mbox) + mbox_post(*mbox, msg, 0); } -err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg) +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg) { - return mbox_post(mbox, msg, -1); + if (!mbox) + return EINVAL; + return mbox_post(*mbox, msg, -1); } -u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout) +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout) { mstime_t rv; - rv = mbox_fetch(mbox, msg, timeout); + if (!mbox) + return SYS_MBOX_EMPTY; + rv = mbox_fetch(*mbox, msg, timeout); if (rv == (mstime_t)-1) return SYS_ARCH_TIMEOUT; else return rv; } -u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg) +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg) +{ + if (!mbox) + return SYS_MBOX_EMPTY; + return mbox_fetch(*mbox, msg, -1); +} + +void sys_mbox_set_invalid(sys_mbox_t *mbox) { - return mbox_fetch(mbox, msg, -1); + if (!!mbox) + mbox_set_invalid(*mbox); } -sys_thread_t sys_thread_new(char *name, void (*thread)(void *), - void *arg, int stacksize, int prio) +int sys_mbox_valid(sys_mbox_t *mbox) +{ + return ((!!mbox) && mbox_is_valid(*mbox)); +} + + +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, + void *arg, int stacksize, int prio) { return start_thread(name, stacksize, prio, thread, arg); } diff --git a/core/lwip/src/core/def.c b/core/lwip/src/core/def.c new file mode 100644 index 00000000..352b5524 --- /dev/null +++ b/core/lwip/src/core/def.c @@ -0,0 +1,108 @@ +/** + * @file + * Common functions used throughout the stack. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Simon Goldschmidt + * + */ + +#include "lwip/opt.h" +#include "lwip/def.h" + +/** + * These are reference implementations of the byte swapping functions. + * Again with the aim of being simple, correct and fully portable. + * Byte swapping is the second thing you would want to optimize. You will + * need to port it to your architecture and in your cc.h: + * + * #define LWIP_PLATFORM_BYTESWAP 1 + * #define LWIP_PLATFORM_HTONS(x) <your_htons> + * #define LWIP_PLATFORM_HTONL(x) <your_htonl> + * + * Note ntohs() and ntohl() are merely references to the htonx counterparts. + */ + +#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) + +/** + * Convert an u16_t from host- to network byte order. + * + * @param n u16_t in host byte order + * @return n in network byte order + */ +u16_t +lwip_htons(u16_t n) +{ + return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); +} + +/** + * Convert an u16_t from network- to host byte order. + * + * @param n u16_t in network byte order + * @return n in host byte order + */ +u16_t +lwip_ntohs(u16_t n) +{ + return lwip_htons(n); +} + +/** + * Convert an u32_t from host- to network byte order. + * + * @param n u32_t in host byte order + * @return n in network byte order + */ +u32_t +lwip_htonl(u32_t n) +{ + return ((n & 0xff) << 24) | + ((n & 0xff00) << 8) | + ((n & 0xff0000UL) >> 8) | + ((n & 0xff000000UL) >> 24); +} + +/** + * Convert an u32_t from network- to host byte order. + * + * @param n u32_t in network byte order + * @return n in host byte order + */ +u32_t +lwip_ntohl(u32_t n) +{ + return lwip_htonl(n); +} + +#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/core/lwip/src/core/dhcp.c b/core/lwip/src/core/dhcp.c index 82068bfd..81b4be27 100644 --- a/core/lwip/src/core/dhcp.c +++ b/core/lwip/src/core/dhcp.c @@ -43,8 +43,6 @@ * with RFC 2131 and RFC 2132. * * TODO: - * - Proper parsing of DHCP messages exploiting file/sname field overloading. - * - Add JavaDoc style documentation (API, internals). * - Support for interfaces other than Ethernet (SLIP, PPP, ...) * * Please coordinate changes and requests with Leon Woestenberg @@ -77,7 +75,7 @@ #include "lwip/udp.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" -#include "lwip/inet.h" +#include "lwip/def.h" #include "lwip/sys.h" #include "lwip/dhcp.h" #include "lwip/autoip.h" @@ -104,16 +102,43 @@ #define REBOOT_TRIES 2 -/* DHCP client state machine functions */ -static void dhcp_handle_ack(struct netif *netif); -static void dhcp_handle_nak(struct netif *netif); -static void dhcp_handle_offer(struct netif *netif); +/** Option handling: options are parsed in dhcp_parse_reply + * and saved in an array where other functions can load them from. + * This might be moved into the struct dhcp (not necessarily since + * lwIP is single-threaded and the array is only used while in recv + * callback). */ +#define DHCP_OPTION_IDX_OVERLOAD 0 +#define DHCP_OPTION_IDX_MSG_TYPE 1 +#define DHCP_OPTION_IDX_SERVER_ID 2 +#define DHCP_OPTION_IDX_LEASE_TIME 3 +#define DHCP_OPTION_IDX_T1 4 +#define DHCP_OPTION_IDX_T2 5 +#define DHCP_OPTION_IDX_SUBNET_MASK 6 +#define DHCP_OPTION_IDX_ROUTER 7 +#define DHCP_OPTION_IDX_DNS_SERVER 8 +#define DHCP_OPTION_IDX_MAX (DHCP_OPTION_IDX_DNS_SERVER + DNS_MAX_SERVERS) + +/** Holds the decoded option values, only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u32_t dhcp_rx_options_val[DHCP_OPTION_IDX_MAX]; +/** Holds a flag which option was received and is contained in dhcp_rx_options_val, + only valid while in dhcp_recv. + @todo: move this into struct dhcp? */ +u8_t dhcp_rx_options_given[DHCP_OPTION_IDX_MAX]; + +#define dhcp_option_given(dhcp, idx) (dhcp_rx_options_given[idx] != 0) +#define dhcp_got_option(dhcp, idx) (dhcp_rx_options_given[idx] = 1) +#define dhcp_clear_option(dhcp, idx) (dhcp_rx_options_given[idx] = 0) +#define dhcp_clear_all_options(dhcp) (memset(dhcp_rx_options_given, 0, sizeof(dhcp_rx_options_given))) +#define dhcp_get_option_value(dhcp, idx) (dhcp_rx_options_val[idx]) +#define dhcp_set_option_value(dhcp, idx, val) (dhcp_rx_options_val[idx] = (val)) + +/* DHCP client state machine functions */ static err_t dhcp_discover(struct netif *netif); static err_t dhcp_select(struct netif *netif); static void dhcp_bind(struct netif *netif); #if DHCP_DOES_ARP_CHECK -static void dhcp_check(struct netif *netif); static err_t dhcp_decline(struct netif *netif); #endif /* DHCP_DOES_ARP_CHECK */ static err_t dhcp_rebind(struct netif *netif); @@ -121,15 +146,7 @@ static err_t dhcp_reboot(struct netif *netif); static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state); /* receive, unfold, parse and free incoming messages */ -static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); -static err_t dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p); -static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type); -static u8_t dhcp_get_option_byte(u8_t *ptr); -#if 0 -static u16_t dhcp_get_option_short(u8_t *ptr); -#endif -static u32_t dhcp_get_option_long(u8_t *ptr); -static void dhcp_free_reply(struct dhcp *dhcp); +static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); /* set the DHCP timers */ static void dhcp_timeout(struct netif *netif); @@ -137,10 +154,10 @@ static void dhcp_t1_timeout(struct netif *netif); static void dhcp_t2_timeout(struct netif *netif); /* build outgoing messages */ -/* create a DHCP request, fill in common headers */ -static err_t dhcp_create_request(struct netif *netif); +/* create a DHCP message, fill in common headers */ +static err_t dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type); /* free a DHCP request */ -static void dhcp_delete_request(struct netif *netif); +static void dhcp_delete_msg(struct dhcp *dhcp); /* add a DHCP option (type, then length in bytes) */ static void dhcp_option(struct dhcp *dhcp, u8_t option_type, u8_t option_len); /* add option values */ @@ -221,18 +238,22 @@ static void dhcp_handle_offer(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; - /* obtain the server address */ - u8_t *option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SERVER_ID); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_handle_offer(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); - if (option_ptr != NULL) { - dhcp->server_ip_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", dhcp->server_ip_addr.addr)); + /* obtain the server address */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SERVER_ID)) { + ip4_addr_set_u32(&dhcp->server_ip_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SERVER_ID))); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): server 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->server_ip_addr))); /* remember offered address */ - ip_addr_set(&dhcp->offered_ip_addr, (struct ip_addr *)&dhcp->msg_in->yiaddr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_handle_offer(): offer for 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_select(netif); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, + ("dhcp_handle_offer(netif=%p) did not get server ID!\n", (void*)netif)); } } @@ -250,28 +271,22 @@ dhcp_select(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; -#if LWIP_NETIF_HOSTNAME - const char *p; -#endif /* LWIP_NETIF_HOSTNAME */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_select(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num)); dhcp_set_state(dhcp, DHCP_REQUESTING); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_REQUEST); - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); /* MUST request the offered IP address */ dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option(dhcp, DHCP_OPTION_SERVER_ID, 4); - dhcp_option_long(dhcp, ntohl(dhcp->server_ip_addr.addr)); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->server_ip_addr))); dhcp_option(dhcp, DHCP_OPTION_PARAMETER_REQUEST_LIST, 4/*num options*/); dhcp_option_byte(dhcp, DHCP_OPTION_SUBNET_MASK); @@ -280,11 +295,15 @@ dhcp_select(struct netif *netif) dhcp_option_byte(dhcp, DHCP_OPTION_DNS_SERVER); #if LWIP_NETIF_HOSTNAME - p = (const char*)netif->hostname; - if (p != NULL) { - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); - while (*p) { - dhcp_option_byte(dhcp, *p++); + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } } } #endif /* LWIP_NETIF_HOSTNAME */ @@ -295,7 +314,7 @@ dhcp_select(struct netif *netif) /* send broadcast to any DHCP server */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_select: REQUESTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("dhcp_select: could not allocate DHCP request\n")); @@ -309,7 +328,6 @@ dhcp_select(struct netif *netif) /** * The DHCP timer that checks for lease renewal/rebind timeouts. - * */ void dhcp_coarse_tmr() @@ -342,7 +360,6 @@ dhcp_coarse_tmr() * * A DHCP server is expected to respond within a short period of time. * This timer checks whether an outstanding DHCP request is timed out. - * */ void dhcp_fine_tmr() @@ -360,7 +377,7 @@ dhcp_fine_tmr() netif->dhcp->request_timeout--; /* { netif->dhcp->request_timeout == 0 } */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_fine_tmr(): request timeout\n")); - /* this clients' request timeout triggered */ + /* this client's request timeout triggered */ dhcp_timeout(netif); } } @@ -445,10 +462,14 @@ dhcp_t1_timeout(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_t1_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || + (dhcp->state == DHCP_RENEWING)) { /* just retry to renew - note that the rebind timer (t2) will * eventually time-out if renew tries fail. */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t1_timeout(): must renew\n")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t1_timeout(): must renew\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_RENEWING, not DHCP_BOUND */ dhcp_renew(netif); } } @@ -463,9 +484,13 @@ dhcp_t2_timeout(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout()\n")); - if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || (dhcp->state == DHCP_RENEWING)) { + if ((dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_BOUND) || + (dhcp->state == DHCP_RENEWING)) { /* just retry to rebind */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_t2_timeout(): must rebind\n")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("dhcp_t2_timeout(): must rebind\n")); + /* This slightly different to RFC2131: DHCPREQUEST will be sent from state + DHCP_REBINDING, not DHCP_BOUND */ dhcp_rebind(netif); } } @@ -479,91 +504,108 @@ static void dhcp_handle_ack(struct netif *netif) { struct dhcp *dhcp = netif->dhcp; - u8_t *option_ptr; +#if LWIP_DNS + u8_t n; +#endif /* LWIP_DNS */ + /* clear options we might not get from the ACK */ - dhcp->offered_sn_mask.addr = 0; - dhcp->offered_gw_addr.addr = 0; - dhcp->offered_bc_addr.addr = 0; + ip_addr_set_zero(&dhcp->offered_sn_mask); + ip_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ /* lease time given? */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_LEASE_TIME); - if (option_ptr != NULL) { + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_LEASE_TIME)) { /* remember offered lease time */ - dhcp->offered_t0_lease = dhcp_get_option_long(option_ptr + 2); + dhcp->offered_t0_lease = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_LEASE_TIME); } /* renewal period given? */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T1); - if (option_ptr != NULL) { + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T1)) { /* remember given renewal period */ - dhcp->offered_t1_renew = dhcp_get_option_long(option_ptr + 2); + dhcp->offered_t1_renew = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T1); } else { /* calculate safe periods for renewal */ dhcp->offered_t1_renew = dhcp->offered_t0_lease / 2; } /* renewal period given? */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_T2); - if (option_ptr != NULL) { + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_T2)) { /* remember given rebind period */ - dhcp->offered_t2_rebind = dhcp_get_option_long(option_ptr + 2); + dhcp->offered_t2_rebind = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_T2); } else { /* calculate safe periods for rebinding */ dhcp->offered_t2_rebind = dhcp->offered_t0_lease; } /* (y)our internet address */ - ip_addr_set(&dhcp->offered_ip_addr, &dhcp->msg_in->yiaddr); + ip_addr_copy(dhcp->offered_ip_addr, dhcp->msg_in->yiaddr); -/** - * Patch #1308 - * TODO: we must check if the file field is not overloaded by DHCP options! - */ -#if 0 - /* boot server address */ - ip_addr_set(&dhcp->offered_si_addr, &dhcp->msg_in->siaddr); - /* boot file name */ - if (dhcp->msg_in->file[0]) { - dhcp->boot_file_name = mem_malloc(strlen(dhcp->msg_in->file) + 1); - strcpy(dhcp->boot_file_name, dhcp->msg_in->file); - } -#endif +#if LWIP_DHCP_BOOTP_FILE + /* copy boot server address, + boot file name copied in dhcp_parse_reply if not overloaded */ + ip_addr_copy(dhcp->offered_si_addr, dhcp->msg_in->siaddr); +#endif /* LWIP_DHCP_BOOTP_FILE */ - /* subnet mask */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_SUBNET_MASK); /* subnet mask given? */ - if (option_ptr != NULL) { - dhcp->offered_sn_mask.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_SUBNET_MASK)) { + /* remember given subnet mask */ + ip4_addr_set_u32(&dhcp->offered_sn_mask, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_SUBNET_MASK))); + dhcp->subnet_mask_given = 1; + } else { + dhcp->subnet_mask_given = 0; } /* gateway router */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_ROUTER); - if (option_ptr != NULL) { - dhcp->offered_gw_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); - } - - /* broadcast address */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_BROADCAST); - if (option_ptr != NULL) { - dhcp->offered_bc_addr.addr = htonl(dhcp_get_option_long(&option_ptr[2])); + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_ROUTER)) { + ip4_addr_set_u32(&dhcp->offered_gw_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_ROUTER))); } - /* DNS servers */ - option_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_DNS_SERVER); - if (option_ptr != NULL) { - u8_t n; - dhcp->dns_count = dhcp_get_option_byte(&option_ptr[1]) / (u32_t)sizeof(struct ip_addr); - /* limit to at most DHCP_MAX_DNS DNS servers */ - if (dhcp->dns_count > DHCP_MAX_DNS) - dhcp->dns_count = DHCP_MAX_DNS; - for (n = 0; n < dhcp->dns_count; n++) { - dhcp->offered_dns_addr[n].addr = htonl(dhcp_get_option_long(&option_ptr[2 + n * 4])); #if LWIP_DNS - dns_setserver( n, (struct ip_addr *)(&(dhcp->offered_dns_addr[n].addr))); -#endif /* LWIP_DNS */ - } -#if LWIP_DNS - dns_setserver( n, (struct ip_addr *)(&ip_addr_any)); + /* DNS servers */ + n = 0; + while(dhcp_option_given(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n) && (n < DNS_MAX_SERVERS)) { + ip_addr_t dns_addr; + ip4_addr_set_u32(&dns_addr, htonl(dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_DNS_SERVER + n))); + dns_setserver(n, &dns_addr); + n++; + } #endif /* LWIP_DNS */ +} + +/** Set a statically allocated struct dhcp to work with. + * Using this prevents dhcp_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct dhcp + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void +dhcp_set_struct(struct netif *netif, struct dhcp *dhcp) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("dhcp != NULL", dhcp != NULL); + LWIP_ASSERT("netif already has a struct dhcp set", netif->dhcp == NULL); + + /* clear data structure */ + memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_OFF); */ + netif->dhcp = dhcp; +} + +/** Removes a struct dhcp from a netif. + * + * ATTENTION: Only use this when not using dhcp_set_struct() to allocate the + * struct dhcp since the memory is passed back to the heap. + * + * @param netif the netif from which to remove the struct dhcp + */ +void dhcp_cleanup(struct netif *netif) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + + if (netif->dhcp != NULL) { + mem_free(netif->dhcp); + netif->dhcp = NULL; } } @@ -592,6 +634,12 @@ dhcp_start(struct netif *netif) it is set when we succeeded starting. */ netif->flags &= ~NETIF_FLAG_DHCP; + /* check hwtype of the netif */ + if ((netif->flags & NETIF_FLAG_ETHARP) == 0) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): No ETHARP netif\n")); + return ERR_ARG; + } + /* check MTU of the netif */ if (netif->mtu < DHCP_MAX_MSG_LEN_MIN_REQUIRED) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): Cannot use this netif with DHCP: MTU is too small\n")); @@ -601,7 +649,7 @@ dhcp_start(struct netif *netif) /* no DHCP client attached yet? */ if (dhcp == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): starting new DHCP client\n")); - dhcp = mem_malloc(sizeof(struct dhcp)); + dhcp = (struct dhcp *)mem_malloc(sizeof(struct dhcp)); if (dhcp == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not allocate dhcp\n")); return ERR_MEM; @@ -616,23 +664,19 @@ dhcp_start(struct netif *netif) udp_remove(dhcp->pcb); } LWIP_ASSERT("pbuf p_out wasn't freed", dhcp->p_out == NULL); - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL && - dhcp->options_in == NULL && dhcp->options_in_len == 0); + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL ); } /* clear data structure */ memset(dhcp, 0, sizeof(struct dhcp)); + /* dhcp_set_state(&dhcp, DHCP_OFF); */ /* allocate UDP PCB */ dhcp->pcb = udp_new(); if (dhcp->pcb == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_start(): could not obtain pcb\n")); - mem_free((void *)dhcp); - netif->dhcp = dhcp = NULL; return ERR_MEM; } -#if IP_SOF_BROADCAST - dhcp->pcb->so_options|=SOF_BROADCAST; -#endif /* IP_SOF_BROADCAST */ + dhcp->pcb->so_options |= SOF_BROADCAST; /* set up local and remote port for the pcb */ udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); udp_connect(dhcp->pcb, IP_ADDR_ANY, DHCP_SERVER_PORT); @@ -663,54 +707,50 @@ dhcp_start(struct netif *netif) void dhcp_inform(struct netif *netif) { - struct dhcp *dhcp, *old_dhcp; + struct dhcp dhcp; err_t result = ERR_OK; - dhcp = mem_malloc(sizeof(struct dhcp)); - if (dhcp == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not allocate dhcp\n")); - return; - } - memset(dhcp, 0, sizeof(struct dhcp)); + struct udp_pcb *pcb; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): allocated dhcp\n")); - dhcp->pcb = udp_new(); - if (dhcp->pcb == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); - goto free_dhcp_and_return; + LWIP_ERROR("netif != NULL", (netif != NULL), return;); + + memset(&dhcp, 0, sizeof(struct dhcp)); + dhcp_set_state(&dhcp, DHCP_INFORM); + + if ((netif->dhcp != NULL) && (netif->dhcp->pcb != NULL)) { + /* re-use existing pcb */ + pcb = netif->dhcp->pcb; + } else { + pcb = udp_new(); + if (pcb == NULL) { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform(): could not obtain pcb")); + return; + } + dhcp.pcb = pcb; + dhcp.pcb->so_options |= SOF_BROADCAST; + udp_bind(dhcp.pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); } - old_dhcp = netif->dhcp; - netif->dhcp = dhcp; - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_inform(): created new udp pcb\n")); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, &dhcp, DHCP_INFORM); if (result == ERR_OK) { + dhcp_option(&dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); + dhcp_option_short(&dhcp, DHCP_MAX_MSG_LEN(netif)); - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_INFORM); - - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); - dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); - - dhcp_option_trailer(dhcp); + dhcp_option_trailer(&dhcp); - pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); + pbuf_realloc(dhcp.p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp.options_out_len); -#if IP_SOF_BROADCAST - dhcp->pcb->so_options|=SOF_BROADCAST; -#endif /* IP_SOF_BROADCAST */ - udp_bind(dhcp->pcb, IP_ADDR_ANY, DHCP_CLIENT_PORT); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_inform: INFORMING\n")); - udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + udp_sendto_if(pcb, dhcp.p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); + dhcp_delete_msg(&dhcp); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_inform: could not allocate DHCP request\n")); } - udp_remove(dhcp->pcb); - dhcp->pcb = NULL; - netif->dhcp = old_dhcp; -free_dhcp_and_return: - mem_free((void *)dhcp); + if (dhcp.pcb != NULL) { + /* otherwise, the existing pcb was used */ + udp_remove(dhcp.pcb); + } } /** Handle a possible change in the network configuration. @@ -738,6 +778,12 @@ dhcp_network_changed(struct netif *netif) break; default: dhcp->tries = 0; +#if LWIP_DHCP_AUTOIP_COOP + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } +#endif /* LWIP_DHCP_AUTOIP_COOP */ dhcp_discover(netif); break; } @@ -750,13 +796,14 @@ dhcp_network_changed(struct netif *netif) * @param netif the network interface on which the reply was received * @param addr The IP address we received a reply from */ -void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr) +void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr) { LWIP_ERROR("netif != NULL", (netif != NULL), return;); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_arp_reply()\n")); /* is a DHCP client doing an ARP check? */ if ((netif->dhcp != NULL) && (netif->dhcp->state == DHCP_CHECKING)) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", addr->addr)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_arp_reply(): CHECKING, arp reply for 0x%08"X32_F"\n", + ip4_addr_get_u32(addr))); /* did a host respond with the address we were offered by the DHCP server? */ if (ip_addr_cmp(addr, &netif->dhcp->offered_ip_addr)) { @@ -786,13 +833,10 @@ dhcp_decline(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline()\n")); dhcp_set_state(dhcp, DHCP_BACKING_OFF); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_DECLINE); if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_DECLINE); - dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option_trailer(dhcp); /* resize pbuf to reflect true size of options */ @@ -800,7 +844,7 @@ dhcp_decline(struct netif *netif) /* per section 4.4.4, broadcast DECLINE messages */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_decline: BACKING OFF\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, @@ -812,7 +856,7 @@ dhcp_decline(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_decline(): set request timeout %"U16_F" msecs\n", msecs)); return result; } -#endif +#endif /* DHCP_DOES_ARP_CHECK */ /** @@ -827,14 +871,12 @@ dhcp_discover(struct netif *netif) err_t result = ERR_OK; u16_t msecs; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover()\n")); - ip_addr_set(&dhcp->offered_ip_addr, IP_ADDR_ANY); + ip_addr_set_any(&dhcp->offered_ip_addr); dhcp_set_state(dhcp, DHCP_SELECTING); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_DISCOVER); if (result == ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: making request\n")); - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_DISCOVER); dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); @@ -853,7 +895,7 @@ dhcp_discover(struct netif *netif) LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: sendto(DISCOVER, IP_ADDR_BROADCAST, DHCP_SERVER_PORT)\n")); udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_discover: deleting()ing\n")); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_discover: SELECTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_discover: could not allocate DHCP request\n")); @@ -882,7 +924,7 @@ dhcp_bind(struct netif *netif) { u32_t timeout; struct dhcp *dhcp; - struct ip_addr sn_mask, gw_addr; + ip_addr_t sn_mask, gw_addr; LWIP_ERROR("dhcp_bind: netif != NULL", (netif != NULL), return;); dhcp = netif->dhcp; LWIP_ERROR("dhcp_bind: dhcp != NULL", (dhcp != NULL), return;); @@ -915,30 +957,29 @@ dhcp_bind(struct netif *netif) } LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_bind(): set request timeout %"U32_F" msecs\n", dhcp->offered_t2_rebind*1000)); } - /* copy offered network mask */ - ip_addr_set(&sn_mask, &dhcp->offered_sn_mask); - /* subnet mask not given? */ - /* TODO: this is not a valid check. what if the network mask is 0? */ - if (sn_mask.addr == 0) { - /* choose a safe subnet mask given the network class */ - u8_t first_octet = ip4_addr1(&sn_mask); + if (dhcp->subnet_mask_given) { + /* copy offered network mask */ + ip_addr_copy(sn_mask, dhcp->offered_sn_mask); + } else { + /* subnet mask not given, choose a safe subnet mask given the network class */ + u8_t first_octet = ip4_addr1(&dhcp->offered_ip_addr); if (first_octet <= 127) { - sn_mask.addr = htonl(0xff000000); + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xff000000UL)); } else if (first_octet >= 192) { - sn_mask.addr = htonl(0xffffff00); + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffffff00UL)); } else { - sn_mask.addr = htonl(0xffff0000); + ip4_addr_set_u32(&sn_mask, PP_HTONL(0xffff0000UL)); } } - ip_addr_set(&gw_addr, &dhcp->offered_gw_addr); + ip_addr_copy(gw_addr, dhcp->offered_gw_addr); /* gateway address not given? */ - if (gw_addr.addr == 0) { + if (ip_addr_isany(&gw_addr)) { /* copy network address */ - gw_addr.addr = (dhcp->offered_ip_addr.addr & sn_mask.addr); + ip_addr_get_network(&gw_addr, &dhcp->offered_ip_addr, &sn_mask); /* use first host address on network as gateway */ - gw_addr.addr |= htonl(0x00000001); + ip4_addr_set_u32(&gw_addr, ip4_addr_get_u32(&gw_addr) | PP_HTONL(0x00000001UL)); } #if LWIP_DHCP_AUTOIP_COOP @@ -948,11 +989,14 @@ dhcp_bind(struct netif *netif) } #endif /* LWIP_DHCP_AUTOIP_COOP */ - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", dhcp->offered_ip_addr.addr)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): IP: 0x%08"X32_F"\n", + ip4_addr_get_u32(&dhcp->offered_ip_addr))); netif_set_ipaddr(netif, &dhcp->offered_ip_addr); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", sn_mask.addr)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): SN: 0x%08"X32_F"\n", + ip4_addr_get_u32(&sn_mask))); netif_set_netmask(netif, &sn_mask); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", gw_addr.addr)); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_STATE, ("dhcp_bind(): GW: 0x%08"X32_F"\n", + ip4_addr_get_u32(&gw_addr))); netif_set_gw(netif, &gw_addr); /* bring the interface up */ netif_set_up(netif); @@ -971,28 +1015,25 @@ dhcp_renew(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; -#if LWIP_NETIF_HOSTNAME - const char *p; -#endif /* LWIP_NETIF_HOSTNAME */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_renew()\n")); dhcp_set_state(dhcp, DHCP_RENEWING); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { - - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_REQUEST); - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if LWIP_NETIF_HOSTNAME - p = (const char*)netif->hostname; - if (p != NULL) { - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); - while (*p) { - dhcp_option_byte(dhcp, *p++); + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } } } #endif /* LWIP_NETIF_HOSTNAME */ @@ -1012,7 +1053,7 @@ dhcp_renew(struct netif *netif) pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_renew: RENEWING\n")); } else { @@ -1037,28 +1078,25 @@ dhcp_rebind(struct netif *netif) struct dhcp *dhcp = netif->dhcp; err_t result; u16_t msecs; -#if LWIP_NETIF_HOSTNAME - const char *p; -#endif /* LWIP_NETIF_HOSTNAME */ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind()\n")); dhcp_set_state(dhcp, DHCP_REBINDING); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { - - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_REQUEST); - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, DHCP_MAX_MSG_LEN(netif)); #if LWIP_NETIF_HOSTNAME - p = (const char*)netif->hostname; - if (p != NULL) { - dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, strlen(p)); - while (*p) { - dhcp_option_byte(dhcp, *p++); + if (netif->hostname != NULL) { + const char *p = (const char*)netif->hostname; + u8_t namelen = (u8_t)strlen(p); + if (namelen > 0) { + LWIP_ASSERT("DHCP: hostname is too long!", namelen < 255); + dhcp_option(dhcp, DHCP_OPTION_HOSTNAME, namelen); + while (*p) { + dhcp_option_byte(dhcp, *p++); + } } } #endif /* LWIP_NETIF_HOSTNAME */ @@ -1077,7 +1115,7 @@ dhcp_rebind(struct netif *netif) /* broadcast to server */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_rebind: REBINDING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_rebind: could not allocate DHCP request\n")); @@ -1104,17 +1142,13 @@ dhcp_reboot(struct netif *netif) dhcp_set_state(dhcp, DHCP_REBOOTING); /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_REQUEST); if (result == ERR_OK) { - - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_REQUEST); - dhcp_option(dhcp, DHCP_OPTION_MAX_MSG_SIZE, DHCP_OPTION_MAX_MSG_SIZE_LEN); dhcp_option_short(dhcp, 576); dhcp_option(dhcp, DHCP_OPTION_REQUESTED_IP, 4); - dhcp_option_long(dhcp, ntohl(dhcp->offered_ip_addr.addr)); + dhcp_option_long(dhcp, ntohl(ip4_addr_get_u32(&dhcp->offered_ip_addr))); dhcp_option_trailer(dhcp); @@ -1122,7 +1156,7 @@ dhcp_reboot(struct netif *netif) /* broadcast to server */ udp_sendto_if(dhcp->pcb, dhcp->p_out, IP_ADDR_BROADCAST, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_reboot: REBOOTING\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_reboot: could not allocate DHCP request\n")); @@ -1151,24 +1185,24 @@ dhcp_release(struct netif *netif) /* idle DHCP client */ dhcp_set_state(dhcp, DHCP_OFF); /* clean old DHCP offer */ - dhcp->server_ip_addr.addr = 0; - dhcp->offered_ip_addr.addr = dhcp->offered_sn_mask.addr = 0; - dhcp->offered_gw_addr.addr = dhcp->offered_bc_addr.addr = 0; + ip_addr_set_zero(&dhcp->server_ip_addr); + ip_addr_set_zero(&dhcp->offered_ip_addr); + ip_addr_set_zero(&dhcp->offered_sn_mask); + ip_addr_set_zero(&dhcp->offered_gw_addr); +#if LWIP_DHCP_BOOTP_FILE + ip_addr_set_zero(&dhcp->offered_si_addr); +#endif /* LWIP_DHCP_BOOTP_FILE */ dhcp->offered_t0_lease = dhcp->offered_t1_renew = dhcp->offered_t2_rebind = 0; - dhcp->dns_count = 0; /* create and initialize the DHCP message header */ - result = dhcp_create_request(netif); + result = dhcp_create_msg(netif, dhcp, DHCP_RELEASE); if (result == ERR_OK) { - dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); - dhcp_option_byte(dhcp, DHCP_RELEASE); - dhcp_option_trailer(dhcp); pbuf_realloc(dhcp->p_out, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN + dhcp->options_out_len); udp_sendto_if(dhcp->pcb, dhcp->p_out, &dhcp->server_ip_addr, DHCP_SERVER_PORT, netif); - dhcp_delete_request(netif); + dhcp_delete_msg(dhcp); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("dhcp_release: RELEASED, DHCP_OFF\n")); } else { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("dhcp_release: could not allocate DHCP request\n")); @@ -1184,7 +1218,6 @@ dhcp_release(struct netif *netif) netif_set_gw(netif, IP_ADDR_ANY); netif_set_netmask(netif, IP_ADDR_ANY); - /* TODO: netif_down(netif); */ return result; } @@ -1196,8 +1229,9 @@ dhcp_release(struct netif *netif) void dhcp_stop(struct netif *netif) { - struct dhcp *dhcp = netif->dhcp; + struct dhcp *dhcp; LWIP_ERROR("dhcp_stop: netif != NULL", (netif != NULL), return;); + dhcp = netif->dhcp; /* Remove the flag that says this netif is handled by DHCP. */ netif->flags &= ~NETIF_FLAG_DHCP; @@ -1205,20 +1239,18 @@ dhcp_stop(struct netif *netif) /* netif is DHCP configured? */ if (dhcp != NULL) { #if LWIP_DHCP_AUTOIP_COOP - if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { - autoip_stop(netif); - dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; - } + if(dhcp->autoip_coop_state == DHCP_AUTOIP_COOP_STATE_ON) { + autoip_stop(netif); + dhcp->autoip_coop_state = DHCP_AUTOIP_COOP_STATE_OFF; + } #endif /* LWIP_DHCP_AUTOIP_COOP */ if (dhcp->pcb != NULL) { udp_remove(dhcp->pcb); dhcp->pcb = NULL; } - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL && - dhcp->options_in == NULL && dhcp->options_in_len == 0); - mem_free((void *)dhcp); - netif->dhcp = NULL; + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); + dhcp_set_state(dhcp, DHCP_OFF); } } @@ -1226,8 +1258,6 @@ dhcp_stop(struct netif *netif) * Set the DHCP state of a DHCP client. * * If the state changed, reset the number of tries. - * - * TODO: we might also want to reset the timeout here? */ static void dhcp_set_state(struct dhcp *dhcp, u8_t new_state) @@ -1235,6 +1265,7 @@ dhcp_set_state(struct dhcp *dhcp, u8_t new_state) if (new_state != dhcp->state) { dhcp->state = new_state; dhcp->tries = 0; + dhcp->request_timeout = 0; } } @@ -1290,84 +1321,208 @@ dhcp_option_long(struct dhcp *dhcp, u32_t value) * */ static err_t -dhcp_unfold_reply(struct dhcp *dhcp, struct pbuf *p) +dhcp_parse_reply(struct dhcp *dhcp, struct pbuf *p) { - u16_t ret; - LWIP_ERROR("dhcp != NULL", (dhcp != NULL), return ERR_ARG;); - /* free any left-overs from previous unfolds */ - dhcp_free_reply(dhcp); - /* options present? */ - if (p->tot_len > (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)) { - dhcp->options_in_len = p->tot_len - (sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); - dhcp->options_in = mem_malloc(dhcp->options_in_len); - if (dhcp->options_in == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_unfold_reply(): could not allocate dhcp->options\n")); - dhcp->options_in_len = 0; - return ERR_MEM; + u8_t *options; + u16_t offset; + u16_t offset_max; + u16_t options_idx; + u16_t options_idx_max; + struct pbuf *q; + int parse_file_as_options = 0; + int parse_sname_as_options = 0; + + /* clear received options */ + dhcp_clear_all_options(dhcp); + /* check that beginning of dhcp_msg (up to and including chaddr) is in first pbuf */ + if (p->len < DHCP_SNAME_OFS) { + return ERR_BUF; + } + dhcp->msg_in = (struct dhcp_msg *)p->payload; +#if LWIP_DHCP_BOOTP_FILE + /* clear boot file name */ + dhcp->boot_file_name[0] = 0; +#endif /* LWIP_DHCP_BOOTP_FILE */ + + /* parse options */ + + /* start with options field */ + options_idx = DHCP_OPTIONS_OFS; + /* parse options to the end of the received packet */ + options_idx_max = p->tot_len; +again: + q = p; + while((q != NULL) && (options_idx >= q->len)) { + options_idx -= q->len; + options_idx_max -= q->len; + q = q->next; + } + if (q == NULL) { + return ERR_BUF; + } + offset = options_idx; + offset_max = options_idx_max; + options = (u8_t*)q->payload; + /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ + while((q != NULL) && (options[offset] != DHCP_OPTION_END) && (offset < offset_max)) { + u8_t op = options[offset]; + u8_t len; + u8_t decode_len = 0; + int decode_idx = -1; + u16_t val_offset = offset + 2; + /* len byte might be in the next pbuf */ + if (offset + 1 < q->len) { + len = options[offset + 1]; + } else { + len = (q->next != NULL ? ((u8_t*)q->next->payload)[0] : 0); } - } - dhcp->msg_in = mem_malloc(sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); - if (dhcp->msg_in == NULL) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_unfold_reply(): could not allocate dhcp->msg_in\n")); - if (dhcp->options_in != NULL) { - mem_free(dhcp->options_in); - dhcp->options_in = NULL; - dhcp->options_in_len = 0; + /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ + decode_len = len; + switch(op) { + /* case(DHCP_OPTION_END): handled above */ + case(DHCP_OPTION_PAD): + /* special option: no len encoded */ + decode_len = len = 0; + /* will be increased below */ + offset--; + break; + case(DHCP_OPTION_SUBNET_MASK): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_SUBNET_MASK; + break; + case(DHCP_OPTION_ROUTER): + decode_len = 4; /* only copy the first given router */ + LWIP_ASSERT("len >= decode_len", len >= decode_len); + decode_idx = DHCP_OPTION_IDX_ROUTER; + break; + case(DHCP_OPTION_DNS_SERVER): + /* special case: there might be more than one server */ + LWIP_ASSERT("len % 4 == 0", len % 4 == 0); + /* limit number of DNS servers */ + decode_len = LWIP_MIN(len, 4 * DNS_MAX_SERVERS); + LWIP_ASSERT("len >= decode_len", len >= decode_len); + decode_idx = DHCP_OPTION_IDX_DNS_SERVER; + break; + case(DHCP_OPTION_LEASE_TIME): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_LEASE_TIME; + break; + case(DHCP_OPTION_OVERLOAD): + LWIP_ASSERT("len == 1", len == 1); + decode_idx = DHCP_OPTION_IDX_OVERLOAD; + break; + case(DHCP_OPTION_MESSAGE_TYPE): + LWIP_ASSERT("len == 1", len == 1); + decode_idx = DHCP_OPTION_IDX_MSG_TYPE; + break; + case(DHCP_OPTION_SERVER_ID): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_SERVER_ID; + break; + case(DHCP_OPTION_T1): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_T1; + break; + case(DHCP_OPTION_T2): + LWIP_ASSERT("len == 4", len == 4); + decode_idx = DHCP_OPTION_IDX_T2; + break; + default: + decode_len = 0; + LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", op)); + break; + } + offset += len + 2; + if (decode_len > 0) { + u32_t value = 0; + u16_t copy_len; +decode_next: + LWIP_ASSERT("check decode_idx", decode_idx >= 0 && decode_idx < DHCP_OPTION_IDX_MAX); + LWIP_ASSERT("option already decoded", !dhcp_option_given(dhcp, decode_idx)); + copy_len = LWIP_MIN(decode_len, 4); + pbuf_copy_partial(q, &value, copy_len, val_offset); + if (decode_len > 4) { + /* decode more than one u32_t */ + LWIP_ASSERT("decode_len % 4 == 0", decode_len % 4 == 0); + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, htonl(value)); + decode_len -= 4; + val_offset += 4; + decode_idx++; + goto decode_next; + } else if (decode_len == 4) { + value = ntohl(value); + } else { + LWIP_ASSERT("invalid decode_len", decode_len == 1); + value = ((u8_t*)&value)[0]; + } + dhcp_got_option(dhcp, decode_idx); + dhcp_set_option_value(dhcp, decode_idx, value); + } + if (offset >= q->len) { + offset -= q->len; + offset_max -= q->len; + q = q->next; + options = (u8_t*)q->payload; } - return ERR_MEM; } - - /** copy the DHCP message without options */ - ret = pbuf_copy_partial(p, dhcp->msg_in, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN, 0); - LWIP_ASSERT("ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN", ret == sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes into dhcp->msg_in[]\n", - sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN)); - - if (dhcp->options_in != NULL) { - /** copy the DHCP options */ - ret = pbuf_copy_partial(p, dhcp->options_in, dhcp->options_in_len, sizeof(struct dhcp_msg) - DHCP_OPTIONS_LEN); - LWIP_ASSERT("ret == dhcp->options_in_len", ret == dhcp->options_in_len); - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_unfold_reply(): copied %"U16_F" bytes to dhcp->options_in[]\n", - dhcp->options_in_len)); + /* is this an overloaded message? */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_OVERLOAD)) { + u32_t overload = dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_OVERLOAD); + dhcp_clear_option(dhcp, DHCP_OPTION_IDX_OVERLOAD); + if (overload == DHCP_OVERLOAD_FILE) { + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME) { + parse_sname_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); + } else if (overload == DHCP_OVERLOAD_SNAME_FILE) { + parse_sname_as_options = 1; + parse_file_as_options = 1; + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); + } else { + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("invalid overload option: %d\n", (int)overload)); + } +#if LWIP_DHCP_BOOTP_FILE + if (!parse_file_as_options) { + /* only do this for ACK messages */ + if (dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE) && + (dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE) == DHCP_ACK)) + /* copy bootp file name, don't care for sname (server hostname) */ + pbuf_copy_partial(p, dhcp->boot_file_name, DHCP_FILE_LEN-1, DHCP_FILE_OFS); + /* make sure the string is really NULL-terminated */ + dhcp->boot_file_name[DHCP_FILE_LEN-1] = 0; + } +#endif /* LWIP_DHCP_BOOTP_FILE */ + } + if (parse_file_as_options) { + /* if both are overloaded, parse file first and then sname (RFC 2131 ch. 4.1) */ + parse_file_as_options = 0; + options_idx = DHCP_FILE_OFS; + options_idx_max = DHCP_FILE_OFS + DHCP_FILE_LEN; + goto again; + } else if (parse_sname_as_options) { + parse_sname_as_options = 0; + options_idx = DHCP_SNAME_OFS; + options_idx_max = DHCP_SNAME_OFS + DHCP_SNAME_LEN; + goto again; } - LWIP_UNUSED_ARG(ret); return ERR_OK; } /** - * Free the incoming DHCP message including contiguous copy of - * its DHCP options. - */ -static void dhcp_free_reply(struct dhcp *dhcp) -{ - if (dhcp->msg_in != NULL) { - mem_free((void *)dhcp->msg_in); - dhcp->msg_in = NULL; - } - if (dhcp->options_in) { - mem_free(dhcp->options_in); - dhcp->options_in = NULL; - dhcp->options_in_len = 0; - } - LWIP_DEBUGF(DHCP_DEBUG, ("dhcp_free_reply(): free'd\n")); -} - -/** * If an incoming DHCP message is in response to us, then trigger the state machine */ -static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +static void +dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { struct netif *netif = (struct netif *)arg; struct dhcp *dhcp = netif->dhcp; struct dhcp_msg *reply_msg = (struct dhcp_msg *)p->payload; - u8_t *options_ptr; u8_t msg_type; u8_t i; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("dhcp_recv(pbuf = %p) from DHCP server %"U16_F".%"U16_F".%"U16_F".%"U16_F" port %"U16_F"\n", (void*)p, - (u16_t)(ntohl(addr->addr) >> 24 & 0xff), (u16_t)(ntohl(addr->addr) >> 16 & 0xff), - (u16_t)(ntohl(addr->addr) >> 8 & 0xff), (u16_t)(ntohl(addr->addr) & 0xff), port)); + ip4_addr1_16(addr), ip4_addr2_16(addr), ip4_addr3_16(addr), ip4_addr4_16(addr), port)); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->len = %"U16_F"\n", p->len)); LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("pbuf->tot_len = %"U16_F"\n", p->tot_len)); /* prevent warnings about unused arguments */ @@ -1375,11 +1530,10 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ LWIP_UNUSED_ARG(addr); LWIP_UNUSED_ARG(port); - LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL && - dhcp->options_in == NULL && dhcp->options_in_len == 0); + LWIP_ASSERT("reply wasn't freed", dhcp->msg_in == NULL); if (p->len < DHCP_MIN_REPLY_LEN) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message too short\n")); + LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP reply message or pbuf too short\n")); goto free_pbuf_and_return; } @@ -1403,7 +1557,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ goto free_pbuf_and_return; } /* option fields could be unfold? */ - if (dhcp_unfold_reply(dhcp, p) != ERR_OK) { + if (dhcp_parse_reply(dhcp, p) != ERR_OK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("problem unfolding DHCP message - too short on memory?\n")); goto free_pbuf_and_return; @@ -1411,21 +1565,19 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("searching DHCP_OPTION_MESSAGE_TYPE\n")); /* obtain pointer to DHCP message type */ - options_ptr = dhcp_get_option_ptr(dhcp, DHCP_OPTION_MESSAGE_TYPE); - if (options_ptr == NULL) { + if (!dhcp_option_given(dhcp, DHCP_OPTION_IDX_MSG_TYPE)) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("DHCP_OPTION_MESSAGE_TYPE option not found\n")); goto free_pbuf_and_return; } /* read DHCP message type */ - msg_type = dhcp_get_option_byte(options_ptr + 2); + msg_type = (u8_t)dhcp_get_option_value(dhcp, DHCP_OPTION_IDX_MSG_TYPE); /* message type is DHCP ACK? */ if (msg_type == DHCP_ACK) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_ACK received\n")); /* in requesting state? */ if (dhcp->state == DHCP_REQUESTING) { dhcp_handle_ack(netif); - dhcp->request_timeout = 0; #if DHCP_DOES_ARP_CHECK /* check if the acknowledged lease address is already in use */ dhcp_check(netif); @@ -1436,7 +1588,6 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ } /* already bound to the given lease address? */ else if ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING)) { - dhcp->request_timeout = 0; dhcp_bind(netif); } } @@ -1445,7 +1596,6 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ ((dhcp->state == DHCP_REBOOTING) || (dhcp->state == DHCP_REQUESTING) || (dhcp->state == DHCP_REBINDING) || (dhcp->state == DHCP_RENEWING ))) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("DHCP_NAK received\n")); - dhcp->request_timeout = 0; dhcp_handle_nak(netif); } /* received a DHCP_OFFER in DHCP_SELECTING state? */ @@ -1456,7 +1606,7 @@ static void dhcp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_ dhcp_handle_offer(netif); } free_pbuf_and_return: - dhcp_free_reply(dhcp); + dhcp->msg_in = NULL; pbuf_free(p); } @@ -1464,11 +1614,12 @@ free_pbuf_and_return: * Create a DHCP request, fill in common headers * * @param netif the netif under DHCP control + * @param dhcp dhcp control struct + * @param message_type message type of the request */ static err_t -dhcp_create_request(struct netif *netif) +dhcp_create_msg(struct netif *netif, struct dhcp *dhcp, u8_t message_type) { - struct dhcp *dhcp; u16_t i; #ifndef DHCP_GLOBAL_XID /** default global transaction identifier starting value (easy to match @@ -1484,23 +1635,23 @@ dhcp_create_request(struct netif *netif) xid_initialised = !xid_initialised; } #endif - LWIP_ERROR("dhcp_create_request: netif != NULL", (netif != NULL), return ERR_ARG;); - dhcp = netif->dhcp; - LWIP_ERROR("dhcp_create_request: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); - LWIP_ASSERT("dhcp_create_request: dhcp->p_out == NULL", dhcp->p_out == NULL); - LWIP_ASSERT("dhcp_create_request: dhcp->msg_out == NULL", dhcp->msg_out == NULL); + LWIP_ERROR("dhcp_create_msg: netif != NULL", (netif != NULL), return ERR_ARG;); + LWIP_ERROR("dhcp_create_msg: dhcp != NULL", (dhcp != NULL), return ERR_VAL;); + LWIP_ASSERT("dhcp_create_msg: dhcp->p_out == NULL", dhcp->p_out == NULL); + LWIP_ASSERT("dhcp_create_msg: dhcp->msg_out == NULL", dhcp->msg_out == NULL); dhcp->p_out = pbuf_alloc(PBUF_TRANSPORT, sizeof(struct dhcp_msg), PBUF_RAM); if (dhcp->p_out == NULL) { LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, - ("dhcp_create_request(): could not allocate pbuf\n")); + ("dhcp_create_msg(): could not allocate pbuf\n")); return ERR_MEM; } - LWIP_ASSERT("dhcp_create_request: check that first pbuf can hold struct dhcp_msg", + LWIP_ASSERT("dhcp_create_msg: check that first pbuf can hold struct dhcp_msg", (dhcp->p_out->len >= sizeof(struct dhcp_msg))); /* reuse transaction identifier in retransmissions */ - if (dhcp->tries==0) + if (dhcp->tries == 0) { xid++; + } dhcp->xid = xid; LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("transaction id xid(%"X32_F")\n", xid)); @@ -1510,19 +1661,23 @@ dhcp_create_request(struct netif *netif) dhcp->msg_out->op = DHCP_BOOTREQUEST; /* TODO: make link layer independent */ dhcp->msg_out->htype = DHCP_HTYPE_ETH; - /* TODO: make link layer independent */ - dhcp->msg_out->hlen = DHCP_HLEN_ETH; + dhcp->msg_out->hlen = netif->hwaddr_len; dhcp->msg_out->hops = 0; dhcp->msg_out->xid = htonl(dhcp->xid); dhcp->msg_out->secs = 0; + /* we don't need the broadcast flag since we can receive unicast traffic + before being fully configured! */ dhcp->msg_out->flags = 0; - dhcp->msg_out->ciaddr.addr = 0; - if (dhcp->state==DHCP_BOUND || dhcp->state==DHCP_RENEWING || dhcp->state==DHCP_REBINDING) { - dhcp->msg_out->ciaddr.addr = netif->ip_addr.addr; - } - dhcp->msg_out->yiaddr.addr = 0; - dhcp->msg_out->siaddr.addr = 0; - dhcp->msg_out->giaddr.addr = 0; + ip_addr_set_zero(&dhcp->msg_out->ciaddr); + /* set ciaddr to netif->ip_addr based on message_type and state */ + if ((message_type == DHCP_INFORM) || (message_type == DHCP_DECLINE) || + ((message_type == DHCP_REQUEST) && /* DHCP_BOUND not used for sending! */ + ((dhcp->state==DHCP_RENEWING) || dhcp->state==DHCP_REBINDING))) { + ip_addr_copy(dhcp->msg_out->ciaddr, netif->ip_addr); + } + ip_addr_set_zero(&dhcp->msg_out->yiaddr); + ip_addr_set_zero(&dhcp->msg_out->siaddr); + ip_addr_set_zero(&dhcp->msg_out->giaddr); for (i = 0; i < DHCP_CHADDR_LEN; i++) { /* copy netif hardware address, pad with zeroes */ dhcp->msg_out->chaddr[i] = (i < netif->hwaddr_len) ? netif->hwaddr[i] : 0/* pad byte*/; @@ -1533,29 +1688,29 @@ dhcp_create_request(struct netif *netif) for (i = 0; i < DHCP_FILE_LEN; i++) { dhcp->msg_out->file[i] = 0; } - dhcp->msg_out->cookie = htonl(0x63825363UL); + dhcp->msg_out->cookie = PP_HTONL(DHCP_MAGIC_COOKIE); dhcp->options_out_len = 0; /* fill options field with an incrementing array (for debugging purposes) */ for (i = 0; i < DHCP_OPTIONS_LEN; i++) { dhcp->msg_out->options[i] = (u8_t)i; /* for debugging only, no matter if truncated */ } + /* Add option MESSAGE_TYPE */ + dhcp_option(dhcp, DHCP_OPTION_MESSAGE_TYPE, DHCP_OPTION_MESSAGE_TYPE_LEN); + dhcp_option_byte(dhcp, message_type); return ERR_OK; } /** * Free previously allocated memory used to send a DHCP request. * - * @param netif the netif under DHCP control + * @param dhcp the dhcp struct to free the request from */ static void -dhcp_delete_request(struct netif *netif) +dhcp_delete_msg(struct dhcp *dhcp) { - struct dhcp *dhcp; - LWIP_ERROR("dhcp_delete_request: netif != NULL", (netif != NULL), return;); - dhcp = netif->dhcp; - LWIP_ERROR("dhcp_delete_request: dhcp != NULL", (dhcp != NULL), return;); - LWIP_ASSERT("dhcp_delete_request: dhcp->p_out != NULL", dhcp->p_out != NULL); - LWIP_ASSERT("dhcp_delete_request: dhcp->msg_out != NULL", dhcp->msg_out != NULL); + LWIP_ERROR("dhcp_delete_msg: dhcp != NULL", (dhcp != NULL), return;); + LWIP_ASSERT("dhcp_delete_msg: dhcp->p_out != NULL", dhcp->p_out != NULL); + LWIP_ASSERT("dhcp_delete_msg: dhcp->msg_out != NULL", dhcp->msg_out != NULL); if (dhcp->p_out != NULL) { pbuf_free(dhcp->p_out); } @@ -1587,136 +1742,4 @@ dhcp_option_trailer(struct dhcp *dhcp) } } -/** - * Find the offset of a DHCP option inside the DHCP message. - * - * @param dhcp DHCP client - * @param option_type - * - * @return a byte offset into the UDP message where the option was found, or - * zero if the given option was not found. - */ -static u8_t *dhcp_get_option_ptr(struct dhcp *dhcp, u8_t option_type) -{ - u8_t overload = DHCP_OVERLOAD_NONE; - - /* options available? */ - if ((dhcp->options_in != NULL) && (dhcp->options_in_len > 0)) { - /* start with options field */ - u8_t *options = (u8_t *)dhcp->options_in; - u16_t offset = 0; - /* at least 1 byte to read and no end marker, then at least 3 bytes to read? */ - while ((offset < dhcp->options_in_len) && (options[offset] != DHCP_OPTION_END)) { - /* LWIP_DEBUGF(DHCP_DEBUG, ("msg_offset=%"U16_F", q->len=%"U16_F, msg_offset, q->len)); */ - /* are the sname and/or file field overloaded with options? */ - if (options[offset] == DHCP_OPTION_OVERLOAD) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded message detected\n")); - /* skip option type and length */ - offset += 2; - overload = options[offset++]; - } - /* requested option found */ - else if (options[offset] == option_type) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset %"U16_F" in options\n", offset)); - return &options[offset]; - /* skip option */ - } else { - LWIP_DEBUGF(DHCP_DEBUG, ("skipping option %"U16_F" in options\n", options[offset])); - /* skip option type */ - offset++; - /* skip option length, and then length bytes */ - offset += 1 + options[offset]; - } - } - /* is this an overloaded message? */ - if (overload != DHCP_OVERLOAD_NONE) { - u16_t field_len; - if (overload == DHCP_OVERLOAD_FILE) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded file field\n")); - options = (u8_t *)&dhcp->msg_in->file; - field_len = DHCP_FILE_LEN; - } else if (overload == DHCP_OVERLOAD_SNAME) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname field\n")); - options = (u8_t *)&dhcp->msg_in->sname; - field_len = DHCP_SNAME_LEN; - /* TODO: check if else if () is necessary */ - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("overloaded sname and file field\n")); - options = (u8_t *)&dhcp->msg_in->sname; - field_len = DHCP_FILE_LEN + DHCP_SNAME_LEN; - } - offset = 0; - - /* at least 1 byte to read and no end marker */ - while ((offset < field_len) && (options[offset] != DHCP_OPTION_END)) { - if (options[offset] == option_type) { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("option found at offset=%"U16_F"\n", offset)); - return &options[offset]; - /* skip option */ - } else { - LWIP_DEBUGF(DHCP_DEBUG | LWIP_DBG_TRACE, ("skipping option %"U16_F"\n", options[offset])); - /* skip option type */ - offset++; - offset += 1 + options[offset]; - } - } - } - } - return NULL; -} - -/** - * Return the byte of DHCP option data. - * - * @param client DHCP client. - * @param ptr pointer obtained by dhcp_get_option_ptr(). - * - * @return byte value at the given address. - */ -static u8_t -dhcp_get_option_byte(u8_t *ptr) -{ - LWIP_DEBUGF(DHCP_DEBUG, ("option byte value=%"U16_F"\n", (u16_t)(*ptr))); - return *ptr; -} - -#if 0 /* currently unused */ -/** - * Return the 16-bit value of DHCP option data. - * - * @param client DHCP client. - * @param ptr pointer obtained by dhcp_get_option_ptr(). - * - * @return byte value at the given address. - */ -static u16_t -dhcp_get_option_short(u8_t *ptr) -{ - u16_t value; - value = *ptr++ << 8; - value |= *ptr; - LWIP_DEBUGF(DHCP_DEBUG, ("option short value=%"U16_F"\n", value)); - return value; -} -#endif - -/** - * Return the 32-bit value of DHCP option data. - * - * @param client DHCP client. - * @param ptr pointer obtained by dhcp_get_option_ptr(). - * - * @return byte value at the given address. - */ -static u32_t dhcp_get_option_long(u8_t *ptr) -{ - u32_t value; - value = (u32_t)(*ptr++) << 24; - value |= (u32_t)(*ptr++) << 16; - value |= (u32_t)(*ptr++) << 8; - value |= (u32_t)(*ptr++); - LWIP_DEBUGF(DHCP_DEBUG, ("option long value=%"U32_F"\n", value)); - return value; -} - #endif /* LWIP_DHCP */ diff --git a/core/lwip/src/core/dns.c b/core/lwip/src/core/dns.c index 4021d1dd..ca807c14 100644 --- a/core/lwip/src/core/dns.c +++ b/core/lwip/src/core/dns.c @@ -78,13 +78,14 @@ #include "lwip/udp.h" #include "lwip/mem.h" +#include "lwip/memp.h" #include "lwip/dns.h" #include <string.h> /** DNS server IP address */ #ifndef DNS_SERVER_ADDRESS -#define DNS_SERVER_ADDRESS inet_addr("208.67.222.222") /* resolver1.opendns.com */ +#define DNS_SERVER_ADDRESS(ipaddr) (ip4_addr_set_u32(ipaddr, ipaddr_addr("208.67.222.222"))) /* resolver1.opendns.com */ #endif /** DNS server port address */ @@ -141,40 +142,26 @@ PACK_STRUCT_END #endif #define SIZEOF_DNS_HDR 12 -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** DNS query message structure */ +/** DNS query message structure. + No packing needed: only used locally on the stack. */ struct dns_query { /* DNS query record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ - PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif + u16_t type; + u16_t cls; +}; #define SIZEOF_DNS_QUERY 4 -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -/** DNS answer message structure */ +/** DNS answer message structure. + No packing needed: only used locally on the stack. */ struct dns_answer { /* DNS answer record starts with either a domain name or a pointer to a name already present somewhere in the packet. */ - PACK_STRUCT_FIELD(u16_t type); - PACK_STRUCT_FIELD(u16_t class); - PACK_STRUCT_FIELD(u32_t ttl); - PACK_STRUCT_FIELD(u16_t len); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif + u16_t type; + u16_t cls; + u32_t ttl; + u16_t len; +}; #define SIZEOF_DNS_ANSWER 10 /** DNS table entry */ @@ -187,21 +174,13 @@ struct dns_table_entry { u8_t err; u32_t ttl; char name[DNS_MAX_NAME_LENGTH]; - struct ip_addr ipaddr; + ip_addr_t ipaddr; /* pointer to callback on DNS query done */ dns_found_callback found; void *arg; }; #if DNS_LOCAL_HOSTLIST -/** struct used for local host-list */ -struct local_hostlist_entry { - /** static hostname */ - const char *name; - /** static host address in network byteorder */ - u32_t addr; - struct local_hostlist_entry *next; -}; #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC /** Local host-list. For hostnames in this list, no @@ -229,7 +208,7 @@ static void dns_init_local(); /* forward declarations */ -static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); static void dns_check_entries(void); /*----------------------------------------------------------------------------- @@ -240,11 +219,10 @@ static void dns_check_entries(void); static struct udp_pcb *dns_pcb; static u8_t dns_seqno; static struct dns_table_entry dns_table[DNS_TABLE_SIZE]; -static struct ip_addr dns_servers[DNS_MAX_SERVERS]; - -#if (DNS_USES_STATIC_BUF == 1) -static u8_t dns_payload[DNS_MSG_SIZE]; -#endif /* (DNS_USES_STATIC_BUF == 1) */ +static ip_addr_t dns_servers[DNS_MAX_SERVERS]; +/** Contiguous buffer for processing responses */ +static u8_t dns_payload_buffer[LWIP_MEM_ALIGN_BUFFER(DNS_MSG_SIZE)]; +static u8_t* dns_payload; /** * Initialize the resolver: set up the UDP pcb and configure the default server @@ -253,10 +231,12 @@ static u8_t dns_payload[DNS_MSG_SIZE]; void dns_init() { - struct ip_addr dnsserver; + ip_addr_t dnsserver; + + dns_payload = (u8_t *)LWIP_MEM_ALIGN(dns_payload_buffer); /* initialize default DNS server address */ - dnsserver.addr = DNS_SERVER_ADDRESS; + DNS_SERVER_ADDRESS(&dnsserver); LWIP_DEBUGF(DNS_DEBUG, ("dns_init: initializing\n")); @@ -290,7 +270,7 @@ dns_init() * @param dnsserver IP address of the DNS server to set */ void -dns_setserver(u8_t numdns, struct ip_addr *dnsserver) +dns_setserver(u8_t numdns, ip_addr_t *dnsserver) { /* * hpa: the lwip code has the dnsserver->addr != 0 test, but that would @@ -298,7 +278,7 @@ dns_setserver(u8_t numdns, struct ip_addr *dnsserver) * DNS server... */ if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) && - (dnsserver != NULL) /* && (dnsserver->addr !=0) */) { + (dnsserver != NULL) /* && !ip_addr_isany(dnsserver) */) { dns_servers[numdns] = (*dnsserver); } } @@ -310,7 +290,7 @@ dns_setserver(u8_t numdns, struct ip_addr *dnsserver) * @return IP address of the indexed DNS server or "ip_addr_any" if the DNS * server has not been configured. */ -struct ip_addr +ip_addr_t dns_getserver(u8_t numdns) { if (numdns < DNS_MAX_SERVERS) { @@ -342,12 +322,18 @@ dns_init_local() struct local_hostlist_entry *entry; /* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */ struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT; + size_t namelen; for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) { - entry = mem_malloc(sizeof(struct local_hostlist_entry)); + struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; + LWIP_ASSERT("invalid host name (NULL)", init_entry->name != NULL); + namelen = strlen(init_entry->name); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); LWIP_ASSERT("mem-error in dns_init_local", entry != NULL); if (entry != NULL) { - struct local_hostlist_entry *init_entry = &local_hostlist_init[i]; - entry->name = init_entry->name; + entry->name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY((char*)entry->name, init_entry->name, namelen); + ((char*)entry->name)[namelen] = 0; entry->addr = init_entry->addr; entry->next = local_hostlist_dynamic; local_hostlist_dynamic = entry; @@ -361,7 +347,7 @@ dns_init_local() * * @param hostname Hostname to look for in the local host-list * @return The first IP address for the hostname in the local host-list or - * INADDR_NONE if not found. + * IPADDR_NONE if not found. */ static u32_t dns_lookup_local(const char *hostname) @@ -370,7 +356,7 @@ dns_lookup_local(const char *hostname) struct local_hostlist_entry *entry = local_hostlist_dynamic; while(entry != NULL) { if(strcmp(entry->name, hostname) == 0) { - return entry->addr; + return ip4_addr_get_u32(&entry->addr); } entry = entry->next; } @@ -378,11 +364,11 @@ dns_lookup_local(const char *hostname) int i; for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) { if(strcmp(local_hostlist_static[i].name, hostname) == 0) { - return local_hostlist_static[i].addr; + return ip4_addr_get_u32(&local_hostlist_static[i].addr); } } #endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ - return INADDR_NONE; + return IPADDR_NONE; } #if DNS_LOCAL_HOSTLIST_IS_DYNAMIC @@ -395,14 +381,14 @@ dns_lookup_local(const char *hostname) * @return the number of removed entries */ int -dns_local_removehost(const char *hostname, const struct ip_addr *addr) +dns_local_removehost(const char *hostname, const ip_addr_t *addr) { int removed = 0; struct local_hostlist_entry *entry = local_hostlist_dynamic; struct local_hostlist_entry *last_entry = NULL; while (entry != NULL) { if (((hostname == NULL) || !strcmp(entry->name, hostname)) && - ((addr == NULL) || (entry->addr == addr->addr))) { + ((addr == NULL) || ip_addr_cmp(&entry->addr, addr))) { struct local_hostlist_entry *free_entry; if (last_entry != NULL) { last_entry->next = entry->next; @@ -411,7 +397,7 @@ dns_local_removehost(const char *hostname, const struct ip_addr *addr) } free_entry = entry; entry = entry->next; - mem_free(free_entry); + memp_free(MEMP_LOCALHOSTLIST, free_entry); removed++; } else { last_entry = entry; @@ -430,15 +416,21 @@ dns_local_removehost(const char *hostname, const struct ip_addr *addr) * @return ERR_OK if succeeded or ERR_MEM on memory error */ err_t -dns_local_addhost(const char *hostname, const struct ip_addr *addr) +dns_local_addhost(const char *hostname, const ip_addr_t *addr) { struct local_hostlist_entry *entry; - entry = mem_malloc(sizeof(struct local_hostlist_entry)); + size_t namelen; + LWIP_ASSERT("invalid host name (NULL)", hostname != NULL); + namelen = strlen(hostname); + LWIP_ASSERT("namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN", namelen <= DNS_LOCAL_HOSTLIST_MAX_NAMELEN); + entry = (struct local_hostlist_entry *)memp_malloc(MEMP_LOCALHOSTLIST); if (entry == NULL) { return ERR_MEM; } - entry->name = hostname; - entry->addr = addr->addr; + entry->name = (char*)entry + sizeof(struct local_hostlist_entry); + MEMCPY((char*)entry->name, hostname, namelen); + ((char*)entry->name)[namelen] = 0; + ip_addr_copy(entry->addr, *addr); entry->next = local_hostlist_dynamic; local_hostlist_dynamic = entry; return ERR_OK; @@ -455,8 +447,8 @@ dns_local_addhost(const char *hostname, const struct ip_addr *addr) * for a hostname. * * @param name the hostname to look up - * @return the hostname's IP address, as u32_t (instead of struct ip_addr to - * better check for failure: != INADDR_NONE) or INADDR_NONE if the hostname + * @return the hostname's IP address, as u32_t (instead of ip_addr_t to + * better check for failure: != IPADDR_NONE) or IPADDR_NONE if the hostname * was not found in the cached dns_table. */ static u32_t @@ -467,12 +459,12 @@ dns_lookup(const char *name) u32_t addr; #endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */ #if DNS_LOCAL_HOSTLIST - if ((addr = dns_lookup_local(name)) != INADDR_NONE) { + if ((addr = dns_lookup_local(name)) != IPADDR_NONE) { return addr; } #endif /* DNS_LOCAL_HOSTLIST */ #ifdef DNS_LOOKUP_LOCAL_EXTERN - if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != INADDR_NONE) { + if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) { return addr; } #endif /* DNS_LOOKUP_LOCAL_EXTERN */ @@ -484,11 +476,11 @@ dns_lookup(const char *name) LWIP_DEBUGF(DNS_DEBUG, ("dns_lookup: \"%s\": found = ", name)); ip_addr_debug_print(DNS_DEBUG, &(dns_table[i].ipaddr)); LWIP_DEBUGF(DNS_DEBUG, ("\n")); - return dns_table[i].ipaddr.addr; + return ip4_addr_get_u32(&dns_table[i].ipaddr); } } - return INADDR_NONE; + return IPADDR_NONE; } #if DNS_DOES_NAME_CHECK @@ -583,7 +575,7 @@ dns_send(u8_t numdns, const char* name, u8_t id) LWIP_DEBUGF(DNS_DEBUG, ("dns_send: dns_servers[%"U16_F"] \"%s\": request\n", (u16_t)(numdns), name)); LWIP_ASSERT("dns server out of array", numdns < DNS_MAX_SERVERS); - LWIP_ASSERT("dns server has no IP address set", dns_servers[numdns].addr != 0); + LWIP_ASSERT("dns server has no IP address set", !ip_addr_isany(&dns_servers[numdns])); /* if here, we have either a new query or a retry on a previous query to process */ p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH + @@ -595,7 +587,7 @@ dns_send(u8_t numdns, const char* name, u8_t id) memset(hdr, 0, SIZEOF_DNS_HDR); hdr->id = htons(id); hdr->flags1 = DNS_FLAG1_RD; - hdr->numquestions = htons(1); + hdr->numquestions = PP_HTONS(1); query = (char*)hdr + SIZEOF_DNS_HDR; pHostname = name; --pHostname; @@ -615,12 +607,12 @@ dns_send(u8_t numdns, const char* name, u8_t id) *query++='\0'; /* fill dns query */ - qry.type = htons(DNS_RRTYPE_A); - qry.class = htons(DNS_RRCLASS_IN); - MEMCPY( query, &qry, SIZEOF_DNS_QUERY); + qry.type = PP_HTONS(DNS_RRTYPE_A); + qry.cls = PP_HTONS(DNS_RRCLASS_IN); + SMEMCPY(query, &qry, SIZEOF_DNS_QUERY); /* resize pbuf to the exact dns query */ - pbuf_realloc(p, (query + SIZEOF_DNS_QUERY) - ((char*)(p->payload))); + pbuf_realloc(p, (u16_t)((query + SIZEOF_DNS_QUERY) - ((char*)(p->payload)))); /* connect to the server for faster receiving */ udp_connect(dns_pcb, &dns_servers[numdns], DNS_SERVER_PORT); @@ -648,6 +640,7 @@ dns_send(u8_t numdns, const char* name, u8_t id) static void dns_check_entry(u8_t i) { + err_t err; struct dns_table_entry *pEntry = &dns_table[i]; LWIP_ASSERT("array index out of bounds", i < DNS_TABLE_SIZE); @@ -662,14 +655,18 @@ dns_check_entry(u8_t i) pEntry->retries = 0; /* send DNS packet for this entry */ - dns_send(pEntry->numdns, pEntry->name, i); + err = dns_send(pEntry->numdns, pEntry->name, i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } break; } case DNS_STATE_ASKING: { if (--pEntry->tmr == 0) { if (++pEntry->retries == DNS_MAX_RETRIES) { - if ((pEntry->numdns+1<DNS_MAX_SERVERS) && (dns_servers[pEntry->numdns+1].addr!=0)) { + if ((pEntry->numdns+1<DNS_MAX_SERVERS) && !ip_addr_isany(&dns_servers[pEntry->numdns+1])) { /* change of server */ pEntry->numdns++; pEntry->tmr = 1; @@ -691,7 +688,11 @@ dns_check_entry(u8_t i) pEntry->tmr = pEntry->retries; /* send DNS packet for this entry */ - dns_send(pEntry->numdns, pEntry->name, i); + err = dns_send(pEntry->numdns, pEntry->name, i); + if (err != ERR_OK) { + LWIP_DEBUGF(DNS_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("dns_send returned error: %s\n", lwip_strerr(err))); + } } break; } @@ -734,20 +735,14 @@ dns_check_entries(void) * @params see udp.h */ static void -dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { - u8_t i; + u16_t i; char *pHostname; struct dns_hdr *hdr; struct dns_answer ans; struct dns_table_entry *pEntry; - u8_t nquestions, nanswers; -#if (DNS_USES_STATIC_BUF == 0) - u8_t dns_payload[DNS_MSG_SIZE]; -#endif /* (DNS_USES_STATIC_BUF == 0) */ -#if (DNS_USES_STATIC_BUF == 2) - u8_t* dns_payload; -#endif /* (DNS_USES_STATIC_BUF == 2) */ + u16_t nquestions, nanswers; LWIP_UNUSED_ARG(arg); LWIP_UNUSED_ARG(pcb); @@ -758,24 +753,15 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u if (p->tot_len > DNS_MSG_SIZE) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too big\n")); /* free pbuf and return */ - goto memerr1; + goto memerr; } /* is the dns message big enough ? */ if (p->tot_len < (SIZEOF_DNS_HDR + SIZEOF_DNS_QUERY + SIZEOF_DNS_ANSWER)) { LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: pbuf too small\n")); /* free pbuf and return */ - goto memerr1; - } - -#if (DNS_USES_STATIC_BUF == 2) - dns_payload = mem_malloc(p->tot_len); - if (dns_payload == NULL) { - LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n")); - /* free pbuf and return */ - goto memerr1; + goto memerr; } -#endif /* (DNS_USES_STATIC_BUF == 2) */ /* copy dns payload inside static buffer for processing */ if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) { @@ -813,20 +799,21 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u /* Skip the name in the "question" part */ pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + SIZEOF_DNS_HDR) + SIZEOF_DNS_QUERY; - while(nanswers > 0) { + while (nanswers > 0) { /* skip answer resource record's host name */ pHostname = (char *) dns_parse_name((unsigned char *)pHostname); /* Check for IP address type and Internet class. Others are discarded. */ - MEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); - if((ntohs(ans.type) == DNS_RRTYPE_A) && (ntohs(ans.class) == DNS_RRCLASS_IN) && (ntohs(ans.len) == sizeof(struct ip_addr)) ) { + SMEMCPY(&ans, pHostname, SIZEOF_DNS_ANSWER); + if((ans.type == PP_HTONS(DNS_RRTYPE_A)) && (ans.cls == PP_HTONS(DNS_RRCLASS_IN)) && + (ans.len == PP_HTONS(sizeof(ip_addr_t))) ) { /* read the answer resource record's TTL, and maximize it if needed */ pEntry->ttl = ntohl(ans.ttl); if (pEntry->ttl > DNS_MAX_TTL) { pEntry->ttl = DNS_MAX_TTL; } /* read the IP address after answer resource record's header */ - MEMCPY( &(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(struct ip_addr)); + SMEMCPY(&(pEntry->ipaddr), (pHostname+SIZEOF_DNS_ANSWER), sizeof(ip_addr_t)); LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response = ", pEntry->name)); ip_addr_debug_print(DNS_DEBUG, (&(pEntry->ipaddr))); LWIP_DEBUGF(DNS_DEBUG, ("\n")); @@ -835,7 +822,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u (*pEntry->found)(pEntry->name, &pEntry->ipaddr, pEntry->arg); } /* deallocate memory and return */ - goto memerr2; + goto memerr; } else { pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len); } @@ -849,7 +836,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u } /* deallocate memory and return */ - goto memerr2; + goto memerr; responseerr: /* ERROR: call specified callback function with NULL as name to indicate an error */ @@ -860,13 +847,7 @@ responseerr: pEntry->state = DNS_STATE_UNUSED; pEntry->found = NULL; -memerr2: -#if (DNS_USES_STATIC_BUF == 2) - /* free dns buffer */ - mem_free(dns_payload); -#endif /* (DNS_USES_STATIC_BUF == 2) */ - -memerr1: +memerr: /* free pbuf */ pbuf_free(p); return; @@ -886,6 +867,7 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) u8_t i; u8_t lseq, lseqi; struct dns_table_entry *pEntry = NULL; + size_t namelen; /* search an unused entry, or the oldest one */ lseq = lseqi = 0; @@ -925,7 +907,9 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) pEntry->seqno = dns_seqno++; pEntry->found = found; pEntry->arg = callback_arg; - strcpy(pEntry->name, name); + namelen = LWIP_MIN(strlen(name), DNS_MAX_NAME_LENGTH-1); + MEMCPY(pEntry->name, name, namelen); + pEntry->name[namelen] = 0; /* force to send query without waiting timer */ dns_check_entry(i); @@ -943,9 +927,10 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) * name is already in the local names table. * - ERR_INPROGRESS enqueue a request to be sent to the DNS server * for resolution if no errors are present. + * - ERR_ARG: dns client not initialized or invalid hostname * * @param hostname the hostname that is to be queried - * @param addr pointer to a struct ip_addr where to store the address if it is already + * @param addr pointer to a ip_addr_t where to store the address if it is already * cached in the dns_table (only valid if ERR_OK is returned!) * @param found a callback function to be called on success, failure or timeout (only if * ERR_INPROGRESS is returned!) @@ -953,28 +938,33 @@ dns_enqueue(const char *name, dns_found_callback found, void *callback_arg) * @return a err_t return code. */ err_t -dns_gethostbyname(const char *hostname, struct ip_addr *addr, dns_found_callback found, +dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg) { + u32_t ipaddr; /* not initialized or no valid server yet, or invalid addr pointer * or invalid hostname or invalid hostname length */ if ((dns_pcb == NULL) || (addr == NULL) || (!hostname) || (!hostname[0]) || (strlen(hostname) >= DNS_MAX_NAME_LENGTH)) { - return ERR_VAL; + return ERR_ARG; } #if LWIP_HAVE_LOOPIF - if (strcmp(hostname,"localhost")==0) { - addr->addr = htonl(INADDR_LOOPBACK); + if (strcmp(hostname, "localhost")==0) { + ip_addr_set_loopback(addr); return ERR_OK; } #endif /* LWIP_HAVE_LOOPIF */ - /* host name already in octet notation? set ip addr and return ERR_OK - * already have this address cached? */ - if (((addr->addr = inet_addr(hostname)) != INADDR_NONE) || - ((addr->addr = dns_lookup(hostname)) != INADDR_NONE)) { + /* host name already in octet notation? set ip addr and return ERR_OK */ + ipaddr = ipaddr_addr(hostname); + if (ipaddr == IPADDR_NONE) { + /* already have this address cached? */ + ipaddr = dns_lookup(hostname); + } + if (ipaddr != IPADDR_NONE) { + ip4_addr_set_u32(addr, ipaddr); return ERR_OK; } diff --git a/core/lwip/src/core/init.c b/core/lwip/src/core/init.c index 775010ac..36038350 100644 --- a/core/lwip/src/core/init.c +++ b/core/lwip/src/core/init.c @@ -49,11 +49,12 @@ #include "lwip/ip.h" #include "lwip/raw.h" #include "lwip/udp.h" -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/snmp_msg.h" #include "lwip/autoip.h" #include "lwip/igmp.h" #include "lwip/dns.h" +#include "lwip/timers.h" #include "netif/etharp.h" /* Compile-time sanity checks for configuration errors. @@ -80,12 +81,12 @@ #if (!LWIP_UDP && LWIP_IGMP) #error "If you want to use IGMP, you have to define LWIP_UDP=1 in your lwipopts.h" #endif +#if (!LWIP_UDP && LWIP_SNMP) + #error "If you want to use SNMP, you have to define LWIP_UDP=1 in your lwipopts.h" +#endif #if (!LWIP_UDP && LWIP_DNS) #error "If you want to use DNS, you have to define LWIP_UDP=1 in your lwipopts.h" #endif -#if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) - #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" -#endif #if (LWIP_ARP && ARP_QUEUEING && (MEMP_NUM_ARP_QUEUE<=0)) #error "If you want to use ARP Queueing, you have to define MEMP_NUM_ARP_QUEUE>=1 in your lwipopts.h" #endif @@ -104,6 +105,9 @@ #if (LWIP_TCP && (TCP_SND_QUEUELEN > 0xffff)) #error "If you want to use TCP, TCP_SND_QUEUELEN must fit in an u16_t, so, you have to reduce it in your lwipopts.h" #endif +#if (LWIP_TCP && (TCP_SND_QUEUELEN < 2)) + #error "TCP_SND_QUEUELEN must be at least 2 for no-copy TCP writes to work" +#endif #if (LWIP_TCP && ((TCP_MAXRTX > 12) || (TCP_SYNMAXRTX > 12))) #error "If you want to use TCP, TCP_MAXRTX and TCP_SYNMAXRTX must less or equal to 12 (due to tcp_backoff table), so, you have to reduce them in your lwipopts.h" #endif @@ -113,9 +117,6 @@ #if (LWIP_IGMP && (MEMP_NUM_IGMP_GROUP<=1)) #error "If you want to use IGMP, you have to define MEMP_NUM_IGMP_GROUP>1 in your lwipopts.h" #endif -#if (PPP_SUPPORT && (NO_SYS==1)) - #error "If you want to use PPP, you have to define NO_SYS=0 in your lwipopts.h" -#endif #if (LWIP_NETIF_API && (NO_SYS==1)) #error "If you want to use NETIF API, you have to define NO_SYS=0 in your lwipopts.h" #endif @@ -147,7 +148,7 @@ #error "One and exactly one of LWIP_EVENT_API and LWIP_CALLBACK_API has to be enabled in your lwipopts.h" #endif /* There must be sufficient timeouts, taking into account requirements of the subsystems. */ -#if ((NO_SYS==0) && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT))) +#if LWIP_TIMERS && (MEMP_NUM_SYS_TIMEOUT < (LWIP_TCP + IP_REASSEMBLY + LWIP_ARP + (2*LWIP_DHCP) + LWIP_AUTOIP + LWIP_IGMP + LWIP_DNS + PPP_SUPPORT)) #error "MEMP_NUM_SYS_TIMEOUT is too low to accomodate all required timeouts" #endif #if (IP_REASSEMBLY && (MEMP_NUM_REASSDATA > IP_REASS_MAX_PBUFS)) @@ -171,6 +172,21 @@ #if PPP_SUPPORT && !PPPOS_SUPPORT & !PPPOE_SUPPORT #error "PPP_SUPPORT needs either PPPOS_SUPPORT or PPPOE_SUPPORT turned on" #endif +#if !LWIP_ETHERNET && (LWIP_ARP || PPPOE_SUPPORT) + #error "LWIP_ETHERNET needs to be turned on for LWIP_ARP or PPPOE_SUPPORT" +#endif +#if LWIP_IGMP && !defined(LWIP_RAND) + #error "When using IGMP, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value" +#endif +#if LWIP_TCPIP_CORE_LOCKING_INPUT && !LWIP_TCPIP_CORE_LOCKING + #error "When using LWIP_TCPIP_CORE_LOCKING_INPUT, LWIP_TCPIP_CORE_LOCKING must be enabled, too" +#endif +#if LWIP_TCP && LWIP_NETIF_TX_SINGLE_PBUF && !TCP_OVERSIZE + #error "LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE enabled to create single-pbuf TCP packets" +#endif +#if IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF + #error "LWIP_NETIF_TX_SINGLE_PBUF does not work with IP_FRAG_USES_STATIC_BUF==1 as that creates pbuf queues" +#endif /* Compile-time checks for deprecated options. @@ -193,11 +209,6 @@ #ifdef ETHARP_ALWAYS_INSERT #error "ETHARP_ALWAYS_INSERT option is deprecated. Remove it from your lwipopts.h." #endif -#if SO_REUSE -/* I removed the lot since this was an ugly hack. It broke the raw-API. - It also came with many ugly goto's, Christiaan Simons. */ - #error "SO_REUSE currently unavailable, this was a hack" -#endif #ifdef LWIP_DEBUG static void @@ -215,13 +226,28 @@ lwip_sanity_check(void) LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_BUF must be at least as much as (2 * TCP_MSS) for things to work smoothly\n")); if (TCP_SND_QUEUELEN < (2 * (TCP_SND_BUF/TCP_MSS))) LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SND_QUEUELEN must be at least as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work\n")); - if (TCP_SNDLOWAT > TCP_SND_BUF) - LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than or equal to TCP_SND_BUF.\n")); + if (TCP_SNDLOWAT >= TCP_SND_BUF) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDLOWAT must be less than TCP_SND_BUF.\n")); + if (TCP_SNDQUEUELOWAT >= TCP_SND_QUEUELEN) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_SNDQUEUELOWAT must be less than TCP_SND_QUEUELEN.\n")); if (TCP_WND > (PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE)) LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is larger than space provided by PBUF_POOL_SIZE*PBUF_POOL_BUFSIZE\n")); if (TCP_WND < TCP_MSS) LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: TCP_WND is smaller than MSS\n")); #endif /* LWIP_TCP */ +#if LWIP_SOCKET + /* Check that the SO_* socket options and SOF_* lwIP-internal flags match */ + if (SO_ACCEPTCONN != SOF_ACCEPTCONN) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_ACCEPTCONN != SOF_ACCEPTCONN\n")); + if (SO_REUSEADDR != SOF_REUSEADDR) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_REUSEADDR != SOF_REUSEADDR\n")); + if (SO_KEEPALIVE != SOF_KEEPALIVE) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_KEEPALIVE != SOF_KEEPALIVE\n")); + if (SO_BROADCAST != SOF_BROADCAST) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_BROADCAST != SOF_BROADCAST\n")); + if (SO_LINGER != SOF_LINGER) + LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: SO_LINGER != SOF_LINGER\n")); +#endif /* LWIP_SOCKET */ } #else /* LWIP_DEBUG */ #define lwip_sanity_check() @@ -238,7 +264,9 @@ lwip_init(void) /* Modules initialization */ stats_init(); +#if !NO_SYS sys_init(); +#endif /* !NO_SYS */ lwip_mem_init(); memp_init(); pbuf_init(); @@ -271,4 +299,8 @@ lwip_init(void) #if LWIP_DNS dns_init(); #endif /* LWIP_DNS */ + +#if LWIP_TIMERS + sys_timeouts_init(); +#endif /* LWIP_TIMERS */ } diff --git a/core/lwip/src/core/ipv4/autoip.c b/core/lwip/src/core/ipv4/autoip.c index 7aa7cea5..92bb4591 100644 --- a/core/lwip/src/core/ipv4/autoip.c +++ b/core/lwip/src/core/ipv4/autoip.c @@ -108,7 +108,7 @@ static void autoip_handle_arp_conflict(struct netif *netif); /* creates a pseudo random LL IP-Address for a network interface */ -static void autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr); +static void autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr); /* sends an ARP probe */ static err_t autoip_arp_probe(struct netif *netif); @@ -131,6 +131,36 @@ autoip_init(void) LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_init()\n")); } +/** Set a statically allocated struct autoip to work with. + * Using this prevents autoip_start to allocate it using mem_malloc. + * + * @param netif the netif for which to set the struct autoip + * @param dhcp (uninitialised) dhcp struct allocated by the application + */ +void +autoip_set_struct(struct netif *netif, struct autoip *autoip) +{ + LWIP_ASSERT("netif != NULL", netif != NULL); + LWIP_ASSERT("autoip != NULL", autoip != NULL); + LWIP_ASSERT("netif already has a struct autoip set", netif->autoip == NULL); + + /* clear data structure */ + memset(autoip, 0, sizeof(struct autoip)); + /* autoip->state = AUTOIP_STATE_OFF; */ + netif->autoip = autoip; +} + +/** Restart AutoIP client and check the next address (conflict detected) + * + * @param netif The netif under AutoIP control + */ +static void +autoip_restart(struct netif *netif) +{ + netif->autoip->tried_llipaddr++; + autoip_start(netif); +} + /** * Handle a IP address conflict after an ARP conflict detection */ @@ -149,7 +179,7 @@ autoip_handle_arp_conflict(struct netif *netif) ("autoip_handle_arp_conflict(): we are defending, but in DEFEND_INTERVAL, retreating\n")); /* TODO: close all TCP sessions */ - autoip_start(netif); + autoip_restart(netif); } else { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n")); @@ -160,7 +190,7 @@ autoip_handle_arp_conflict(struct netif *netif) LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_handle_arp_conflict(): we do not defend, retreating\n")); /* TODO: close all TCP sessions */ - autoip_start(netif); + autoip_restart(netif); } } @@ -171,7 +201,7 @@ autoip_handle_arp_conflict(struct netif *netif) * @param ipaddr ip address to initialize */ static void -autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr) +autoip_create_addr(struct netif *netif, ip_addr_t *ipaddr) { /* Here we create an IP-Address out of range 169.254.1.0 to 169.254.254.255 * compliant to RFC 3927 Section 2.1 @@ -190,11 +220,12 @@ autoip_create_addr(struct netif *netif, struct ip_addr *ipaddr) } LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) && (addr <= AUTOIP_RANGE_END)); - ipaddr->addr = htonl(addr); + ip4_addr_set_u32(ipaddr, htonl(addr)); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, - ("autoip_create_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n", - (u16_t)(netif->autoip->tried_llipaddr), (u32_t)(ipaddr->addr))); + ("autoip_create_addr(): tried_llipaddr=%"U16_F", %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (u16_t)(netif->autoip->tried_llipaddr), ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), + ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); } /** @@ -232,11 +263,13 @@ static err_t autoip_bind(struct netif *netif) { struct autoip *autoip = netif->autoip; - struct ip_addr sn_mask, gw_addr; + ip_addr_t sn_mask, gw_addr; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, - ("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n", - (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr)); + ("autoip_bind(netif=%p) %c%c%"U16_F" %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + (void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, + ip4_addr1_16(&autoip->llipaddr), ip4_addr2_16(&autoip->llipaddr), + ip4_addr3_16(&autoip->llipaddr), ip4_addr4_16(&autoip->llipaddr))); IP4_ADDR(&sn_mask, 255, 255, 0, 0); IP4_ADDR(&gw_addr, 0, 0, 0, 0); @@ -269,9 +302,9 @@ autoip_start(struct netif *netif) /* Set IP-Address, Netmask and Gateway to 0 to make sure that * ARP Packets are formed correctly */ - netif->ip_addr.addr = 0; - netif->netmask.addr = 0; - netif->gw.addr = 0; + ip_addr_set_zero(&netif->ip_addr); + ip_addr_set_zero(&netif->netmask); + ip_addr_set_zero(&netif->gw); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("autoip_start(netif=%p) %c%c%"U16_F"\n", (void*)netif, netif->name[0], @@ -280,13 +313,13 @@ autoip_start(struct netif *netif) /* no AutoIP client attached yet? */ LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): starting new AUTOIP client\n")); - autoip = mem_malloc(sizeof(struct autoip)); + autoip = (struct autoip *)mem_malloc(sizeof(struct autoip)); if(autoip == NULL) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): could not allocate autoip\n")); return ERR_MEM; } - memset( autoip, 0, sizeof(struct autoip)); + memset(autoip, 0, sizeof(struct autoip)); /* store this AutoIP client in the netif */ netif->autoip = autoip; LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_start(): allocated autoip")); @@ -294,12 +327,11 @@ autoip_start(struct netif *netif) autoip->state = AUTOIP_STATE_OFF; autoip->ttw = 0; autoip->sent_num = 0; - memset(&autoip->llipaddr, 0, sizeof(struct ip_addr)); + ip_addr_set_zero(&autoip->llipaddr); autoip->lastconflict = 0; } autoip_create_addr(netif, &(autoip->llipaddr)); - autoip->tried_llipaddr++; autoip_start_probing(netif); return result; @@ -312,6 +344,10 @@ autoip_start_probing(struct netif *netif) autoip->state = AUTOIP_STATE_PROBING; autoip->sent_num = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_start_probing(): changing state to PROBING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); /* time to wait to first probe, this is randomly * choosen out of 0 to PROBE_WAIT seconds. @@ -385,6 +421,10 @@ autoip_tmr() netif->autoip->state = AUTOIP_STATE_ANNOUNCING; netif->autoip->sent_num = 0; netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to ANNOUNCING: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); } else { autoip_arp_probe(netif); LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, @@ -422,6 +462,10 @@ autoip_tmr() netif->autoip->state = AUTOIP_STATE_BOUND; netif->autoip->sent_num = 0; netif->autoip->ttw = 0; + LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, + ("autoip_tmr(): changing state to BOUND: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(&netif->autoip->llipaddr), ip4_addr2_16(&netif->autoip->llipaddr), + ip4_addr3_16(&netif->autoip->llipaddr), ip4_addr4_16(&netif->autoip->llipaddr))); } } break; @@ -448,20 +492,15 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) * when probing ip.dst == llipaddr && hw.src != netif->hwaddr * we have a conflict and must solve it */ - struct ip_addr sipaddr, dipaddr; + ip_addr_t sipaddr, dipaddr; struct eth_addr netifaddr; - netifaddr.addr[0] = netif->hwaddr[0]; - netifaddr.addr[1] = netif->hwaddr[1]; - netifaddr.addr[2] = netif->hwaddr[2]; - netifaddr.addr[3] = netif->hwaddr[3]; - netifaddr.addr[4] = netif->hwaddr[4]; - netifaddr.addr[5] = netif->hwaddr[5]; + ETHADDR16_COPY(netifaddr.addr, netif->hwaddr); /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ - SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); - SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); if ((netif->autoip->state == AUTOIP_STATE_PROBING) || ((netif->autoip->state == AUTOIP_STATE_ANNOUNCING) && @@ -477,7 +516,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr) !eth_addr_cmp(&netifaddr, &hdr->shwaddr))) { LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING, ("autoip_arp_reply(): Probe Conflict detected\n")); - autoip_start(netif); + autoip_restart(netif); } } else { /* RFC 3927 Section 2.5: diff --git a/core/lwip/src/core/ipv4/icmp.c b/core/lwip/src/core/ipv4/icmp.c index b97a587a..32902a52 100644 --- a/core/lwip/src/core/ipv4/icmp.c +++ b/core/lwip/src/core/ipv4/icmp.c @@ -44,7 +44,6 @@ #if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/icmp.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/ip.h" #include "lwip/def.h" @@ -83,14 +82,13 @@ icmp_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_DEBUG */ struct icmp_echo_hdr *iecho; struct ip_hdr *iphdr; - struct ip_addr tmpaddr; s16_t hlen; ICMP_STATS_INC(icmp.recv); snmp_inc_icmpinmsgs(); - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; hlen = IPH_HL(iphdr) * 4; if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len)); @@ -102,19 +100,23 @@ icmp_input(struct pbuf *p, struct netif *inp) code = *(((u8_t *)p->payload)+1); #endif /* LWIP_DEBUG */ switch (type) { + case ICMP_ER: + /* This is OK, echo reply might have been parsed by a raw PCB + (as obviously, an echo request has been sent, too). */ + break; case ICMP_ECHO: #if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING { int accepted = 1; #if !LWIP_MULTICAST_PING /* multicast destination address? */ - if (ip_addr_ismulticast(&iphdr->dest)) { + if (ip_addr_ismulticast(¤t_iphdr_dest)) { accepted = 0; } #endif /* LWIP_MULTICAST_PING */ #if !LWIP_BROADCAST_PING /* broadcast destination address? */ - if (ip_addr_isbroadcast(&iphdr->dest, inp)) { + if (ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { accepted = 0; } #endif /* LWIP_BROADCAST_PING */ @@ -163,7 +165,7 @@ icmp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("icmp_input: copying to new pbuf failed\n", 0); goto memerr; } - iphdr = r->payload; + iphdr = (struct ip_hdr *)r->payload; /* switch r->payload back to icmp header */ if (pbuf_header(r, -hlen)) { LWIP_ASSERT("icmp_input: restoring original p->payload failed\n", 0); @@ -184,16 +186,15 @@ icmp_input(struct pbuf *p, struct netif *inp) /* At this point, all checks are OK. */ /* We generate an answer by switching the dest and src ip addresses, * setting the icmp type to ECHO_RESPONSE and updating the checksum. */ - iecho = p->payload; - tmpaddr.addr = iphdr->src.addr; - iphdr->src.addr = iphdr->dest.addr; - iphdr->dest.addr = tmpaddr.addr; + iecho = (struct icmp_echo_hdr *)p->payload; + ip_addr_copy(iphdr->src, *ip_current_dest_addr()); + ip_addr_copy(iphdr->dest, *ip_current_src_addr()); ICMPH_TYPE_SET(iecho, ICMP_ER); /* adjust the checksum */ - if (iecho->chksum >= htons(0xffff - (ICMP_ECHO << 8))) { - iecho->chksum += htons(ICMP_ECHO << 8) + 1; + if (iecho->chksum >= PP_HTONS(0xffffU - (ICMP_ECHO << 8))) { + iecho->chksum += PP_HTONS(ICMP_ECHO << 8) + 1; } else { - iecho->chksum += htons(ICMP_ECHO << 8); + iecho->chksum += PP_HTONS(ICMP_ECHO << 8); } /* Set the correct TTL and recalculate the header checksum. */ @@ -213,7 +214,8 @@ icmp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("Can't move over header in packet", 0); } else { err_t ret; - ret = ip_output_if(p, &(iphdr->src), IP_HDRINCL, + /* send an ICMP packet, src addr is the dest addr of the curren packet */ + ret = ip_output_if(p, ip_current_dest_addr(), IP_HDRINCL, ICMP_TTL, 0, IP_PROTO_ICMP, inp); if (ret != ERR_OK) { LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ip_output_if returned an error: %c.\n", ret)); @@ -288,6 +290,7 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) struct ip_hdr *iphdr; /* we can use the echo header here */ struct icmp_echo_hdr *icmphdr; + ip_addr_t iphdr_src; /* ICMP header + IP header + 8 bytes of data */ q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE, @@ -299,14 +302,14 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) LWIP_ASSERT("check that first pbuf can hold icmp message", (q->len >= (sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE))); - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded from ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->src)); LWIP_DEBUGF(ICMP_DEBUG, (" to ")); ip_addr_debug_print(ICMP_DEBUG, &(iphdr->dest)); LWIP_DEBUGF(ICMP_DEBUG, ("\n")); - icmphdr = q->payload; + icmphdr = (struct icmp_echo_hdr *)q->payload; icmphdr->type = type; icmphdr->code = code; icmphdr->id = 0; @@ -324,7 +327,8 @@ icmp_send_response(struct pbuf *p, u8_t type, u8_t code) snmp_inc_icmpoutmsgs(); /* increase number of destination unreachable messages attempted to send */ snmp_inc_icmpouttimeexcds(); - ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP); + ip_addr_copy(iphdr_src, iphdr->src); + ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP); pbuf_free(q); } diff --git a/core/lwip/src/core/ipv4/igmp.c b/core/lwip/src/core/ipv4/igmp.c index 7c07bc46..4e4405e1 100644 --- a/core/lwip/src/core/ipv4/igmp.c +++ b/core/lwip/src/core/ipv4/igmp.c @@ -86,7 +86,6 @@ Steve Reynolds #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/ip.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" @@ -96,13 +95,60 @@ Steve Reynolds #include "string.h" -/*----------------------------------------------------------------------------- - * Globales - *----------------------------------------------------------------------------*/ +/* + * IGMP constants + */ +#define IGMP_TTL 1 +#define IGMP_MINLEN 8 +#define ROUTER_ALERT 0x9404U +#define ROUTER_ALERTLEN 4 + +/* + * IGMP message types, including version number. + */ +#define IGMP_MEMB_QUERY 0x11 /* Membership query */ +#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ +#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ +#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ + +/* Group membership states */ +#define IGMP_GROUP_NON_MEMBER 0 +#define IGMP_GROUP_DELAYING_MEMBER 1 +#define IGMP_GROUP_IDLE_MEMBER 2 + +/** + * IGMP packet format. + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct igmp_msg { + PACK_STRUCT_FIELD(u8_t igmp_msgtype); + PACK_STRUCT_FIELD(u8_t igmp_maxresp); + PACK_STRUCT_FIELD(u16_t igmp_checksum); + PACK_STRUCT_FIELD(ip_addr_p_t igmp_group_address); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + + +static struct igmp_group *igmp_lookup_group(struct netif *ifp, ip_addr_t *addr); +static err_t igmp_remove_group(struct igmp_group *group); +static void igmp_timeout( struct igmp_group *group); +static void igmp_start_timer(struct igmp_group *group, u8_t max_time); +static void igmp_stop_timer(struct igmp_group *group); +static void igmp_delaying_member(struct igmp_group *group, u8_t maxresp); +static err_t igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif); +static void igmp_send(struct igmp_group *group, u8_t type); + static struct igmp_group* igmp_group_list; -static struct ip_addr allsystems; -static struct ip_addr allrouters; +static ip_addr_t allsystems; +static ip_addr_t allrouters; + /** * Initialize the IGMP module @@ -128,7 +174,7 @@ igmp_dump_group_list() while (group != NULL) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_dump_group_list: [%"U32_F"] ", (u32_t)(group->group_state))); ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); group = group->next; } LWIP_DEBUGF(IGMP_DEBUG, ("\n")); @@ -160,7 +206,7 @@ igmp_start(struct netif *netif) LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD ")); ip_addr_debug_print(IGMP_DEBUG, &allsystems); LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif)); - netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER); + netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER); } return ERR_OK; @@ -185,7 +231,7 @@ igmp_stop(struct netif *netif) while (group != NULL) { next = group->next; /* is it a group joined on this interface? */ - if (group->interface == netif) { + if (group->netif == netif) { /* is it the first group of the list? */ if (group == igmp_group_list) { igmp_group_list = next; @@ -219,15 +265,15 @@ igmp_stop(struct netif *netif) * @param netif network interface on which report IGMP memberships */ void -igmp_report_groups( struct netif *netif) +igmp_report_groups(struct netif *netif) { struct igmp_group *group = igmp_group_list; LWIP_DEBUGF(IGMP_DEBUG, ("igmp_report_groups: sending IGMP reports on if %p\n", netif)); while (group != NULL) { - if (group->interface == netif) { - igmp_delaying_member( group, IGMP_JOIN_DELAYING_MEMBER_TMR); + if (group->netif == netif) { + igmp_delaying_member(group, IGMP_JOIN_DELAYING_MEMBER_TMR); } group = group->next; } @@ -242,12 +288,12 @@ igmp_report_groups( struct netif *netif) * NULL if the group wasn't found. */ struct igmp_group * -igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr) +igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr) { struct igmp_group *group = igmp_group_list; while (group != NULL) { - if ((group->interface == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { + if ((group->netif == ifp) && (ip_addr_cmp(&(group->group_address), addr))) { return group; } group = group->next; @@ -268,7 +314,7 @@ igmp_lookfor_group(struct netif *ifp, struct ip_addr *addr) * NULL on memory error. */ struct igmp_group * -igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) +igmp_lookup_group(struct netif *ifp, ip_addr_t *addr) { struct igmp_group *group = igmp_group_list; @@ -280,9 +326,9 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) } /* Group doesn't exist yet, create a new one */ - group = memp_malloc(MEMP_IGMP_GROUP); + group = (struct igmp_group *)memp_malloc(MEMP_IGMP_GROUP); if (group != NULL) { - group->interface = ifp; + group->netif = ifp; ip_addr_set(&(group->group_address), addr); group->timer = 0; /* Not running */ group->group_state = IGMP_GROUP_NON_MEMBER; @@ -306,7 +352,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr) * @param group the group to remove from the global igmp_group_list * @return ERR_OK if group was removed from the list, an err_t otherwise */ -err_t +static err_t igmp_remove_group(struct igmp_group *group) { err_t err = ERR_OK; @@ -341,15 +387,17 @@ igmp_remove_group(struct igmp_group *group) * @param dest destination ip address of the igmp packet */ void -igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) +igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest) { struct ip_hdr * iphdr; struct igmp_msg* igmp; struct igmp_group* group; struct igmp_group* groupref; + IGMP_STATS_INC(igmp.recv); + /* Note that the length CAN be greater than 8 but only 8 are used - All are included in the checksum */ - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) { pbuf_free(p); IGMP_STATS_INC(igmp.lenerr); @@ -373,11 +421,12 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) } /* Packet is ok so find an existing group */ - group = igmp_lookfor_group(inp, dest); /* use the incoming IP address! */ + group = igmp_lookfor_group(inp, dest); /* use the destination IP address of incoming packet */ /* If group can be found or create... */ if (!group) { pbuf_free(p); + IGMP_STATS_INC(igmp.drop); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP frame not for us\n")); return; } @@ -386,50 +435,56 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) switch (igmp->igmp_msgtype) { case IGMP_MEMB_QUERY: { /* IGMP_MEMB_QUERY to the "all systems" address ? */ - if ((ip_addr_cmp(dest, &allsystems)) && (igmp->igmp_group_address.addr == 0)) { + if ((ip_addr_cmp(dest, &allsystems)) && ip_addr_isany(&igmp->igmp_group_address)) { /* THIS IS THE GENERAL QUERY */ LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: General IGMP_MEMB_QUERY on \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); if (igmp->igmp_maxresp == 0) { - IGMP_STATS_INC(igmp.v1_rxed); + IGMP_STATS_INC(igmp.rx_v1); LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: got an all hosts query with time== 0 - this is V1 and not implemented - treat as v2\n")); igmp->igmp_maxresp = IGMP_V1_DELAYING_MEMBER_TMR; + } else { + IGMP_STATS_INC(igmp.rx_general); } - IGMP_STATS_INC(igmp.group_query_rxed); groupref = igmp_group_list; while (groupref) { /* Do not send messages on the all systems group address! */ - if ((groupref->interface == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { - igmp_delaying_member( groupref, igmp->igmp_maxresp); + if ((groupref->netif == inp) && (!(ip_addr_cmp(&(groupref->group_address), &allsystems)))) { + igmp_delaying_member(groupref, igmp->igmp_maxresp); } groupref = groupref->next; } } else { /* IGMP_MEMB_QUERY to a specific group ? */ - if (group->group_address.addr != 0) { + if (!ip_addr_isany(&igmp->igmp_group_address)) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_MEMB_QUERY to a specific group ")); - ip_addr_debug_print(IGMP_DEBUG, &group->group_address); - if (ip_addr_cmp (dest, &allsystems)) { + ip_addr_debug_print(IGMP_DEBUG, &igmp->igmp_group_address); + if (ip_addr_cmp(dest, &allsystems)) { + ip_addr_t groupaddr; LWIP_DEBUGF(IGMP_DEBUG, (" using \"ALL SYSTEMS\" address (224.0.0.1) [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); - /* we first need to re-lookfor the group since we used dest last time */ - group = igmp_lookfor_group(inp, &igmp->igmp_group_address); + /* we first need to re-look for the group since we used dest last time */ + ip_addr_copy(groupaddr, igmp->igmp_group_address); + group = igmp_lookfor_group(inp, &groupaddr); } else { LWIP_DEBUGF(IGMP_DEBUG, (" with the group address as destination [igmp_maxresp=%i]\n", (int)(igmp->igmp_maxresp))); } if (group != NULL) { - IGMP_STATS_INC(igmp.unicast_query); - igmp_delaying_member( group, igmp->igmp_maxresp); + IGMP_STATS_INC(igmp.rx_group); + igmp_delaying_member(group, igmp->igmp_maxresp); + } else { + IGMP_STATS_INC(igmp.drop); } + } else { + IGMP_STATS_INC(igmp.proterr); } } break; } case IGMP_V2_MEMB_REPORT: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: IGMP_V2_MEMB_REPORT\n")); - - IGMP_STATS_INC(igmp.report_rxed); + IGMP_STATS_INC(igmp.rx_report); if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { /* This is on a specific group we have already looked up */ group->timer = 0; /* stopped */ @@ -440,7 +495,8 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) } default: { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %d in state %d on group %p on if %p\n", - igmp->igmp_msgtype, group->group_state, &group, group->interface)); + igmp->igmp_msgtype, group->group_state, &group, group->netif)); + IGMP_STATS_INC(igmp.proterr); break; } } @@ -457,7 +513,7 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest) * @return ERR_OK if group was joined on the netif(s), an err_t otherwise */ err_t -igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) +igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct igmp_group *group; @@ -493,7 +549,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER); } - IGMP_STATS_INC(igmp.join_sent); + IGMP_STATS_INC(igmp.tx_join); igmp_send(group, IGMP_V2_MEMB_REPORT); igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR); @@ -527,7 +583,7 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) * @return ERR_OK if group was left on the netif(s), an err_t otherwise */ err_t -igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) +igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr) { err_t err = ERR_VAL; /* no matching interface */ struct igmp_group *group; @@ -556,7 +612,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr) /* If we are the last reporter for this group */ if (group->last_reporter_flag) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: sending leaving group\n")); - IGMP_STATS_INC(igmp.leave_sent); + IGMP_STATS_INC(igmp.tx_leave); igmp_send(group, IGMP_LEAVE_GROUP); } @@ -602,8 +658,8 @@ igmp_tmr(void) struct igmp_group *group = igmp_group_list; while (group != NULL) { - if (group->timer != 0) { - group->timer -= 1; + if (group->timer > 0) { + group->timer--; if (group->timer == 0) { igmp_timeout(group); } @@ -618,15 +674,16 @@ igmp_tmr(void) * * @param group an igmp_group for which a timeout is reached */ -void +static void igmp_timeout(struct igmp_group *group) { /* If the state is IGMP_GROUP_DELAYING_MEMBER then we send a report for this group */ if (group->group_state == IGMP_GROUP_DELAYING_MEMBER) { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_timeout: report membership for group with address ")); ip_addr_debug_print(IGMP_DEBUG, &(group->group_address)); - LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->interface)); + LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif)); + IGMP_STATS_INC(igmp.tx_report); igmp_send(group, IGMP_V2_MEMB_REPORT); } } @@ -638,13 +695,15 @@ igmp_timeout(struct igmp_group *group) * @param max_time the time in multiples of IGMP_TMR_INTERVAL (decrease with * every call to igmp_tmr()) */ -void +static void igmp_start_timer(struct igmp_group *group, u8_t max_time) { - /** - * @todo Important !! this should be random 0 -> max_time. Find out how to do this - */ - group->timer = max_time; + /* ensure the input value is > 0 */ + if (max_time == 0) { + max_time = 1; + } + /* ensure the random value is > 0 */ + group->timer = (LWIP_RAND() % (max_time - 1)) + 1; } /** @@ -652,7 +711,7 @@ igmp_start_timer(struct igmp_group *group, u8_t max_time) * * @param group the igmp_group for which to stop the timer */ -void +static void igmp_stop_timer(struct igmp_group *group) { group->timer = 0; @@ -664,12 +723,13 @@ igmp_stop_timer(struct igmp_group *group) * @param group the igmp_group for which "delaying" membership report * @param maxresp query delay */ -void -igmp_delaying_member( struct igmp_group *group, u8_t maxresp) +static void +igmp_delaying_member(struct igmp_group *group, u8_t maxresp) { if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) || - ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && (maxresp > group->timer))) { - igmp_start_timer(group, (maxresp)/2); + ((group->group_state == IGMP_GROUP_DELAYING_MEMBER) && + ((group->timer == 0) || (maxresp < group->timer)))) { + igmp_start_timer(group, maxresp); group->group_state = IGMP_GROUP_DELAYING_MEMBER; } } @@ -693,15 +753,15 @@ igmp_delaying_member( struct igmp_group *group, u8_t maxresp) * ERR_BUF if p doesn't have enough space for IP/LINK headers * returns errors returned by netif->output */ -err_t -igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, - u8_t ttl, u8_t proto, struct netif *netif) +static err_t +igmp_ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, struct netif *netif) { /* This is the "router alert" option */ u16_t ra[2]; - ra[0] = htons (ROUTER_ALERT); + ra[0] = PP_HTONS(ROUTER_ALERT); ra[1] = 0x0000; /* Router shall examine packet */ - return ip_output_if_opt(p, src, dest, ttl, 0, proto, netif, ra, ROUTER_ALERTLEN); + IGMP_STATS_INC(igmp.xmit); + return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN); } /** @@ -710,32 +770,31 @@ igmp_ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, * @param group the group to which to send the packet * @param type the type of igmp packet to send */ -void +static void igmp_send(struct igmp_group *group, u8_t type) { struct pbuf* p = NULL; struct igmp_msg* igmp = NULL; - struct ip_addr src = {0}; - struct ip_addr* dest = NULL; + ip_addr_t src = *IP_ADDR_ANY; + ip_addr_t* dest = NULL; /* IP header + "router alert" option + IGMP header */ p = pbuf_alloc(PBUF_TRANSPORT, IGMP_MINLEN, PBUF_RAM); if (p) { - igmp = p->payload; + igmp = (struct igmp_msg *)p->payload; LWIP_ASSERT("igmp_send: check that first pbuf can hold struct igmp_msg", (p->len >= sizeof(struct igmp_msg))); - ip_addr_set(&src, &((group->interface)->ip_addr)); + ip_addr_copy(src, group->netif->ip_addr); if (type == IGMP_V2_MEMB_REPORT) { dest = &(group->group_address); - IGMP_STATS_INC(igmp.report_sent); - ip_addr_set(&(igmp->igmp_group_address), &(group->group_address)); + ip_addr_copy(igmp->igmp_group_address, group->group_address); group->last_reporter_flag = 1; /* Remember we were the last to report */ } else { if (type == IGMP_LEAVE_GROUP) { dest = &allrouters; - ip_addr_set(&(igmp->igmp_group_address), &(group->group_address)); + ip_addr_copy(igmp->igmp_group_address, group->group_address); } } @@ -743,14 +802,15 @@ igmp_send(struct igmp_group *group, u8_t type) igmp->igmp_msgtype = type; igmp->igmp_maxresp = 0; igmp->igmp_checksum = 0; - igmp->igmp_checksum = inet_chksum( igmp, IGMP_MINLEN); + igmp->igmp_checksum = inet_chksum(igmp, IGMP_MINLEN); - igmp_ip_output_if(p, &src, dest, IGMP_TTL, IP_PROTO_IGMP, group->interface); + igmp_ip_output_if(p, &src, dest, group->netif); } pbuf_free(p); } else { LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n")); + IGMP_STATS_INC(igmp.memerr); } } diff --git a/core/lwip/src/core/ipv4/inet.c b/core/lwip/src/core/ipv4/inet.c index 69baf1d5..e283a576 100644 --- a/core/lwip/src/core/ipv4/inet.c +++ b/core/lwip/src/core/ipv4/inet.c @@ -40,239 +40,3 @@ #include "lwip/inet.h" -/* Here for now until needed in other places in lwIP */ -#ifndef isprint -#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) -#define isprint(c) in_range(c, 0x20, 0x7f) -#define isdigit(c) in_range(c, '0', '9') -#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) -#define islower(c) in_range(c, 'a', 'z') -#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') -#endif - -/** - * Ascii internet address interpretation routine. - * The value returned is in network order. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @return ip address in network order - */ -u32_t -inet_addr(const char *cp) -{ - struct in_addr val; - - if (inet_aton(cp, &val)) { - return (val.s_addr); - } - return (INADDR_NONE); -} - -/** - * Check whether "cp" is a valid ascii representation - * of an Internet address and convert to a binary address. - * Returns 1 if the address is valid, 0 if not. - * This replaces inet_addr, the return value from which - * cannot distinguish between failure and a local broadcast address. - * - * @param cp IP address in ascii represenation (e.g. "127.0.0.1") - * @param addr pointer to which to save the ip address in network order - * @return 1 if cp could be converted to addr, 0 on failure - */ -int -inet_aton(const char *cp, struct in_addr *addr) -{ - u32_t val; - u8_t base; - char c; - u32_t parts[4]; - u32_t *pp = parts; - - c = *cp; - for (;;) { - /* - * Collect number up to ``.''. - * Values are specified as for C: - * 0x=hex, 0=octal, 1-9=decimal. - */ - if (!isdigit(c)) - return (0); - val = 0; - base = 10; - if (c == '0') { - c = *++cp; - if (c == 'x' || c == 'X') { - base = 16; - c = *++cp; - } else - base = 8; - } - for (;;) { - if (isdigit(c)) { - val = (val * base) + (int)(c - '0'); - c = *++cp; - } else if (base == 16 && isxdigit(c)) { - val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); - c = *++cp; - } else - break; - } - if (c == '.') { - /* - * Internet format: - * a.b.c.d - * a.b.c (with c treated as 16 bits) - * a.b (with b treated as 24 bits) - */ - if (pp >= parts + 3) - return (0); - *pp++ = val; - c = *++cp; - } else - break; - } - /* - * Check for trailing characters. - */ - if (c != '\0' && !isspace(c)) - return (0); - /* - * Concoct the address according to - * the number of parts specified. - */ - switch (pp - parts + 1) { - - case 0: - return (0); /* initial nondigit */ - - case 1: /* a -- 32 bits */ - break; - - case 2: /* a.b -- 8.24 bits */ - if (val > 0xffffffUL) - return (0); - val |= parts[0] << 24; - break; - - case 3: /* a.b.c -- 8.8.16 bits */ - if (val > 0xffff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16); - break; - - case 4: /* a.b.c.d -- 8.8.8.8 bits */ - if (val > 0xff) - return (0); - val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); - break; - } - if (addr) - addr->s_addr = htonl(val); - return (1); -} - -/** - * Convert numeric IP address into decimal dotted ASCII representation. - * returns ptr to static buffer; not reentrant! - * - * @param addr ip address in network order to convert - * @return pointer to a global static (!) buffer that holds the ASCII - * represenation of addr - */ -char * -inet_ntoa(struct in_addr addr) -{ - static char str[16]; - u32_t s_addr = addr.s_addr; - char inv[3]; - char *rp; - u8_t *ap; - u8_t rem; - u8_t n; - u8_t i; - - rp = str; - ap = (u8_t *)&s_addr; - for(n = 0; n < 4; n++) { - i = 0; - do { - rem = *ap % (u8_t)10; - *ap /= (u8_t)10; - inv[i++] = '0' + rem; - } while(*ap); - while(i--) - *rp++ = inv[i]; - *rp++ = '.'; - ap++; - } - *--rp = 0; - return str; -} - -/** - * These are reference implementations of the byte swapping functions. - * Again with the aim of being simple, correct and fully portable. - * Byte swapping is the second thing you would want to optimize. You will - * need to port it to your architecture and in your cc.h: - * - * #define LWIP_PLATFORM_BYTESWAP 1 - * #define LWIP_PLATFORM_HTONS(x) <your_htons> - * #define LWIP_PLATFORM_HTONL(x) <your_htonl> - * - * Note ntohs() and ntohl() are merely references to the htonx counterparts. - */ - -#if (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) - -/** - * Convert an u16_t from host- to network byte order. - * - * @param n u16_t in host byte order - * @return n in network byte order - */ -u16_t -htons(u16_t n) -{ - return ((n & 0xff) << 8) | ((n & 0xff00) >> 8); -} - -/** - * Convert an u16_t from network- to host byte order. - * - * @param n u16_t in network byte order - * @return n in host byte order - */ -u16_t -ntohs(u16_t n) -{ - return htons(n); -} - -/** - * Convert an u32_t from host- to network byte order. - * - * @param n u32_t in host byte order - * @return n in network byte order - */ -u32_t -htonl(u32_t n) -{ - return ((n & 0xff) << 24) | - ((n & 0xff00) << 8) | - ((n & 0xff0000UL) >> 8) | - ((n & 0xff000000UL) >> 24); -} - -/** - * Convert an u32_t from network- to host byte order. - * - * @param n u32_t in network byte order - * @return n in host byte order - */ -u32_t -ntohl(u32_t n) -{ - return htonl(n); -} - -#endif /* (LWIP_PLATFORM_BYTESWAP == 0) && (BYTE_ORDER == LITTLE_ENDIAN) */ diff --git a/core/lwip/src/core/ipv4/inet_chksum.c b/core/lwip/src/core/ipv4/inet_chksum.c index 185881ef..960252f6 100644 --- a/core/lwip/src/core/ipv4/inet_chksum.c +++ b/core/lwip/src/core/ipv4/inet_chksum.c @@ -39,9 +39,10 @@ #include "lwip/opt.h" #include "lwip/inet_chksum.h" -#include "lwip/inet.h" +#include "lwip/def.h" #include <stddef.h> +#include <string.h> /* These are some reference implementations of the checksum algorithm, with the * aim of being simple, correct and fully portable. Checksumming is the @@ -57,7 +58,7 @@ #ifndef LWIP_CHKSUM # define LWIP_CHKSUM lwip_standard_chksum # ifndef LWIP_CHKSUM_ALGORITHM -# define LWIP_CHKSUM_ALGORITHM 1 +# define LWIP_CHKSUM_ALGORITHM 2 # endif #endif /* If none set: */ @@ -65,18 +66,6 @@ # define LWIP_CHKSUM_ALGORITHM 0 #endif -/** Like the name says... */ -#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) -/* little endian and PLATFORM_BYTESWAP defined */ -#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) -#else -/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ -#define SWAP_BYTES_IN_WORD(w) ((w & 0xff) << 8) | ((w & 0xff00) >> 8) -#endif - -/** Split an u32_t in two u16_ts and add them up */ -#define FOLD_U32T(u) ((u >> 16) + (u & 0x0000ffffUL)) - #if (LWIP_CHKSUM_ALGORITHM == 1) /* Version #1 */ /** * lwip checksum @@ -145,10 +134,10 @@ lwip_standard_chksum(void *dataptr, u16_t len) static u16_t lwip_standard_chksum(void *dataptr, int len) { - u8_t *pb = dataptr; + u8_t *pb = (u8_t *)dataptr; u16_t *ps, t = 0; u32_t sum = 0; - int odd = ((u32_t)pb & 1); + int odd = ((mem_ptr_t)pb & 1); /* Get aligned to u16_t */ if (odd && len > 0) { @@ -157,7 +146,7 @@ lwip_standard_chksum(void *dataptr, int len) } /* Add the bulk of the data */ - ps = (u16_t *)pb; + ps = (u16_t *)(void *)pb; while (len > 1) { sum += *ps++; len -= 2; @@ -165,7 +154,7 @@ lwip_standard_chksum(void *dataptr, int len) /* Consume left-over byte, if any */ if (len > 0) { - ((u8_t *)&t)[0] = *(u8_t *)ps;; + ((u8_t *)&t)[0] = *(u8_t *)ps; } /* Add end bytes */ @@ -181,7 +170,7 @@ lwip_standard_chksum(void *dataptr, int len) sum = SWAP_BYTES_IN_WORD(sum); } - return sum; + return (u16_t)sum; } #endif @@ -201,12 +190,12 @@ lwip_standard_chksum(void *dataptr, int len) static u16_t lwip_standard_chksum(void *dataptr, int len) { - u8_t *pb = dataptr; + u8_t *pb = (u8_t *)dataptr; u16_t *ps, t = 0; u32_t *pl; u32_t sum = 0, tmp; /* starts at odd byte address? */ - int odd = ((u32_t)pb & 1); + int odd = ((mem_ptr_t)pb & 1); if (odd && len > 0) { ((u8_t *)&t)[1] = *pb++; @@ -215,7 +204,7 @@ lwip_standard_chksum(void *dataptr, int len) ps = (u16_t *)pb; - if (((u32_t)ps & 3) && len > 1) { + if (((mem_ptr_t)ps & 3) && len > 1) { sum += *ps++; len -= 2; } @@ -263,7 +252,7 @@ lwip_standard_chksum(void *dataptr, int len) sum = SWAP_BYTES_IN_WORD(sum); } - return sum; + return (u16_t)sum; } #endif @@ -281,10 +270,11 @@ lwip_standard_chksum(void *dataptr, int len) */ u16_t inet_chksum_pseudo(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, + ip_addr_t *src, ip_addr_t *dest, u8_t proto, u16_t proto_len) { u32_t acc; + u32_t addr; struct pbuf *q; u8_t swapped; @@ -309,10 +299,12 @@ inet_chksum_pseudo(struct pbuf *p, if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } - acc += (src->addr & 0xffffUL); - acc += ((src->addr >> 16) & 0xffffUL); - acc += (dest->addr & 0xffffUL); - acc += ((dest->addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(src); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); @@ -336,14 +328,13 @@ inet_chksum_pseudo(struct pbuf *p, * @param proto_len length of the ip data part (used for checksum of pseudo header) * @return checksum (as u16_t) to be saved directly in the protocol header */ -/* Currently only used by UDPLITE, although this could change in the future. */ -#if LWIP_UDPLITE u16_t inet_chksum_pseudo_partial(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, + ip_addr_t *src, ip_addr_t *dest, u8_t proto, u16_t proto_len, u16_t chksum_len) { u32_t acc; + u32_t addr; struct pbuf *q; u8_t swapped; u16_t chklen; @@ -374,10 +365,12 @@ inet_chksum_pseudo_partial(struct pbuf *p, if (swapped) { acc = SWAP_BYTES_IN_WORD(acc); } - acc += (src->addr & 0xffffUL); - acc += ((src->addr >> 16) & 0xffffUL); - acc += (dest->addr & 0xffffUL); - acc += ((dest->addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(src); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); + addr = ip4_addr_get_u32(dest); + acc += (addr & 0xffffUL); + acc += ((addr >> 16) & 0xffffUL); acc += (u32_t)htons((u16_t)proto); acc += (u32_t)htons(proto_len); @@ -388,7 +381,6 @@ inet_chksum_pseudo_partial(struct pbuf *p, LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc)); return (u16_t)~(acc & 0xffffUL); } -#endif /* LWIP_UDPLITE */ /* inet_chksum: * @@ -436,3 +428,23 @@ inet_chksum_pbuf(struct pbuf *p) } return (u16_t)~(acc & 0xffffUL); } + +/* These are some implementations for LWIP_CHKSUM_COPY, which copies data + * like MEMCPY but generates a checksum at the same time. Since this is a + * performance-sensitive function, you might want to create your own version + * in assembly targeted at your hardware by defining it in lwipopts.h: + * #define LWIP_CHKSUM_COPY(dst, src, len) your_chksum_copy(dst, src, len) + */ + +#if (LWIP_CHKSUM_COPY_ALGORITHM == 1) /* Version #1 */ +/** Safe but slow: first call MEMCPY, then call LWIP_CHKSUM. + * For architectures with big caches, data might still be in cache when + * generating the checksum after copying. + */ +u16_t +lwip_chksum_copy(void *dst, const void *src, u16_t len) +{ + MEMCPY(dst, src, len); + return LWIP_CHKSUM(dst, len); +} +#endif /* (LWIP_CHKSUM_COPY_ALGORITHM == 1) */ diff --git a/core/lwip/src/core/ipv4/ip.c b/core/lwip/src/core/ipv4/ip.c index b1e98f33..6f248716 100644 --- a/core/lwip/src/core/ipv4/ip.c +++ b/core/lwip/src/core/ipv4/ip.c @@ -43,21 +43,56 @@ #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/ip_frag.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/icmp.h" #include "lwip/igmp.h" #include "lwip/raw.h" #include "lwip/udp.h" -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/snmp.h" #include "lwip/dhcp.h" +#include "lwip/autoip.h" #include "lwip/stats.h" #include "arch/perf.h" #include <string.h> +/** Set this to 0 in the rare case of wanting to call an extra function to + * generate the IP checksum (in contrast to calculating it on-the-fly). */ +#ifndef LWIP_INLINE_IP_CHKSUM +#define LWIP_INLINE_IP_CHKSUM 1 +#endif +#if LWIP_INLINE_IP_CHKSUM && CHECKSUM_GEN_IP +#define CHECKSUM_GEN_IP_INLINE 1 +#else +#define CHECKSUM_GEN_IP_INLINE 0 +#endif + +#if LWIP_DHCP || defined(LWIP_IP_ACCEPT_UDP_PORT) +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 1 + +/** Some defines for DHCP to let link-layer-addressed packets through while the + * netif is down. + * To use this in your own application/protocol, define LWIP_IP_ACCEPT_UDP_PORT + * to return 1 if the port is accepted and 0 if the port is not accepted. + */ +#if LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) +/* accept DHCP client port and custom port */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (((port) == PP_NTOHS(DHCP_CLIENT_PORT)) \ + || (LWIP_IP_ACCEPT_UDP_PORT(port))) +#elif defined(LWIP_IP_ACCEPT_UDP_PORT) /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept custom port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) (LWIP_IP_ACCEPT_UDP_PORT(dst_port)) +#else /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ +/* accept DHCP client port only */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(port) ((port) == PP_NTOHS(DHCP_CLIENT_PORT)) +#endif /* LWIP_DHCP && defined(LWIP_IP_ACCEPT_UDP_PORT) */ + +#else /* LWIP_DHCP */ +#define IP_ACCEPT_LINK_LAYER_ADDRESSING 0 +#endif /* LWIP_DHCP */ + /** * The interface that provided the packet for the current callback * invocation. @@ -68,6 +103,13 @@ struct netif *current_netif; * Header of the input packet currently being processed. */ const struct ip_hdr *current_header; +/** Source IP address of current_header */ +ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +ip_addr_t current_iphdr_dest; + +/** The IP header ID of the next outgoing IP packet */ +static u16_t ip_id; /** * Finds the appropriate network interface for a given IP address. It @@ -79,7 +121,7 @@ const struct ip_hdr *current_header; * @return the netif on which to send to reach dest */ struct netif * -ip_route(struct ip_addr *dest) +ip_route(ip_addr_t *dest) { struct netif *netif; @@ -94,7 +136,8 @@ ip_route(struct ip_addr *dest) } } if ((netif_default == NULL) || (!netif_is_up(netif_default))) { - LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to 0x%"X32_F"\n", dest->addr)); + LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_route: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); snmp_inc_ipoutnoroutes(); return NULL; @@ -112,28 +155,35 @@ ip_route(struct ip_addr *dest) * @param p the packet to forward (p->payload points to IP header) * @param iphdr the IP header of the input packet * @param inp the netif on which this packet was received - * @return the netif on which the packet was sent (NULL if it wasn't sent) */ -static struct netif * +static void ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) { struct netif *netif; PERF_START; + + /* RFC3927 2.7: do not forward link-local addresses */ + if (ip_addr_islinklocal(¤t_iphdr_dest)) { + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; + } + /* Find network interface where to forward this IP packet to. */ - netif = ip_route((struct ip_addr *)&(iphdr->dest)); + netif = ip_route(¤t_iphdr_dest); if (netif == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for 0x%"X32_F" found\n", - iphdr->dest.addr)); - snmp_inc_ipoutnoroutes(); - return (struct netif *)NULL; + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: no forwarding route for %"U16_F".%"U16_F".%"U16_F".%"U16_F" found\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); + goto return_noroute; } /* Do not forward packets onto the same network interface on which * they arrived. */ if (netif == inp) { LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not bouncing packets back on incoming interface.\n")); - snmp_inc_ipoutnoroutes(); - return (struct netif *)NULL; + goto return_noroute; } /* decrement TTL */ @@ -147,18 +197,19 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) icmp_time_exceeded(p, ICMP_TE_TTL); } #endif /* LWIP_ICMP */ - return (struct netif *)NULL; + return; } /* Incrementally update the IP checksum. */ - if (IPH_CHKSUM(iphdr) >= htons(0xffff - 0x100)) { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100) + 1); + if (IPH_CHKSUM(iphdr) >= PP_HTONS(0xffffU - 0x100)) { + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100) + 1); } else { - IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + htons(0x100)); + IPH_CHKSUM_SET(iphdr, IPH_CHKSUM(iphdr) + PP_HTONS(0x100)); } - LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to 0x%"X32_F"\n", - iphdr->dest.addr)); + LWIP_DEBUGF(IP_DEBUG, ("ip_forward: forwarding packet to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(¤t_iphdr_dest), ip4_addr2_16(¤t_iphdr_dest), + ip4_addr3_16(¤t_iphdr_dest), ip4_addr4_16(¤t_iphdr_dest))); IP_STATS_INC(ip.fw); IP_STATS_INC(ip.xmit); @@ -166,8 +217,10 @@ ip_forward(struct pbuf *p, struct ip_hdr *iphdr, struct netif *inp) PERF_STOP("ip_forward"); /* transmit pbuf on chosen interface */ - netif->output(netif, p, (struct ip_addr *)&(iphdr->dest)); - return netif; + netif->output(netif, p, ¤t_iphdr_dest); + return; +return_noroute: + snmp_inc_ipoutnoroutes(); } #endif /* IP_FORWARD */ @@ -192,15 +245,15 @@ ip_input(struct pbuf *p, struct netif *inp) struct netif *netif; u16_t iphdr_hlen; u16_t iphdr_len; -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING int check_ip_src=1; -#endif /* LWIP_DHCP */ +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ IP_STATS_INC(ip.recv); snmp_inc_ipinreceives(); /* identify the IP header */ - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; if (IPH_V(iphdr) != 4) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_WARNING, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr))); ip_debug_print(p); @@ -257,10 +310,14 @@ ip_input(struct pbuf *p, struct netif *inp) * but we'll do it anyway just to be sure that its done. */ pbuf_realloc(p, iphdr_len); + /* copy IP addresses to aligned ip_addr_t */ + ip_addr_copy(current_iphdr_dest, iphdr->dest); + ip_addr_copy(current_iphdr_src, iphdr->src); + /* match packet against an interface, i.e. is this packet for us? */ #if LWIP_IGMP - if (ip_addr_ismulticast(&(iphdr->dest))) { - if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, &(iphdr->dest)))) { + if (ip_addr_ismulticast(¤t_iphdr_dest)) { + if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ¤t_iphdr_dest))) { netif = inp; } else { netif = NULL; @@ -275,22 +332,33 @@ ip_input(struct pbuf *p, struct netif *inp) netif = inp; do { LWIP_DEBUGF(IP_DEBUG, ("ip_input: iphdr->dest 0x%"X32_F" netif->ip_addr 0x%"X32_F" (0x%"X32_F", 0x%"X32_F", 0x%"X32_F")\n", - iphdr->dest.addr, netif->ip_addr.addr, - iphdr->dest.addr & netif->netmask.addr, - netif->ip_addr.addr & netif->netmask.addr, - iphdr->dest.addr & ~(netif->netmask.addr))); + ip4_addr_get_u32(&iphdr->dest), ip4_addr_get_u32(&netif->ip_addr), + ip4_addr_get_u32(&iphdr->dest) & ip4_addr_get_u32(&netif->netmask), + ip4_addr_get_u32(&netif->ip_addr) & ip4_addr_get_u32(&netif->netmask), + ip4_addr_get_u32(&iphdr->dest) & ~ip4_addr_get_u32(&netif->netmask))); /* interface is up and configured? */ if ((netif_is_up(netif)) && (!ip_addr_isany(&(netif->ip_addr)))) { /* unicast to this interface address? */ - if (ip_addr_cmp(&(iphdr->dest), &(netif->ip_addr)) || + if (ip_addr_cmp(¤t_iphdr_dest, &(netif->ip_addr)) || /* or broadcast on this interface network address? */ - ip_addr_isbroadcast(&(iphdr->dest), netif)) { + ip_addr_isbroadcast(¤t_iphdr_dest, netif)) { LWIP_DEBUGF(IP_DEBUG, ("ip_input: packet accepted on interface %c%c\n", netif->name[0], netif->name[1])); /* break out of for loop */ break; } +#if LWIP_AUTOIP + /* connections to link-local addresses must persist after changing + the netif's address (RFC3927 ch. 1.9) */ + if ((netif->autoip != NULL) && + ip_addr_cmp(¤t_iphdr_dest, &(netif->autoip->llipaddr))) { + LWIP_DEBUGF(IP_DEBUG, ("ip_input: LLA packet accepted on interface %c%c\n", + netif->name[0], netif->name[1])); + /* break out of for loop */ + break; + } +#endif /* LWIP_AUTOIP */ } if (first) { first = 0; @@ -304,32 +372,38 @@ ip_input(struct pbuf *p, struct netif *inp) } while(netif != NULL); } -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING /* Pass DHCP messages regardless of destination address. DHCP traffic is addressed * using link layer addressing (such as Ethernet MAC) so we must not filter on IP. * According to RFC 1542 section 3.1.1, referred by RFC 2131). + * + * If you want to accept private broadcast communication while a netif is down, + * define LWIP_IP_ACCEPT_UDP_PORT(dst_port), e.g.: + * + * #define LWIP_IP_ACCEPT_UDP_PORT(dst_port) ((dst_port) == PP_NTOHS(12345)) */ if (netif == NULL) { /* remote port is DHCP server? */ if (IPH_PROTO(iphdr) == IP_PROTO_UDP) { + struct udp_hdr *udphdr = (struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: UDP packet to DHCP client port %"U16_F"\n", - ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest))); - if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) { + ntohs(udphdr->dest))); + if (IP_ACCEPT_LINK_LAYER_ADDRESSED_PORT(udphdr->dest)) { LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: DHCP packet accepted.\n")); netif = inp; check_ip_src = 0; } } } -#endif /* LWIP_DHCP */ +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ /* broadcast or multicast packet source address? Compliant with RFC 1122: 3.2.1.3 */ -#if LWIP_DHCP +#if IP_ACCEPT_LINK_LAYER_ADDRESSING /* DHCP servers need 0.0.0.0 to be allowed as source address (RFC 1.1.2.2: 3.2.1.3/a) */ - if (check_ip_src && (iphdr->src.addr != 0)) -#endif /* LWIP_DHCP */ - { if ((ip_addr_isbroadcast(&(iphdr->src), inp)) || - (ip_addr_ismulticast(&(iphdr->src)))) { + if (check_ip_src && !ip_addr_isany(¤t_iphdr_src)) +#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */ + { if ((ip_addr_isbroadcast(¤t_iphdr_src, inp)) || + (ip_addr_ismulticast(¤t_iphdr_src))) { /* packet source is not valid */ LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n")); /* free (drop) packet pbufs */ @@ -347,7 +421,7 @@ ip_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE, ("ip_input: packet not for us.\n")); #if IP_FORWARD /* non-broadcast packet? */ - if (!ip_addr_isbroadcast(&(iphdr->dest), inp)) { + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp)) { /* try to forward IP packet on (other) interfaces */ ip_forward(p, iphdr, inp); } else @@ -360,17 +434,17 @@ ip_input(struct pbuf *p, struct netif *inp) return ERR_OK; } /* packet consists of multiple fragments? */ - if ((IPH_OFFSET(iphdr) & htons(IP_OFFMASK | IP_MF)) != 0) { + if ((IPH_OFFSET(iphdr) & PP_HTONS(IP_OFFMASK | IP_MF)) != 0) { #if IP_REASSEMBLY /* packet fragment reassembly code present? */ LWIP_DEBUGF(IP_DEBUG, ("IP packet is a fragment (id=0x%04"X16_F" tot_len=%"U16_F" len=%"U16_F" MF=%"U16_F" offset=%"U16_F"), calling ip_reass()\n", - ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & htons(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); + ntohs(IPH_ID(iphdr)), p->tot_len, ntohs(IPH_LEN(iphdr)), !!(IPH_OFFSET(iphdr) & PP_HTONS(IP_MF)), (ntohs(IPH_OFFSET(iphdr)) & IP_OFFMASK)*8)); /* reassemble the packet*/ p = ip_reass(p); /* packet not fully reassembled yet? */ if (p == NULL) { return ERR_OK; } - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; #else /* IP_REASSEMBLY == 0, no packet fragment reassembly code present */ pbuf_free(p); LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n", @@ -387,7 +461,7 @@ ip_input(struct pbuf *p, struct netif *inp) #if LWIP_IGMP /* there is an extra "router alert" option in IGMP messages which we allow for but do not police */ - if((iphdr_hlen > IP_HLEN && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { + if((iphdr_hlen > IP_HLEN) && (IPH_PROTO(iphdr) != IP_PROTO_IGMP)) { #else if (iphdr_hlen > IP_HLEN) { #endif /* LWIP_IGMP */ @@ -439,14 +513,14 @@ ip_input(struct pbuf *p, struct netif *inp) #endif /* LWIP_ICMP */ #if LWIP_IGMP case IP_PROTO_IGMP: - igmp_input(p,inp,&(iphdr->dest)); + igmp_input(p, inp, ¤t_iphdr_dest); break; #endif /* LWIP_IGMP */ default: #if LWIP_ICMP /* send ICMP destination protocol unreachable unless is was a broadcast */ - if (!ip_addr_isbroadcast(&(iphdr->dest), inp) && - !ip_addr_ismulticast(&(iphdr->dest))) { + if (!ip_addr_isbroadcast(¤t_iphdr_dest, inp) && + !ip_addr_ismulticast(¤t_iphdr_dest)) { p->payload = iphdr; icmp_dest_unreach(p, ICMP_DUR_PROTO); } @@ -463,6 +537,8 @@ ip_input(struct pbuf *p, struct netif *inp) current_netif = NULL; current_header = NULL; + ip_addr_set_any(¤t_iphdr_src); + ip_addr_set_any(¤t_iphdr_dest); return ERR_OK; } @@ -493,7 +569,7 @@ ip_input(struct pbuf *p, struct netif *inp) * unique identifiers independent of destination" */ err_t -ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif) { @@ -507,13 +583,20 @@ ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, * @ param ip_options pointer to the IP options, copied into the IP header * @ param optlen length of ip_options */ -err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen) { #endif /* IP_OPTIONS_SEND */ struct ip_hdr *iphdr; - static u16_t ip_id = 0; + ip_addr_t dest_addr; +#if CHECKSUM_GEN_IP_INLINE + u32_t chk_sum = 0; +#endif /* CHECKSUM_GEN_IP_INLINE */ + + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); snmp_inc_ipoutrequests(); @@ -523,6 +606,9 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest #if IP_OPTIONS_SEND u16_t optlen_aligned = 0; if (optlen != 0) { +#if CHECKSUM_GEN_IP_INLINE + int i; +#endif /* CHECKSUM_GEN_IP_INLINE */ /* round up to a multiple of 4 */ optlen_aligned = ((optlen + 3) & ~3); ip_hlen += optlen_aligned; @@ -538,6 +624,11 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest /* zero the remaining bytes */ memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen); } +#if CHECKSUM_GEN_IP_INLINE + for (i = 0; i < optlen_aligned/2; i++) { + chk_sum += ((u16_t*)p->payload)[i]; + } +#endif /* CHECKSUM_GEN_IP_INLINE */ } #endif /* IP_OPTIONS_SEND */ /* generate IP header */ @@ -549,35 +640,63 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest return ERR_BUF; } - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; LWIP_ASSERT("check that first pbuf can hold struct ip_hdr", (p->len >= sizeof(struct ip_hdr))); IPH_TTL_SET(iphdr, ttl); IPH_PROTO_SET(iphdr, proto); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += LWIP_MAKE_U16(proto, ttl); +#endif /* CHECKSUM_GEN_IP_INLINE */ - ip_addr_set(&(iphdr->dest), dest); + /* dest cannot be NULL here */ + ip_addr_copy(iphdr->dest, *dest); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->dest) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->dest) >> 16; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_VHLTOS_SET(iphdr, 4, ip_hlen / 4, tos); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_v_hl_tos; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_LEN_SET(iphdr, htons(p->tot_len)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_len; +#endif /* CHECKSUM_GEN_IP_INLINE */ IPH_OFFSET_SET(iphdr, 0); IPH_ID_SET(iphdr, htons(ip_id)); +#if CHECKSUM_GEN_IP_INLINE + chk_sum += iphdr->_id; +#endif /* CHECKSUM_GEN_IP_INLINE */ ++ip_id; if (ip_addr_isany(src)) { - ip_addr_set(&(iphdr->src), &(netif->ip_addr)); + ip_addr_copy(iphdr->src, netif->ip_addr); } else { - ip_addr_set(&(iphdr->src), src); + /* src cannot be NULL here */ + ip_addr_copy(iphdr->src, *src); } +#if CHECKSUM_GEN_IP_INLINE + chk_sum += ip4_addr_get_u32(&iphdr->src) & 0xFFFF; + chk_sum += ip4_addr_get_u32(&iphdr->src) >> 16; + chk_sum = (chk_sum >> 16) + (chk_sum & 0xFFFF); + chk_sum = (chk_sum >> 16) + chk_sum; + chk_sum = ~chk_sum; + iphdr->_chksum = chk_sum; /* network order */ +#else /* CHECKSUM_GEN_IP_INLINE */ IPH_CHKSUM_SET(iphdr, 0); #if CHECKSUM_GEN_IP IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, ip_hlen)); #endif +#endif /* CHECKSUM_GEN_IP_INLINE */ } else { /* IP header already included in p */ - iphdr = p->payload; - dest = &(iphdr->dest); + iphdr = (struct ip_hdr *)p->payload; + ip_addr_copy(dest_addr, iphdr->dest); + dest = &dest_addr; } IP_STATS_INC(ip.xmit); @@ -591,13 +710,18 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()")); return netif_loop_output(netif, p, dest); } +#if LWIP_IGMP + if ((p->flags & PBUF_FLAG_MCASTLOOP) != 0) { + netif_loop_output(netif, p, dest); + } +#endif /* LWIP_IGMP */ #endif /* ENABLE_LOOPBACK */ #if IP_FRAG /* don't fragment if interface has mtu set to 0 [loopif] */ if (netif->mtu && (p->tot_len > netif->mtu)) { - return ip_frag(p,netif,dest); + return ip_frag(p, netif, dest); } -#endif +#endif /* IP_FRAG */ LWIP_DEBUGF(IP_DEBUG, ("netif->output()")); return netif->output(netif, p, dest); @@ -621,13 +745,18 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest * see ip_output_if() for more return values */ err_t -ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto) { struct netif *netif; + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); return ERR_RTE; } @@ -655,14 +784,19 @@ ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, * see ip_output_if() for more return values */ err_t -ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint) { struct netif *netif; err_t err; + /* pbufs passed to IP must have a ref-count of 1 as their payload pointer + gets altered as the packet is passed down the stack */ + LWIP_ASSERT("p->ref == 1", p->ref == 1); + if ((netif = ip_route(dest)) == NULL) { - LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to 0x%"X32_F"\n", dest->addr)); + LWIP_DEBUGF(IP_DEBUG, ("ip_output: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dest), ip4_addr2_16(dest), ip4_addr3_16(dest), ip4_addr4_16(dest))); IP_STATS_INC(ip.rterr); return ERR_RTE; } @@ -682,7 +816,7 @@ ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, void ip_debug_print(struct pbuf *p) { - struct ip_hdr *iphdr = p->payload; + struct ip_hdr *iphdr = (struct ip_hdr *)p->payload; u8_t *payload; payload = (u8_t *)iphdr + IP_HLEN; @@ -708,16 +842,16 @@ ip_debug_print(struct pbuf *p) ntohs(IPH_CHKSUM(iphdr)))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (src)\n", - ip4_addr1(&iphdr->src), - ip4_addr2(&iphdr->src), - ip4_addr3(&iphdr->src), - ip4_addr4(&iphdr->src))); + ip4_addr1_16(&iphdr->src), + ip4_addr2_16(&iphdr->src), + ip4_addr3_16(&iphdr->src), + ip4_addr4_16(&iphdr->src))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); LWIP_DEBUGF(IP_DEBUG, ("| %3"U16_F" | %3"U16_F" | %3"U16_F" | %3"U16_F" | (dest)\n", - ip4_addr1(&iphdr->dest), - ip4_addr2(&iphdr->dest), - ip4_addr3(&iphdr->dest), - ip4_addr4(&iphdr->dest))); + ip4_addr1_16(&iphdr->dest), + ip4_addr2_16(&iphdr->dest), + ip4_addr3_16(&iphdr->dest), + ip4_addr4_16(&iphdr->dest))); LWIP_DEBUGF(IP_DEBUG, ("+-------------------------------+\n")); } #endif /* IP_DEBUG */ diff --git a/core/lwip/src/core/ipv4/ip_addr.c b/core/lwip/src/core/ipv4/ip_addr.c index 94bf4678..8f633ff2 100644 --- a/core/lwip/src/core/ipv4/ip_addr.c +++ b/core/lwip/src/core/ipv4/ip_addr.c @@ -38,15 +38,11 @@ #include "lwip/opt.h" #include "lwip/ip_addr.h" -#include "lwip/inet.h" #include "lwip/netif.h" -#define IP_ADDR_ANY_VALUE 0x00000000UL -#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL - /* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */ -const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE }; -const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE }; +const ip_addr_t ip_addr_any = { IPADDR_ANY }; +const ip_addr_t ip_addr_broadcast = { IPADDR_BROADCAST }; /** * Determine if an address is a broadcast address on a network interface @@ -55,30 +51,262 @@ const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE }; * @param netif the network interface against which the address is checked * @return returns non-zero if the address is a broadcast address */ -u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif) +u8_t +ip4_addr_isbroadcast(u32_t addr, const struct netif *netif) { - u32_t addr2test; + ip_addr_t ipaddr; + ip4_addr_set_u32(&ipaddr, addr); - addr2test = addr->addr; /* all ones (broadcast) or all zeroes (old skool broadcast) */ - if ((~addr2test == IP_ADDR_ANY_VALUE) || - (addr2test == IP_ADDR_ANY_VALUE)) + if ((~addr == IPADDR_ANY) || + (addr == IPADDR_ANY)) { return 1; /* no broadcast support on this network interface? */ - else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) + } else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) { /* the given address cannot be a broadcast address * nor can we check against any broadcast addresses */ return 0; /* address matches network interface address exactly? => no broadcast */ - else if (addr2test == netif->ip_addr.addr) + } else if (addr == ip4_addr_get_u32(&netif->ip_addr)) { return 0; /* on the same (sub) network... */ - else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask)) + } else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask)) /* ...and host identifier bits are all ones? =>... */ - && ((addr2test & ~netif->netmask.addr) == - (IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr))) + && ((addr & ~ip4_addr_get_u32(&netif->netmask)) == + (IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) { /* => network broadcast address */ return 1; - else + } else { return 0; + } +} + +/** Checks if a netmask is valid (starting with ones, then only zeros) + * + * @param netmask the IPv4 netmask to check (in network byte order!) + * @return 1 if the netmask is valid, 0 if it is not + */ +u8_t +ip4_addr_netmask_valid(u32_t netmask) +{ + u32_t mask; + u32_t nm_hostorder = lwip_htonl(netmask); + + /* first, check for the first zero */ + for (mask = 1UL << 31 ; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) == 0) { + break; + } + } + /* then check that there is no one */ + for (; mask != 0; mask >>= 1) { + if ((nm_hostorder & mask) != 0) { + /* there is a one after the first zero -> invalid */ + return 0; + } + } + /* no one after the first zero -> valid */ + return 1; +} + +/* Here for now until needed in other places in lwIP */ +#ifndef isprint +#define in_range(c, lo, up) ((u8_t)c >= lo && (u8_t)c <= up) +#define isprint(c) in_range(c, 0x20, 0x7f) +#define isdigit(c) in_range(c, '0', '9') +#define isxdigit(c) (isdigit(c) || in_range(c, 'a', 'f') || in_range(c, 'A', 'F')) +#define islower(c) in_range(c, 'a', 'z') +#define isspace(c) (c == ' ' || c == '\f' || c == '\n' || c == '\r' || c == '\t' || c == '\v') +#endif + +/** + * Ascii internet address interpretation routine. + * The value returned is in network order. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @return ip address in network order + */ +u32_t +ipaddr_addr(const char *cp) +{ + ip_addr_t val; + + if (ipaddr_aton(cp, &val)) { + return ip4_addr_get_u32(&val); + } + return (IPADDR_NONE); +} + +/** + * Check whether "cp" is a valid ascii representation + * of an Internet address and convert to a binary address. + * Returns 1 if the address is valid, 0 if not. + * This replaces inet_addr, the return value from which + * cannot distinguish between failure and a local broadcast address. + * + * @param cp IP address in ascii represenation (e.g. "127.0.0.1") + * @param addr pointer to which to save the ip address in network order + * @return 1 if cp could be converted to addr, 0 on failure + */ +int +ipaddr_aton(const char *cp, ip_addr_t *addr) +{ + u32_t val; + u8_t base; + char c; + u32_t parts[4]; + u32_t *pp = parts; + + c = *cp; + for (;;) { + /* + * Collect number up to ``.''. + * Values are specified as for C: + * 0x=hex, 0=octal, 1-9=decimal. + */ + if (!isdigit(c)) + return (0); + val = 0; + base = 10; + if (c == '0') { + c = *++cp; + if (c == 'x' || c == 'X') { + base = 16; + c = *++cp; + } else + base = 8; + } + for (;;) { + if (isdigit(c)) { + val = (val * base) + (int)(c - '0'); + c = *++cp; + } else if (base == 16 && isxdigit(c)) { + val = (val << 4) | (int)(c + 10 - (islower(c) ? 'a' : 'A')); + c = *++cp; + } else + break; + } + if (c == '.') { + /* + * Internet format: + * a.b.c.d + * a.b.c (with c treated as 16 bits) + * a.b (with b treated as 24 bits) + */ + if (pp >= parts + 3) { + return (0); + } + *pp++ = val; + c = *++cp; + } else + break; + } + /* + * Check for trailing characters. + */ + if (c != '\0' && !isspace(c)) { + return (0); + } + /* + * Concoct the address according to + * the number of parts specified. + */ + switch (pp - parts + 1) { + + case 0: + return (0); /* initial nondigit */ + + case 1: /* a -- 32 bits */ + break; + + case 2: /* a.b -- 8.24 bits */ + if (val > 0xffffffUL) { + return (0); + } + val |= parts[0] << 24; + break; + + case 3: /* a.b.c -- 8.8.16 bits */ + if (val > 0xffff) { + return (0); + } + val |= (parts[0] << 24) | (parts[1] << 16); + break; + + case 4: /* a.b.c.d -- 8.8.8.8 bits */ + if (val > 0xff) { + return (0); + } + val |= (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8); + break; + default: + LWIP_ASSERT("unhandled", 0); + break; + } + if (addr) { + ip4_addr_set_u32(addr, htonl(val)); + } + return (1); +} + +/** + * Convert numeric IP address into decimal dotted ASCII representation. + * returns ptr to static buffer; not reentrant! + * + * @param addr ip address in network order to convert + * @return pointer to a global static (!) buffer that holds the ASCII + * represenation of addr + */ +char * +ipaddr_ntoa(const ip_addr_t *addr) +{ + static char str[16]; + return ipaddr_ntoa_r(addr, str, 16); +} + +/** + * Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used. + * + * @param addr ip address in network order to convert + * @param buf target buffer where the string is stored + * @param buflen length of buf + * @return either pointer to buf which now holds the ASCII + * representation of addr or NULL if buf was too small + */ +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen) +{ + u32_t s_addr; + char inv[3]; + char *rp; + u8_t *ap; + u8_t rem; + u8_t n; + u8_t i; + int len = 0; + + s_addr = ip4_addr_get_u32(addr); + + rp = buf; + ap = (u8_t *)&s_addr; + for(n = 0; n < 4; n++) { + i = 0; + do { + rem = *ap % (u8_t)10; + *ap /= (u8_t)10; + inv[i++] = '0' + rem; + } while(*ap); + while(i--) { + if (len++ >= buflen) { + return NULL; + } + *rp++ = inv[i]; + } + if (len++ >= buflen) { + return NULL; + } + *rp++ = '.'; + ap++; + } + *--rp = 0; + return buf; } diff --git a/core/lwip/src/core/ipv4/ip_frag.c b/core/lwip/src/core/ipv4/ip_frag.c index 1939d831..8d184345 100644 --- a/core/lwip/src/core/ipv4/ip_frag.c +++ b/core/lwip/src/core/ipv4/ip_frag.c @@ -40,8 +40,7 @@ #include "lwip/opt.h" #include "lwip/ip_frag.h" -#include "lwip/ip.h" -#include "lwip/inet.h" +#include "lwip/def.h" #include "lwip/inet_chksum.h" #include "lwip/netif.h" #include "lwip/snmp.h" @@ -81,7 +80,10 @@ /** This is a helper struct which holds the starting * offset and the ending offset of this fragment to * easily chain the fragments. - * It has to be packed since it has to fit inside the IP header. + * It has the same packing requirements as the IP header, since it replaces + * the IP header in memory in incoming fragments (after copying it) to keep + * track of the various fragments. (-> If the IP header doesn't need packing, + * this struct doesn't need packing, too.) */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" @@ -155,7 +157,8 @@ ip_reass_tmr(void) static int ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *prev) { - int pbufs_freed = 0; + u16_t pbufs_freed = 0; + u8_t clen; struct pbuf *p; struct ip_reass_helper *iprh; @@ -175,7 +178,9 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p /* Then, copy the original header into it. */ SMEMCPY(p->payload, &ipr->iphdr, IP_HLEN); icmp_time_exceeded(p, ICMP_TE_FRAG); - pbufs_freed += pbuf_clen(p); + clen = pbuf_clen(p); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; pbuf_free(p); } #endif /* LWIP_ICMP */ @@ -189,8 +194,10 @@ ip_reass_free_complete_datagram(struct ip_reassdata *ipr, struct ip_reassdata *p pcur = p; /* get the next pointer before freeing */ p = iprh->next_pbuf; - pbufs_freed += pbuf_clen(pcur); - pbuf_free(pcur); + clen = pbuf_clen(pcur); + LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff); + pbufs_freed += clen; + pbuf_free(pcur); } /* Then, unchain the struct ip_reassdata from the list and free it. */ ip_reass_dequeue_datagram(ipr, prev); @@ -263,11 +270,11 @@ ip_reass_enqueue_new_datagram(struct ip_hdr *fraghdr, int clen) { struct ip_reassdata* ipr; /* No matching previous fragment found, allocate a new reassdata struct */ - ipr = memp_malloc(MEMP_REASSDATA); + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); if (ipr == NULL) { #if IP_REASS_FREE_OLDEST if (ip_reass_remove_oldest_datagram(fraghdr, clen) >= clen) { - ipr = memp_malloc(MEMP_REASSDATA); + ipr = (struct ip_reassdata *)memp_malloc(MEMP_REASSDATA); } if (ipr == NULL) #endif /* IP_REASS_FREE_OLDEST */ @@ -548,7 +555,7 @@ ip_reass(struct pbuf *p) * to an existing one */ /* check for 'no more fragments', and update queue entry*/ - if ((ntohs(IPH_OFFSET(fraghdr)) & IP_MF) == 0) { + if ((IPH_OFFSET(fraghdr) & PP_NTOHS(IP_MF)) == 0) { ipr->flags |= IP_REASS_FLAG_LASTFRAG; ipr->datagram_len = offset + len; LWIP_DEBUGF(IP_REASS_DEBUG, @@ -609,6 +616,38 @@ nullreturn: #if IP_FRAG #if IP_FRAG_USES_STATIC_BUF static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; +#else /* IP_FRAG_USES_STATIC_BUF */ + +#if !LWIP_NETIF_TX_SINGLE_PBUF +/** Allocate a new struct pbuf_custom_ref */ +static struct pbuf_custom_ref* +ip_frag_alloc_pbuf_custom_ref(void) +{ + return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF); +} + +/** Free a struct pbuf_custom_ref */ +static void +ip_frag_free_pbuf_custom_ref(struct pbuf_custom_ref* p) +{ + LWIP_ASSERT("p != NULL", p != NULL); + memp_free(MEMP_FRAG_PBUF, p); +} + +/** Free-callback function to free a 'struct pbuf_custom_ref', called by + * pbuf_free. */ +static void +ipfrag_free_pbuf_custom(struct pbuf *p) +{ + struct pbuf_custom_ref *pcr = (struct pbuf_custom_ref*)p; + LWIP_ASSERT("pcr != NULL", pcr != NULL); + LWIP_ASSERT("pcr == p", (void*)pcr == (void*)p); + if (pcr->original != NULL) { + pbuf_free(pcr->original); + } + ip_frag_free_pbuf_custom_ref(pcr); +} +#endif /* !LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /** @@ -625,13 +664,15 @@ static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU + MEM_ALIGNMENT - 1)]; * @return ERR_OK if sent successfully, err_t otherwise */ err_t -ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) +ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest) { struct pbuf *rambuf; #if IP_FRAG_USES_STATIC_BUF struct pbuf *header; #else +#if !LWIP_NETIF_TX_SINGLE_PBUF struct pbuf *newpbuf; +#endif struct ip_hdr *original_iphdr; #endif struct ip_hdr *iphdr; @@ -642,7 +683,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) u16_t last; u16_t poff = IP_HLEN; u16_t tmp; -#if !IP_FRAG_USES_STATIC_BUF +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF u16_t newpbuflen = 0; u16_t left_to_copy; #endif @@ -662,10 +703,10 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) rambuf->payload = LWIP_MEM_ALIGN((void *)buf); /* Copy the IP header in it */ - iphdr = rambuf->payload; + iphdr = (struct ip_hdr *)rambuf->payload; SMEMCPY(iphdr, p->payload, IP_HLEN); #else /* IP_FRAG_USES_STATIC_BUF */ - original_iphdr = p->payload; + original_iphdr = (struct ip_hdr *)p->payload; iphdr = original_iphdr; #endif /* IP_FRAG_USES_STATIC_BUF */ @@ -683,8 +724,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) /* Set new offset and MF flag */ tmp = omf | (IP_OFFMASK & (ofo)); - if (!last) + if (!last) { tmp = tmp | IP_MF; + } /* Fill this fragment */ cop = last ? left : nfb * 8; @@ -692,6 +734,23 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) #if IP_FRAG_USES_STATIC_BUF poff += pbuf_copy_partial(p, (u8_t*)iphdr + IP_HLEN, cop, poff); #else /* IP_FRAG_USES_STATIC_BUF */ +#if LWIP_NETIF_TX_SINGLE_PBUF + rambuf = pbuf_alloc(PBUF_IP, cop, PBUF_RAM); + if (rambuf == NULL) { + return ERR_MEM; + } + LWIP_ASSERT("this needs a pbuf in one piece!", + (rambuf->len == rambuf->tot_len) && (rambuf->next == NULL)); + poff += pbuf_copy_partial(p, rambuf->payload, cop, poff); + /* make room for the IP header */ + if(pbuf_header(rambuf, IP_HLEN)) { + pbuf_free(rambuf); + return ERR_MEM; + } + /* fill in the IP header */ + SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); + iphdr = rambuf->payload; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ /* When not using a static buffer, create a chain of pbufs. * The first will be a PBUF_RAM holding the link and IP header. * The rest will be PBUF_REFs mirroring the pbuf chain to be fragged, @@ -704,7 +763,7 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) LWIP_ASSERT("this needs a pbuf in one piece!", (p->len >= (IP_HLEN))); SMEMCPY(rambuf->payload, original_iphdr, IP_HLEN); - iphdr = rambuf->payload; + iphdr = (struct ip_hdr *)rambuf->payload; /* Can just adjust p directly for needed offset. */ p->payload = (u8_t *)p->payload + poff; @@ -712,29 +771,40 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) left_to_copy = cop; while (left_to_copy) { + struct pbuf_custom_ref *pcr; newpbuflen = (left_to_copy < p->len) ? left_to_copy : p->len; /* Is this pbuf already empty? */ if (!newpbuflen) { p = p->next; continue; } - newpbuf = pbuf_alloc(PBUF_RAW, 0, PBUF_REF); - if (newpbuf == NULL) { + pcr = ip_frag_alloc_pbuf_custom_ref(); + if (pcr == NULL) { pbuf_free(rambuf); return ERR_MEM; } /* Mirror this pbuf, although we might not need all of it. */ - newpbuf->payload = p->payload; - newpbuf->len = newpbuf->tot_len = newpbuflen; + newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen); + if (newpbuf == NULL) { + ip_frag_free_pbuf_custom_ref(pcr); + pbuf_free(rambuf); + return ERR_MEM; + } + pbuf_ref(p); + pcr->original = p; + pcr->pc.custom_free_function = ipfrag_free_pbuf_custom; + /* Add it to end of rambuf's chain, but using pbuf_cat, not pbuf_chain * so that it is removed when pbuf_dechain is later called on rambuf. */ pbuf_cat(rambuf, newpbuf); left_to_copy -= newpbuflen; - if (left_to_copy) + if (left_to_copy) { p = p->next; + } } poff = newpbuflen; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ #endif /* IP_FRAG_USES_STATIC_BUF */ /* Correct header */ @@ -744,8 +814,9 @@ ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest) IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, IP_HLEN)); #if IP_FRAG_USES_STATIC_BUF - if (last) + if (last) { pbuf_realloc(rambuf, left + IP_HLEN); + } /* This part is ugly: we alloc a RAM based pbuf for * the link level header for each chunk and then diff --git a/core/lwip/src/core/mem.c b/core/lwip/src/core/mem.c index 83c97536..2934e5a9 100644 --- a/core/lwip/src/core/mem.c +++ b/core/lwip/src/core/mem.c @@ -61,6 +61,7 @@ #include "lwip/mem.h" #include "lwip/sys.h" #include "lwip/stats.h" +#include "lwip/err.h" #include <string.h> @@ -81,7 +82,7 @@ mem_malloc(mem_size_t size) memp_t poolnr; mem_size_t required_size = size + sizeof(struct memp_malloc_helper); - for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr++) { + for (poolnr = MEMP_POOL_FIRST; poolnr <= MEMP_POOL_LAST; poolnr = (memp_t)(poolnr + 1)) { #if MEM_USE_POOLS_TRY_BIGGER_POOL again: #endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */ @@ -154,7 +155,7 @@ mem_free(void *rmem) struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; - /** index (-> ram[next]) of the next struct */ + /** index (-> ram[prev]) of the previous struct */ mem_size_t prev; /** 1: this area is used; 0: this area is unused */ u8_t used; @@ -171,8 +172,16 @@ struct mem { #define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) #define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) +/** If you want to relocate the heap to external memory, simply define + * LWIP_RAM_HEAP_POINTER as a void-pointer to that location. + * If so, make sure the memory at that location is big enough (see below on + * how that space is calculated). */ +#ifndef LWIP_RAM_HEAP_POINTER /** the heap. we need one struct mem at the end and some room for alignment */ -static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; +u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; +#define LWIP_RAM_HEAP_POINTER ram_heap +#endif /* LWIP_RAM_HEAP_POINTER */ + /** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */ static u8_t *ram; /** the last entry, always unused! */ @@ -181,7 +190,7 @@ static struct mem *ram_end; static struct mem *lfree; /** concurrent access protection */ -static sys_sem_t mem_sem; +static sys_mutex_t mem_mutex; #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT @@ -199,8 +208,8 @@ static volatile u8_t mem_free_count; /* Protect the heap only by using a semaphore */ #define LWIP_MEM_FREE_DECL_PROTECT() -#define LWIP_MEM_FREE_PROTECT() sys_arch_sem_wait(mem_sem, 0) -#define LWIP_MEM_FREE_UNPROTECT() sys_sem_signal(mem_sem) +#define LWIP_MEM_FREE_PROTECT() sys_mutex_lock(&mem_mutex) +#define LWIP_MEM_FREE_UNPROTECT() sys_mutex_unlock(&mem_mutex) /* mem_malloc is protected using semaphore AND LWIP_MEM_ALLOC_PROTECT */ #define LWIP_MEM_ALLOC_DECL_PROTECT() #define LWIP_MEM_ALLOC_PROTECT() @@ -215,7 +224,7 @@ static volatile u8_t mem_free_count; * one empty struct mem pointing to another empty struct mem. * * @param mem this points to a struct mem which just has been freed - * @internal this function is only called by mem_free() and mem_realloc() + * @internal this function is only called by mem_free() and mem_trim() * * This assumes access to the heap is protected by the calling function * already. @@ -233,25 +242,25 @@ plug_holes(struct mem *mem) /* plug hole forward */ LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE_ALIGNED", mem->next <= MEM_SIZE_ALIGNED); - nmem = (struct mem *)&ram[mem->next]; + nmem = (struct mem *)(void *)&ram[mem->next]; if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) { /* if mem->next is unused and not end of ram, combine mem and mem->next */ if (lfree == nmem) { lfree = mem; } mem->next = nmem->next; - ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram; + ((struct mem *)(void *)&ram[nmem->next])->prev = (mem_size_t)((u8_t *)mem - ram); } /* plug hole backward */ - pmem = (struct mem *)&ram[mem->prev]; + pmem = (struct mem *)(void *)&ram[mem->prev]; if (pmem != mem && pmem->used == 0) { /* if mem->prev is unused, combine mem and mem->prev */ if (lfree == mem) { lfree = pmem; } pmem->next = mem->next; - ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram; + ((struct mem *)(void *)&ram[mem->next])->prev = (mem_size_t)((u8_t *)pmem - ram); } } @@ -267,24 +276,26 @@ lwip_mem_init(void) (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap */ - ram = LWIP_MEM_ALIGN(ram_heap); + ram = (u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER); /* initialize the start of the heap */ - mem = (struct mem *)ram; + mem = (struct mem *)(void *)ram; mem->next = MEM_SIZE_ALIGNED; mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ - ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; + ram_end = (struct mem *)(void *)&ram[MEM_SIZE_ALIGNED]; ram_end->used = 1; ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; - mem_sem = sys_sem_new(1); - /* initialize the lowest-free pointer to the start of the heap */ - lfree = (struct mem *)ram; + lfree = (struct mem *)(void *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); + + if(sys_mutex_new(&mem_mutex) != ERR_OK) { + LWIP_ASSERT("failed to create mem_mutex", 0); + } } /** @@ -320,7 +331,7 @@ mem_free(void *rmem) /* protect the heap from concurrent access */ LWIP_MEM_FREE_PROTECT(); /* Get the corresponding struct mem ... */ - mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... which has to be in a used state ... */ LWIP_ASSERT("mem_free: mem->used", mem->used); /* ... and is now unused. */ @@ -331,7 +342,7 @@ mem_free(void *rmem) lfree = mem; } - MEM_STATS_DEC_USED(used, mem->next - ((u8_t *)mem - ram)); + MEM_STATS_DEC_USED(used, mem->next - (mem_size_t)(((u8_t *)mem - ram))); /* finally, see if prev or next are free also */ plug_holes(mem); @@ -342,9 +353,7 @@ mem_free(void *rmem) } /** - * In contrast to its name, mem_realloc can only shrink memory, not expand it. - * Since the only use (for now) is in pbuf_realloc (which also can only shrink), - * this shouldn't be a problem! + * Shrink memory returned by mem_malloc(). * * @param rmem pointer to memory allocated by mem_malloc the is to be shrinked * @param newsize required size after shrinking (needs to be smaller than or @@ -354,7 +363,7 @@ mem_free(void *rmem) * or freed! */ void * -mem_realloc(void *rmem, mem_size_t newsize) +mem_trim(void *rmem, mem_size_t newsize) { mem_size_t size; mem_size_t ptr, ptr2; @@ -375,12 +384,12 @@ mem_realloc(void *rmem, mem_size_t newsize) return NULL; } - LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram && + LWIP_ASSERT("mem_trim: legal memory", (u8_t *)rmem >= (u8_t *)ram && (u8_t *)rmem < (u8_t *)ram_end); if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) { SYS_ARCH_DECL_PROTECT(lev); - LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_realloc: illegal memory\n")); + LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_trim: illegal memory\n")); /* protect mem stats from concurrent access */ SYS_ARCH_PROTECT(lev); MEM_STATS_INC(illegal); @@ -388,12 +397,12 @@ mem_realloc(void *rmem, mem_size_t newsize) return rmem; } /* Get the corresponding struct mem ... */ - mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); + mem = (struct mem *)(void *)((u8_t *)rmem - SIZEOF_STRUCT_MEM); /* ... and its offset pointer */ - ptr = (u8_t *)mem - ram; + ptr = (mem_size_t)((u8_t *)mem - ram); size = mem->next - ptr - SIZEOF_STRUCT_MEM; - LWIP_ASSERT("mem_realloc can only shrink memory", newsize <= size); + LWIP_ASSERT("mem_trim can only shrink memory", newsize <= size); if (newsize > size) { /* not supported */ return NULL; @@ -406,9 +415,7 @@ mem_realloc(void *rmem, mem_size_t newsize) /* protect the heap from concurrent access */ LWIP_MEM_FREE_PROTECT(); - MEM_STATS_DEC_USED(used, (size - newsize)); - - mem2 = (struct mem *)&ram[mem->next]; + mem2 = (struct mem *)(void *)&ram[mem->next]; if(mem2->used == 0) { /* The next struct is unused, we can simply move it at little */ mem_size_t next; @@ -417,9 +424,9 @@ mem_realloc(void *rmem, mem_size_t newsize) /* create new struct mem which is moved directly after the shrinked mem */ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; if (lfree == mem2) { - lfree = (struct mem *)&ram[ptr2]; + lfree = (struct mem *)(void *)&ram[ptr2]; } - mem2 = (struct mem *)&ram[ptr2]; + mem2 = (struct mem *)(void *)&ram[ptr2]; mem2->used = 0; /* restore the next pointer */ mem2->next = next; @@ -431,8 +438,9 @@ mem_realloc(void *rmem, mem_size_t newsize) * let 'mem2->next->prev' point to mem2 again. but only if mem2->next is not * the end of the heap */ if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)&ram[mem2->next])->prev = ptr2; + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } + MEM_STATS_DEC_USED(used, (size - newsize)); /* no need to plug holes, we've already done that */ } else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) { /* Next struct is used but there's room for another struct mem with @@ -443,7 +451,7 @@ mem_realloc(void *rmem, mem_size_t newsize) * region that couldn't hold data, but when mem->next gets freed, * the 2 regions would be combined, resulting in more free memory */ ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize; - mem2 = (struct mem *)&ram[ptr2]; + mem2 = (struct mem *)(void *)&ram[ptr2]; if (mem2 < lfree) { lfree = mem2; } @@ -452,8 +460,9 @@ mem_realloc(void *rmem, mem_size_t newsize) mem2->prev = ptr; mem->next = ptr2; if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)&ram[mem2->next])->prev = ptr2; + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } + MEM_STATS_DEC_USED(used, (size - newsize)); /* the original mem->next is used, so no need to plug holes! */ } /* else { @@ -506,7 +515,7 @@ mem_malloc(mem_size_t size) } /* protect the heap from concurrent access */ - sys_arch_sem_wait(mem_sem, 0); + sys_mutex_lock(&mem_mutex); LWIP_MEM_ALLOC_PROTECT(); #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT /* run as long as a mem_free disturbed mem_malloc */ @@ -517,9 +526,9 @@ mem_malloc(mem_size_t size) /* Scan through the heap searching for a free block that is big enough, * beginning with the lowest free block. */ - for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; - ptr = ((struct mem *)&ram[ptr])->next) { - mem = (struct mem *)&ram[ptr]; + for (ptr = (mem_size_t)((u8_t *)lfree - ram); ptr < MEM_SIZE_ALIGNED - size; + ptr = ((struct mem *)(void *)&ram[ptr])->next) { + mem = (struct mem *)(void *)&ram[ptr]; #if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT mem_free_count = 0; LWIP_MEM_ALLOC_UNPROTECT(); @@ -549,7 +558,7 @@ mem_malloc(mem_size_t size) */ ptr2 = ptr + SIZEOF_STRUCT_MEM + size; /* create mem2 struct */ - mem2 = (struct mem *)&ram[ptr2]; + mem2 = (struct mem *)(void *)&ram[ptr2]; mem2->used = 0; mem2->next = mem->next; mem2->prev = ptr; @@ -558,7 +567,7 @@ mem_malloc(mem_size_t size) mem->used = 1; if (mem2->next != MEM_SIZE_ALIGNED) { - ((struct mem *)&ram[mem2->next])->prev = ptr2; + ((struct mem *)(void *)&ram[mem2->next])->prev = ptr2; } MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM)); } else { @@ -570,7 +579,7 @@ mem_malloc(mem_size_t size) * will always be used at this point! */ mem->used = 1; - MEM_STATS_INC_USED(used, mem->next - ((u8_t *)mem - ram)); + MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram)); } if (mem == lfree) { @@ -579,12 +588,12 @@ mem_malloc(mem_size_t size) LWIP_MEM_ALLOC_UNPROTECT(); /* prevent high interrupt latency... */ LWIP_MEM_ALLOC_PROTECT(); - lfree = (struct mem *)&ram[lfree->next]; + lfree = (struct mem *)(void *)&ram[lfree->next]; } LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used))); } LWIP_MEM_ALLOC_UNPROTECT(); - sys_sem_signal(mem_sem); + sys_mutex_unlock(&mem_mutex); LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.", (mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end); LWIP_ASSERT("mem_malloc: allocated memory properly aligned.", @@ -602,7 +611,7 @@ mem_malloc(mem_size_t size) LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size)); MEM_STATS_INC(err); LWIP_MEM_ALLOC_UNPROTECT(); - sys_sem_signal(mem_sem); + sys_mutex_unlock(&mem_mutex); return NULL; } diff --git a/core/lwip/src/core/memp.c b/core/lwip/src/core/memp.c index dea18154..4da879a5 100644 --- a/core/lwip/src/core/memp.c +++ b/core/lwip/src/core/memp.c @@ -44,15 +44,20 @@ #include "lwip/pbuf.h" #include "lwip/udp.h" #include "lwip/raw.h" -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/igmp.h" #include "lwip/api.h" #include "lwip/api_msg.h" #include "lwip/tcpip.h" #include "lwip/sys.h" +#include "lwip/timers.h" #include "lwip/stats.h" #include "netif/etharp.h" #include "lwip/ip_frag.h" +#include "lwip/snmp_structs.h" +#include "lwip/snmp_msg.h" +#include "lwip/dns.h" +#include "netif/ppp_oe.h" #include <string.h> @@ -142,12 +147,33 @@ static const char *memp_desc[MEMP_MAX] = { }; #endif /* LWIP_DEBUG */ -/** This is the actual memory used by the pools. */ +#if MEMP_SEPARATE_POOLS + +/** This creates each memory pool. These are named memp_memory_XXX_base (where + * XXX is the name of the pool defined in memp_std.h). + * To relocate a pool, declare it as extern in cc.h. Example for GCC: + * extern u8_t __attribute__((section(".onchip_mem"))) memp_memory_UDP_PCB_base[]; + */ +#define LWIP_MEMPOOL(name,num,size,desc) u8_t memp_memory_ ## name ## _base \ + [((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; +#include "lwip/memp_std.h" + +/** This array holds the base of each memory pool. */ +static u8_t *const memp_bases[] = { +#define LWIP_MEMPOOL(name,num,size,desc) memp_memory_ ## name ## _base, +#include "lwip/memp_std.h" +}; + +#else /* MEMP_SEPARATE_POOLS */ + +/** This is the actual memory used by the pools (all pools in one big block). */ static u8_t memp_memory[MEM_ALIGNMENT - 1 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) #include "lwip/memp_std.h" ]; +#endif /* MEMP_SEPARATE_POOLS */ + #if MEMP_SANITY_CHECK /** * Check that memp-lists don't form a circle @@ -172,31 +198,74 @@ memp_sanity(void) } #endif /* MEMP_SANITY_CHECK*/ #if MEMP_OVERFLOW_CHECK +#if defined(LWIP_DEBUG) && MEMP_STATS +static const char * memp_overflow_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc) "/"desc, +#include "lwip/memp_std.h" + }; +#endif + /** * Check if a memp element was victim of an overflow * (e.g. the restricted area after it has been altered) * * @param p the memp element to check - * @param memp_size the element size of the pool p comes from + * @param memp_type the pool p comes from */ static void -memp_overflow_check_element(struct memp *p, u16_t memp_size) +memp_overflow_check_element_overflow(struct memp *p, u16_t memp_type) { u16_t k; u8_t *m; -#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; - for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { +#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE + memp_sizes[memp_type]; + for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { if (m[k] != 0xcd) { - LWIP_ASSERT("detected memp underflow!", 0); + char errstr[128] = "detected memp overflow in pool "; + char digit[] = "0"; + if(memp_type >= 10) { + digit[0] = '0' + (memp_type/10); + strcat(errstr, digit); + } + digit[0] = '0' + (memp_type%10); + strcat(errstr, digit); +#if defined(LWIP_DEBUG) && MEMP_STATS + strcat(errstr, memp_overflow_names[memp_type]); +#endif + LWIP_ASSERT(errstr, 0); } } #endif -#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0 - m = (u8_t*)p + MEMP_SIZE + memp_size; - for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) { +} + +/** + * Check if a memp element was victim of an underflow + * (e.g. the restricted area before it has been altered) + * + * @param p the memp element to check + * @param memp_type the pool p comes from + */ +static void +memp_overflow_check_element_underflow(struct memp *p, u16_t memp_type) +{ + u16_t k; + u8_t *m; +#if MEMP_SANITY_REGION_BEFORE_ALIGNED > 0 + m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED; + for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) { if (m[k] != 0xcd) { - LWIP_ASSERT("detected memp overflow!", 0); + char errstr[128] = "detected memp underflow in pool "; + char digit[] = "0"; + if(memp_type >= 10) { + digit[0] = '0' + (memp_type/10); + strcat(errstr, digit); + } + digit[0] = '0' + (memp_type%10); + strcat(errstr, digit); +#if defined(LWIP_DEBUG) && MEMP_STATS + strcat(errstr, memp_overflow_names[memp_type]); +#endif + LWIP_ASSERT(errstr, 0); } } #endif @@ -213,11 +282,19 @@ memp_overflow_check_all(void) u16_t i, j; struct memp *p; - p = LWIP_MEM_ALIGN(memp_memory); + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); + for (i = 0; i < MEMP_MAX; ++i) { + p = p; + for (j = 0; j < memp_num[i]; ++j) { + memp_overflow_check_element_overflow(p, i); + p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); + } + } + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { - memp_overflow_check_element(p, memp_sizes[i]); + memp_overflow_check_element_underflow(p, i); p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED); } } @@ -233,7 +310,7 @@ memp_overflow_init(void) struct memp *p; u8_t *m; - p = LWIP_MEM_ALIGN(memp_memory); + p = (struct memp *)LWIP_MEM_ALIGN(memp_memory); for (i = 0; i < MEMP_MAX; ++i) { p = p; for (j = 0; j < memp_num[i]; ++j) { @@ -269,15 +346,20 @@ memp_init(void) MEMP_STATS_AVAIL(avail, i, memp_num[i]); } - memp = LWIP_MEM_ALIGN(memp_memory); +#if !MEMP_SEPARATE_POOLS + memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory); +#endif /* !MEMP_SEPARATE_POOLS */ /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; +#if MEMP_SEPARATE_POOLS + memp = (struct memp*)memp_bases[i]; +#endif /* MEMP_SEPARATE_POOLS */ /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; memp_tab[i] = memp; - memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] + memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif @@ -331,7 +413,7 @@ memp_malloc_fn(memp_t type, const char* file, const int line) MEMP_STATS_INC_USED(used, type); LWIP_ASSERT("memp_malloc: memp properly aligned", ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0); - memp = (struct memp*)((u8_t*)memp + MEMP_SIZE); + memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE); } else { LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type])); MEMP_STATS_INC(err, type); @@ -360,14 +442,15 @@ memp_free(memp_t type, void *mem) LWIP_ASSERT("memp_free: mem properly aligned", ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0); - memp = (struct memp *)((u8_t*)mem - MEMP_SIZE); + memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE); SYS_ARCH_PROTECT(old_level); #if MEMP_OVERFLOW_CHECK #if MEMP_OVERFLOW_CHECK >= 2 memp_overflow_check_all(); #else - memp_overflow_check_element(memp, memp_sizes[type]); + memp_overflow_check_element_overflow(memp, type); + memp_overflow_check_element_underflow(memp, type); #endif /* MEMP_OVERFLOW_CHECK >= 2 */ #endif /* MEMP_OVERFLOW_CHECK */ diff --git a/core/lwip/src/core/netif.c b/core/lwip/src/core/netif.c index b52cd02a..f190b1f2 100644 --- a/core/lwip/src/core/netif.c +++ b/core/lwip/src/core/netif.c @@ -41,10 +41,11 @@ #include "lwip/def.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/snmp.h" #include "lwip/igmp.h" #include "netif/etharp.h" +#include "lwip/stats.h" #if ENABLE_LOOPBACK #include "lwip/sys.h" #if LWIP_NETIF_LOOPBACK_MULTITHREADING @@ -60,20 +61,64 @@ #endif /* LWIP_DHCP */ #if LWIP_NETIF_STATUS_CALLBACK -#define NETIF_STATUS_CALLBACK(n) { if (n->status_callback) (n->status_callback)(n); } +#define NETIF_STATUS_CALLBACK(n) do{ if (n->status_callback) { (n->status_callback)(n); }}while(0) #else -#define NETIF_STATUS_CALLBACK(n) { /* NOP */ } +#define NETIF_STATUS_CALLBACK(n) #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK -#define NETIF_LINK_CALLBACK(n) { if (n->link_callback) (n->link_callback)(n); } +#define NETIF_LINK_CALLBACK(n) do{ if (n->link_callback) { (n->link_callback)(n); }}while(0) #else -#define NETIF_LINK_CALLBACK(n) { /* NOP */ } +#define NETIF_LINK_CALLBACK(n) #endif /* LWIP_NETIF_LINK_CALLBACK */ struct netif *netif_list; struct netif *netif_default; +#if LWIP_HAVE_LOOPIF +static struct netif loop_netif; + +/** + * Initialize a lwip network interface structure for a loopback interface + * + * @param netif the lwip network interface structure for this loopif + * @return ERR_OK if the loopif is initialized + * ERR_MEM if private data couldn't be allocated + */ +static err_t +netif_loopif_init(struct netif *netif) +{ + /* initialize the snmp variables and counters inside the struct netif + * ifSpeed: no assumption can be made! + */ + NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); + + netif->name[0] = 'l'; + netif->name[1] = 'o'; + netif->output = netif_loop_output; + return ERR_OK; +} +#endif /* LWIP_HAVE_LOOPIF */ + +void +netif_init(void) +{ +#if LWIP_HAVE_LOOPIF + ip_addr_t loop_ipaddr, loop_netmask, loop_gw; + IP4_ADDR(&loop_gw, 127,0,0,1); + IP4_ADDR(&loop_ipaddr, 127,0,0,1); + IP4_ADDR(&loop_netmask, 255,0,0,0); + +#if NO_SYS + netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, ip_input); +#else /* NO_SYS */ + netif_add(&loop_netif, &loop_ipaddr, &loop_netmask, &loop_gw, NULL, netif_loopif_init, tcpip_input); +#endif /* NO_SYS */ + netif_set_up(&loop_netif); + +#endif /* LWIP_HAVE_LOOPIF */ +} + /** * Add a network interface to the list of lwIP netifs. * @@ -89,18 +134,17 @@ struct netif *netif_default; * @return netif, or NULL if failed. */ struct netif * -netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, - struct ip_addr *gw, - void *state, - err_t (* init)(struct netif *netif), - err_t (* input)(struct pbuf *p, struct netif *netif)) +netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input) { static u8_t netifnum = 0; + LWIP_ASSERT("No init function given", init != NULL); + /* reset new interface configuration state */ - netif->ip_addr.addr = 0; - netif->netmask.addr = 0; - netif->gw.addr = 0; + ip_addr_set_zero(&netif->ip_addr); + ip_addr_set_zero(&netif->netmask); + ip_addr_set_zero(&netif->gw); netif->flags = 0; #if LWIP_DHCP /* netif not under DHCP control by default */ @@ -150,7 +194,7 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, #if LWIP_IGMP /* start IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { - igmp_start( netif); + igmp_start(netif); } #endif /* LWIP_IGMP */ @@ -175,8 +219,8 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, * @param gw the new default gateway */ void -netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, - struct ip_addr *gw) +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw) { netif_set_ipaddr(netif, ipaddr); netif_set_netmask(netif, netmask); @@ -188,41 +232,47 @@ netif_set_addr(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netm * * @param netif the network interface to remove */ -void netif_remove(struct netif * netif) +void +netif_remove(struct netif *netif) { - if ( netif == NULL ) return; + if (netif == NULL) { + return; + } #if LWIP_IGMP /* stop IGMP processing */ if (netif->flags & NETIF_FLAG_IGMP) { - igmp_stop( netif); + igmp_stop(netif); } #endif /* LWIP_IGMP */ + if (netif_is_up(netif)) { + /* set netif down before removing (call callback function) */ + netif_set_down(netif); + } snmp_delete_ipaddridx_tree(netif); /* is it the first netif? */ if (netif_list == netif) { netif_list = netif->next; - snmp_dec_iflist(); - } - else { + } else { /* look for netif further down the list */ struct netif * tmpNetif; for (tmpNetif = netif_list; tmpNetif != NULL; tmpNetif = tmpNetif->next) { if (tmpNetif->next == netif) { tmpNetif->next = netif->next; - snmp_dec_iflist(); break; } } if (tmpNetif == NULL) return; /* we didn't find any netif today */ } + snmp_dec_iflist(); /* this netif is default? */ - if (netif_default == netif) + if (netif_default == netif) { /* reset default netif */ netif_set_default(NULL); + } LWIP_DEBUGF( NETIF_DEBUG, ("netif_remove: removed netif\n") ); } @@ -266,7 +316,7 @@ netif_find(char *name) * default gateway */ void -netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) +netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr) { /* TODO: Handling of obsolete pcbs */ /* See: http://mail.gnu.org/archive/html/lwip-users/2003-03/msg00118.html */ @@ -275,14 +325,18 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) struct tcp_pcb_listen *lpcb; /* address is actually being changed? */ - if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) - { + if ((ip_addr_cmp(ipaddr, &(netif->ip_addr))) == 0) { /* extern struct tcp_pcb *tcp_active_pcbs; defined by tcp.h */ LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: netif address being changed\n")); pcb = tcp_active_pcbs; while (pcb != NULL) { /* PCB bound to current local interface address? */ - if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) { + if (ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr)) +#if LWIP_AUTOIP + /* connections to link-local addresses must persist (RFC3927 ch. 1.9) */ + && !ip_addr_islinklocal(&(pcb->local_ip)) +#endif /* LWIP_AUTOIP */ + ) { /* this connection must be aborted */ struct tcp_pcb *next = pcb->next; LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb)); @@ -312,10 +366,10 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], - ip4_addr1(&netif->ip_addr), - ip4_addr2(&netif->ip_addr), - ip4_addr3(&netif->ip_addr), - ip4_addr4(&netif->ip_addr))); + ip4_addr1_16(&netif->ip_addr), + ip4_addr2_16(&netif->ip_addr), + ip4_addr3_16(&netif->ip_addr), + ip4_addr4_16(&netif->ip_addr))); } /** @@ -327,15 +381,15 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr) * @note call netif_set_addr() if you also want to change ip address and netmask */ void -netif_set_gw(struct netif *netif, struct ip_addr *gw) +netif_set_gw(struct netif *netif, ip_addr_t *gw) { ip_addr_set(&(netif->gw), gw); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], - ip4_addr1(&netif->gw), - ip4_addr2(&netif->gw), - ip4_addr3(&netif->gw), - ip4_addr4(&netif->gw))); + ip4_addr1_16(&netif->gw), + ip4_addr2_16(&netif->gw), + ip4_addr3_16(&netif->gw), + ip4_addr4_16(&netif->gw))); } /** @@ -348,7 +402,7 @@ netif_set_gw(struct netif *netif, struct ip_addr *gw) * default gateway */ void -netif_set_netmask(struct netif *netif, struct ip_addr *netmask) +netif_set_netmask(struct netif *netif, ip_addr_t *netmask) { snmp_delete_iprteidx_tree(0, netif); /* set new netmask to netif */ @@ -356,10 +410,10 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask) snmp_insert_iprteidx_tree(0, netif); LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", netif->name[0], netif->name[1], - ip4_addr1(&netif->netmask), - ip4_addr2(&netif->netmask), - ip4_addr3(&netif->netmask), - ip4_addr4(&netif->netmask))); + ip4_addr1_16(&netif->netmask), + ip4_addr2_16(&netif->netmask), + ip4_addr3_16(&netif->netmask), + ip4_addr4_16(&netif->netmask))); } /** @@ -371,13 +425,10 @@ netif_set_netmask(struct netif *netif, struct ip_addr *netmask) void netif_set_default(struct netif *netif) { - if (netif == NULL) - { + if (netif == NULL) { /* remove default route */ snmp_delete_iprteidx_tree(1, netif); - } - else - { + } else { /* install default route */ snmp_insert_iprteidx_tree(1, netif); } @@ -397,29 +448,30 @@ netif_set_default(struct netif *netif) */ void netif_set_up(struct netif *netif) { - if ( !(netif->flags & NETIF_FLAG_UP )) { + if (!(netif->flags & NETIF_FLAG_UP)) { netif->flags |= NETIF_FLAG_UP; #if LWIP_SNMP snmp_get_sysuptime(&netif->ts); #endif /* LWIP_SNMP */ - NETIF_LINK_CALLBACK(netif); NETIF_STATUS_CALLBACK(netif); + if (netif->flags & NETIF_FLAG_LINK_UP) { #if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_gratuitous(netif); - } + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & (NETIF_FLAG_ETHARP)) { + etharp_gratuitous(netif); + } #endif /* LWIP_ARP */ #if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups( netif); + } #endif /* LWIP_IGMP */ + } } } @@ -433,73 +485,65 @@ void netif_set_up(struct netif *netif) */ void netif_set_down(struct netif *netif) { - if ( netif->flags & NETIF_FLAG_UP ) - { - netif->flags &= ~NETIF_FLAG_UP; + if (netif->flags & NETIF_FLAG_UP) { + netif->flags &= ~NETIF_FLAG_UP; #if LWIP_SNMP - snmp_get_sysuptime(&netif->ts); + snmp_get_sysuptime(&netif->ts); #endif - - NETIF_LINK_CALLBACK(netif); - NETIF_STATUS_CALLBACK(netif); - } -} -/** - * Ask if an interface is up - */ -u8_t netif_is_up(struct netif *netif) -{ - return (netif->flags & NETIF_FLAG_UP)?1:0; + NETIF_STATUS_CALLBACK(netif); + } } #if LWIP_NETIF_STATUS_CALLBACK /** * Set callback to be called when interface is brought up/down */ -void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif )) +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback) { - if ( netif ) - netif->status_callback = status_callback; + if (netif) { + netif->status_callback = status_callback; + } } #endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_LINK_CALLBACK /** * Called by a driver when its link goes up */ void netif_set_link_up(struct netif *netif ) { - netif->flags |= NETIF_FLAG_LINK_UP; + if (!(netif->flags & NETIF_FLAG_LINK_UP)) { + netif->flags |= NETIF_FLAG_LINK_UP; #if LWIP_DHCP - if (netif->dhcp) { - dhcp_network_changed(netif); - } + if (netif->dhcp) { + dhcp_network_changed(netif); + } #endif /* LWIP_DHCP */ #if LWIP_AUTOIP - if (netif->autoip) { - autoip_network_changed(netif); - } + if (netif->autoip) { + autoip_network_changed(netif); + } #endif /* LWIP_AUTOIP */ - if (netif->flags & NETIF_FLAG_UP) { + if (netif->flags & NETIF_FLAG_UP) { #if LWIP_ARP - /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ - if (netif->flags & NETIF_FLAG_ETHARP) { - etharp_gratuitous(netif); - } + /* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */ + if (netif->flags & NETIF_FLAG_ETHARP) { + etharp_gratuitous(netif); + } #endif /* LWIP_ARP */ #if LWIP_IGMP - /* resend IGMP memberships */ - if (netif->flags & NETIF_FLAG_IGMP) { - igmp_report_groups( netif); - } + /* resend IGMP memberships */ + if (netif->flags & NETIF_FLAG_IGMP) { + igmp_report_groups( netif); + } #endif /* LWIP_IGMP */ + } + NETIF_LINK_CALLBACK(netif); } - NETIF_LINK_CALLBACK(netif); } /** @@ -507,22 +551,17 @@ void netif_set_link_up(struct netif *netif ) */ void netif_set_link_down(struct netif *netif ) { - netif->flags &= ~NETIF_FLAG_LINK_UP; - NETIF_LINK_CALLBACK(netif); -} - -/** - * Ask if a link is up - */ -u8_t netif_is_link_up(struct netif *netif) -{ - return (netif->flags & NETIF_FLAG_LINK_UP) ? 1 : 0; + if (netif->flags & NETIF_FLAG_LINK_UP) { + netif->flags &= ~NETIF_FLAG_LINK_UP; + NETIF_LINK_CALLBACK(netif); + } } +#if LWIP_NETIF_LINK_CALLBACK /** * Set callback to be called when link is brought up/down */ -void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif )) +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback) { if (netif) { netif->link_callback = link_callback; @@ -547,7 +586,7 @@ void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct */ err_t netif_loop_output(struct netif *netif, struct pbuf *p, - struct ip_addr *ipaddr) + ip_addr_t *ipaddr) { struct pbuf *r; err_t err; @@ -555,22 +594,36 @@ netif_loop_output(struct netif *netif, struct pbuf *p, #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = 0; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if LWIP_SNMP +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* LWIP_SNMP */ SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(ipaddr); /* Allocate a new pbuf */ r = pbuf_alloc(PBUF_LINK, p->tot_len, PBUF_RAM); if (r == NULL) { + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); return ERR_MEM; } #if LWIP_LOOPBACK_MAX_PBUFS clen = pbuf_clen(r); /* check for overflow or too many pbuf on queue */ if(((netif->loop_cnt_current + clen) < netif->loop_cnt_current) || - ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { - pbuf_free(r); - r = NULL; - return ERR_MEM; + ((netif->loop_cnt_current + clen) > LWIP_LOOPBACK_MAX_PBUFS)) { + pbuf_free(r); + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); + return ERR_MEM; } netif->loop_cnt_current += clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ @@ -578,7 +631,9 @@ netif_loop_output(struct netif *netif, struct pbuf *p, /* Copy the whole pbuf queue p into the single pbuf r */ if ((err = pbuf_copy(r, p)) != ERR_OK) { pbuf_free(r); - r = NULL; + LINK_STATS_INC(link.memerr); + LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(stats_if); return err; } @@ -599,9 +654,13 @@ netif_loop_output(struct netif *netif, struct pbuf *p, } SYS_ARCH_UNPROTECT(lev); + LINK_STATS_INC(link.xmit); + snmp_add_ifoutoctets(stats_if, p->tot_len); + snmp_inc_ifoutucastpkts(stats_if); + #if LWIP_NETIF_LOOPBACK_MULTITHREADING /* For multithreading environment, schedule a call to netif_poll */ - tcpip_callback((void (*)(void *))(netif_poll), netif); + tcpip_callback((tcpip_callback_fn)netif_poll, netif); #endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */ return ERR_OK; @@ -617,13 +676,22 @@ void netif_poll(struct netif *netif) { struct pbuf *in; + /* If we have a loopif, SNMP counters are adjusted for it, + * if not they are adjusted for 'netif'. */ +#if LWIP_SNMP +#if LWIP_HAVE_LOOPIF + struct netif *stats_if = &loop_netif; +#else /* LWIP_HAVE_LOOPIF */ + struct netif *stats_if = netif; +#endif /* LWIP_HAVE_LOOPIF */ +#endif /* LWIP_SNMP */ SYS_ARCH_DECL_PROTECT(lev); do { /* Get a packet from the list. With SYS_LIGHTWEIGHT_PROT=1, this is protected */ SYS_ARCH_PROTECT(lev); in = netif->loop_first; - if(in != NULL) { + if (in != NULL) { struct pbuf *in_end = in; #if LWIP_LOOPBACK_MAX_PBUFS u8_t clen = pbuf_clen(in); @@ -632,12 +700,12 @@ netif_poll(struct netif *netif) ((netif->loop_cnt_current - clen) < netif->loop_cnt_current)); netif->loop_cnt_current -= clen; #endif /* LWIP_LOOPBACK_MAX_PBUFS */ - while(in_end->len != in_end->tot_len) { + while (in_end->len != in_end->tot_len) { LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL); in_end = in_end->next; } /* 'in_end' now points to the last pbuf from 'in' */ - if(in_end == netif->loop_last) { + if (in_end == netif->loop_last) { /* this was the last pbuf in the list */ netif->loop_first = netif->loop_last = NULL; } else { @@ -650,16 +718,19 @@ netif_poll(struct netif *netif) } SYS_ARCH_UNPROTECT(lev); - if(in != NULL) { + if (in != NULL) { + LINK_STATS_INC(link.recv); + snmp_add_ifinoctets(stats_if, in->tot_len); + snmp_inc_ifinucastpkts(stats_if); /* loopback packets are always IP packets! */ - if(ip_input(in, netif) != ERR_OK) { + if (ip_input(in, netif) != ERR_OK) { pbuf_free(in); } /* Don't reference the packet any more! */ in = NULL; } /* go on while there is a packet on the list */ - } while(netif->loop_first != NULL); + } while (netif->loop_first != NULL); } #if !LWIP_NETIF_LOOPBACK_MULTITHREADING diff --git a/core/lwip/src/core/pbuf.c b/core/lwip/src/core/pbuf.c index 11cc2e67..dd9ff64e 100644 --- a/core/lwip/src/core/pbuf.c +++ b/core/lwip/src/core/pbuf.c @@ -71,7 +71,10 @@ #include "lwip/sys.h" #include "arch/perf.h" #if TCP_QUEUE_OOSEQ -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" +#endif +#if LWIP_CHECKSUM_ON_COPY +#include "lwip/inet_chksum.h" #endif #include <string.h> @@ -81,9 +84,9 @@ aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */ #define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE) -#if !TCP_QUEUE_OOSEQ || NO_SYS +#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS #define PBUF_POOL_IS_EMPTY() -#else /* !TCP_QUEUE_OOSEQ || NO_SYS */ +#else /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ /** Define this to 0 to prevent freeing ooseq pbufs when the PBUF_POOL is empty */ #ifndef PBUF_POOL_FREE_OOSEQ #define PBUF_POOL_FREE_OOSEQ 1 @@ -145,7 +148,7 @@ pbuf_pool_is_empty(void) } } #endif /* PBUF_POOL_FREE_OOSEQ */ -#endif /* !TCP_QUEUE_OOSEQ || NO_SYS */ +#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */ /** * Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type). @@ -211,7 +214,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) switch (type) { case PBUF_POOL: /* allocate head of pbuf chain into p */ - p = memp_malloc(MEMP_PBUF_POOL); + p = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc: allocated pbuf %p\n", (void *)p)); if (p == NULL) { PBUF_POOL_IS_EMPTY(); @@ -244,7 +247,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) rem_len = length - p->len; /* any remaining pbufs to be allocated? */ while (rem_len > 0) { - q = memp_malloc(MEMP_PBUF_POOL); + q = (struct pbuf *)memp_malloc(MEMP_PBUF_POOL); if (q == NULL) { PBUF_POOL_IS_EMPTY(); /* free chain so far allocated */ @@ -298,7 +301,7 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) /* pbuf references existing (externally allocated) RAM payload? */ case PBUF_REF: /* only allocate memory for the pbuf structure */ - p = memp_malloc(MEMP_PBUF); + p = (struct pbuf *)memp_malloc(MEMP_PBUF); if (p == NULL) { LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n", @@ -323,6 +326,67 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type) return p; } +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Initialize a custom pbuf (already allocated). + * + * @param layer flag to define header size + * @param length size of the pbuf's payload + * @param type type of the pbuf (only used to treat the pbuf accordingly, as + * this function allocates no memory) + * @param p pointer to the custom pbuf to initialize (already allocated) + * @param payload_mem pointer to the buffer that is used for payload and headers, + * must be at least big enough to hold 'length' plus the header size, + * may be NULL if set later + * @param payload_mem_len the size of the 'payload_mem' buffer, must be at least + * big enough to hold 'length' plus the header size + */ +struct pbuf* +pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, struct pbuf_custom *p, + void *payload_mem, u16_t payload_mem_len) +{ + u16_t offset; + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloced_custom(length=%"U16_F")\n", length)); + + /* determine header offset */ + offset = 0; + switch (l) { + case PBUF_TRANSPORT: + /* add room for transport (often TCP) layer header */ + offset += PBUF_TRANSPORT_HLEN; + /* FALLTHROUGH */ + case PBUF_IP: + /* add room for IP layer header */ + offset += PBUF_IP_HLEN; + /* FALLTHROUGH */ + case PBUF_LINK: + /* add room for link layer header */ + offset += PBUF_LINK_HLEN; + break; + case PBUF_RAW: + break; + default: + LWIP_ASSERT("pbuf_alloced_custom: bad pbuf layer", 0); + return NULL; + } + + if (LWIP_MEM_ALIGN_SIZE(offset) + length < payload_mem_len) { + LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_WARNING, ("pbuf_alloced_custom(length=%"U16_F") buffer too short\n", length)); + return NULL; + } + + p->pbuf.next = NULL; + if (payload_mem != NULL) { + p->pbuf.payload = LWIP_MEM_ALIGN((void *)((u8_t *)payload_mem + offset)); + } else { + p->pbuf.payload = NULL; + } + p->pbuf.flags = PBUF_FLAG_IS_CUSTOM; + p->pbuf.len = p->pbuf.tot_len = length; + p->pbuf.type = type; + p->pbuf.ref = 1; + return &p->pbuf; +} +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ /** * Shrink a pbuf chain to a desired length. @@ -383,8 +447,8 @@ pbuf_realloc(struct pbuf *p, u16_t new_len) /* (other types merely adjust their length fields */ if ((q->type == PBUF_RAM) && (rem_len != q->len)) { /* reallocate and adjust the length of the pbuf that will be split */ - q = mem_realloc(q, (u8_t *)q->payload - (u8_t *)q + rem_len); - LWIP_ASSERT("mem_realloc give q == NULL", q != NULL); + q = (struct pbuf *)mem_trim(q, (u16_t)((u8_t *)q->payload - (u8_t *)q) + rem_len); + LWIP_ASSERT("mem_trim returned q == NULL", q != NULL); } /* adjust length fields for new last pbuf */ q->len = rem_len; @@ -428,8 +492,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment) u16_t increment_magnitude; LWIP_ASSERT("p != NULL", p != NULL); - if ((header_size_increment == 0) || (p == NULL)) + if ((header_size_increment == 0) || (p == NULL)) { return 0; + } if (header_size_increment < 0){ increment_magnitude = -header_size_increment; @@ -478,8 +543,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment) * bail out unsuccesfully */ return 1; } - } - else { + } else { /* Unknown type */ LWIP_ASSERT("bad pbuf type", 0); return 1; @@ -570,15 +634,25 @@ pbuf_free(struct pbuf *p) q = p->next; LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: deallocating %p\n", (void *)p)); type = p->type; - /* is this a pbuf from the pool? */ - if (type == PBUF_POOL) { - memp_free(MEMP_PBUF_POOL, p); - /* is this a ROM or RAM referencing pbuf? */ - } else if (type == PBUF_ROM || type == PBUF_REF) { - memp_free(MEMP_PBUF, p); - /* type == PBUF_RAM */ - } else { - mem_free(p); +#if LWIP_SUPPORT_CUSTOM_PBUF + /* is this a custom pbuf? */ + if ((p->flags & PBUF_FLAG_IS_CUSTOM) != 0) { + struct pbuf_custom *pc = (struct pbuf_custom*)p; + LWIP_ASSERT("pc->custom_free_function != NULL", pc->custom_free_function != NULL); + pc->custom_free_function(p); + } else +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + { + /* is this a pbuf from the pool? */ + if (type == PBUF_POOL) { + memp_free(MEMP_PBUF_POOL, p); + /* is this a ROM or RAM referencing pbuf? */ + } else if (type == PBUF_ROM || type == PBUF_REF) { + memp_free(MEMP_PBUF, p); + /* type == PBUF_RAM */ + } else { + mem_free(p); + } } count++; /* proceed to next pbuf */ @@ -900,8 +974,8 @@ pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len) /** * Creates a single pbuf out of a queue of pbufs. * - * @remark: The source pbuf 'p' is not freed by this function because that can - * be illegal in some places! + * @remark: Either the source pbuf 'p' is freed by this function or the original + * pbuf 'p' is returned, therefore the caller has to check the result! * * @param p the source pbuf * @param layer pbuf_layer of the new pbuf @@ -927,3 +1001,156 @@ pbuf_coalesce(struct pbuf *p, pbuf_layer layer) pbuf_free(p); return q; } + +#if LWIP_CHECKSUM_ON_COPY +/** + * Copies data into a single pbuf (*not* into a pbuf queue!) and updates + * the checksum while copying + * + * @param p the pbuf to copy data into + * @param start_offset offset of p->payload where to copy the data to + * @param dataptr data to copy into the pbuf + * @param len length of data to copy into the pbuf + * @param chksum pointer to the checksum which is updated + * @return ERR_OK if successful, another error if the data does not fit + * within the (first) pbuf (no pbuf queues!) + */ +err_t +pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum) +{ + u32_t acc; + u16_t copy_chksum; + char *dst_ptr; + LWIP_ASSERT("p != NULL", p != NULL); + LWIP_ASSERT("dataptr != NULL", dataptr != NULL); + LWIP_ASSERT("chksum != NULL", chksum != NULL); + LWIP_ASSERT("len != 0", len != 0); + + if ((start_offset >= p->len) || (start_offset + len > p->len)) { + return ERR_ARG; + } + + dst_ptr = ((char*)p->payload) + start_offset; + copy_chksum = LWIP_CHKSUM_COPY(dst_ptr, dataptr, len); + if ((start_offset & 1) != 0) { + copy_chksum = SWAP_BYTES_IN_WORD(copy_chksum); + } + acc = *chksum; + acc += copy_chksum; + *chksum = FOLD_U32T(acc); + return ERR_OK; +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + + /** Get one byte from the specified position in a pbuf + * WARNING: returns zero for offset >= p->tot_len + * + * @param p pbuf to parse + * @param offset offset into p of the byte to return + * @return byte at an offset into p OR ZERO IF 'offset' >= p->tot_len + */ +u8_t +pbuf_get_at(struct pbuf* p, u16_t offset) +{ + u16_t copy_from = offset; + struct pbuf* q = p; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= copy_from)) { + copy_from -= q->len; + q = q->next; + } + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > copy_from)) { + return ((u8_t*)q->payload)[copy_from]; + } + return 0; +} + +/** Compare pbuf contents at specified offset with memory s2, both of length n + * + * @param p pbuf to compare + * @param offset offset into p at wich to start comparing + * @param s2 buffer to compare + * @param n length of buffer to compare + * @return zero if equal, nonzero otherwise + * (0xffff if p is too short, diffoffset+1 otherwise) + */ +u16_t +pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n) +{ + u16_t start = offset; + struct pbuf* q = p; + + /* get the correct pbuf */ + while ((q != NULL) && (q->len <= start)) { + start -= q->len; + q = q->next; + } + /* return requested data if pbuf is OK */ + if ((q != NULL) && (q->len > start)) { + u16_t i; + for(i = 0; i < n; i++) { + u8_t a = pbuf_get_at(q, start + i); + u8_t b = ((u8_t*)s2)[i]; + if (a != b) { + return i+1; + } + } + return 0; + } + return 0xffff; +} + +/** Find occurrence of mem (with length mem_len) in pbuf p, starting at offset + * start_offset. + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param mem search for the contents of this buffer + * @param mem_len length of 'mem' + * @param start_offset offset into p at which to start searching + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset) +{ + u16_t i; + u16_t max = p->tot_len - mem_len; + if (p->tot_len >= mem_len + start_offset) { + for(i = start_offset; i <= max; ) { + u16_t plus = pbuf_memcmp(p, i, mem, mem_len); + if (plus == 0) { + return i; + } else { + i += plus; + } + } + } + return 0xFFFF; +} + +/** Find occurrence of substr with length substr_len in pbuf p, start at offset + * start_offset + * WARNING: in contrast to strstr(), this one does not stop at the first \0 in + * the pbuf/source string! + * + * @param p pbuf to search, maximum length is 0xFFFE since 0xFFFF is used as + * return value 'not found' + * @param substr string to search for in p, maximum length is 0xFFFE + * @return 0xFFFF if substr was not found in p or the index where it was found + */ +u16_t +pbuf_strstr(struct pbuf* p, const char* substr) +{ + size_t substr_len; + if ((substr == NULL) || (substr[0] == 0) || (p->tot_len == 0xFFFF)) { + return 0xFFFF; + } + substr_len = strlen(substr); + if (substr_len >= 0xFFFF) { + return 0xFFFF; + } + return pbuf_memfind(p, substr, (u16_t)substr_len, 0); +} diff --git a/core/lwip/src/core/raw.c b/core/lwip/src/core/raw.c index 2f105fe6..9fcb1003 100644 --- a/core/lwip/src/core/raw.c +++ b/core/lwip/src/core/raw.c @@ -44,12 +44,10 @@ #include "lwip/def.h" #include "lwip/memp.h" -#include "lwip/inet.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/raw.h" #include "lwip/stats.h" -#include "lwip/snmp.h" #include "arch/perf.h" #include <string.h> @@ -84,7 +82,7 @@ raw_input(struct pbuf *p, struct netif *inp) LWIP_UNUSED_ARG(inp); - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; proto = IPH_PROTO(iphdr); prev = NULL; @@ -92,16 +90,18 @@ raw_input(struct pbuf *p, struct netif *inp) /* loop through all raw pcbs until the packet is eaten by one */ /* this allows multiple pcbs to match against the packet by design */ while ((eaten == 0) && (pcb != NULL)) { - if (pcb->protocol == proto) { + if ((pcb->protocol == proto) && + (ip_addr_isany(&pcb->local_ip) || + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest))) { #if IP_SOF_BROADCAST_RECV /* broadcast filter? */ - if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(&(iphdr->dest), inp)) + if ((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(¤t_iphdr_dest, inp)) #endif /* IP_SOF_BROADCAST_RECV */ { /* receive callback function available? */ if (pcb->recv != NULL) { /* the receive callback function did not eat the packet? */ - if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0) { + if (pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr()) != 0) { /* receive function ate the packet */ p = NULL; eaten = 1; @@ -139,7 +139,7 @@ raw_input(struct pbuf *p, struct netif *inp) * @see raw_disconnect() */ err_t -raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) +raw_bind(struct raw_pcb *pcb, ip_addr_t *ipaddr) { ip_addr_set(&pcb->local_ip, ipaddr); return ERR_OK; @@ -159,7 +159,7 @@ raw_bind(struct raw_pcb *pcb, struct ip_addr *ipaddr) * @see raw_disconnect() and raw_sendto() */ err_t -raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) +raw_connect(struct raw_pcb *pcb, ip_addr_t *ipaddr) { ip_addr_set(&pcb->remote_ip, ipaddr); return ERR_OK; @@ -180,10 +180,7 @@ raw_connect(struct raw_pcb *pcb, struct ip_addr *ipaddr) * available for others. */ void -raw_recv(struct raw_pcb *pcb, - u8_t (* recv)(void *arg, struct raw_pcb *upcb, struct pbuf *p, - struct ip_addr *addr), - void *recv_arg) +raw_recv(struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ pcb->recv = recv; @@ -203,11 +200,11 @@ raw_recv(struct raw_pcb *pcb, * */ err_t -raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) +raw_sendto(struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr) { err_t err; struct netif *netif; - struct ip_addr *src_ip; + ip_addr_t *src_ip; struct pbuf *q; /* q will be sent down the stack */ LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n")); @@ -221,8 +218,10 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("raw_sendto: could not allocate header\n")); return ERR_MEM; } - /* chain header q in front of given pbuf p */ - pbuf_chain(q, p); + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p */ + pbuf_chain(q, p); + } /* { first pbuf q points to header pbuf } */ LWIP_DEBUGF(RAW_DEBUG, ("raw_sendto: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); } else { @@ -235,7 +234,8 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) } if ((netif = ip_route(ipaddr)) == NULL) { - LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr)); + LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { pbuf_free(q); @@ -245,7 +245,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr) #if IP_SOF_BROADCAST /* broadcast filter? */ - if ( ((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif) ) { + if (((pcb->so_options & SOF_BROADCAST) == 0) && ip_addr_isbroadcast(ipaddr, netif)) { LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb)); /* free any temporary header pbuf allocated by pbuf_header() */ if (q != p) { @@ -332,12 +332,13 @@ raw_remove(struct raw_pcb *pcb) * @see raw_remove() */ struct raw_pcb * -raw_new(u8_t proto) { +raw_new(u8_t proto) +{ struct raw_pcb *pcb; LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_new\n")); - pcb = memp_malloc(MEMP_RAW_PCB); + pcb = (struct raw_pcb *)memp_malloc(MEMP_RAW_PCB); /* could allocate RAW PCB? */ if (pcb != NULL) { /* initialize PCB to all zeroes */ diff --git a/core/lwip/src/core/snmp/asn1_dec.c b/core/lwip/src/core/snmp/asn1_dec.c index 650fb403..1d565820 100644 --- a/core/lwip/src/core/snmp/asn1_dec.c +++ b/core/lwip/src/core/snmp/asn1_dec.c @@ -61,7 +61,7 @@ snmp_asn1_dec_type(struct pbuf *p, u16_t ofs, u8_t *type) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; *type = *msg_ptr; return ERR_OK; @@ -94,7 +94,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (*msg_ptr < 0x80) @@ -125,7 +125,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -160,7 +160,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; } else { @@ -186,7 +186,7 @@ snmp_asn1_dec_length(struct pbuf *p, u16_t ofs, u8_t *octets_used, u16_t *length /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -249,7 +249,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if ((len > 0) && (len < 6)) { @@ -273,7 +273,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -295,7 +295,7 @@ snmp_asn1_dec_u32t(struct pbuf *p, u16_t ofs, u16_t len, u32_t *value) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -349,7 +349,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if ((len > 0) && (len < 5)) { @@ -386,7 +386,7 @@ snmp_asn1_dec_s32t(struct pbuf *p, u16_t ofs, u16_t len, s32_t *value) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -439,7 +439,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; oid->len = 0; @@ -493,7 +493,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -519,7 +519,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -551,7 +551,7 @@ snmp_asn1_dec_oid(struct pbuf *p, u16_t ofs, u16_t len, struct snmp_obj_id *oid) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -607,7 +607,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (raw_len >= len) { @@ -623,7 +623,7 @@ snmp_asn1_dec_raw(struct pbuf *p, u16_t ofs, u16_t len, u16_t raw_len, u8_t *raw /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else diff --git a/core/lwip/src/core/snmp/asn1_enc.c b/core/lwip/src/core/snmp/asn1_enc.c index 77af6b4b..64dfc5f6 100644 --- a/core/lwip/src/core/snmp/asn1_enc.c +++ b/core/lwip/src/core/snmp/asn1_enc.c @@ -190,7 +190,7 @@ snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; *msg_ptr = type; return ERR_OK; @@ -222,12 +222,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (length < 0x80) { - *msg_ptr = length; + *msg_ptr = (u8_t)length; return ERR_OK; } else if (length < 0x100) @@ -239,14 +239,14 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; } else { /* next octet in same pbuf */ msg_ptr++; } - *msg_ptr = length; + *msg_ptr = (u8_t)length; return ERR_OK; } else @@ -265,7 +265,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -276,12 +276,12 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) if (i == 0) { /* least significant length octet */ - *msg_ptr = length; + *msg_ptr = (u8_t)length; } else { /* most significant length octet */ - *msg_ptr = length >> 8; + *msg_ptr = (u8_t)(length >> 8); } } return ERR_OK; @@ -305,7 +305,7 @@ snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length) * @see snmp_asn1_enc_u32t_cnt() */ err_t -snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) +snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value) { u16_t plen, base; u8_t *msg_ptr; @@ -317,7 +317,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (octets_needed == 5) @@ -331,7 +331,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -343,14 +343,14 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) while (octets_needed > 1) { octets_needed--; - *msg_ptr = value >> (octets_needed << 3); + *msg_ptr = (u8_t)(value >> (octets_needed << 3)); ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -360,7 +360,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) } } /* (only) one least significant octet */ - *msg_ptr = value; + *msg_ptr = (u8_t)value; return ERR_OK; } p = p->next; @@ -381,7 +381,7 @@ snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value) * @see snmp_asn1_enc_s32t_cnt() */ err_t -snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value) +snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value) { u16_t plen, base; u8_t *msg_ptr; @@ -393,20 +393,20 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; while (octets_needed > 1) { octets_needed--; - *msg_ptr = value >> (octets_needed << 3); + *msg_ptr = (u8_t)(value >> (octets_needed << 3)); ofs += 1; if (ofs >= plen) { /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -416,7 +416,7 @@ snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value) } } /* (only) one least significant octet */ - *msg_ptr = value; + *msg_ptr = (u8_t)value; return ERR_OK; } p = p->next; @@ -447,7 +447,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; if (ident_len > 1) @@ -460,7 +460,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) else { /* calculate prefix */ - *msg_ptr = (ident[0] * 40) + ident[1]; + *msg_ptr = (u8_t)((ident[0] * 40) + ident[1]); } ofs += 1; if (ofs >= plen) @@ -468,7 +468,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -498,7 +498,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) { u8_t code; - code = sub_id >> shift; + code = (u8_t)(sub_id >> shift); if ((code != 0) || (tail != 0)) { tail = 1; @@ -509,7 +509,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -529,7 +529,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else @@ -559,7 +559,7 @@ snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident) * @return ERR_OK if successfull, ERR_ARG if we can't (or won't) encode */ err_t -snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw) +snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw) { u16_t plen, base; u8_t *msg_ptr; @@ -571,7 +571,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw) plen += p->len; if (ofs < plen) { - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; msg_ptr += ofs - base; while (raw_len > 1) @@ -586,7 +586,7 @@ snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw) /* next octet in next pbuf */ p = p->next; if (p == NULL) { return ERR_ARG; } - msg_ptr = p->payload; + msg_ptr = (u8_t*)p->payload; plen += p->len; } else diff --git a/core/lwip/src/core/snmp/mib2.c b/core/lwip/src/core/snmp/mib2.c index bc5830d6..29decd30 100644 --- a/core/lwip/src/core/snmp/mib2.c +++ b/core/lwip/src/core/snmp/mib2.c @@ -43,10 +43,12 @@ #include "lwip/netif.h" #include "lwip/ip.h" #include "lwip/ip_frag.h" -#include "lwip/tcp.h" +#include "lwip/mem.h" +#include "lwip/tcp_impl.h" #include "lwip/udp.h" #include "lwip/snmp_asn1.h" #include "lwip/snmp_structs.h" +#include "lwip/sys.h" #include "netif/etharp.h" /** @@ -131,20 +133,20 @@ const s32_t snmp_ids[28] = { 17, 18, 19, 20, 21, 22, 24, 25, 26, 27, 28, 29, 30 }; struct mib_node* const snmp_nodes[28] = { - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar, - (struct mib_node* const)&snmp_scalar, (struct mib_node* const)&snmp_scalar + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar, + (struct mib_node*)&snmp_scalar, (struct mib_node*)&snmp_scalar }; const struct mib_array_node snmp = { &noleafs_get_object_def, @@ -176,7 +178,7 @@ struct mib_list_rootnode udp_root = { }; const s32_t udpentry_ids[2] = { 1, 2 }; struct mib_node* const udpentry_nodes[2] = { - (struct mib_node* const)&udp_root, (struct mib_node* const)&udp_root, + (struct mib_node*)&udp_root, (struct mib_node*)&udp_root, }; const struct mib_array_node udpentry = { &noleafs_get_object_def, @@ -190,7 +192,7 @@ const struct mib_array_node udpentry = { }; s32_t udptable_id = 1; -struct mib_node* udptable_node = (struct mib_node* const)&udpentry; +struct mib_node* udptable_node = (struct mib_node*)&udpentry; struct mib_ram_array_node udptable = { &noleafs_get_object_def, &noleafs_get_value, @@ -212,9 +214,9 @@ const mib_scalar_node udp_scalar = { }; const s32_t udp_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const udp_nodes[5] = { - (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar, - (struct mib_node* const)&udp_scalar, (struct mib_node* const)&udp_scalar, - (struct mib_node* const)&udptable + (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, + (struct mib_node*)&udp_scalar, (struct mib_node*)&udp_scalar, + (struct mib_node*)&udptable }; const struct mib_array_node udp = { &noleafs_get_object_def, @@ -244,9 +246,9 @@ struct mib_list_rootnode tcpconntree_root = { }; const s32_t tcpconnentry_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const tcpconnentry_nodes[5] = { - (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, - (struct mib_node* const)&tcpconntree_root, (struct mib_node* const)&tcpconntree_root, - (struct mib_node* const)&tcpconntree_root + (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, + (struct mib_node*)&tcpconntree_root, (struct mib_node*)&tcpconntree_root, + (struct mib_node*)&tcpconntree_root }; const struct mib_array_node tcpconnentry = { &noleafs_get_object_def, @@ -260,7 +262,7 @@ const struct mib_array_node tcpconnentry = { }; s32_t tcpconntable_id = 1; -struct mib_node* tcpconntable_node = (struct mib_node* const)&tcpconnentry; +struct mib_node* tcpconntable_node = (struct mib_node*)&tcpconnentry; struct mib_ram_array_node tcpconntable = { &noleafs_get_object_def, &noleafs_get_value, @@ -284,14 +286,14 @@ const mib_scalar_node tcp_scalar = { }; const s32_t tcp_ids[15] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; struct mib_node* const tcp_nodes[15] = { - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcpconntable, (struct mib_node* const)&tcp_scalar, - (struct mib_node* const)&tcp_scalar + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcpconntable, (struct mib_node*)&tcp_scalar, + (struct mib_node*)&tcp_scalar }; const struct mib_array_node tcp = { &noleafs_get_object_def, @@ -316,19 +318,19 @@ const mib_scalar_node icmp_scalar = { }; const s32_t icmp_ids[26] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26 }; struct mib_node* const icmp_nodes[26] = { - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar, - (struct mib_node* const)&icmp_scalar, (struct mib_node* const)&icmp_scalar + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar, + (struct mib_node*)&icmp_scalar, (struct mib_node*)&icmp_scalar }; const struct mib_array_node icmp = { &noleafs_get_object_def, @@ -355,8 +357,8 @@ struct mib_list_rootnode ipntomtree_root = { }; const s32_t ipntomentry_ids[4] = { 1, 2, 3, 4 }; struct mib_node* const ipntomentry_nodes[4] = { - (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root, - (struct mib_node* const)&ipntomtree_root, (struct mib_node* const)&ipntomtree_root + (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root, + (struct mib_node*)&ipntomtree_root, (struct mib_node*)&ipntomtree_root }; const struct mib_array_node ipntomentry = { &noleafs_get_object_def, @@ -370,7 +372,7 @@ const struct mib_array_node ipntomentry = { }; s32_t ipntomtable_id = 1; -struct mib_node* ipntomtable_node = (struct mib_node* const)&ipntomentry; +struct mib_node* ipntomtable_node = (struct mib_node*)&ipntomentry; struct mib_ram_array_node ipntomtable = { &noleafs_get_object_def, &noleafs_get_value, @@ -396,13 +398,13 @@ struct mib_list_rootnode iprtetree_root = { }; const s32_t iprteentry_ids[13] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 }; struct mib_node* const iprteentry_nodes[13] = { - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root, (struct mib_node* const)&iprtetree_root, - (struct mib_node* const)&iprtetree_root + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root, (struct mib_node*)&iprtetree_root, + (struct mib_node*)&iprtetree_root }; const struct mib_array_node iprteentry = { &noleafs_get_object_def, @@ -416,7 +418,7 @@ const struct mib_array_node iprteentry = { }; s32_t iprtetable_id = 1; -struct mib_node* iprtetable_node = (struct mib_node* const)&iprteentry; +struct mib_node* iprtetable_node = (struct mib_node*)&iprteentry; struct mib_ram_array_node iprtetable = { &noleafs_get_object_def, &noleafs_get_value, @@ -442,11 +444,11 @@ struct mib_list_rootnode ipaddrtree_root = { }; const s32_t ipaddrentry_ids[5] = { 1, 2, 3, 4, 5 }; struct mib_node* const ipaddrentry_nodes[5] = { - (struct mib_node* const)&ipaddrtree_root, - (struct mib_node* const)&ipaddrtree_root, - (struct mib_node* const)&ipaddrtree_root, - (struct mib_node* const)&ipaddrtree_root, - (struct mib_node* const)&ipaddrtree_root + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root, + (struct mib_node*)&ipaddrtree_root }; const struct mib_array_node ipaddrentry = { &noleafs_get_object_def, @@ -460,7 +462,7 @@ const struct mib_array_node ipaddrentry = { }; s32_t ipaddrtable_id = 1; -struct mib_node* ipaddrtable_node = (struct mib_node* const)&ipaddrentry; +struct mib_node* ipaddrtable_node = (struct mib_node*)&ipaddrentry; struct mib_ram_array_node ipaddrtable = { &noleafs_get_object_def, &noleafs_get_value, @@ -483,18 +485,18 @@ const mib_scalar_node ip_scalar = { }; const s32_t ip_ids[23] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23 }; struct mib_node* const ip_nodes[23] = { - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ip_scalar, - (struct mib_node* const)&ip_scalar, (struct mib_node* const)&ipaddrtable, - (struct mib_node* const)&iprtetable, (struct mib_node* const)&ipntomtable, - (struct mib_node* const)&ip_scalar + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ip_scalar, + (struct mib_node*)&ip_scalar, (struct mib_node*)&ipaddrtable, + (struct mib_node*)&iprtetable, (struct mib_node*)&ipntomtable, + (struct mib_node*)&ip_scalar }; const struct mib_array_node mib2_ip = { &noleafs_get_object_def, @@ -521,9 +523,9 @@ struct mib_list_rootnode arptree_root = { }; const s32_t atentry_ids[3] = { 1, 2, 3 }; struct mib_node* const atentry_nodes[3] = { - (struct mib_node* const)&arptree_root, - (struct mib_node* const)&arptree_root, - (struct mib_node* const)&arptree_root + (struct mib_node*)&arptree_root, + (struct mib_node*)&arptree_root, + (struct mib_node*)&arptree_root }; const struct mib_array_node atentry = { &noleafs_get_object_def, @@ -537,7 +539,7 @@ const struct mib_array_node atentry = { }; const s32_t attable_id = 1; -struct mib_node* const attable_node = (struct mib_node* const)&atentry; +struct mib_node* const attable_node = (struct mib_node*)&atentry; const struct mib_array_node attable = { &noleafs_get_object_def, &noleafs_get_value, @@ -551,7 +553,7 @@ const struct mib_array_node attable = { /* at .1.3.6.1.2.1.3 */ s32_t at_id = 1; -struct mib_node* mib2_at_node = (struct mib_node* const)&attable; +struct mib_node* mib2_at_node = (struct mib_node*)&attable; struct mib_ram_array_node at = { &noleafs_get_object_def, &noleafs_get_value, @@ -582,17 +584,17 @@ struct mib_list_rootnode iflist_root = { }; const s32_t ifentry_ids[22] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22 }; struct mib_node* const ifentry_nodes[22] = { - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root, - (struct mib_node* const)&iflist_root, (struct mib_node* const)&iflist_root + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root, + (struct mib_node*)&iflist_root, (struct mib_node*)&iflist_root }; const struct mib_array_node ifentry = { &noleafs_get_object_def, @@ -606,7 +608,7 @@ const struct mib_array_node ifentry = { }; s32_t iftable_id = 1; -struct mib_node* iftable_node = (struct mib_node* const)&ifentry; +struct mib_node* iftable_node = (struct mib_node*)&ifentry; struct mib_ram_array_node iftable = { &noleafs_get_object_def, &noleafs_get_value, @@ -629,7 +631,7 @@ const mib_scalar_node interfaces_scalar = { }; const s32_t interfaces_ids[2] = { 1, 2 }; struct mib_node* const interfaces_nodes[2] = { - (struct mib_node* const)&interfaces_scalar, (struct mib_node* const)&iftable + (struct mib_node*)&interfaces_scalar, (struct mib_node*)&iftable }; const struct mib_array_node interfaces = { &noleafs_get_object_def, @@ -655,10 +657,10 @@ const mib_scalar_node sys_tem_scalar = { }; const s32_t sys_tem_ids[7] = { 1, 2, 3, 4, 5, 6, 7 }; struct mib_node* const sys_tem_nodes[7] = { - (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, - (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, - (struct mib_node* const)&sys_tem_scalar, (struct mib_node* const)&sys_tem_scalar, - (struct mib_node* const)&sys_tem_scalar + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar, (struct mib_node*)&sys_tem_scalar, + (struct mib_node*)&sys_tem_scalar }; /* work around name issue with 'sys_tem', some compiler(s?) seem to reserve 'system' */ const struct mib_array_node sys_tem = { @@ -692,16 +694,16 @@ const s32_t mib2_ids[MIB2_GROUPS] = 11 }; struct mib_node* const mib2_nodes[MIB2_GROUPS] = { - (struct mib_node* const)&sys_tem, - (struct mib_node* const)&interfaces, - (struct mib_node* const)&at, - (struct mib_node* const)&mib2_ip, - (struct mib_node* const)&icmp, + (struct mib_node*)&sys_tem, + (struct mib_node*)&interfaces, + (struct mib_node*)&at, + (struct mib_node*)&mib2_ip, + (struct mib_node*)&icmp, #if LWIP_TCP - (struct mib_node* const)&tcp, + (struct mib_node*)&tcp, #endif - (struct mib_node* const)&udp, - (struct mib_node* const)&snmp + (struct mib_node*)&udp, + (struct mib_node*)&snmp }; const struct mib_array_node mib2 = { @@ -717,7 +719,7 @@ const struct mib_array_node mib2 = { /* mgmt .1.3.6.1.2 */ const s32_t mgmt_ids[1] = { 1 }; -struct mib_node* const mgmt_nodes[1] = { (struct mib_node* const)&mib2 }; +struct mib_node* const mgmt_nodes[1] = { (struct mib_node*)&mib2 }; const struct mib_array_node mgmt = { &noleafs_get_object_def, &noleafs_get_value, @@ -731,8 +733,10 @@ const struct mib_array_node mgmt = { /* internet .1.3.6.1 */ #if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ s32_t internet_ids[2] = { 2, 4 }; -struct mib_node* const internet_nodes[2] = { (struct mib_node* const)&mgmt, (struct mib_node* const)&private }; +struct mib_node* const internet_nodes[2] = { (struct mib_node*)&mgmt, (struct mib_node*)&mib_private }; const struct mib_array_node internet = { &noleafs_get_object_def, &noleafs_get_value, @@ -745,7 +749,7 @@ const struct mib_array_node internet = { }; #else const s32_t internet_ids[1] = { 2 }; -struct mib_node* const internet_nodes[1] = { (struct mib_node* const)&mgmt }; +struct mib_node* const internet_nodes[1] = { (struct mib_node*)&mgmt }; const struct mib_array_node internet = { &noleafs_get_object_def, &noleafs_get_value, @@ -898,11 +902,11 @@ static u32_t snmpinpkts = 0, * @param src points to source * @param n number of octets to copy. */ -void ocstrncpy(u8_t *dst, u8_t *src, u8_t n) +static void ocstrncpy(u8_t *dst, u8_t *src, u16_t n) { - while (n > 0) - { - n--; + u16_t i = n; + while (i > 0) { + i--; *dst++ = *src++; } } @@ -916,9 +920,9 @@ void ocstrncpy(u8_t *dst, u8_t *src, u8_t n) */ void objectidncpy(s32_t *dst, s32_t *src, u8_t n) { - while(n > 0) - { - n--; + u8_t i = n; + while(i > 0) { + i--; *dst++ = *src++; } } @@ -1082,18 +1086,16 @@ void snmp_dec_iflist(void) * Inserts ARP table indexes (.xIfIndex.xNetAddress) * into arp table index trees (both atTable and ipNetToMediaTable). */ -void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip) +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip) { struct mib_list_rootnode *at_rn; struct mib_list_node *at_node; - struct ip_addr hip; s32_t arpidx[5]; u8_t level, tree; LWIP_ASSERT("ni != NULL", ni != NULL); snmp_netiftoifindex(ni, &arpidx[0]); - hip.addr = ntohl(ip->addr); - snmp_iptooid(&hip, &arpidx[1]); + snmp_iptooid(ip, &arpidx[1]); for (tree = 0; tree < 2; tree++) { @@ -1156,17 +1158,15 @@ void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip) * Removes ARP table indexes (.xIfIndex.xNetAddress) * from arp table index trees. */ -void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip) +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip) { struct mib_list_rootnode *at_rn, *next, *del_rn[5]; struct mib_list_node *at_n, *del_n[5]; - struct ip_addr hip; s32_t arpidx[5]; u8_t fc, tree, level, del_cnt; snmp_netiftoifindex(ni, &arpidx[0]); - hip.addr = ntohl(ip->addr); - snmp_iptooid(&hip, &arpidx[1]); + snmp_iptooid(ip, &arpidx[1]); for (tree = 0; tree < 2; tree++) { @@ -1319,13 +1319,11 @@ void snmp_insert_ipaddridx_tree(struct netif *ni) { struct mib_list_rootnode *ipa_rn; struct mib_list_node *ipa_node; - struct ip_addr ip; s32_t ipaddridx[4]; u8_t level; LWIP_ASSERT("ni != NULL", ni != NULL); - ip.addr = ntohl(ni->ip_addr.addr); - snmp_iptooid(&ip, &ipaddridx[0]); + snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); level = 0; ipa_rn = &ipaddrtree_root; @@ -1375,13 +1373,11 @@ void snmp_delete_ipaddridx_tree(struct netif *ni) { struct mib_list_rootnode *ipa_rn, *next, *del_rn[4]; struct mib_list_node *ipa_n, *del_n[4]; - struct ip_addr ip; s32_t ipaddridx[4]; u8_t fc, level, del_cnt; LWIP_ASSERT("ni != NULL", ni != NULL); - ip.addr = ntohl(ni->ip_addr.addr); - snmp_iptooid(&ip, &ipaddridx[0]); + snmp_iptooid(&ni->ip_addr, &ipaddridx[0]); /* mark nodes for deletion */ level = 0; @@ -1443,20 +1439,22 @@ void snmp_delete_ipaddridx_tree(struct netif *ni) void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) { u8_t insert = 0; - struct ip_addr dst; + ip_addr_t dst; if (dflt != 0) { /* the default route 0.0.0.0 */ - dst.addr = 0; + ip_addr_set_any(&dst); insert = 1; } else { /* route to the network address */ - dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); + ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); /* exclude 0.0.0.0 network (reserved for default rte) */ - if (dst.addr != 0) insert = 1; + if (!ip_addr_isany(&dst)) { + insert = 1; + } } if (insert) { @@ -1517,23 +1515,25 @@ void snmp_insert_iprteidx_tree(u8_t dflt, struct netif *ni) */ void snmp_delete_iprteidx_tree(u8_t dflt, struct netif *ni) { - u8_t delete = 0; - struct ip_addr dst; + u8_t del = 0; + ip_addr_t dst; if (dflt != 0) { /* the default route 0.0.0.0 */ - dst.addr = 0; - delete = 1; + ip_addr_set_any(&dst); + del = 1; } else { /* route to the network address */ - dst.addr = ntohl(ni->ip_addr.addr & ni->netmask.addr); + ip_addr_get_network(&dst, &ni->ip_addr, &ni->netmask); /* exclude 0.0.0.0 network (reserved for default rte) */ - if (dst.addr != 0) delete = 1; + if (!ip_addr_isany(&dst)) { + del = 1; + } } - if (delete) + if (del) { struct mib_list_rootnode *iprte_rn, *next, *del_rn[4]; struct mib_list_node *iprte_n, *del_n[4]; @@ -1793,13 +1793,11 @@ void snmp_insert_udpidx_tree(struct udp_pcb *pcb) { struct mib_list_rootnode *udp_rn; struct mib_list_node *udp_node; - struct ip_addr ip; s32_t udpidx[5]; u8_t level; LWIP_ASSERT("pcb != NULL", pcb != NULL); - ip.addr = ntohl(pcb->local_ip.addr); - snmp_iptooid(&ip, &udpidx[0]); + snmp_iptooid(&pcb->local_ip, &udpidx[0]); udpidx[4] = pcb->local_port; udp_rn = &udp_root; @@ -1845,29 +1843,28 @@ void snmp_insert_udpidx_tree(struct udp_pcb *pcb) */ void snmp_delete_udpidx_tree(struct udp_pcb *pcb) { + struct udp_pcb *npcb; struct mib_list_rootnode *udp_rn, *next, *del_rn[5]; struct mib_list_node *udp_n, *del_n[5]; - struct ip_addr ip; s32_t udpidx[5]; u8_t bindings, fc, level, del_cnt; LWIP_ASSERT("pcb != NULL", pcb != NULL); - ip.addr = ntohl(pcb->local_ip.addr); - snmp_iptooid(&ip, &udpidx[0]); + snmp_iptooid(&pcb->local_ip, &udpidx[0]); udpidx[4] = pcb->local_port; /* count PCBs for a given binding (e.g. when reusing ports or for temp output PCBs) */ bindings = 0; - pcb = udp_pcbs; - while ((pcb != NULL)) + npcb = udp_pcbs; + while ((npcb != NULL)) { - if ((pcb->local_ip.addr == ip.addr) && - (pcb->local_port == udpidx[4])) + if (ip_addr_cmp(&npcb->local_ip, &pcb->local_ip) && + (npcb->local_port == udpidx[4])) { bindings++; } - pcb = pcb->next; + npcb = npcb->next; } if (bindings == 1) { @@ -2129,7 +2126,8 @@ system_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def system.%"U16_F".0\n",(u16_t)id)); switch (id) { @@ -2201,32 +2199,33 @@ system_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* sysDescr */ - ocstrncpy(value,sysdescr_ptr, len); + ocstrncpy((u8_t*)value, sysdescr_ptr, len); break; case 2: /* sysObjectID */ objectidncpy((s32_t*)value, (s32_t*)sysobjid.id, (u8_t)(len / sizeof(s32_t))); break; case 3: /* sysUpTime */ { - snmp_get_sysuptime(value); + snmp_get_sysuptime((u32_t*)value); } break; case 4: /* sysContact */ - ocstrncpy(value,syscontact_ptr,len); + ocstrncpy((u8_t*)value, syscontact_ptr, len); break; case 5: /* sysName */ - ocstrncpy(value,sysname_ptr,len); + ocstrncpy((u8_t*)value, sysname_ptr, len); break; case 6: /* sysLocation */ - ocstrncpy(value,syslocation_ptr,len); + ocstrncpy((u8_t*)value, syslocation_ptr, len); break; case 7: /* sysServices */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = sysservices; } break; @@ -2240,7 +2239,8 @@ system_set_test(struct obj_def *od, u16_t len, void *value) LWIP_UNUSED_ARG(value); set_ok = 0; - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 4: /* sysContact */ @@ -2273,20 +2273,22 @@ system_set_value(struct obj_def *od, u16_t len, void *value) { u8_t id; - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid len", len <= 0xff); + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 4: /* sysContact */ - ocstrncpy(syscontact_ptr,value,len); - *syscontact_len_ptr = len; + ocstrncpy(syscontact_ptr, (u8_t*)value, len); + *syscontact_len_ptr = (u8_t)len; break; case 5: /* sysName */ - ocstrncpy(sysname_ptr,value,len); - *sysname_len_ptr = len; + ocstrncpy(sysname_ptr, (u8_t*)value, len); + *sysname_len_ptr = (u8_t)len; break; case 6: /* sysLocation */ - ocstrncpy(syslocation_ptr,value,len); - *syslocation_len_ptr = len; + ocstrncpy(syslocation_ptr, (u8_t*)value, len); + *syslocation_len_ptr = (u8_t)len; break; }; } @@ -2335,7 +2337,7 @@ interfaces_get_value(struct obj_def *od, u16_t len, void *value) LWIP_UNUSED_ARG(len); if (od->id_inst_ptr[0] == 1) { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = iflist_root.count; } } @@ -2360,7 +2362,8 @@ ifentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ifentry.%"U16_F"\n",(u16_t)id)); switch (id) { @@ -2461,43 +2464,43 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) u8_t id; snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ifIndex */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* ifDescr */ - ocstrncpy(value,(u8_t*)netif->name,len); + ocstrncpy((u8_t*)value, (u8_t*)netif->name, len); break; case 3: /* ifType */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = netif->link_type; } break; case 4: /* ifMtu */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = netif->mtu; } break; case 5: /* ifSpeed */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->link_speed; } break; case 6: /* ifPhysAddress */ - ocstrncpy(value,netif->hwaddr,len); + ocstrncpy((u8_t*)value, netif->hwaddr, len); break; case 7: /* ifAdminStatus */ -#if LWIP_NETIF_LINK_CALLBACK { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; if (netif_is_up(netif)) { if (netif_is_link_up(netif)) @@ -2515,10 +2518,9 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) } } break; -#endif case 8: /* ifOperStatus */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; if (netif_is_up(netif)) { *sint_ptr = 1; @@ -2531,31 +2533,31 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) break; case 9: /* ifLastChange */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ts; } break; case 10: /* ifInOctets */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinoctets; } break; case 11: /* ifInUcastPkts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinucastpkts; } break; case 12: /* ifInNUcastPkts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifinnucastpkts; } break; case 13: /* ifInDiscarts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifindiscards; } break; @@ -2563,45 +2565,45 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) case 15: /* ifInUnkownProtos */ /** @todo add these counters! */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; case 16: /* ifOutOctets */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutoctets; } break; case 17: /* ifOutUcastPkts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutucastpkts; } break; case 18: /* ifOutNUcastPkts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutnucastpkts; } break; case 19: /* ifOutDiscarts */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = netif->ifoutdiscards; } break; case 20: /* ifOutErrors */ /** @todo add this counter! */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; case 21: /* ifOutQLen */ /** @todo figure out if this must be 0 (no queue) or 1? */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = 0; } break; @@ -2613,19 +2615,20 @@ ifentry_get_value(struct obj_def *od, u16_t len, void *value) #if !SNMP_SAFE_REQUESTS static u8_t -ifentry_set_test (struct obj_def *od, u16_t len, void *value) +ifentry_set_test(struct obj_def *od, u16_t len, void *value) { struct netif *netif; u8_t id, set_ok; + LWIP_UNUSED_ARG(len); set_ok = 0; snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - id = od->id_inst_ptr[0]; + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 7: /* ifAdminStatus */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; if (*sint_ptr == 1 || *sint_ptr == 2) set_ok = 1; } @@ -2635,18 +2638,19 @@ ifentry_set_test (struct obj_def *od, u16_t len, void *value) } static void -ifentry_set_value (struct obj_def *od, u16_t len, void *value) +ifentry_set_value(struct obj_def *od, u16_t len, void *value) { struct netif *netif; u8_t id; + LWIP_UNUSED_ARG(len); snmp_ifindextonetif(od->id_inst_ptr[1], &netif); - id = od->id_inst_ptr[0]; + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 7: /* ifAdminStatus */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; if (*sint_ptr == 1) { netif_set_up(netif); @@ -2719,9 +2723,9 @@ atentry_get_value(struct obj_def *od, u16_t len, void *value) #if LWIP_ARP u8_t id; struct eth_addr* ethaddr_ret; - struct ip_addr* ipaddr_ret; + ip_addr_t* ipaddr_ret; #endif /* LWIP_ARP */ - struct ip_addr ip; + ip_addr_t ip; struct netif *netif; LWIP_UNUSED_ARG(len); @@ -2729,30 +2733,30 @@ atentry_get_value(struct obj_def *od, u16_t len, void *value) snmp_ifindextonetif(od->id_inst_ptr[1], &netif); snmp_oidtoip(&od->id_inst_ptr[2], &ip); - ip.addr = htonl(ip.addr); #if LWIP_ARP /** @todo implement a netif_find_addr */ if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) { - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* atIfIndex */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* atPhysAddress */ { - struct eth_addr *dst = value; + struct eth_addr *dst = (struct eth_addr*)value; *dst = *ethaddr_ret; } break; case 3: /* atNetAddress */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; *dst = *ipaddr_ret; } @@ -2775,7 +2779,8 @@ ip_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def ip.%"U16_F".0\n",(u16_t)id)); switch (id) { @@ -2833,12 +2838,13 @@ ip_get_value(struct obj_def *od, u16_t len, void *value) u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipForwarding */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; #if IP_FORWARD /* forwarding */ *sint_ptr = 1; @@ -2850,73 +2856,73 @@ ip_get_value(struct obj_def *od, u16_t len, void *value) break; case 2: /* ipDefaultTTL */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = IP_DEFAULT_TTL; } break; case 3: /* ipInReceives */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinreceives; } break; case 4: /* ipInHdrErrors */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinhdrerrors; } break; case 5: /* ipInAddrErrors */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinaddrerrors; } break; case 6: /* ipForwDatagrams */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipforwdatagrams; } break; case 7: /* ipInUnknownProtos */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipinunknownprotos; } break; case 8: /* ipInDiscards */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipindiscards; } break; case 9: /* ipInDelivers */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipindelivers; } break; case 10: /* ipOutRequests */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutrequests; } break; case 11: /* ipOutDiscards */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutdiscards; } break; case 12: /* ipOutNoRoutes */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipoutnoroutes; } break; case 13: /* ipReasmTimeout */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; #if IP_REASSEMBLY *sint_ptr = IP_REASS_MAXAGE; #else @@ -2926,44 +2932,44 @@ ip_get_value(struct obj_def *od, u16_t len, void *value) break; case 14: /* ipReasmReqds */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmreqds; } break; case 15: /* ipReasmOKs */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmoks; } break; case 16: /* ipReasmFails */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipreasmfails; } break; case 17: /* ipFragOKs */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragoks; } break; case 18: /* ipFragFails */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragfails; } break; case 19: /* ipFragCreates */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = ipfragcreates; } break; case 23: /* ipRoutingDiscards */ /** @todo can lwIP discard routes at all?? hardwire this to 0?? */ { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; *uint_ptr = iproutingdiscards; } break; @@ -2984,11 +2990,12 @@ static u8_t ip_set_test(struct obj_def *od, u16_t len, void *value) { u8_t id, set_ok; - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; LWIP_UNUSED_ARG(len); set_ok = 0; - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipForwarding */ @@ -3027,7 +3034,8 @@ ip_addrentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; switch (id) { case 1: /* ipAdEntAddr */ @@ -3063,12 +3071,11 @@ ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; u16_t ifidx; - struct ip_addr ip; + ip_addr_t ip; struct netif *netif = netif_list; LWIP_UNUSED_ARG(len); snmp_oidtoip(&od->id_inst_ptr[1], &ip); - ip.addr = htonl(ip.addr); ifidx = 0; while ((netif != NULL) && !ip_addr_cmp(&ip, &netif->ip_addr)) { @@ -3078,39 +3085,40 @@ ip_addrentry_get_value(struct obj_def *od, u16_t len, void *value) if (netif != NULL) { - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipAdEntAddr */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; *dst = netif->ip_addr; } break; case 2: /* ipAdEntIfIndex */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = ifidx + 1; } break; case 3: /* ipAdEntNetMask */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; *dst = netif->netmask; } break; case 4: /* ipAdEntBcastAddr */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; /* lwIP oddity, there's no broadcast address in the netif we can rely on */ - *sint_ptr = ip_addr_broadcast.addr & 1; + *sint_ptr = IPADDR_BROADCAST & 1; } break; case 5: /* ipAdEntReasmMaxSize */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; #if IP_REASSEMBLY /* @todo The theoretical maximum is IP_REASS_MAX_PBUFS * size of the pbufs, * but only if receiving one fragmented packet at a time. @@ -3148,7 +3156,8 @@ ip_rteentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; switch (id) { case 1: /* ipRouteDest */ @@ -3202,15 +3211,14 @@ static void ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) { struct netif *netif; - struct ip_addr dest; + ip_addr_t dest; s32_t *ident; u8_t id; ident = od->id_inst_ptr; snmp_oidtoip(&ident[1], &dest); - dest.addr = htonl(dest.addr); - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* ip_route() uses default netif for default route */ netif = netif_default; @@ -3227,37 +3235,38 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) } if (netif != NULL) { - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; switch (id) { case 1: /* ipRouteDest */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* default rte has 0.0.0.0 dest */ - dst->addr = 0; + ip_addr_set_zero(dst); } else { /* netifs have netaddress dest */ - dst->addr = netif->ip_addr.addr & netif->netmask.addr; + ip_addr_get_network(dst, &netif->ip_addr, &netif->netmask); } } break; case 2: /* ipRouteIfIndex */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; snmp_netiftoifindex(netif, sint_ptr); } break; case 3: /* ipRouteMetric1 */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* default rte has metric 1 */ *sint_ptr = 1; @@ -3274,16 +3283,16 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) case 6: /* ipRouteMetric4 */ case 12: /* ipRouteMetric5 */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; /* not used */ *sint_ptr = -1; } break; case 7: /* ipRouteNextHop */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* default rte: gateway */ *dst = netif->gw; @@ -3297,9 +3306,9 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) break; case 8: /* ipRouteType */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* default rte is indirect */ *sint_ptr = 4; @@ -3313,14 +3322,14 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) break; case 9: /* ipRouteProto */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; /* locally defined routes */ *sint_ptr = 2; } break; case 10: /* ipRouteAge */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; /** @todo (sysuptime - timestamp last change) / 100 @see snmp_insert_iprteidx_tree() */ *sint_ptr = 0; @@ -3328,12 +3337,12 @@ ip_rteentry_get_value(struct obj_def *od, u16_t len, void *value) break; case 11: /* ipRouteMask */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; - if (dest.addr == 0) + if (ip_addr_isany(&dest)) { /* default rte use 0.0.0.0 mask */ - dst->addr = 0; + ip_addr_set_zero(dst); } else { @@ -3363,7 +3372,8 @@ ip_ntomentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; switch (id) { case 1: /* ipNetToMediaIfIndex */ @@ -3404,9 +3414,9 @@ ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) #if LWIP_ARP u8_t id; struct eth_addr* ethaddr_ret; - struct ip_addr* ipaddr_ret; + ip_addr_t* ipaddr_ret; #endif /* LWIP_ARP */ - struct ip_addr ip; + ip_addr_t ip; struct netif *netif; LWIP_UNUSED_ARG(len); @@ -3414,37 +3424,37 @@ ip_ntomentry_get_value(struct obj_def *od, u16_t len, void *value) snmp_ifindextonetif(od->id_inst_ptr[1], &netif); snmp_oidtoip(&od->id_inst_ptr[2], &ip); - ip.addr = htonl(ip.addr); #if LWIP_ARP /** @todo implement a netif_find_addr */ if (etharp_find_addr(netif, &ip, ðaddr_ret, &ipaddr_ret) > -1) { - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* ipNetToMediaIfIndex */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = od->id_inst_ptr[1]; } break; case 2: /* ipNetToMediaPhysAddress */ { - struct eth_addr *dst = value; + struct eth_addr *dst = (struct eth_addr*)value; *dst = *ethaddr_ret; } break; case 3: /* ipNetToMediaNetAddress */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; *dst = *ipaddr_ret; } break; case 4: /* ipNetToMediaType */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; /* dynamic (?) */ *sint_ptr = 3; } @@ -3481,11 +3491,12 @@ icmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) static void icmp_get_value(struct obj_def *od, u16_t len, void *value) { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* icmpInMsgs */ @@ -3584,7 +3595,8 @@ tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; LWIP_DEBUGF(SNMP_MIB_DEBUG,("get_object_def tcp.%"U16_F".0\n",(u16_t)id)); switch (id) @@ -3634,12 +3646,13 @@ tcp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) static void tcp_get_value(struct obj_def *od, u16_t len, void *value) { - u32_t *uint_ptr = value; - s32_t *sint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; + s32_t *sint_ptr = (s32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* tcpRtoAlgorithm, vanj(4) */ @@ -3759,16 +3772,14 @@ tcpconnentry_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) static void tcpconnentry_get_value(struct obj_def *od, u16_t len, void *value) { - struct ip_addr lip, rip; + ip_addr_t lip, rip; u16_t lport, rport; s32_t *ident; ident = od->id_inst_ptr; snmp_oidtoip(&ident[1], &lip); - lip.addr = htonl(lip.addr); lport = ident[5]; snmp_oidtoip(&ident[6], &rip); - rip.addr = htonl(rip.addr); rport = ident[10]; /** @todo find matching PCB */ @@ -3803,11 +3814,12 @@ udp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) static void udp_get_value(struct obj_def *od, u16_t len, void *value) { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* udpInDatagrams */ @@ -3869,17 +3881,17 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value) { u8_t id; struct udp_pcb *pcb; - struct ip_addr ip; + ip_addr_t ip; u16_t port; LWIP_UNUSED_ARG(len); snmp_oidtoip(&od->id_inst_ptr[1], &ip); - ip.addr = htonl(ip.addr); - port = od->id_inst_ptr[5]; + LWIP_ASSERT("invalid port", (od->id_inst_ptr[5] >= 0) && (od->id_inst_ptr[5] <= 0xffff)); + port = (u16_t)od->id_inst_ptr[5]; pcb = udp_pcbs; while ((pcb != NULL) && - !((pcb->local_ip.addr == ip.addr) && + !(ip_addr_cmp(&pcb->local_ip, &ip) && (pcb->local_port == port))) { pcb = pcb->next; @@ -3887,18 +3899,19 @@ udpentry_get_value(struct obj_def *od, u16_t len, void *value) if (pcb != NULL) { - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* udpLocalAddress */ { - struct ip_addr *dst = value; + ip_addr_t *dst = (ip_addr_t*)value; *dst = pcb->local_ip; } break; case 2: /* udpLocalPort */ { - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; *sint_ptr = pcb->local_port; } break; @@ -3919,7 +3932,8 @@ snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) od->id_inst_len = ident_len; od->id_inst_ptr = ident; - id = ident[0]; + LWIP_ASSERT("invalid id", (ident[0] >= 0) && (ident[0] <= 0xff)); + id = (u8_t)ident[0]; switch (id) { case 1: /* snmpInPkts */ @@ -3976,11 +3990,12 @@ snmp_get_object_def(u8_t ident_len, s32_t *ident, struct obj_def *od) static void snmp_get_value(struct obj_def *od, u16_t len, void *value) { - u32_t *uint_ptr = value; + u32_t *uint_ptr = (u32_t*)value; u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; switch (id) { case 1: /* snmpInPkts */ @@ -4084,11 +4099,12 @@ snmp_set_test(struct obj_def *od, u16_t len, void *value) LWIP_UNUSED_ARG(len); set_ok = 0; - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; if (id == 30) { /* snmpEnableAuthenTraps */ - s32_t *sint_ptr = value; + s32_t *sint_ptr = (s32_t*)value; if (snmpenableauthentraps_ptr != &snmpenableauthentraps_default) { @@ -4116,12 +4132,14 @@ snmp_set_value(struct obj_def *od, u16_t len, void *value) u8_t id; LWIP_UNUSED_ARG(len); - id = od->id_inst_ptr[0]; + LWIP_ASSERT("invalid id", (od->id_inst_ptr[0] >= 0) && (od->id_inst_ptr[0] <= 0xff)); + id = (u8_t)od->id_inst_ptr[0]; if (id == 30) { /* snmpEnableAuthenTraps */ - s32_t *sint_ptr = value; - *snmpenableauthentraps_ptr = *sint_ptr; + /* @todo @fixme: which kind of pointer is 'value'? s32_t or u8_t??? */ + u8_t *ptr = (u8_t*)value; + *snmpenableauthentraps_ptr = *ptr; } } diff --git a/core/lwip/src/core/snmp/mib_structs.c b/core/lwip/src/core/snmp/mib_structs.c index 39a29496..2f185cb4 100644 --- a/core/lwip/src/core/snmp/mib_structs.c +++ b/core/lwip/src/core/snmp/mib_structs.c @@ -37,7 +37,8 @@ #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ #include "lwip/snmp_structs.h" -#include "lwip/mem.h" +#include "lwip/memp.h" +#include "lwip/netif.h" /** .iso.org.dod.internet address prefix, @see snmp_iso_*() */ const s32_t prefix[4] = {1, 3, 6, 1}; @@ -94,7 +95,7 @@ void snmp_ifindextonetif(s32_t ifindex, struct netif **netif) { struct netif *nif = netif_list; - u16_t i, ifidx; + s32_t i, ifidx; ifidx = ifindex - 1; i = 0; @@ -132,18 +133,9 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx) * @param ip points to output struct */ void -snmp_oidtoip(s32_t *ident, struct ip_addr *ip) +snmp_oidtoip(s32_t *ident, ip_addr_t *ip) { - u32_t ipa; - - ipa = ident[0]; - ipa <<= 8; - ipa |= ident[1]; - ipa <<= 8; - ipa |= ident[2]; - ipa <<= 8; - ipa |= ident[3]; - ip->addr = ipa; + IP4_ADDR(ip, ident[0], ident[1], ident[2], ident[3]); } /** @@ -152,15 +144,12 @@ snmp_oidtoip(s32_t *ident, struct ip_addr *ip) * @param ident points to s32_t ident[4] output */ void -snmp_iptooid(struct ip_addr *ip, s32_t *ident) +snmp_iptooid(ip_addr_t *ip, s32_t *ident) { - u32_t ipa; - - ipa = ip->addr; - ident[0] = (ipa >> 24) & 0xff; - ident[1] = (ipa >> 16) & 0xff; - ident[2] = (ipa >> 8) & 0xff; - ident[3] = ipa & 0xff; + ident[0] = ip4_addr1(ip); + ident[1] = ip4_addr2(ip); + ident[2] = ip4_addr3(ip); + ident[3] = ip4_addr4(ip); } struct mib_list_node * @@ -168,7 +157,7 @@ snmp_mib_ln_alloc(s32_t id) { struct mib_list_node *ln; - ln = (struct mib_list_node *)mem_malloc(sizeof(struct mib_list_node)); + ln = (struct mib_list_node *)memp_malloc(MEMP_SNMP_NODE); if (ln != NULL) { ln->prev = NULL; @@ -182,7 +171,7 @@ snmp_mib_ln_alloc(s32_t id) void snmp_mib_ln_free(struct mib_list_node *ln) { - mem_free(ln); + memp_free(MEMP_SNMP_NODE, ln); } struct mib_list_rootnode * @@ -190,7 +179,7 @@ snmp_mib_lrn_alloc(void) { struct mib_list_rootnode *lrn; - lrn = (struct mib_list_rootnode*)mem_malloc(sizeof(struct mib_list_rootnode)); + lrn = (struct mib_list_rootnode*)memp_malloc(MEMP_SNMP_ROOTNODE); if (lrn != NULL) { lrn->get_object_def = noleafs_get_object_def; @@ -209,7 +198,7 @@ snmp_mib_lrn_alloc(void) void snmp_mib_lrn_free(struct mib_list_rootnode *lrn) { - mem_free(lrn); + memp_free(MEMP_SNMP_ROOTNODE, lrn); } /** @@ -456,7 +445,7 @@ snmp_mib_node_delete(struct mib_list_rootnode *rn, struct mib_list_node *n) * @param node points to the root of the tree ('.internet') * @param ident_len the length of the supplied object identifier * @param ident points to the array of sub identifiers - * @param np points to the found object instance (rerurn) + * @param np points to the found object instance (return) * @return pointer to the requested parent (!) node if success, NULL otherwise */ struct mib_node * @@ -753,7 +742,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); /* non-leaf, store right child ptr and id */ - j = i + 1; + LWIP_ASSERT("i < 0xff", i < 0xff); + j = (u8_t)i + 1; while ((j < an->maxlength) && (empty_table(an->nptr[j]))) { j++; @@ -995,7 +985,8 @@ snmp_expand_tree(struct mib_node *node, u8_t ident_len, s32_t *ident, struct snm LWIP_DEBUGF(SNMP_MIB_DEBUG,("non-leaf node\n")); /* non-leaf, store right child ptr and id */ - j = i + 1; + LWIP_ASSERT("i < 0xff", i < 0xff); + j = (u8_t)i + 1; if (j < len) { /* right node is the current external node */ diff --git a/core/lwip/src/core/snmp/msg_in.c b/core/lwip/src/core/snmp/msg_in.c index d0c3c753..2dfb55b2 100644 --- a/core/lwip/src/core/snmp/msg_in.c +++ b/core/lwip/src/core/snmp/msg_in.c @@ -36,14 +36,14 @@ #if LWIP_SNMP /* don't build if not configured for use in lwipopts.h */ -#include "lwip/ip_addr.h" -#include "lwip/mem.h" -#include "lwip/udp.h" -#include "lwip/stats.h" #include "lwip/snmp.h" #include "lwip/snmp_asn1.h" #include "lwip/snmp_msg.h" #include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/memp.h" +#include "lwip/udp.h" +#include "lwip/stats.h" #include <string.h> @@ -58,7 +58,7 @@ struct snmp_msg_pstat msg_input_list[SNMP_CONCURRENT_REQUESTS]; /* UDP Protocol Control Block */ struct udp_pcb *snmp1_pcb; -static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port); +static void snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port); static err_t snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); static err_t snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_msg_pstat *m_stat); @@ -88,6 +88,15 @@ snmp_init(void) msg_ps++; } trap_msg.pcb = snmp1_pcb; + +#ifdef SNMP_PRIVATE_MIB_INIT + /* If defined, rhis must be a function-like define to initialize the + * private MIB after the stack has been initialized. + * The private MIB can also be initialized in tcpip_callback (or after + * the stack is initialized), this define is only for convenience. */ + SNMP_PRIVATE_MIB_INIT(); +#endif /* SNMP_PRIVATE_MIB_INIT */ + /* The coldstart trap will only be output if our outgoing interface is up & configured */ snmp_coldstart_trap(); @@ -150,7 +159,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) /* translate answer into a known lifeform */ en->get_object_def_a(request_id, np.ident_len, np.ident, &msg_ps->ext_object_def); - if (msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) + if ((msg_ps->ext_object_def.instance != MIB_OBJECT_NONE) && + (msg_ps->ext_object_def.access & MIB_ACCESS_READ)) { msg_ps->state = SNMP_MSG_EXTERNAL_GET_VALUE; en->get_value_q(request_id, &msg_ps->ext_object_def); @@ -171,7 +181,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) en = msg_ps->ext_mib_node; /* allocate output varbind */ - vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); LWIP_ASSERT("vb != NULL",vb != NULL); if (vb != NULL) { @@ -186,10 +196,12 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) msg_ps->vb_ptr->ident_len = 0; vb->value_type = msg_ps->ext_object_def.asn_type; - vb->value_len = msg_ps->ext_object_def.v_len; + LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); + vb->value_len = (u8_t)msg_ps->ext_object_def.v_len; if (vb->value_len > 0) { - vb->value = mem_malloc(vb->value_len); + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); + vb->value = memp_malloc(MEMP_SNMP_VALUE); LWIP_ASSERT("vb->value != NULL",vb->value != NULL); if (vb->value != NULL) { @@ -205,7 +217,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: no variable space\n")); msg_ps->vb_ptr->ident = vb->ident; msg_ps->vb_ptr->ident_len = vb->ident_len; - mem_free(vb); + memp_free(MEMP_SNMP_VARBIND, vb); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } @@ -268,7 +280,8 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; mn->get_object_def(np.ident_len, np.ident, &object_def); - if (object_def.instance != MIB_OBJECT_NONE) + if ((object_def.instance != MIB_OBJECT_NONE) && + (object_def.access & MIB_ACCESS_READ)) { mn = mn; } @@ -283,7 +296,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; /* allocate output varbind */ - vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); LWIP_ASSERT("vb != NULL",vb != NULL); if (vb != NULL) { @@ -298,10 +311,13 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) msg_ps->vb_ptr->ident_len = 0; vb->value_type = object_def.asn_type; - vb->value_len = object_def.v_len; + LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); + vb->value_len = (u8_t)object_def.v_len; if (vb->value_len > 0) { - vb->value = mem_malloc(vb->value_len); + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", + vb->value_len <= SNMP_MAX_VALUE_SIZE); + vb->value = memp_malloc(MEMP_SNMP_VALUE); LWIP_ASSERT("vb->value != NULL",vb->value != NULL); if (vb->value != NULL) { @@ -315,7 +331,7 @@ snmp_msg_get_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_msg_event: couldn't allocate variable space\n")); msg_ps->vb_ptr->ident = vb->ident; msg_ps->vb_ptr->ident_len = vb->ident_len; - mem_free(vb); + memp_free(MEMP_SNMP_VARBIND, vb); snmp_error_response(msg_ps,SNMP_ES_TOOBIG); } } @@ -394,9 +410,10 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) /* get_value() answer */ en = msg_ps->ext_mib_node; + LWIP_ASSERT("invalid length", msg_ps->ext_object_def.v_len <= 0xff); vb = snmp_varbind_alloc(&msg_ps->ext_oid, msg_ps->ext_object_def.asn_type, - msg_ps->ext_object_def.v_len); + (u8_t)msg_ps->ext_object_def.v_len); if (vb != NULL) { en->get_value_a(request_id, &msg_ps->ext_object_def, vb->value_len, vb->value); @@ -468,7 +485,8 @@ snmp_msg_getnext_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) msg_ps->state = SNMP_MSG_INTERNAL_GET_OBJDEF; mn->get_object_def(1, &oid.id[oid.len - 1], &object_def); - vb = snmp_varbind_alloc(&oid, object_def.asn_type, object_def.v_len); + LWIP_ASSERT("invalid length", object_def.v_len <= 0xff); + vb = snmp_varbind_alloc(&oid, object_def.asn_type, (u8_t)object_def.v_len); if (vb != NULL) { msg_ps->state = SNMP_MSG_INTERNAL_GET_VALUE; @@ -538,7 +556,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) /* set_test() answer*/ en = msg_ps->ext_mib_node; - if (msg_ps->ext_object_def.access == MIB_OBJECT_READ_WRITE) + if (msg_ps->ext_object_def.access & MIB_ACCESS_WRITE) { if ((msg_ps->ext_object_def.asn_type == msg_ps->vb_ptr->value_type) && (en->set_test_a(request_id,&msg_ps->ext_object_def, @@ -653,7 +671,7 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps) { msg_ps->state = SNMP_MSG_INTERNAL_SET_TEST; - if (object_def.access == MIB_OBJECT_READ_WRITE) + if (object_def.access & MIB_ACCESS_WRITE) { if ((object_def.asn_type == msg_ps->vb_ptr->value_type) && (mn->set_test(&object_def,msg_ps->vb_ptr->value_len,msg_ps->vb_ptr->value) != 0)) @@ -788,123 +806,85 @@ snmp_msg_event(u8_t request_id) /* lwIP UDP receive callback function */ static void -snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port) +snmp_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { - struct udp_hdr *udphdr; + struct snmp_msg_pstat *msg_ps; + u8_t req_idx; + err_t err_ret; + u16_t payload_len = p->tot_len; + u16_t payload_ofs = 0; + u16_t varbind_ofs = 0; /* suppress unused argument warning */ LWIP_UNUSED_ARG(arg); - /* peek in the UDP header (goto IP payload) */ - if(pbuf_header(p, UDP_HLEN)){ - LWIP_ASSERT("Can't move to UDP header", 0); + + /* traverse input message process list, look for SNMP_MSG_EMPTY */ + msg_ps = &msg_input_list[0]; + req_idx = 0; + while ((req_idx < SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) + { + req_idx++; + msg_ps++; + } + if (req_idx == SNMP_CONCURRENT_REQUESTS) + { + /* exceeding number of concurrent requests */ pbuf_free(p); return; } - udphdr = p->payload; - /* check if datagram is really directed at us (including broadcast requests) */ - if ((pcb == snmp1_pcb) && (ntohs(udphdr->dest) == SNMP_IN_PORT)) + /* accepting request */ + snmp_inc_snmpinpkts(); + /* record used 'protocol control block' */ + msg_ps->pcb = pcb; + /* source address (network order) */ + msg_ps->sip = *addr; + /* source port (host order (lwIP oddity)) */ + msg_ps->sp = port; + + /* check total length, version, community, pdu type */ + err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); + /* Only accept requests and requests without error (be robust) */ + /* Reject response and trap headers or error requests as input! */ + if ((err_ret != ERR_OK) || + ((msg_ps->rt != SNMP_ASN1_PDU_GET_REQ) && + (msg_ps->rt != SNMP_ASN1_PDU_GET_NEXT_REQ) && + (msg_ps->rt != SNMP_ASN1_PDU_SET_REQ)) || + ((msg_ps->error_status != SNMP_ES_NOERROR) || + (msg_ps->error_index != 0)) ) { - struct snmp_msg_pstat *msg_ps; - u8_t req_idx; - - /* traverse input message process list, look for SNMP_MSG_EMPTY */ - msg_ps = &msg_input_list[0]; - req_idx = 0; - while ((req_idx<SNMP_CONCURRENT_REQUESTS) && (msg_ps->state != SNMP_MSG_EMPTY)) - { - req_idx++; - msg_ps++; - } - if (req_idx != SNMP_CONCURRENT_REQUESTS) - { - err_t err_ret; - u16_t payload_len; - u16_t payload_ofs; - u16_t varbind_ofs = 0; - - /* accepting request */ - snmp_inc_snmpinpkts(); - /* record used 'protocol control block' */ - msg_ps->pcb = pcb; - /* source address (network order) */ - msg_ps->sip = *addr; - /* source port (host order (lwIP oddity)) */ - msg_ps->sp = port; - /* read UDP payload length from UDP header */ - payload_len = ntohs(udphdr->len) - UDP_HLEN; - - /* adjust to UDP payload */ - payload_ofs = UDP_HLEN; - - /* check total length, version, community, pdu type */ - err_ret = snmp_pdu_header_check(p, payload_ofs, payload_len, &varbind_ofs, msg_ps); - if (((msg_ps->rt == SNMP_ASN1_PDU_GET_REQ) || - (msg_ps->rt == SNMP_ASN1_PDU_GET_NEXT_REQ) || - (msg_ps->rt == SNMP_ASN1_PDU_SET_REQ)) && - ((msg_ps->error_status == SNMP_ES_NOERROR) && - (msg_ps->error_index == 0)) ) - { - /* Only accept requests and requests without error (be robust) */ - err_ret = err_ret; - } - else - { - /* Reject response and trap headers or error requests as input! */ - err_ret = ERR_ARG; - } - if (err_ret == ERR_OK) - { - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); - - /* Builds a list of variable bindings. Copy the varbinds from the pbuf - chain to glue them when these are divided over two or more pbuf's. */ - err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); - if ((err_ret == ERR_OK) && (msg_ps->invb.count > 0)) - { - /* we've decoded the incoming message, release input msg now */ - pbuf_free(p); - - msg_ps->error_status = SNMP_ES_NOERROR; - msg_ps->error_index = 0; - /* find object for each variable binding */ - msg_ps->state = SNMP_MSG_SEARCH_OBJ; - /* first variable binding from list to inspect */ - msg_ps->vb_idx = 0; - - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); - - /* handle input event and as much objects as possible in one go */ - snmp_msg_event(req_idx); - } - else - { - /* varbind-list decode failed, or varbind list empty. - drop request silently, do not return error! - (errors are only returned for a specific varbind failure) */ - pbuf_free(p); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); - } - } - else - { - /* header check failed - drop request silently, do not return error! */ - pbuf_free(p); - LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); - } - } - else - { - /* exceeding number of concurrent requests */ - pbuf_free(p); - } + /* header check failed drop request silently, do not return error! */ + pbuf_free(p); + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_header_check() failed\n")); + return; } - else + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv ok, community %s\n", msg_ps->community)); + + /* Builds a list of variable bindings. Copy the varbinds from the pbuf + chain to glue them when these are divided over two or more pbuf's. */ + err_ret = snmp_pdu_dec_varbindlist(p, varbind_ofs, &varbind_ofs, msg_ps); + /* we've decoded the incoming message, release input msg now */ + pbuf_free(p); + if ((err_ret != ERR_OK) || (msg_ps->invb.count == 0)) { - /* datagram not for us */ - pbuf_free(p); + /* varbind-list decode failed, or varbind list empty. + drop request silently, do not return error! + (errors are only returned for a specific varbind failure) */ + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_pdu_dec_varbindlist() failed\n")); + return; } + + msg_ps->error_status = SNMP_ES_NOERROR; + msg_ps->error_index = 0; + /* find object for each variable binding */ + msg_ps->state = SNMP_MSG_SEARCH_OBJ; + /* first variable binding from list to inspect */ + msg_ps->vb_idx = 0; + + LWIP_DEBUGF(SNMP_MSG_DEBUG, ("snmp_recv varbind cnt=%"U16_F"\n",(u16_t)msg_ps->invb.count)); + + /* handle input event and as much objects as possible in one go */ + snmp_msg_event(req_idx); } /** @@ -978,7 +958,7 @@ snmp_pdu_header_check(struct pbuf *p, u16_t ofs, u16_t pdu_len, u16_t *ofs_ret, /* add zero terminator */ len = ((len < (SNMP_COMMUNITY_STR_LEN))?(len):(SNMP_COMMUNITY_STR_LEN)); m_stat->community[len] = 0; - m_stat->com_strlen = len; + m_stat->com_strlen = (u8_t)len; if (strncmp(snmp_publiccommunity, (const char*)m_stat->community, SNMP_COMMUNITY_STR_LEN) != 0) { /** @todo: move this if we need to check more names */ @@ -1195,7 +1175,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ vb = snmp_varbind_alloc(&oid, type, sizeof(s32_t)); if (vb != NULL) { - s32_t *vptr = vb->value; + s32_t *vptr = (s32_t*)vb->value; derr = snmp_asn1_dec_s32t(p, ofs + 1 + len_octets, len, vptr); snmp_varbind_tail_add(&m_stat->invb, vb); @@ -1211,7 +1191,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ vb = snmp_varbind_alloc(&oid, type, sizeof(u32_t)); if (vb != NULL) { - u32_t *vptr = vb->value; + u32_t *vptr = (u32_t*)vb->value; derr = snmp_asn1_dec_u32t(p, ofs + 1 + len_octets, len, vptr); snmp_varbind_tail_add(&m_stat->invb, vb); @@ -1223,10 +1203,11 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): - vb = snmp_varbind_alloc(&oid, type, len); + LWIP_ASSERT("invalid length", len <= 0xff); + vb = snmp_varbind_alloc(&oid, type, (u8_t)len); if (vb != NULL) { - derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); + derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); snmp_varbind_tail_add(&m_stat->invb, vb); } else @@ -1254,7 +1235,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ if (vb != NULL) { u8_t i = oid_value.len; - s32_t *vptr = vb->value; + s32_t *vptr = (s32_t*)vb->value; while(i > 0) { @@ -1277,7 +1258,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_ vb = snmp_varbind_alloc(&oid, type, 4); if (vb != NULL) { - derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, vb->value); + derr = snmp_asn1_dec_raw(p, ofs + 1 + len_octets, len, vb->value_len, (u8_t*)vb->value); snmp_varbind_tail_add(&m_stat->invb, vb); } else @@ -1323,7 +1304,7 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) { struct snmp_varbind *vb; - vb = (struct snmp_varbind *)mem_malloc(sizeof(struct snmp_varbind)); + vb = (struct snmp_varbind *)memp_malloc(MEMP_SNMP_VARBIND); LWIP_ASSERT("vb != NULL",vb != NULL); if (vb != NULL) { @@ -1335,12 +1316,13 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) vb->ident_len = i; if (i > 0) { + LWIP_ASSERT("SNMP_MAX_TREE_DEPTH is configured too low", i <= SNMP_MAX_TREE_DEPTH); /* allocate array of s32_t for our object identifier */ - vb->ident = (s32_t*)mem_malloc(sizeof(s32_t) * i); + vb->ident = (s32_t*)memp_malloc(MEMP_SNMP_VALUE); LWIP_ASSERT("vb->ident != NULL",vb->ident != NULL); if (vb->ident == NULL) { - mem_free(vb); + memp_free(MEMP_SNMP_VARBIND, vb); return NULL; } while(i > 0) @@ -1358,16 +1340,17 @@ snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len) vb->value_len = len; if (len > 0) { + LWIP_ASSERT("SNMP_MAX_OCTET_STRING_LEN is configured too low", vb->value_len <= SNMP_MAX_VALUE_SIZE); /* allocate raw bytes for our object value */ - vb->value = mem_malloc(len); + vb->value = memp_malloc(MEMP_SNMP_VALUE); LWIP_ASSERT("vb->value != NULL",vb->value != NULL); if (vb->value == NULL) { if (vb->ident != NULL) { - mem_free(vb->ident); + memp_free(MEMP_SNMP_VALUE, vb->ident); } - mem_free(vb); + memp_free(MEMP_SNMP_VARBIND, vb); return NULL; } } @@ -1385,13 +1368,13 @@ snmp_varbind_free(struct snmp_varbind *vb) { if (vb->value != NULL ) { - mem_free(vb->value); + memp_free(MEMP_SNMP_VALUE, vb->value); } if (vb->ident != NULL ) { - mem_free(vb->ident); + memp_free(MEMP_SNMP_VALUE, vb->ident); } - mem_free(vb); + memp_free(MEMP_SNMP_VARBIND, vb); } void diff --git a/core/lwip/src/core/snmp/msg_out.c b/core/lwip/src/core/snmp/msg_out.c index b705aaca..4778bee6 100644 --- a/core/lwip/src/core/snmp/msg_out.c +++ b/core/lwip/src/core/snmp/msg_out.c @@ -55,7 +55,7 @@ struct snmp_trap_dst { /* destination IP address in network order */ - struct ip_addr dip; + ip_addr_t dip; /* set to 0 when disabled, >0 when enabled */ u8_t enable; }; @@ -92,11 +92,11 @@ snmp_trap_dst_enable(u8_t dst_idx, u8_t enable) * @param dst IPv4 address in host order. */ void -snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst) +snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst) { if (dst_idx < SNMP_TRAP_DESTINATIONS) { - trap_dst[dst_idx].dip.addr = htonl(dst->addr); + ip_addr_set(&trap_dst[dst_idx].dip, dst); } } @@ -221,23 +221,24 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) { struct snmp_trap_dst *td; struct netif *dst_if; - struct ip_addr dst_ip; + ip_addr_t dst_ip; struct pbuf *p; u16_t i,tot_len; for (i=0, td = &trap_dst[0]; i<SNMP_TRAP_DESTINATIONS; i++, td++) { - if ((td->enable != 0) && (td->dip.addr != 0)) + if ((td->enable != 0) && !ip_addr_isany(&td->dip)) { /* network order trap destination */ - trap_msg.dip.addr = td->dip.addr; + ip_addr_copy(trap_msg.dip, td->dip); /* lookup current source address for this dst */ dst_if = ip_route(&td->dip); - dst_ip.addr = ntohl(dst_if->ip_addr.addr); - trap_msg.sip_raw[0] = dst_ip.addr >> 24; - trap_msg.sip_raw[1] = dst_ip.addr >> 16; - trap_msg.sip_raw[2] = dst_ip.addr >> 8; - trap_msg.sip_raw[3] = dst_ip.addr; + ip_addr_copy(dst_ip, dst_if->ip_addr); + /* @todo: what about IPv6? */ + trap_msg.sip_raw[0] = ip4_addr1(&dst_ip); + trap_msg.sip_raw[1] = ip4_addr2(&dst_ip); + trap_msg.sip_raw[2] = ip4_addr3(&dst_ip); + trap_msg.sip_raw[3] = ip4_addr4(&dst_ip); trap_msg.gen_trap = generic_trap; trap_msg.spc_trap = specific_trap; if (generic_trap == SNMP_GENTRAP_ENTERPRISESPC) @@ -269,11 +270,8 @@ snmp_send_trap(s8_t generic_trap, struct snmp_obj_id *eoid, s32_t specific_trap) snmp_inc_snmpouttraps(); snmp_inc_snmpoutpkts(); - /** connect to the TRAP destination */ - udp_connect(trap_msg.pcb, &trap_msg.dip, SNMP_TRAP_PORT); - udp_send(trap_msg.pcb, p); - /** disassociate remote address and port with this pcb */ - udp_disconnect(trap_msg.pcb); + /** send to the TRAP destination */ + udp_sendto(trap_msg.pcb, p, &trap_msg.dip, SNMP_TRAP_PORT); pbuf_free(p); } @@ -435,13 +433,13 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root) switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): - sint_ptr = vb->value; + sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t_cnt(*sint_ptr, &vb->vlen); break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): - uint_ptr = vb->value; + uint_ptr = (u32_t*)vb->value; snmp_asn1_enc_u32t_cnt(*uint_ptr, &vb->vlen); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): @@ -451,7 +449,7 @@ snmp_varbind_list_sum(struct snmp_varbind_root *root) vb->vlen = vb->value_len; break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): - sint_ptr = vb->value; + sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid_cnt(vb->value_len / sizeof(s32_t), sint_ptr, &vb->vlen); break; default: @@ -649,25 +647,25 @@ snmp_varbind_list_enc(struct snmp_varbind_root *root, struct pbuf *p, u16_t ofs) switch (vb->value_type) { case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_INTEG): - sint_ptr = vb->value; + sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_s32t(p, ofs, vb->vlen, *sint_ptr); break; case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_COUNTER): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_GAUGE): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_TIMETICKS): - uint_ptr = vb->value; + uint_ptr = (u32_t*)vb->value; snmp_asn1_enc_u32t(p, ofs, vb->vlen, *uint_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OC_STR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_IPADDR): case (SNMP_ASN1_APPLIC | SNMP_ASN1_PRIMIT | SNMP_ASN1_OPAQUE): - raw_ptr = vb->value; + raw_ptr = (u8_t*)vb->value; snmp_asn1_enc_raw(p, ofs, vb->vlen, raw_ptr); break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_NUL): break; case (SNMP_ASN1_UNIV | SNMP_ASN1_PRIMIT | SNMP_ASN1_OBJ_ID): - sint_ptr = vb->value; + sint_ptr = (s32_t*)vb->value; snmp_asn1_enc_oid(p, ofs, vb->value_len / sizeof(s32_t), sint_ptr); break; default: diff --git a/core/lwip/src/core/stats.c b/core/lwip/src/core/stats.c index a036d83b..69f97d41 100644 --- a/core/lwip/src/core/stats.c +++ b/core/lwip/src/core/stats.c @@ -48,6 +48,25 @@ struct stats_ lwip_stats; +void stats_init(void) +{ +#ifdef LWIP_DEBUG +#if MEMP_STATS + const char * memp_names[] = { +#define LWIP_MEMPOOL(name,num,size,desc) desc, +#include "lwip/memp_std.h" + }; + int i; + for (i = 0; i < MEMP_MAX; i++) { + lwip_stats.memp[i].name = memp_names[i]; + } +#endif /* MEMP_STATS */ +#if MEM_STATS + lwip_stats.mem.name = "MEM"; +#endif /* MEM_STATS */ +#endif /* LWIP_DEBUG */ +} + #if LWIP_STATS_DISPLAY void stats_display_proto(struct stats_proto *proto, char *name) @@ -72,15 +91,20 @@ void stats_display_igmp(struct stats_igmp *igmp) { LWIP_PLATFORM_DIAG(("\nIGMP\n\t")); - LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", igmp->xmit)); + LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", igmp->recv)); + LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", igmp->drop)); LWIP_PLATFORM_DIAG(("chkerr: %"STAT_COUNTER_F"\n\t", igmp->chkerr)); - LWIP_PLATFORM_DIAG(("v1_rxed: %"STAT_COUNTER_F"\n\t", igmp->v1_rxed)); - LWIP_PLATFORM_DIAG(("join_sent: %"STAT_COUNTER_F"\n\t", igmp->join_sent)); - LWIP_PLATFORM_DIAG(("leave_sent: %"STAT_COUNTER_F"\n\t", igmp->leave_sent)); - LWIP_PLATFORM_DIAG(("unicast_query: %"STAT_COUNTER_F"\n\t", igmp->unicast_query)); - LWIP_PLATFORM_DIAG(("report_sent: %"STAT_COUNTER_F"\n\t", igmp->report_sent)); - LWIP_PLATFORM_DIAG(("report_rxed: %"STAT_COUNTER_F"\n\t", igmp->report_rxed)); - LWIP_PLATFORM_DIAG(("group_query_rxed: %"STAT_COUNTER_F"\n", igmp->group_query_rxed)); + LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr)); + LWIP_PLATFORM_DIAG(("memerr: %"STAT_COUNTER_F"\n\t", igmp->memerr)); + LWIP_PLATFORM_DIAG(("proterr: %"STAT_COUNTER_F"\n\t", igmp->proterr)); + LWIP_PLATFORM_DIAG(("rx_v1: %"STAT_COUNTER_F"\n\t", igmp->rx_v1)); + LWIP_PLATFORM_DIAG(("rx_group: %"STAT_COUNTER_F"\n", igmp->rx_group)); + LWIP_PLATFORM_DIAG(("rx_general: %"STAT_COUNTER_F"\n", igmp->rx_general)); + LWIP_PLATFORM_DIAG(("rx_report: %"STAT_COUNTER_F"\n\t", igmp->rx_report)); + LWIP_PLATFORM_DIAG(("tx_join: %"STAT_COUNTER_F"\n\t", igmp->tx_join)); + LWIP_PLATFORM_DIAG(("tx_leave: %"STAT_COUNTER_F"\n\t", igmp->tx_leave)); + LWIP_PLATFORM_DIAG(("tx_report: %"STAT_COUNTER_F"\n\t", igmp->tx_report)); } #endif /* IGMP_STATS */ @@ -115,12 +139,15 @@ void stats_display_sys(struct stats_sys *sys) { LWIP_PLATFORM_DIAG(("\nSYS\n\t")); - LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); - LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); - LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); - LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); - LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); - LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); + LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used)); + LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max)); + LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err)); + LWIP_PLATFORM_DIAG(("mutex.used: %"U32_F"\n\t", (u32_t)sys->mutex.used)); + LWIP_PLATFORM_DIAG(("mutex.max: %"U32_F"\n\t", (u32_t)sys->mutex.max)); + LWIP_PLATFORM_DIAG(("mutex.err: %"U32_F"\n\t", (u32_t)sys->mutex.err)); + LWIP_PLATFORM_DIAG(("mbox.used: %"U32_F"\n\t", (u32_t)sys->mbox.used)); + LWIP_PLATFORM_DIAG(("mbox.max: %"U32_F"\n\t", (u32_t)sys->mbox.max)); + LWIP_PLATFORM_DIAG(("mbox.err: %"U32_F"\n\t", (u32_t)sys->mbox.err)); } #endif /* SYS_STATS */ diff --git a/core/lwip/src/core/sys.c b/core/lwip/src/core/sys.c index cb5e86a7..d3a77deb 100644 --- a/core/lwip/src/core/sys.c +++ b/core/lwip/src/core/sys.c @@ -38,309 +38,29 @@ #include "lwip/opt.h" -#if (NO_SYS == 0) /* don't build if not configured for use in lwipopts.h */ - #include "lwip/sys.h" -#include "lwip/def.h" -#include "lwip/memp.h" -#include "lwip/tcpip.h" - -/** - * Struct used for sys_sem_wait_timeout() to tell wether the time - * has run out or the semaphore has really become available. - */ -struct sswt_cb -{ - s16_t timeflag; - sys_sem_t *psem; -}; - -/** - * Wait (forever) for a message to arrive in an mbox. - * While waiting, timeouts (for this thread) are processed. - * - * @param mbox the mbox to fetch the message from - * @param msg the place to store the message - */ -void -sys_mbox_fetch(sys_mbox_t mbox, void **msg) -{ - u32_t time_needed; - struct sys_timeouts *timeouts; - struct sys_timeo *tmptimeout; - sys_timeout_handler h; - void *arg; - - again: - timeouts = sys_arch_timeouts(); - - if (!timeouts || !timeouts->next) { - UNLOCK_TCPIP_CORE(); - time_needed = sys_arch_mbox_fetch(mbox, msg, 0); - LOCK_TCPIP_CORE(); - } else { - if (timeouts->next->time > 0) { - UNLOCK_TCPIP_CORE(); - time_needed = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time); - LOCK_TCPIP_CORE(); - } else { - time_needed = SYS_ARCH_TIMEOUT; - } - - if (time_needed == SYS_ARCH_TIMEOUT) { - /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message - could be fetched. We should now call the timeout handler and - deallocate the memory allocated for the timeout. */ - tmptimeout = timeouts->next; - timeouts->next = tmptimeout->next; - h = tmptimeout->h; - arg = tmptimeout->arg; - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (h != NULL) { - LWIP_DEBUGF(SYS_DEBUG, ("smf calling h=%p(%p)\n", *(void**)&h, arg)); - h(arg); - } - - /* We try again to fetch a message from the mbox. */ - goto again; - } else { - /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout - occured. The time variable is set to the number of - milliseconds we waited for the message. */ - if (time_needed < timeouts->next->time) { - timeouts->next->time -= time_needed; - } else { - timeouts->next->time = 0; - } - } - } -} - -/** - * Wait (forever) for a semaphore to become available. - * While waiting, timeouts (for this thread) are processed. - * - * @param sem semaphore to wait for - */ -void -sys_sem_wait(sys_sem_t sem) -{ - u32_t time_needed; - struct sys_timeouts *timeouts; - struct sys_timeo *tmptimeout; - sys_timeout_handler h; - void *arg; - - again: - - timeouts = sys_arch_timeouts(); - - if (!timeouts || !timeouts->next) { - sys_arch_sem_wait(sem, 0); - } else { - if (timeouts->next->time > 0) { - time_needed = sys_arch_sem_wait(sem, timeouts->next->time); - } else { - time_needed = SYS_ARCH_TIMEOUT; - } - - if (time_needed == SYS_ARCH_TIMEOUT) { - /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message - could be fetched. We should now call the timeout handler and - deallocate the memory allocated for the timeout. */ - tmptimeout = timeouts->next; - timeouts->next = tmptimeout->next; - h = tmptimeout->h; - arg = tmptimeout->arg; - memp_free(MEMP_SYS_TIMEOUT, tmptimeout); - if (h != NULL) { - LWIP_DEBUGF(SYS_DEBUG, ("ssw h=%p(%p)\n", *(void**)&h, (void *)arg)); - h(arg); - } - - /* We try again to fetch a message from the mbox. */ - goto again; - } else { - /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout - occured. The time variable is set to the number of - milliseconds we waited for the message. */ - if (time_needed < timeouts->next->time) { - timeouts->next->time -= time_needed; - } else { - timeouts->next->time = 0; - } - } - } -} - -/** - * Create a one-shot timer (aka timeout). Timeouts are processed in the - * following cases: - * - while waiting for a message using sys_mbox_fetch() - * - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout() - * - while sleeping using the inbuilt sys_msleep() - * - * @param msecs time in milliseconds after that the timer should expire - * @param h callback function to call when msecs have elapsed - * @param arg argument to pass to the callback function - */ -void -sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg) -{ - struct sys_timeouts *timeouts; - struct sys_timeo *timeout, *t; - - timeout = memp_malloc(MEMP_SYS_TIMEOUT); - if (timeout == NULL) { - LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL); - return; - } - timeout->next = NULL; - timeout->h = h; - timeout->arg = arg; - timeout->time = msecs; - - timeouts = sys_arch_timeouts(); - LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n", - (void *)timeout, msecs, *(void**)&h, (void *)arg)); +/* Most of the functions defined in sys.h must be implemented in the + * architecture-dependent file sys_arch.c */ - if (timeouts == NULL) { - LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL); - return; - } - - if (timeouts->next == NULL) { - timeouts->next = timeout; - return; - } - - if (timeouts->next->time > msecs) { - timeouts->next->time -= msecs; - timeout->next = timeouts->next; - timeouts->next = timeout; - } else { - for(t = timeouts->next; t != NULL; t = t->next) { - timeout->time -= t->time; - if (t->next == NULL || t->next->time > timeout->time) { - if (t->next != NULL) { - t->next->time -= timeout->time; - } - timeout->next = t->next; - t->next = timeout; - break; - } - } - } -} - -/** - * Go through timeout list (for this task only) and remove the first matching - * entry, even though the timeout has not triggered yet. - * - * @note This function only works as expected if there is only one timeout - * calling 'h' in the list of timeouts. - * - * @param h callback function that would be called by the timeout - * @param arg callback argument that would be passed to h -*/ -void -sys_untimeout(sys_timeout_handler h, void *arg) -{ - struct sys_timeouts *timeouts; - struct sys_timeo *prev_t, *t; - - timeouts = sys_arch_timeouts(); - - if (timeouts == NULL) { - LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL); - return; - } - if (timeouts->next == NULL) { - return; - } - - for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { - if ((t->h == h) && (t->arg == arg)) { - /* We have a match */ - /* Unlink from previous in list */ - if (prev_t == NULL) { - timeouts->next = t->next; - } else { - prev_t->next = t->next; - } - /* If not the last one, add time of this one back to next */ - if (t->next != NULL) { - t->next->time += t->time; - } - memp_free(MEMP_SYS_TIMEOUT, t); - return; - } - } - return; -} +#if !NO_SYS /** - * Timeout handler function for sys_sem_wait_timeout() - * - * @param arg struct sswt_cb* used to signal a semaphore and end waiting. - */ -static void -sswt_handler(void *arg) -{ - struct sswt_cb *sswt_cb = (struct sswt_cb *) arg; - - /* Timeout. Set flag to TRUE and signal semaphore */ - sswt_cb->timeflag = 1; - sys_sem_signal(*(sswt_cb->psem)); -} - -/** - * Wait for a semaphore with timeout (specified in ms) - * - * @param sem semaphore to wait - * @param timeout timeout in ms (0: wait forever) - * @return 0 on timeout, 1 otherwise - */ -int -sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout) -{ - struct sswt_cb sswt_cb; - - sswt_cb.psem = &sem; - sswt_cb.timeflag = 0; - - /* If timeout is zero, then just wait forever */ - if (timeout > 0) { - /* Create a timer and pass it the address of our flag */ - sys_timeout(timeout, sswt_handler, &sswt_cb); - } - sys_sem_wait(sem); - /* Was it a timeout? */ - if (sswt_cb.timeflag) { - /* timeout */ - return 0; - } else { - /* Not a timeout. Remove timeout entry */ - sys_untimeout(sswt_handler, &sswt_cb); - return 1; - } -} - -/** - * Sleep for some ms. Timeouts are processed while sleeping. + * Sleep for some ms. Timeouts are NOT processed while sleeping. * * @param ms number of milliseconds to sleep */ void sys_msleep(u32_t ms) { - sys_sem_t delaysem = sys_sem_new(0); - - sys_sem_wait_timeout(delaysem, ms); - - sys_sem_free(delaysem); + if (ms > 0) { + sys_sem_t delaysem; + err_t err = sys_sem_new(&delaysem, 0); + if (err == ERR_OK) { + sys_arch_sem_wait(&delaysem, ms); + sys_sem_free(&delaysem); + } + } } - -#endif /* NO_SYS */ +#endif /* !NO_SYS */ diff --git a/core/lwip/src/core/tcp.c b/core/lwip/src/core/tcp.c index 29cdf185..c629bc4e 100644 --- a/core/lwip/src/core/tcp.c +++ b/core/lwip/src/core/tcp.c @@ -49,12 +49,13 @@ #include "lwip/memp.h" #include "lwip/snmp.h" #include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/debug.h" #include "lwip/stats.h" #include <string.h> -const char *tcp_state_str[] = { +const char * const tcp_state_str[] = { "CLOSED", "LISTEN", "SYN_SENT", @@ -78,17 +79,25 @@ const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 }; /* The TCP PCB lists. */ /** List of all TCP PCBs bound but not yet (connected || listening) */ -struct tcp_pcb *tcp_bound_pcbs; +struct tcp_pcb *tcp_bound_pcbs; /** List of all TCP PCBs in LISTEN state */ union tcp_listen_pcbs_t tcp_listen_pcbs; /** List of all TCP PCBs that are in a state in which * they accept or send data. */ -struct tcp_pcb *tcp_active_pcbs; +struct tcp_pcb *tcp_active_pcbs; /** List of all TCP PCBs in TIME-WAIT state */ struct tcp_pcb *tcp_tw_pcbs; +#define NUM_TCP_PCB_LISTS 4 +#define NUM_TCP_PCB_LISTS_NO_TIME_WAIT 3 +/** An array with all (non-temporary) PCB lists, mainly used for smaller code size */ +struct tcp_pcb ** const tcp_pcb_lists[] = {&tcp_listen_pcbs.pcbs, &tcp_bound_pcbs, + &tcp_active_pcbs, &tcp_tw_pcbs}; + +/** Only used for temporary storage. */ struct tcp_pcb *tcp_tmp_pcb; +/** Timer counter to handle calling slow-timer from tcp_tmr() */ static u8_t tcp_timer; static u16_t tcp_new_port(void); @@ -110,7 +119,9 @@ tcp_tmr(void) } /** - * Closes the connection held by the PCB. + * Closes the TX side of a connection held by the PCB. + * For tcp_close(), a RST is sent if the application didn't receive all data + * (tcp_recved() not called for all data passed to recv callback). * * Listening pcbs are freed and may not be referenced any more. * Connection pcbs are freed if not yet connected and may not be referenced @@ -123,15 +134,34 @@ tcp_tmr(void) * @return ERR_OK if connection has been closed * another err_t if closing failed and pcb is not freed */ -err_t -tcp_close(struct tcp_pcb *pcb) +static err_t +tcp_close_shutdown(struct tcp_pcb *pcb, u8_t rst_on_unacked_data) { err_t err; -#if TCP_DEBUG - LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); - tcp_debug_print_state(pcb->state); -#endif /* TCP_DEBUG */ + if (rst_on_unacked_data && (pcb->state != LISTEN)) { + if ((pcb->refused_data != NULL) || (pcb->rcv_wnd != TCP_WND)) { + /* Not all data received by application, send RST to tell the remote + side about this. */ + LWIP_ASSERT("pcb->flags & TF_RXCLOSED", pcb->flags & TF_RXCLOSED); + + /* don't call tcp_abort here: we must not deallocate the pcb since + that might not be expected when calling tcp_close */ + tcp_rst(pcb->snd_nxt, pcb->rcv_nxt, &pcb->local_ip, &pcb->remote_ip, + pcb->local_port, pcb->remote_port); + + tcp_pcb_purge(pcb); + + /* TODO: to which state do we move now? */ + + /* move to TIME_WAIT since we close actively */ + TCP_RMV(&tcp_active_pcbs, pcb); + pcb->state = TIME_WAIT; + TCP_REG(&tcp_tw_pcbs, pcb); + + return ERR_OK; + } + } switch (pcb->state) { case CLOSED: @@ -143,13 +173,15 @@ tcp_close(struct tcp_pcb *pcb) * is erroneous, but this should never happen as the pcb has in those cases * been freed, and so any remaining handles are bogus. */ err = ERR_OK; - TCP_RMV(&tcp_bound_pcbs, pcb); + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } memp_free(MEMP_TCP_PCB, pcb); pcb = NULL; break; case LISTEN: err = ERR_OK; - tcp_pcb_remove((struct tcp_pcb **)&tcp_listen_pcbs.pcbs, pcb); + tcp_pcb_remove(&tcp_listen_pcbs.pcbs, pcb); memp_free(MEMP_TCP_PCB_LISTEN, pcb); pcb = NULL; break; @@ -161,21 +193,21 @@ tcp_close(struct tcp_pcb *pcb) snmp_inc_tcpattemptfails(); break; case SYN_RCVD: - err = tcp_send_ctrl(pcb, TCP_FIN); + err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpattemptfails(); pcb->state = FIN_WAIT_1; } break; case ESTABLISHED: - err = tcp_send_ctrl(pcb, TCP_FIN); + err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = FIN_WAIT_1; } break; case CLOSE_WAIT: - err = tcp_send_ctrl(pcb, TCP_FIN); + err = tcp_send_fin(pcb); if (err == ERR_OK) { snmp_inc_tcpestabresets(); pcb->state = LAST_ACK; @@ -195,13 +227,86 @@ tcp_close(struct tcp_pcb *pcb) returns (unsent data is sent from tcp timer functions, also), we don't care for the return value of tcp_output for now. */ /* @todo: When implementing SO_LINGER, this must be changed somehow: - If SOF_LINGER is set, the data should be sent when tcp_close returns. */ + If SOF_LINGER is set, the data should be sent and acked before close returns. + This can only be valid for sequential APIs, not for the raw API. */ tcp_output(pcb); } return err; } /** + * Closes the connection held by the PCB. + * + * Listening pcbs are freed and may not be referenced any more. + * Connection pcbs are freed if not yet connected and may not be referenced + * any more. If a connection is established (at least SYN received or in + * a closing state), the connection is closed, and put in a closing state. + * The pcb is then automatically freed in tcp_slowtmr(). It is therefore + * unsafe to reference it (unless an error is returned). + * + * @param pcb the tcp_pcb to close + * @return ERR_OK if connection has been closed + * another err_t if closing failed and pcb is not freed + */ +err_t +tcp_close(struct tcp_pcb *pcb) +{ +#if TCP_DEBUG + LWIP_DEBUGF(TCP_DEBUG, ("tcp_close: closing in ")); + tcp_debug_print_state(pcb->state); +#endif /* TCP_DEBUG */ + + if (pcb->state != LISTEN) { + /* Set a flag not to receive any more data... */ + pcb->flags |= TF_RXCLOSED; + } + /* ... and close */ + return tcp_close_shutdown(pcb, 1); +} + +/** + * Causes all or part of a full-duplex connection of this PCB to be shut down. + * This doesn't deallocate the PCB! + * + * @param pcb PCB to shutdown + * @param shut_rx shut down receive side if this is != 0 + * @param shut_tx shut down send side if this is != 0 + * @return ERR_OK if shutdown succeeded (or the PCB has already been shut down) + * another err_t on error. + */ +err_t +tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx) +{ + if (pcb->state == LISTEN) { + return ERR_CONN; + } + if (shut_rx) { + /* shut down the receive side: free buffered data... */ + if (pcb->refused_data != NULL) { + pbuf_free(pcb->refused_data); + pcb->refused_data = NULL; + } + /* ... and set a flag not to receive any more data */ + pcb->flags |= TF_RXCLOSED; + } + if (shut_tx) { + /* This can't happen twice since if it succeeds, the pcb's state is changed. + Only close in these states as the others directly deallocate the PCB */ + switch (pcb->state) { + case SYN_RCVD: + case ESTABLISHED: + case CLOSE_WAIT: + return tcp_close_shutdown(pcb, 0); + default: + /* don't shut down other states */ + break; + } + } + /* @todo: return another err_t if not in correct state or already shut? */ + return ERR_OK; +} + +/** * Abandons a connection and optionally sends a RST to the remote * host. Deletes the local protocol control block. This is done when * a connection is killed because of shortage of memory. @@ -214,13 +319,15 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) { u32_t seqno, ackno; u16_t remote_port, local_port; - struct ip_addr remote_ip, local_ip; + ip_addr_t remote_ip, local_ip; #if LWIP_CALLBACK_API - void (* errf)(void *arg, err_t err); + tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ void *errf_arg; - + /* pcb->state LISTEN not allowed here */ + LWIP_ASSERT("don't call tcp_abort/tcp_abandon for listen-pcbs", + pcb->state != LISTEN); /* Figure out on which TCP PCB list we are, and remove us. If we are in an active state, call the receive function associated with the PCB with a NULL argument, and send an RST to the remote end. */ @@ -230,8 +337,8 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) } else { seqno = pcb->snd_nxt; ackno = pcb->rcv_nxt; - ip_addr_set(&local_ip, &(pcb->local_ip)); - ip_addr_set(&remote_ip, &(pcb->remote_ip)); + ip_addr_copy(local_ip, pcb->local_ip); + ip_addr_copy(remote_ip, pcb->remote_ip); local_port = pcb->local_port; remote_port = pcb->remote_port; #if LWIP_CALLBACK_API @@ -260,6 +367,22 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) } /** + * Aborts the connection by sending a RST (reset) segment to the remote + * host. The pcb is deallocated. This function never fails. + * + * ATTENTION: When calling this from one of the TCP callbacks, make + * sure you always return ERR_ABRT (and never return ERR_ABRT otherwise + * or you will risk accessing deallocated memory or memory leaks! + * + * @param pcb the tcp pcb to abort + */ +void +tcp_abort(struct tcp_pcb *pcb) +{ + tcp_abandon(pcb, 1); +} + +/** * Binds the connection to a local portnumber and IP address. If the * IP address is not given (i.e., ipaddr == NULL), the IP address of * the outgoing network interface is used instead. @@ -270,57 +393,51 @@ tcp_abandon(struct tcp_pcb *pcb, int reset) * to any local address * @param port the local port to bind to * @return ERR_USE if the port is already in use + * ERR_VAL if bind failed because the PCB is not in a valid state * ERR_OK if bound */ err_t -tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { + int i; + int max_pcb_list = NUM_TCP_PCB_LISTS; struct tcp_pcb *cpcb; - LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + LWIP_ERROR("tcp_bind: can only bind in state CLOSED", pcb->state == CLOSED, return ERR_VAL); + +#if SO_REUSE + /* Unless the REUSEADDR flag is set, + we have to check the pcbs in TIME-WAIT state, also. + We do not dump TIME_WAIT pcb's; they can still be matched by incoming + packets using both local and remote IP addresses and ports to distinguish. + */ + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + max_pcb_list = NUM_TCP_PCB_LISTS_NO_TIME_WAIT; + } +#endif /* SO_REUSE */ if (port == 0) { port = tcp_new_port(); } - /* Check if the address already is in use. */ - /* Check the listen pcbs. */ - for(cpcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; - cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { - if (ip_addr_isany(&(cpcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - return ERR_USE; - } - } - } - /* Check the connected pcbs. */ - for(cpcb = tcp_active_pcbs; - cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { - if (ip_addr_isany(&(cpcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - return ERR_USE; - } - } - } - /* Check the bound, not yet connected pcbs. */ - for(cpcb = tcp_bound_pcbs; cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { - if (ip_addr_isany(&(cpcb->local_ip)) || - ip_addr_isany(ipaddr) || - ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - return ERR_USE; - } - } - } - /* @todo: until SO_REUSEADDR is implemented (see task #6995 on savannah), - * we have to check the pcbs in TIME-WAIT state, also: */ - for(cpcb = tcp_tw_pcbs; cpcb != NULL; cpcb = cpcb->next) { - if (cpcb->local_port == port) { - if (ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { - return ERR_USE; + + /* Check if the address already is in use (on all lists) */ + for (i = 0; i < max_pcb_list; i++) { + for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if (cpcb->local_port == port) { +#if SO_REUSE + /* Omit checking for the same port if both pcbs have REUSEADDR set. + For SO_REUSEADDR, the duplicate-check for a 5-tuple is done in + tcp_connect. */ + if (((pcb->so_options & SOF_REUSEADDR) == 0) || + ((cpcb->so_options & SOF_REUSEADDR) == 0)) +#endif /* SO_REUSE */ + { + if (ip_addr_isany(&(cpcb->local_ip)) || + ip_addr_isany(ipaddr) || + ip_addr_cmp(&(cpcb->local_ip), ipaddr)) { + return ERR_USE; + } + } } } } @@ -374,19 +491,37 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) if (pcb->state == LISTEN) { return pcb; } - lpcb = memp_malloc(MEMP_TCP_PCB_LISTEN); +#if SO_REUSE + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + /* Since SOF_REUSEADDR allows reusing a local address before the pcb's usage + is declared (listen-/connection-pcb), we have to make sure now that + this port is only used once for every local IP. */ + for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { + if (lpcb->local_port == pcb->local_port) { + if (ip_addr_cmp(&lpcb->local_ip, &pcb->local_ip)) { + /* this address/port is already used */ + return NULL; + } + } + } + } +#endif /* SO_REUSE */ + lpcb = (struct tcp_pcb_listen *)memp_malloc(MEMP_TCP_PCB_LISTEN); if (lpcb == NULL) { return NULL; } lpcb->callback_arg = pcb->callback_arg; lpcb->local_port = pcb->local_port; lpcb->state = LISTEN; + lpcb->prio = pcb->prio; lpcb->so_options = pcb->so_options; lpcb->so_options |= SOF_ACCEPTCONN; lpcb->ttl = pcb->ttl; lpcb->tos = pcb->tos; - ip_addr_set(&lpcb->local_ip, &pcb->local_ip); - TCP_RMV(&tcp_bound_pcbs, pcb); + ip_addr_copy(lpcb->local_ip, pcb->local_ip); + if (pcb->local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } memp_free(MEMP_TCP_PCB, pcb); #if LWIP_CALLBACK_API lpcb->accept = tcp_accept_null; @@ -395,7 +530,7 @@ tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog) lpcb->accepts_pending = 0; lpcb->backlog = (backlog ? backlog : 1); #endif /* TCP_LISTEN_BACKLOG */ - TCP_REG(&tcp_listen_pcbs.listen_pcbs, lpcb); + TCP_REG(&tcp_listen_pcbs.pcbs, (struct tcp_pcb *)lpcb); return (struct tcp_pcb *)lpcb; } @@ -420,7 +555,9 @@ u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb) pcb->rcv_ann_wnd = 0; } else { /* keep the right edge of window constant */ - pcb->rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; + u32_t new_rcv_ann_wnd = pcb->rcv_ann_right_edge - pcb->rcv_nxt; + LWIP_ASSERT("new_rcv_ann_wnd <= 0xffff", new_rcv_ann_wnd <= 0xffff); + pcb->rcv_ann_wnd = (u16_t)new_rcv_ann_wnd; } return 0; } @@ -443,17 +580,20 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) len <= 0xffff - pcb->rcv_wnd ); pcb->rcv_wnd += len; - if (pcb->rcv_wnd > TCP_WND) + if (pcb->rcv_wnd > TCP_WND) { pcb->rcv_wnd = TCP_WND; + } wnd_inflation = tcp_update_rcv_ann_wnd(pcb); /* If the change in the right edge of window is significant (default - * watermark is TCP_WND/2), then send an explicit update now. + * watermark is TCP_WND/4), then send an explicit update now. * Otherwise wait for a packet to be sent in the normal course of * events (or more window to be available later) */ - if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) + if (wnd_inflation >= TCP_WND_UPDATE_THRESHOLD) { tcp_ack_now(pcb); + tcp_output(pcb); + } LWIP_DEBUGF(TCP_DEBUG, ("tcp_recved: recveived %"U16_F" bytes, wnd %"U16_F" (%"U16_F").\n", len, pcb->rcv_wnd, TCP_WND - pcb->rcv_wnd)); @@ -468,31 +608,26 @@ tcp_recved(struct tcp_pcb *pcb, u16_t len) static u16_t tcp_new_port(void) { + int i; struct tcp_pcb *pcb; #ifndef TCP_LOCAL_PORT_RANGE_START -#define TCP_LOCAL_PORT_RANGE_START 4096 -#define TCP_LOCAL_PORT_RANGE_END 0x7fff +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define TCP_LOCAL_PORT_RANGE_START 0xc000 +#define TCP_LOCAL_PORT_RANGE_END 0xffff #endif static u16_t port = TCP_LOCAL_PORT_RANGE_START; again: - if (++port > TCP_LOCAL_PORT_RANGE_END) { + if (port++ >= TCP_LOCAL_PORT_RANGE_END) { port = TCP_LOCAL_PORT_RANGE_START; } - - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == port) { - goto again; - } - } - for(pcb = tcp_tw_pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == port) { - goto again; - } - } - for(pcb = (struct tcp_pcb *)tcp_listen_pcbs.pcbs; pcb != NULL; pcb = pcb->next) { - if (pcb->local_port == port) { - goto again; + /* Check all PCB lists. */ + for (i = 0; i < NUM_TCP_PCB_LISTS; i++) { + for(pcb = *tcp_pcb_lists[i]; pcb != NULL; pcb = pcb->next) { + if (pcb->local_port == port) { + goto again; + } } } return port; @@ -511,13 +646,14 @@ tcp_new_port(void) * other err_t values if connect request couldn't be sent */ err_t -tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, - err_t (* connected)(void *arg, struct tcp_pcb *tpcb, err_t err)) +tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr, u16_t port, + tcp_connected_fn connected) { err_t ret; u32_t iss; + u16_t old_local_port; - LWIP_ERROR("tcp_connect: can only connected from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); + LWIP_ERROR("tcp_connect: can only connect from state CLOSED", pcb->state == CLOSED, return ERR_ISCONN); LWIP_DEBUGF(TCP_DEBUG, ("tcp_connect to port %"U16_F"\n", port)); if (ipaddr != NULL) { @@ -526,9 +662,44 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, return ERR_VAL; } pcb->remote_port = port; + + /* check if we have a route to the remote host */ + if (ip_addr_isany(&(pcb->local_ip))) { + /* no local IP address set, yet. */ + struct netif *netif = ip_route(&(pcb->remote_ip)); + if (netif == NULL) { + /* Don't even try to send a SYN packet if we have no route + since that will fail. */ + return ERR_RTE; + } + /* Use the netif's IP address as local address. */ + ip_addr_copy(pcb->local_ip, netif->ip_addr); + } + + old_local_port = pcb->local_port; if (pcb->local_port == 0) { pcb->local_port = tcp_new_port(); } +#if SO_REUSE + if ((pcb->so_options & SOF_REUSEADDR) != 0) { + /* Since SOF_REUSEADDR allows reusing a local address, we have to make sure + now that the 5-tuple is unique. */ + struct tcp_pcb *cpcb; + int i; + /* Don't check listen- and bound-PCBs, check active- and TIME-WAIT PCBs. */ + for (i = 2; i < NUM_TCP_PCB_LISTS; i++) { + for(cpcb = *tcp_pcb_lists[i]; cpcb != NULL; cpcb = cpcb->next) { + if ((cpcb->local_port == pcb->local_port) && + (cpcb->remote_port == port) && + ip_addr_cmp(&cpcb->local_ip, &pcb->local_ip) && + ip_addr_cmp(&cpcb->remote_ip, ipaddr)) { + /* linux returns EISCONN here, but ERR_USE should be OK for us */ + return ERR_USE; + } + } + } + } +#endif /* SO_REUSE */ iss = tcp_next_iss(); pcb->rcv_nxt = 0; pcb->snd_nxt = iss; @@ -546,25 +717,27 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, #endif /* TCP_CALCULATE_EFF_SEND_MSS */ pcb->cwnd = 1; pcb->ssthresh = pcb->mss * 10; - pcb->state = SYN_SENT; -#if LWIP_CALLBACK_API +#if LWIP_CALLBACK_API pcb->connected = connected; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(connected); #endif /* LWIP_CALLBACK_API */ - TCP_RMV(&tcp_bound_pcbs, pcb); - TCP_REG(&tcp_active_pcbs, pcb); - snmp_inc_tcpactiveopens(); - - ret = tcp_enqueue(pcb, NULL, 0, TCP_SYN, 0, TF_SEG_OPTS_MSS -#if LWIP_TCP_TIMESTAMPS - | TF_SEG_OPTS_TS -#endif - ); - if (ret == ERR_OK) { + /* Send a SYN together with the MSS option. */ + ret = tcp_enqueue_flags(pcb, TCP_SYN); + if (ret == ERR_OK) { + /* SYN segment was enqueued, changed the pcbs state now */ + pcb->state = SYN_SENT; + if (old_local_port != 0) { + TCP_RMV(&tcp_bound_pcbs, pcb); + } + TCP_REG(&tcp_active_pcbs, pcb); + snmp_inc_tcpactiveopens(); + tcp_output(pcb); } return ret; -} +} /** * Called every 500 ms and implements the retransmission timer and the timer that @@ -576,7 +749,7 @@ tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr, u16_t port, void tcp_slowtmr(void) { - struct tcp_pcb *pcb, *pcb2, *prev; + struct tcp_pcb *pcb, *prev; u16_t eff_wnd; u8_t pcb_remove; /* flag if a PCB should be removed */ u8_t pcb_reset; /* flag if a RST should be sent when removing */ @@ -643,8 +816,8 @@ tcp_slowtmr(void) /* Reduce congestion window and ssthresh. */ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); pcb->ssthresh = eff_wnd >> 1; - if (pcb->ssthresh < pcb->mss) { - pcb->ssthresh = pcb->mss * 2; + if (pcb->ssthresh < (pcb->mss << 1)) { + pcb->ssthresh = (pcb->mss << 1); } pcb->cwnd = pcb->mss; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F @@ -667,21 +840,21 @@ tcp_slowtmr(void) } /* Check if KEEPALIVE should be sent */ - if((pcb->so_options & SOF_KEEPALIVE) && - ((pcb->state == ESTABLISHED) || + if((pcb->so_options & SOF_KEEPALIVE) && + ((pcb->state == ESTABLISHED) || (pcb->state == CLOSE_WAIT))) { #if LWIP_TCP_KEEPALIVE - if((u32_t)(tcp_ticks - pcb->tmr) > + if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + (pcb->keep_cnt*pcb->keep_intvl)) / TCP_SLOW_INTERVAL) #else - if((u32_t)(tcp_ticks - pcb->tmr) > + if((u32_t)(tcp_ticks - pcb->tmr) > (pcb->keep_idle + TCP_MAXIDLE) / TCP_SLOW_INTERVAL) #endif /* LWIP_TCP_KEEPALIVE */ { LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: KEEPALIVE timeout. Aborting connection to %"U16_F".%"U16_F".%"U16_F".%"U16_F".\n", - ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), - ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); ++pcb_remove; ++pcb_reset; @@ -704,7 +877,7 @@ tcp_slowtmr(void) /* If this PCB has queued out of sequence data, but has been inactive for too long, will drop the data (it will eventually be retransmitted). */ -#if TCP_QUEUE_OOSEQ +#if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL && (u32_t)tcp_ticks - pcb->tmr >= pcb->rto * TCP_OOSEQ_TIMEOUT) { tcp_segs_free(pcb->ooseq); @@ -732,7 +905,8 @@ tcp_slowtmr(void) /* If the PCB should be removed, do it. */ if (pcb_remove) { - tcp_pcb_purge(pcb); + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); /* Remove PCB from tcp_active_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_active_pcbs", pcb != tcp_active_pcbs); @@ -749,30 +923,31 @@ tcp_slowtmr(void) pcb->local_port, pcb->remote_port); } - pcb2 = pcb->next; - memp_free(MEMP_TCP_PCB, pcb); - pcb = pcb2; + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); } else { + /* get the 'next' element now and work with 'prev' below (in case of abort) */ + prev = pcb; + pcb = pcb->next; /* We check if we should poll the connection. */ - ++pcb->polltmr; - if (pcb->polltmr >= pcb->pollinterval) { - pcb->polltmr = 0; + ++prev->polltmr; + if (prev->polltmr >= prev->pollinterval) { + prev->polltmr = 0; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: polling application\n")); - TCP_EVENT_POLL(pcb, err); + TCP_EVENT_POLL(prev, err); + /* if err == ERR_ABRT, 'prev' is already deallocated */ if (err == ERR_OK) { - tcp_output(pcb); + tcp_output(prev); } } - - prev = pcb; - pcb = pcb->next; } } /* Steps through all of the TIME-WAIT PCBs. */ - prev = NULL; + prev = NULL; pcb = tcp_tw_pcbs; while (pcb != NULL) { LWIP_ASSERT("tcp_slowtmr: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); @@ -787,7 +962,8 @@ tcp_slowtmr(void) /* If the PCB should be removed, do it. */ if (pcb_remove) { - tcp_pcb_purge(pcb); + struct tcp_pcb *pcb2; + tcp_pcb_purge(pcb); /* Remove PCB from tcp_tw_pcbs list. */ if (prev != NULL) { LWIP_ASSERT("tcp_slowtmr: middle tcp != tcp_tw_pcbs", pcb != tcp_tw_pcbs); @@ -797,9 +973,9 @@ tcp_slowtmr(void) LWIP_ASSERT("tcp_slowtmr: first pcb == tcp_tw_pcbs", tcp_tw_pcbs == pcb); tcp_tw_pcbs = pcb->next; } - pcb2 = pcb->next; - memp_free(MEMP_TCP_PCB, pcb); - pcb = pcb2; + pcb2 = pcb; + pcb = pcb->next; + memp_free(MEMP_TCP_PCB, pcb2); } else { prev = pcb; pcb = pcb->next; @@ -816,9 +992,10 @@ tcp_slowtmr(void) void tcp_fasttmr(void) { - struct tcp_pcb *pcb; + struct tcp_pcb *pcb = tcp_active_pcbs; - for(pcb = tcp_active_pcbs; pcb != NULL; pcb = pcb->next) { + while(pcb != NULL) { + struct tcp_pcb *next = pcb->next; /* If there is data which was previously "refused" by upper layer */ if (pcb->refused_data != NULL) { /* Notify again application with data previously received. */ @@ -827,15 +1004,21 @@ tcp_fasttmr(void) TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); if (err == ERR_OK) { pcb->refused_data = NULL; + } else if (err == ERR_ABRT) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + pcb = NULL; } } - /* send delayed ACKs */ - if (pcb->flags & TF_ACK_DELAY) { + /* send delayed ACKs */ + if (pcb && (pcb->flags & TF_ACK_DELAY)) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_fasttmr: delayed ACK\n")); tcp_ack_now(pcb); + tcp_output(pcb); pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); } + + pcb = next; } } @@ -843,42 +1026,34 @@ tcp_fasttmr(void) * Deallocates a list of TCP segments (tcp_seg structures). * * @param seg tcp_seg list of TCP segments to free - * @return the number of pbufs that were deallocated */ -u8_t +void tcp_segs_free(struct tcp_seg *seg) { - u8_t count = 0; - struct tcp_seg *next; while (seg != NULL) { - next = seg->next; - count += tcp_seg_free(seg); + struct tcp_seg *next = seg->next; + tcp_seg_free(seg); seg = next; } - return count; } /** * Frees a TCP segment (tcp_seg structure). * * @param seg single tcp_seg to free - * @return the number of pbufs that were deallocated */ -u8_t +void tcp_seg_free(struct tcp_seg *seg) { - u8_t count = 0; - if (seg != NULL) { if (seg->p != NULL) { - count = pbuf_free(seg->p); + pbuf_free(seg->p); #if TCP_DEBUG seg->p = NULL; #endif /* TCP_DEBUG */ } memp_free(MEMP_TCP_SEG, seg); } - return count; } /** @@ -892,8 +1067,8 @@ tcp_setprio(struct tcp_pcb *pcb, u8_t prio) { pcb->prio = prio; } -#if TCP_QUEUE_OOSEQ +#if TCP_QUEUE_OOSEQ /** * Returns a copy of the given TCP segment. * The pbuf and data are not copied, only the pointers @@ -906,7 +1081,7 @@ tcp_seg_copy(struct tcp_seg *seg) { struct tcp_seg *cseg; - cseg = memp_malloc(MEMP_TCP_SEG); + cseg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG); if (cseg == NULL) { return NULL; } @@ -914,7 +1089,7 @@ tcp_seg_copy(struct tcp_seg *seg) pbuf_ref(cseg->p); return cseg; } -#endif +#endif /* TCP_QUEUE_OOSEQ */ #if LWIP_CALLBACK_API /** @@ -966,7 +1141,7 @@ tcp_kill_prio(u8_t prio) LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_prio: killing oldest PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); - } + } } /** @@ -992,7 +1167,7 @@ tcp_kill_timewait(void) LWIP_DEBUGF(TCP_DEBUG, ("tcp_kill_timewait: killing oldest TIME-WAIT PCB %p (%"S32_F")\n", (void *)inactive, inactivity)); tcp_abort(inactive); - } + } } /** @@ -1007,19 +1182,19 @@ tcp_alloc(u8_t prio) struct tcp_pcb *pcb; u32_t iss; - pcb = memp_malloc(MEMP_TCP_PCB); + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { /* Try killing oldest connection in TIME-WAIT. */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing off oldest TIME-WAIT connection\n")); tcp_kill_timewait(); /* Try to allocate a tcp_pcb again. */ - pcb = memp_malloc(MEMP_TCP_PCB); + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb == NULL) { /* Try killing active connections with lower priority than the new one. */ LWIP_DEBUGF(TCP_DEBUG, ("tcp_alloc: killing connection with prio lower than %d\n", prio)); tcp_kill_prio(prio); /* Try to allocate a tcp_pcb again. */ - pcb = memp_malloc(MEMP_TCP_PCB); + pcb = (struct tcp_pcb *)memp_malloc(MEMP_TCP_PCB); if (pcb != NULL) { /* adjust err stats: memp_malloc failed twice before */ MEMP_STATS_DEC(err, MEMP_TCP_PCB); @@ -1032,7 +1207,7 @@ tcp_alloc(u8_t prio) } if (pcb != NULL) { memset(pcb, 0, sizeof(struct tcp_pcb)); - pcb->prio = TCP_PRIO_NORMAL; + pcb->prio = prio; pcb->snd_buf = TCP_SND_BUF; pcb->snd_queuelen = 0; pcb->rcv_wnd = TCP_WND; @@ -1113,8 +1288,7 @@ tcp_arg(struct tcp_pcb *pcb, void *arg) * @param recv callback function to call for this pcb when data is received */ void -tcp_recv(struct tcp_pcb *pcb, - err_t (* recv)(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err)) +tcp_recv(struct tcp_pcb *pcb, tcp_recv_fn recv) { pcb->recv = recv; } @@ -1127,8 +1301,7 @@ tcp_recv(struct tcp_pcb *pcb, * @param sent callback function to call for this pcb when data is successfully sent */ void -tcp_sent(struct tcp_pcb *pcb, - err_t (* sent)(void *arg, struct tcp_pcb *tpcb, u16_t len)) +tcp_sent(struct tcp_pcb *pcb, tcp_sent_fn sent) { pcb->sent = sent; } @@ -1138,14 +1311,13 @@ tcp_sent(struct tcp_pcb *pcb, * has occured on the connection. * * @param pcb tcp_pcb to set the err callback - * @param errf callback function to call for this pcb when a fatal error + * @param err callback function to call for this pcb when a fatal error * has occured on the connection */ void -tcp_err(struct tcp_pcb *pcb, - void (* errf)(void *arg, err_t err)) +tcp_err(struct tcp_pcb *pcb, tcp_err_fn err) { - pcb->errf = errf; + pcb->errf = err; } /** @@ -1157,8 +1329,7 @@ tcp_err(struct tcp_pcb *pcb, * connection has been connected to another host */ void -tcp_accept(struct tcp_pcb *pcb, - err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err)) +tcp_accept(struct tcp_pcb *pcb, tcp_accept_fn accept) { pcb->accept = accept; } @@ -1172,11 +1343,12 @@ tcp_accept(struct tcp_pcb *pcb, * */ void -tcp_poll(struct tcp_pcb *pcb, - err_t (* poll)(void *arg, struct tcp_pcb *tpcb), u8_t interval) +tcp_poll(struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval) { #if LWIP_CALLBACK_API pcb->poll = poll; +#else /* LWIP_CALLBACK_API */ + LWIP_UNUSED_ARG(poll); #endif /* LWIP_CALLBACK_API */ pcb->pollinterval = interval; } @@ -1228,21 +1400,24 @@ tcp_pcb_purge(struct tcp_pcb *pcb) if (pcb->unacked != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->unacked\n")); } -#if TCP_QUEUE_OOSEQ /* LW */ +#if TCP_QUEUE_OOSEQ if (pcb->ooseq != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } + tcp_segs_free(pcb->ooseq); + pcb->ooseq = NULL; +#endif /* TCP_QUEUE_OOSEQ */ /* Stop the retransmission timer as it will expect data on unacked queue if it fires */ pcb->rtime = -1; - tcp_segs_free(pcb->ooseq); - pcb->ooseq = NULL; -#endif /* TCP_QUEUE_OOSEQ */ tcp_segs_free(pcb->unsent); tcp_segs_free(pcb->unacked); pcb->unacked = pcb->unsent = NULL; +#if TCP_OVERSIZE + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ } } @@ -1301,7 +1476,7 @@ tcp_next_iss(void) * calculating the minimum of TCP_MSS and that netif's mtu (if set). */ u16_t -tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) +tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr) { u16_t mss_s; struct netif *outif; @@ -1311,8 +1486,7 @@ tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr) mss_s = outif->mtu - IP_HLEN - TCP_HLEN; /* RFC 1122, chap 4.2.2.6: * Eff.snd.MSS = min(SendMSS+20, MMS_S) - TCPhdrsize - IPoptionsize - * We correct for TCP options in tcp_enqueue(), and don't support - * IP options + * We correct for TCP options in tcp_write(), and don't support IP options. */ sendmss = LWIP_MIN(sendmss, mss_s); } diff --git a/core/lwip/src/core/tcp_in.c b/core/lwip/src/core/tcp_in.c index 51e87759..90952648 100644 --- a/core/lwip/src/core/tcp_in.c +++ b/core/lwip/src/core/tcp_in.c @@ -45,13 +45,12 @@ #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/def.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" #include "lwip/mem.h" #include "lwip/memp.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/snmp.h" @@ -94,6 +93,10 @@ tcp_input(struct pbuf *p, struct netif *inp) { struct tcp_pcb *pcb, *prev; struct tcp_pcb_listen *lpcb; +#if SO_REUSE + struct tcp_pcb *lpcb_prev = NULL; + struct tcp_pcb_listen *lpcb_any = NULL; +#endif /* SO_REUSE */ u8_t hdrlen; err_t err; @@ -102,7 +105,7 @@ tcp_input(struct pbuf *p, struct netif *inp) TCP_STATS_INC(tcp.recv); snmp_inc_tcpinsegs(); - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; tcphdr = (struct tcp_hdr *)((u8_t *)p->payload + IPH_HL(iphdr) * 4); #if TCP_INPUT_DEBUG @@ -121,8 +124,8 @@ tcp_input(struct pbuf *p, struct netif *inp) } /* Don't even process incoming broadcasts/multicasts. */ - if (ip_addr_isbroadcast(&(iphdr->dest), inp) || - ip_addr_ismulticast(&(iphdr->dest))) { + if (ip_addr_isbroadcast(¤t_iphdr_dest, inp) || + ip_addr_ismulticast(¤t_iphdr_dest)) { TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); @@ -132,11 +135,10 @@ tcp_input(struct pbuf *p, struct netif *inp) #if CHECKSUM_CHECK_TCP /* Verify TCP checksum. */ - if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), - (struct ip_addr *)&(iphdr->dest), + if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_TCP, p->tot_len) != 0) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packet discarded due to failing checksum 0x%04"X16_F"\n", - inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), (struct ip_addr *)&(iphdr->dest), + inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_TCP, p->tot_len))); #if TCP_DEBUG tcp_debug_print(tcphdr); @@ -183,8 +185,8 @@ tcp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("tcp_input: active pcb->state != LISTEN", pcb->state != LISTEN); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { /* Move this PCB to the front of the list so that subsequent lookups will be faster (we exploit locality in TCP segment @@ -208,8 +210,8 @@ tcp_input(struct pbuf *p, struct netif *inp) LWIP_ASSERT("tcp_input: TIME-WAIT pcb->state == TIME-WAIT", pcb->state == TIME_WAIT); if (pcb->remote_port == tcphdr->src && pcb->local_port == tcphdr->dest && - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)) && - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest))) { + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src) && + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest)) { /* We don't really care enough to move this PCB to the front of the list since we are not very likely to receive that many segments for connections in TIME-WAIT. */ @@ -220,31 +222,55 @@ tcp_input(struct pbuf *p, struct netif *inp) } } - /* Finally, if we still did not get a match, we check all PCBs that - are LISTENing for incoming connections. */ + /* Finally, if we still did not get a match, we check all PCBs that + are LISTENing for incoming connections. */ prev = NULL; for(lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) { - if ((ip_addr_isany(&(lpcb->local_ip)) || - ip_addr_cmp(&(lpcb->local_ip), &(iphdr->dest))) && - lpcb->local_port == tcphdr->dest) { - /* Move this PCB to the front of the list so that subsequent - lookups will be faster (we exploit locality in TCP segment - arrivals). */ - if (prev != NULL) { - ((struct tcp_pcb_listen *)prev)->next = lpcb->next; - /* our successor is the remainder of the listening list */ - lpcb->next = tcp_listen_pcbs.listen_pcbs; - /* put this listening pcb at the head of the listening list */ - tcp_listen_pcbs.listen_pcbs = lpcb; + if (lpcb->local_port == tcphdr->dest) { +#if SO_REUSE + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest)) { + /* found an exact match */ + break; + } else if(ip_addr_isany(&(lpcb->local_ip))) { + /* found an ANY-match */ + lpcb_any = lpcb; + lpcb_prev = prev; } - - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); - tcp_listen_input(lpcb); - pbuf_free(p); - return; +#else /* SO_REUSE */ + if (ip_addr_cmp(&(lpcb->local_ip), ¤t_iphdr_dest) || + ip_addr_isany(&(lpcb->local_ip))) { + /* found a match */ + break; + } +#endif /* SO_REUSE */ } prev = (struct tcp_pcb *)lpcb; } +#if SO_REUSE + /* first try specific local IP */ + if (lpcb == NULL) { + /* only pass to ANY if no specific local IP has been found */ + lpcb = lpcb_any; + prev = lpcb_prev; + } +#endif /* SO_REUSE */ + if (lpcb != NULL) { + /* Move this PCB to the front of the list so that subsequent + lookups will be faster (we exploit locality in TCP segment + arrivals). */ + if (prev != NULL) { + ((struct tcp_pcb_listen *)prev)->next = lpcb->next; + /* our successor is the remainder of the listening list */ + lpcb->next = tcp_listen_pcbs.listen_pcbs; + /* put this listening pcb at the head of the listening list */ + tcp_listen_pcbs.listen_pcbs = lpcb; + } + + LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: packed for LISTENing connection.\n")); + tcp_listen_input(lpcb); + pbuf_free(p); + return; + } } #if TCP_INPUT_DEBUG @@ -265,7 +291,6 @@ tcp_input(struct pbuf *p, struct netif *inp) /* Set up a tcp_seg structure. */ inseg.next = NULL; inseg.len = p->tot_len; - inseg.dataptr = p->payload; inseg.p = p; inseg.tcphdr = tcphdr; @@ -279,8 +304,10 @@ tcp_input(struct pbuf *p, struct netif *inp) TCP_EVENT_RECV(pcb, pcb->refused_data, ERR_OK, err); if (err == ERR_OK) { pcb->refused_data = NULL; - } else { - /* drop incoming packets, because pcb is "full" */ + } else if ((err == ERR_ABRT) || (tcplen > 0)) { + /* if err == ERR_ABRT, 'pcb' is already deallocated */ + /* Drop incoming packets because pcb is "full" (only if the incoming + segment contains data). */ LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_input: drop incoming packets, because pcb is \"full\"\n")); TCP_STATS_INC(tcp.drop); snmp_inc_tcpinerrs(); @@ -313,15 +340,29 @@ tcp_input(struct pbuf *p, struct netif *inp) now. */ if (pcb->acked > 0) { TCP_EVENT_SENT(pcb, pcb->acked, err); + if (err == ERR_ABRT) { + goto aborted; + } } - + if (recv_data != NULL) { - if(flags & TCP_PSH) { + LWIP_ASSERT("pcb->refused_data == NULL", pcb->refused_data == NULL); + if (pcb->flags & TF_RXCLOSED) { + /* received data although already closed -> abort (send RST) to + notify the remote host that not all data has been processed */ + pbuf_free(recv_data); + tcp_abort(pcb); + goto aborted; + } + if (flags & TCP_PSH) { recv_data->flags |= PBUF_FLAG_PUSH; } /* Notify application that data has been received. */ TCP_EVENT_RECV(pcb, recv_data, ERR_OK, err); + if (err == ERR_ABRT) { + goto aborted; + } /* If the upper layer can't receive this data, store it */ if (err != ERR_OK) { @@ -333,7 +374,15 @@ tcp_input(struct pbuf *p, struct netif *inp) /* If a FIN segment was received, we call the callback function with a NULL buffer to indicate EOF. */ if (recv_flags & TF_GOT_FIN) { - TCP_EVENT_RECV(pcb, NULL, ERR_OK, err); + /* correct rcv_wnd as the application won't call tcp_recved() + for the FIN's seqno */ + if (pcb->rcv_wnd != TCP_WND) { + pcb->rcv_wnd++; + } + TCP_EVENT_CLOSED(pcb, err); + if (err == ERR_ABRT) { + goto aborted; + } } tcp_input_pcb = NULL; @@ -346,8 +395,11 @@ tcp_input(struct pbuf *p, struct netif *inp) #endif /* TCP_INPUT_DEBUG */ } } + /* Jump target if pcb has been aborted in a callback (by calling tcp_abort()). + Below this line, 'pcb' may not be dereferenced! */ +aborted: tcp_input_pcb = NULL; - + recv_data = NULL; /* give up our reference to inseg.p */ if (inseg.p != NULL) @@ -364,7 +416,7 @@ tcp_input(struct pbuf *p, struct netif *inp) TCP_STATS_INC(tcp.proterr); TCP_STATS_INC(tcp.drop); tcp_rst(ackno, seqno + tcplen, - &(iphdr->dest), &(iphdr->src), + ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } pbuf_free(p); @@ -399,7 +451,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) RST. */ LWIP_DEBUGF(TCP_RST_DEBUG, ("tcp_listen_input: ACK in LISTEN, sending reset\n")); tcp_rst(ackno + 1, seqno + tcplen, - &(iphdr->dest), &(iphdr->src), + ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } else if (flags & TCP_SYN) { LWIP_DEBUGF(TCP_DEBUG, ("TCP connection request %"U16_F" -> %"U16_F".\n", tcphdr->src, tcphdr->dest)); @@ -422,9 +474,9 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) pcb->accepts_pending++; #endif /* TCP_LISTEN_BACKLOG */ /* Set up the new PCB. */ - ip_addr_set(&(npcb->local_ip), &(iphdr->dest)); + ip_addr_copy(npcb->local_ip, current_iphdr_dest); npcb->local_port = pcb->local_port; - ip_addr_set(&(npcb->remote_ip), &(iphdr->src)); + ip_addr_copy(npcb->remote_ip, current_iphdr_src); npcb->remote_port = tcphdr->src; npcb->state = SYN_RCVD; npcb->rcv_nxt = seqno + 1; @@ -437,7 +489,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) npcb->accept = pcb->accept; #endif /* LWIP_CALLBACK_API */ /* inherit socket options */ - npcb->so_options = pcb->so_options & (SOF_DEBUG|SOF_DONTROUTE|SOF_KEEPALIVE|SOF_OOBINLINE|SOF_LINGER); + npcb->so_options = pcb->so_options & SOF_INHERITED; /* Register the new PCB so that we can begin receiving segments for it. */ TCP_REG(&tcp_active_pcbs, npcb); @@ -451,12 +503,7 @@ tcp_listen_input(struct tcp_pcb_listen *pcb) snmp_inc_tcppassiveopens(); /* Send a SYN|ACK together with the MSS option. */ - rc = tcp_enqueue(npcb, NULL, 0, TCP_SYN | TCP_ACK, 0, TF_SEG_OPTS_MSS -#if LWIP_TCP_TIMESTAMPS - /* and maybe include the TIMESTAMP option */ - | (npcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0) -#endif - ); + rc = tcp_enqueue_flags(npcb, TCP_SYN | TCP_ACK); if (rc != ERR_OK) { tcp_abandon(npcb, 0); return rc; @@ -492,7 +539,7 @@ tcp_timewait_input(struct tcp_pcb *pcb) should be sent in reply */ if (TCP_SEQ_BETWEEN(seqno, pcb->rcv_nxt, pcb->rcv_nxt+pcb->rcv_wnd)) { /* If the SYN is in the window it is an error, send a reset */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); return ERR_OK; } @@ -565,8 +612,10 @@ tcp_process(struct tcp_pcb *pcb) return ERR_OK; } - /* Update the PCB (in)activity timer. */ - pcb->tmr = tcp_ticks; + if ((pcb->flags & TF_RXCLOSED) == 0) { + /* Update the PCB (in)activity timer unless rx is closed (see tcp_shutdown) */ + pcb->tmr = tcp_ticks; + } pcb->keep_cnt_sent = 0; tcp_parseopt(pcb); @@ -616,12 +665,15 @@ tcp_process(struct tcp_pcb *pcb) /* Call the user specified function to call when sucessfully * connected. */ TCP_EVENT_CONNECTED(pcb, ERR_OK, err); + if (err == ERR_ABRT) { + return ERR_ABRT; + } tcp_ack_now(pcb); } /* received ACK? possibly a half-open connection */ else if (flags & TCP_ACK) { /* send a RST to bring the other side in a non-synchronized state. */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } break; @@ -640,7 +692,10 @@ tcp_process(struct tcp_pcb *pcb) if (err != ERR_OK) { /* If the accept function returns with an error, we abort * the connection. */ - tcp_abort(pcb); + /* Already aborted? */ + if (err != ERR_ABRT) { + tcp_abort(pcb); + } return ERR_ABRT; } old_cwnd = pcb->cwnd; @@ -659,11 +714,9 @@ tcp_process(struct tcp_pcb *pcb) tcp_ack_now(pcb); pcb->state = CLOSE_WAIT; } - } - /* incorrect ACK number */ - else { - /* send RST */ - tcp_rst(ackno, seqno + tcplen, &(iphdr->dest), &(iphdr->src), + } else { + /* incorrect ACK number, send RST */ + tcp_rst(ackno, seqno + tcplen, ip_current_dest_addr(), ip_current_src_addr(), tcphdr->dest, tcphdr->src); } } else if ((flags & TCP_SYN) && (seqno == pcb->rcv_nxt - 1)) { @@ -758,7 +811,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) (next->tcphdr->seqno + next->len))) { /* cseg with FIN already processed */ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN) { - TCPH_FLAGS_SET(cseg->tcphdr, TCPH_FLAGS(cseg->tcphdr) | TCP_FIN); + TCPH_SET_FLAG(cseg->tcphdr, TCP_FIN); } old_seg = next; next = next->next; @@ -773,7 +826,7 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) } cseg->next = next; } -#endif +#endif /* TCP_QUEUE_OOSEQ */ /** * Called by tcp_process. Checks if the given segment is an ACK for outstanding @@ -793,7 +846,7 @@ tcp_receive(struct tcp_pcb *pcb) struct tcp_seg *next; #if TCP_QUEUE_OOSEQ struct tcp_seg *prev, *cseg; -#endif +#endif /* TCP_QUEUE_OOSEQ */ struct pbuf *p; s32_t off; s16_t m; @@ -1113,9 +1166,6 @@ tcp_receive(struct tcp_pcb *pcb) LWIP_ASSERT("pbuf_header failed", 0); } } - /* KJM following line changed to use p->payload rather than inseg->p->payload - to fix bug #9076 */ - inseg.dataptr = p->payload; inseg.len -= (u16_t)(pcb->rcv_nxt - seqno); inseg.tcphdr->seqno = seqno = pcb->rcv_nxt; } @@ -1143,7 +1193,7 @@ tcp_receive(struct tcp_pcb *pcb) if (tcplen > pcb->rcv_wnd) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: other end overran receive window" - "seqno %"U32_F" len %"U32_F" right edge %"U32_F"\n", + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { /* Must remove the FIN from the header as we're trimming @@ -1161,60 +1211,53 @@ tcp_receive(struct tcp_pcb *pcb) (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); } #if TCP_QUEUE_OOSEQ + /* Received in-sequence data, adjust ooseq data if: + - FIN has been received or + - inseq overlaps with ooseq */ if (pcb->ooseq != NULL) { if (TCPH_FLAGS(inseg.tcphdr) & TCP_FIN) { LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: received in-order FIN, binning ooseq queue\n")); /* Received in-order FIN means anything that was received * out of order must now have been received in-order, so - * bin the ooseq queue - * rcv_nxt - * . |--ooseq--| - * .==seg============|FIN - */ + * bin the ooseq queue */ while (pcb->ooseq != NULL) { struct tcp_seg *old_ooseq = pcb->ooseq; pcb->ooseq = pcb->ooseq->next; tcp_seg_free(old_ooseq); - } - } + } + } else { - struct tcp_seg* next = pcb->ooseq; - struct tcp_seg *old_seg; - /* rcv_nxt - * . |--ooseq--| - * .==seg============| - */ + next = pcb->ooseq; + /* Remove all segments on ooseq that are covered by inseg already. + * FIN is copied from ooseq to inseg if present. */ while (next && TCP_SEQ_GEQ(seqno + tcplen, next->tcphdr->seqno + next->len)) { - /* inseg doesn't have FIN (already processed) */ + /* inseg cannot have FIN here (already processed above) */ if (TCPH_FLAGS(next->tcphdr) & TCP_FIN && (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) == 0) { - TCPH_FLAGS_SET(inseg.tcphdr, - TCPH_FLAGS(inseg.tcphdr) | TCP_FIN); + TCPH_SET_FLAG(inseg.tcphdr, TCP_FIN); tcplen = TCP_TCPLEN(&inseg); } - old_seg = next; + prev = next; next = next->next; - tcp_seg_free(old_seg); + tcp_seg_free(prev); } - /* rcv_nxt - * . |--ooseq--| - * .==seg============| - */ + /* Now trim right side of inseg if it overlaps with the first + * segment on ooseq */ if (next && TCP_SEQ_GT(seqno + tcplen, next->tcphdr->seqno)) { - /* FIN in inseg already handled by dropping whole ooseq queue */ - inseg.len = (u16_t)(pcb->ooseq->tcphdr->seqno - seqno); + /* inseg cannot have FIN here (already processed above) */ + inseg.len = (u16_t)(next->tcphdr->seqno - seqno); if (TCPH_FLAGS(inseg.tcphdr) & TCP_SYN) { inseg.len -= 1; } pbuf_realloc(inseg.p, inseg.len); tcplen = TCP_TCPLEN(&inseg); LWIP_ASSERT("tcp_receive: segment not trimmed correctly to ooseq queue\n", - (seqno + tcplen) == pcb->ooseq->tcphdr->seqno); + (seqno + tcplen) == next->tcphdr->seqno); } pcb->ooseq = next; } @@ -1252,7 +1295,7 @@ tcp_receive(struct tcp_pcb *pcb) #if TCP_QUEUE_OOSEQ /* We now check if we have segments on the ->ooseq queue that - is now in sequence. */ + are now in sequence. */ while (pcb->ooseq != NULL && pcb->ooseq->tcphdr->seqno == pcb->rcv_nxt) { @@ -1392,6 +1435,24 @@ tcp_receive(struct tcp_pcb *pcb) next->len = (u16_t)(seqno - next->tcphdr->seqno); pbuf_realloc(next->p, next->len); } + /* check if the remote side overruns our receive window */ + if ((u32_t)tcplen + seqno > pcb->rcv_nxt + (u32_t)pcb->rcv_wnd) { + LWIP_DEBUGF(TCP_INPUT_DEBUG, + ("tcp_receive: other end overran receive window" + "seqno %"U32_F" len %"U16_F" right edge %"U32_F"\n", + seqno, tcplen, pcb->rcv_nxt + pcb->rcv_wnd)); + if (TCPH_FLAGS(next->next->tcphdr) & TCP_FIN) { + /* Must remove the FIN from the header as we're trimming + * that byte of sequence-space from the packet */ + TCPH_FLAGS_SET(next->next->tcphdr, TCPH_FLAGS(next->next->tcphdr) &~ TCP_FIN); + } + /* Adjust length of segment to fit in the window. */ + next->next->len = pcb->rcv_nxt + pcb->rcv_wnd - seqno; + pbuf_realloc(next->next->p, next->next->len); + tcplen = TCP_TCPLEN(next->next); + LWIP_ASSERT("tcp_receive: segment not trimmed correctly to rcv_wnd\n", + (seqno + tcplen) == (pcb->rcv_nxt + pcb->rcv_wnd)); + } } break; } diff --git a/core/lwip/src/core/tcp_out.c b/core/lwip/src/core/tcp_out.c index ddada420..86e09195 100644 --- a/core/lwip/src/core/tcp_out.c +++ b/core/lwip/src/core/tcp_out.c @@ -42,382 +42,643 @@ #if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ -#include "lwip/tcp.h" +#include "lwip/tcp_impl.h" #include "lwip/def.h" #include "lwip/mem.h" #include "lwip/memp.h" #include "lwip/sys.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/stats.h" #include "lwip/snmp.h" #include <string.h> +/* Define some copy-macros for checksum-on-copy so that the code looks + nicer by preventing too many ifdef's. */ +#if TCP_CHECKSUM_ON_COPY +#define TCP_DATA_COPY(dst, src, len, seg) do { \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), \ + len, &seg->chksum, &seg->chksum_swapped); \ + seg->flags |= TF_SEG_DATA_CHECKSUMMED; } while(0) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) \ + tcp_seg_add_chksum(LWIP_CHKSUM_COPY(dst, src, len), len, chksum, chksum_swapped); +#else /* TCP_CHECKSUM_ON_COPY*/ +#define TCP_DATA_COPY(dst, src, len, seg) MEMCPY(dst, src, len) +#define TCP_DATA_COPY2(dst, src, len, chksum, chksum_swapped) MEMCPY(dst, src, len) +#endif /* TCP_CHECKSUM_ON_COPY*/ + +/** Define this to 1 for an extra check that the output checksum is valid + * (usefule when the checksum is generated by the application, not the stack) */ +#ifndef TCP_CHECKSUM_ON_COPY_SANITY_CHECK +#define TCP_CHECKSUM_ON_COPY_SANITY_CHECK 0 +#endif + /* Forward declarations.*/ static void tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb); -static struct tcp_hdr * -tcp_output_set_header(struct tcp_pcb *pcb, struct pbuf *p, int optlen, +/** Allocate a pbuf and create a tcphdr at p->payload, used for output + * functions other than the default tcp_output -> tcp_output_segment + * (e.g. tcp_send_empty_ack, etc.) + * + * @param pcb tcp pcb for which to send a packet (used to initialize tcp_hdr) + * @param optlen length of header-options + * @param datalen length of tcp data to reserve in pbuf + * @param seqno_be seqno in network byte order (big-endian) + * @return pbuf with p->payload being the tcp_hdr + */ +static struct pbuf * +tcp_output_alloc_header(struct tcp_pcb *pcb, u16_t optlen, u16_t datalen, u32_t seqno_be /* already in network byte order */) { - struct tcp_hdr *tcphdr = p->payload; - tcphdr->src = htons(pcb->local_port); - tcphdr->dest = htons(pcb->remote_port); - tcphdr->seqno = seqno_be; - tcphdr->ackno = htonl(pcb->rcv_nxt); - TCPH_FLAGS_SET(tcphdr, TCP_ACK); - tcphdr->wnd = htons(pcb->rcv_ann_wnd); - tcphdr->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, (5 + optlen / 4)); - tcphdr->chksum = 0; - - /* If we're sending a packet, update the announced right window edge */ - pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; - - return tcphdr; + struct tcp_hdr *tcphdr; + struct pbuf *p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen + datalen, PBUF_RAM); + if (p != NULL) { + LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", + (p->len >= TCP_HLEN + optlen)); + tcphdr = (struct tcp_hdr *)p->payload; + tcphdr->src = htons(pcb->local_port); + tcphdr->dest = htons(pcb->remote_port); + tcphdr->seqno = seqno_be; + tcphdr->ackno = htonl(pcb->rcv_nxt); + TCPH_HDRLEN_FLAGS_SET(tcphdr, (5 + optlen / 4), TCP_ACK); + tcphdr->wnd = htons(pcb->rcv_ann_wnd); + tcphdr->chksum = 0; + tcphdr->urgp = 0; + + /* If we're sending a packet, update the announced right window edge */ + pcb->rcv_ann_right_edge = pcb->rcv_nxt + pcb->rcv_ann_wnd; + } + return p; } /** - * Called by tcp_close() to send a segment including flags but not data. + * Called by tcp_close() to send a segment including FIN flag but not data. * * @param pcb the tcp_pcb over which to send a segment - * @param flags the flags to set in the segment header * @return ERR_OK if sent, another err_t otherwise */ err_t -tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags) +tcp_send_fin(struct tcp_pcb *pcb) { + /* first, try to add the fin to the last unsent segment */ + if (pcb->unsent != NULL) { + struct tcp_seg *last_unsent; + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + if ((TCPH_FLAGS(last_unsent->tcphdr) & (TCP_SYN | TCP_FIN | TCP_RST)) == 0) { + /* no SYN/FIN/RST flag in the header, we can add the FIN flag */ + TCPH_SET_FLAG(last_unsent->tcphdr, TCP_FIN); + return ERR_OK; + } + } /* no data, no length, flags, copy=1, no optdata */ - return tcp_enqueue(pcb, NULL, 0, flags, TCP_WRITE_FLAG_COPY, 0); + return tcp_enqueue_flags(pcb, TCP_FIN); } /** - * Write data for sending (but does not send it immediately). + * Create a TCP segment with prefilled header. * - * It waits in the expectation of more data being sent soon (as - * it can send them more efficiently by combining them together). - * To prompt the system to send data now, call tcp_output() after - * calling tcp_write(). - * - * @param pcb Protocol control block of the TCP connection to enqueue data for. - * @param data pointer to the data to send - * @param len length (in bytes) of the data to send - * @param apiflags combination of following flags : - * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack - * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, - * @return ERR_OK if enqueued, another err_t on error - * - * @see tcp_write() + * Called by tcp_write and tcp_enqueue_flags. + * + * @param pcb Protocol control block for the TCP connection. + * @param p pbuf that is used to hold the TCP header. + * @param flags TCP flags for header. + * @param seqno TCP sequence number of this packet + * @param optflags options to include in TCP header + * @return a new tcp_seg pointing to p, or NULL. + * The TCP header is filled in except ackno and wnd. + * p is freed on failure. */ -err_t -tcp_write(struct tcp_pcb *pcb, const void *data, u16_t len, u8_t apiflags) +static struct tcp_seg * +tcp_create_segment(struct tcp_pcb *pcb, struct pbuf *p, u8_t flags, u32_t seqno, u8_t optflags) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", (void *)pcb, - data, len, (u16_t)apiflags)); - /* connection is in valid state for data transmission? */ - if (pcb->state == ESTABLISHED || - pcb->state == CLOSE_WAIT || - pcb->state == SYN_SENT || - pcb->state == SYN_RCVD) { - if (len > 0) { -#if LWIP_TCP_TIMESTAMPS - return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, - pcb->flags & TF_TIMESTAMP ? TF_SEG_OPTS_TS : 0); -#else - return tcp_enqueue(pcb, (void *)data, len, 0, apiflags, 0); -#endif - } - return ERR_OK; - } else { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); - return ERR_CONN; + struct tcp_seg *seg; + u8_t optlen = LWIP_TCP_OPT_LENGTH(optflags); + + if ((seg = (struct tcp_seg *)memp_malloc(MEMP_TCP_SEG)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no memory.\n")); + pbuf_free(p); + return NULL; } -} + seg->flags = optflags; + seg->next = NULL; + seg->p = p; + seg->len = p->tot_len - optlen; +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = 0; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = 0; + seg->chksum_swapped = 0; + /* check optflags */ + LWIP_ASSERT("invalid optflags passed: TF_SEG_DATA_CHECKSUMMED", + (optflags & TF_SEG_DATA_CHECKSUMMED) == 0); +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* build TCP header */ + if (pbuf_header(p, TCP_HLEN)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_create_segment: no room for TCP header in pbuf.\n")); + TCP_STATS_INC(tcp.err); + tcp_seg_free(seg); + return NULL; + } + seg->tcphdr = (struct tcp_hdr *)seg->p->payload; + seg->tcphdr->src = htons(pcb->local_port); + seg->tcphdr->dest = htons(pcb->remote_port); + seg->tcphdr->seqno = htonl(seqno); + /* ackno is set in tcp_output */ + TCPH_HDRLEN_FLAGS_SET(seg->tcphdr, (5 + optlen / 4), flags); + /* wnd and chksum are set in tcp_output */ + seg->tcphdr->urgp = 0; + return seg; +} /** - * Enqueue data and/or TCP options for transmission + * Allocate a PBUF_RAM pbuf, perhaps with extra space at the end. * - * Called by tcp_connect(), tcp_listen_input(), tcp_send_ctrl() and tcp_write(). + * This function is like pbuf_alloc(layer, length, PBUF_RAM) except + * there may be extra bytes available at the end. * - * @param pcb Protocol control block for the TCP connection to enqueue data for. - * @param arg Pointer to the data to be enqueued for sending. - * @param len Data length in bytes - * @param flags tcp header flags to set in the outgoing segment - * @param apiflags combination of following flags : - * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack - * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, - * @param optflags options to include in segment later on (see definition of struct tcp_seg) + * @param layer flag to define header size. + * @param length size of the pbuf's payload. + * @param max_length maximum usable size of payload+oversize. + * @param oversize pointer to a u16_t that will receive the number of usable tail bytes. + * @param pcb The TCP connection that willo enqueue the pbuf. + * @param apiflags API flags given to tcp_write. + * @param first_seg true when this pbuf will be used in the first enqueued segment. + * @param */ -err_t -tcp_enqueue(struct tcp_pcb *pcb, void *arg, u16_t len, - u8_t flags, u8_t apiflags, u8_t optflags) +#if TCP_OVERSIZE +static struct pbuf * +tcp_pbuf_prealloc(pbuf_layer layer, u16_t length, u16_t max_length, + u16_t *oversize, struct tcp_pcb *pcb, u8_t apiflags, + u8_t first_seg) { struct pbuf *p; - struct tcp_seg *seg, *useg, *queue; - u32_t seqno; - u16_t left, seglen; - void *ptr; - u16_t queuelen; - u8_t optlen; + u16_t alloc = length; + +#if LWIP_NETIF_TX_SINGLE_PBUF + LWIP_UNUSED_ARG(max_length); + LWIP_UNUSED_ARG(pcb); + LWIP_UNUSED_ARG(apiflags); + LWIP_UNUSED_ARG(first_seg); + /* always create MSS-sized pbufs */ + alloc = TCP_MSS; +#else /* LWIP_NETIF_TX_SINGLE_PBUF */ + if (length < max_length) { + /* Should we allocate an oversized pbuf, or just the minimum + * length required? If tcp_write is going to be called again + * before this segment is transmitted, we want the oversized + * buffer. If the segment will be transmitted immediately, we can + * save memory by allocating only length. We use a simple + * heuristic based on the following information: + * + * Did the user set TCP_WRITE_FLAG_MORE? + * + * Will the Nagle algorithm defer transmission of this segment? + */ + if ((apiflags & TCP_WRITE_FLAG_MORE) || + (!(pcb->flags & TF_NODELAY) && + (!first_seg || + pcb->unsent != NULL || + pcb->unacked != NULL))) { + alloc = LWIP_MIN(max_length, LWIP_MEM_ALIGN_SIZE(length + TCP_OVERSIZE)); + } + } +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + p = pbuf_alloc(layer, alloc, PBUF_RAM); + if (p == NULL) { + return NULL; + } + LWIP_ASSERT("need unchained pbuf", p->next == NULL); + *oversize = p->len - length; + /* trim p->len to the currently used size */ + p->len = p->tot_len = length; + return p; +} +#else /* TCP_OVERSIZE */ +#define tcp_pbuf_prealloc(layer, length, mx, os, pcb, api, fst) pbuf_alloc((layer), (length), PBUF_RAM) +#endif /* TCP_OVERSIZE */ - LWIP_DEBUGF(TCP_OUTPUT_DEBUG, - ("tcp_enqueue(pcb=%p, arg=%p, len=%"U16_F", flags=%"X16_F", apiflags=%"U16_F")\n", - (void *)pcb, arg, len, (u16_t)flags, (u16_t)apiflags)); - LWIP_ERROR("tcp_enqueue: packet needs payload, options, or SYN/FIN (programmer violates API)", - ((len != 0) || (optflags != 0) || ((flags & (TCP_SYN | TCP_FIN)) != 0)), - return ERR_ARG;); - LWIP_ERROR("tcp_enqueue: len != 0 || arg == NULL (programmer violates API)", - ((len != 0) || (arg == NULL)), return ERR_ARG;); +#if TCP_CHECKSUM_ON_COPY +/** Add a checksum of newly added data to the segment */ +static void +tcp_seg_add_chksum(u16_t chksum, u16_t len, u16_t *seg_chksum, + u8_t *seg_chksum_swapped) +{ + u32_t helper; + /* add chksum to old chksum and fold to u16_t */ + helper = chksum + *seg_chksum; + chksum = FOLD_U32T(helper); + if ((len & 1) != 0) { + *seg_chksum_swapped = 1 - *seg_chksum_swapped; + chksum = SWAP_BYTES_IN_WORD(chksum); + } + *seg_chksum = chksum; +} +#endif /* TCP_CHECKSUM_ON_COPY */ + +/** Checks if tcp_write is allowed or not (checks state, snd_buf and snd_queuelen). + * + * @param pcb the tcp pcb to check for + * @param len length of data to send (checked agains snd_buf) + * @return ERR_OK if tcp_write is allowed to proceed, another err_t otherwise + */ +static err_t +tcp_write_checks(struct tcp_pcb *pcb, u16_t len) +{ + /* connection is in invalid state for data transmission? */ + if ((pcb->state != ESTABLISHED) && + (pcb->state != CLOSE_WAIT) && + (pcb->state != SYN_SENT) && + (pcb->state != SYN_RCVD)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_STATE | LWIP_DBG_LEVEL_SEVERE, ("tcp_write() called in invalid state\n")); + return ERR_CONN; + } else if (len == 0) { + return ERR_OK; + } /* fail on too much data */ if (len > pcb->snd_buf) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("tcp_enqueue: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", len, pcb->snd_buf)); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too much data (len=%"U16_F" > snd_buf=%"U16_F")\n", + len, pcb->snd_buf)); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; } - left = len; - ptr = arg; - optlen = LWIP_TCP_OPT_LENGTH(optflags); - - /* seqno will be the sequence number of the first segment enqueued - * by the call to this function. */ - seqno = pcb->snd_lbb; - - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); /* If total number of pbufs on the unsent/unacked queues exceeds the * configured maximum, return an error */ - queuelen = pcb->snd_queuelen; /* check for configured max queuelen and possible overflow */ - if ((queuelen >= TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_WARNING, - ("tcp_enqueue: too long queue %"U16_F" (max %"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_write: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, TCP_SND_QUEUELEN)); TCP_STATS_INC(tcp.memerr); pcb->flags |= TF_NAGLEMEMERR; return ERR_MEM; } - if (queuelen != 0) { - LWIP_ASSERT("tcp_enqueue: pbufs on queue => at least one queue non-empty", + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_write: pbufs on queue => at least one queue non-empty", pcb->unacked != NULL || pcb->unsent != NULL); } else { - LWIP_ASSERT("tcp_enqueue: no pbufs on queue => both queues empty", + LWIP_ASSERT("tcp_write: no pbufs on queue => both queues empty", pcb->unacked == NULL && pcb->unsent == NULL); } + return ERR_OK; +} - /* First, break up the data into segments and tuck them together in - * the local "queue" variable. */ - useg = queue = seg = NULL; - seglen = 0; - while (queue == NULL || left > 0) { - /* The segment length (including options) should be at most the MSS */ - seglen = left > (pcb->mss - optlen) ? (pcb->mss - optlen) : left; - - /* Allocate memory for tcp_seg, and fill in fields. */ - seg = memp_malloc(MEMP_TCP_SEG); - if (seg == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_enqueue: could not allocate memory for tcp_seg\n")); - goto memerr; - } - seg->next = NULL; - seg->p = NULL; +/** + * Write data for sending (but does not send it immediately). + * + * It waits in the expectation of more data being sent soon (as + * it can send them more efficiently by combining them together). + * To prompt the system to send data now, call tcp_output() after + * calling tcp_write(). + * + * @param pcb Protocol control block for the TCP connection to enqueue data for. + * @param arg Pointer to the data to be enqueued for sending. + * @param len Data length in bytes + * @param apiflags combination of following flags : + * - TCP_WRITE_FLAG_COPY (0x01) data will be copied into memory belonging to the stack + * - TCP_WRITE_FLAG_MORE (0x02) for TCP connection, PSH flag will be set on last segment sent, + * @return ERR_OK if enqueued, another err_t on error + */ +err_t +tcp_write(struct tcp_pcb *pcb, const void *arg, u16_t len, u8_t apiflags) +{ + struct pbuf *concat_p = NULL; + struct tcp_seg *last_unsent = NULL, *seg = NULL, *prev_seg = NULL, *queue = NULL; + u16_t pos = 0; /* position in 'arg' data */ + u16_t queuelen; + u8_t optlen = 0; + u8_t optflags = 0; +#if TCP_OVERSIZE + u16_t oversize = 0; + u16_t oversize_used = 0; +#endif /* TCP_OVERSIZE */ +#if TCP_CHECKSUM_ON_COPY + u16_t concat_chksum = 0; + u8_t concat_chksum_swapped = 0; + u16_t concat_chksummed = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ + err_t err; + +#if LWIP_NETIF_TX_SINGLE_PBUF + /* Always copy to try to create single pbufs for TX */ + apiflags |= TCP_WRITE_FLAG_COPY; +#endif /* LWIP_NETIF_TX_SINGLE_PBUF */ + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_write(pcb=%p, data=%p, len=%"U16_F", apiflags=%"U16_F")\n", + (void *)pcb, arg, len, (u16_t)apiflags)); + LWIP_ERROR("tcp_write: arg == NULL (programmer violates API)", + arg != NULL, return ERR_ARG;); + + err = tcp_write_checks(pcb, len); + if (err != ERR_OK) { + return err; + } + queuelen = pcb->snd_queuelen; - /* first segment of to-be-queued data? */ - if (queue == NULL) { - queue = seg; +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + optflags = TF_SEG_OPTS_TS; + optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); + } +#endif /* LWIP_TCP_TIMESTAMPS */ + + + /* + * TCP segmentation is done in three phases with increasing complexity: + * + * 1. Copy data directly into an oversized pbuf. + * 2. Chain a new pbuf to the end of pcb->unsent. + * 3. Create new segments. + * + * We may run out of memory at any point. In that case we must + * return ERR_MEM and not change anything in pcb. Therefore, all + * changes are recorded in local variables and committed at the end + * of the function. Some pcb fields are maintained in local copies: + * + * queuelen = pcb->snd_queuelen + * oversize = pcb->unsent_oversize + * + * These variables are set consistently by the phases: + * + * seg points to the last segment tampered with. + * + * pos records progress as data is segmented. + */ + + /* Find the tail of the unsent queue. */ + if (pcb->unsent != NULL) { + u16_t space; + u16_t unsent_optlen; + + /* @todo: this could be sped up by keeping last_unsent in the pcb */ + for (last_unsent = pcb->unsent; last_unsent->next != NULL; + last_unsent = last_unsent->next); + + /* Usable space at the end of the last unsent segment */ + unsent_optlen = LWIP_TCP_OPT_LENGTH(last_unsent->flags); + space = pcb->mss - (last_unsent->len + unsent_optlen); + + /* + * Phase 1: Copy data directly into an oversized pbuf. + * + * The number of bytes copied is recorded in the oversize_used + * variable. The actual copying is done at the bottom of the + * function. + */ +#if TCP_OVERSIZE +#if TCP_OVERSIZE_DBGCHECK + /* check that pcb->unsent_oversize matches last_unsent->unsent_oversize */ + LWIP_ASSERT("unsent_oversize mismatch (pcb vs. last_unsent)", + pcb->unsent_oversize == last_unsent->oversize_left); +#endif /* TCP_OVERSIZE_DBGCHECK */ + oversize = pcb->unsent_oversize; + if (oversize > 0) { + LWIP_ASSERT("inconsistent oversize vs. space", oversize_used <= space); + seg = last_unsent; + oversize_used = oversize < len ? oversize : len; + pos += oversize_used; + oversize -= oversize_used; + space -= oversize_used; } - /* subsequent segments of to-be-queued data */ - else { - /* Attach the segment to the end of the queued segments */ - LWIP_ASSERT("useg != NULL", useg != NULL); - useg->next = seg; + /* now we are either finished or oversize is zero */ + LWIP_ASSERT("inconsistend oversize vs. len", (oversize == 0) || (pos == len)); +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: Chain a new pbuf to the end of pcb->unsent. + * + * We don't extend segments containing SYN/FIN flags or options + * (len==0). The new pbuf is kept in concat_p and pbuf_cat'ed at + * the end. + */ + if ((pos < len) && (space > 0) && (last_unsent->len > 0)) { + u16_t seglen = space < len - pos ? space : len - pos; + seg = last_unsent; + + /* Create a pbuf with a copy or reference to seglen bytes. We + * can use PBUF_RAW here since the data appears in the middle of + * a segment. A header will never be prepended. */ + if (apiflags & TCP_WRITE_FLAG_COPY) { + /* Data is copied */ + if ((concat_p = tcp_pbuf_prealloc(PBUF_RAW, seglen, space, &oversize, pcb, apiflags, 1)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", + seglen)); + goto memerr; + } +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ + TCP_DATA_COPY2(concat_p->payload, (u8_t*)arg + pos, seglen, &concat_chksum, &concat_chksum_swapped); +#if TCP_CHECKSUM_ON_COPY + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + } else { + /* Data is not copied */ + if ((concat_p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, + ("tcp_write: could not allocate memory for zero-copy pbuf\n")); + goto memerr; + } +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + tcp_seg_add_chksum(~inet_chksum((u8_t*)arg + pos, seglen), seglen, + &concat_chksum, &concat_chksum_swapped); + concat_chksummed += seglen; +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + concat_p->payload = (u8_t*)arg + pos; + } + + pos += seglen; + queuelen += pbuf_clen(concat_p); } - /* remember last segment of to-be-queued data for next iteration */ - useg = seg; + } else { +#if TCP_OVERSIZE + LWIP_ASSERT("unsent_oversize mismatch (pcb->unsent is NULL)", + pcb->unsent_oversize == 0); +#endif /* TCP_OVERSIZE */ + } + + /* + * Phase 3: Create new segments. + * + * The new segments are chained together in the local 'queue' + * variable, ready to be appended to pcb->unsent. + */ + while (pos < len) { + struct pbuf *p; + u16_t left = len - pos; + u16_t max_len = pcb->mss - optlen; + u16_t seglen = left > max_len ? max_len : left; +#if TCP_CHECKSUM_ON_COPY + u16_t chksum = 0; + u8_t chksum_swapped = 0; +#endif /* TCP_CHECKSUM_ON_COPY */ - /* If copy is set, memory should be allocated - * and data copied into pbuf, otherwise data comes from - * ROM or other static memory, and need not be copied. */ if (apiflags & TCP_WRITE_FLAG_COPY) { - if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, seglen + optlen, PBUF_RAM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_enqueue : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); + /* If copy is set, memory should be allocated and data copied + * into pbuf */ + if ((p = tcp_pbuf_prealloc(PBUF_TRANSPORT, seglen + optlen, pcb->mss, &oversize, pcb, apiflags, queue == NULL)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write : could not allocate memory for pbuf copy size %"U16_F"\n", seglen)); goto memerr; } - LWIP_ASSERT("check that first pbuf can hold the complete seglen", - (seg->p->len >= seglen + optlen)); - queuelen += pbuf_clen(seg->p); - if (arg != NULL) { - MEMCPY((char *)seg->p->payload + optlen, ptr, seglen); - } - seg->dataptr = seg->p->payload; - } - /* do not copy data */ - else { - /* First, allocate a pbuf for the headers. */ - if ((seg->p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_enqueue: could not allocate memory for header pbuf\n")); + LWIP_ASSERT("tcp_write: check that first pbuf can hold the complete seglen", + (p->len >= seglen)); + TCP_DATA_COPY2((char *)p->payload + optlen, (u8_t*)arg + pos, seglen, &chksum, &chksum_swapped); + } else { + /* Copy is not set: First allocate a pbuf for holding the data. + * Since the referenced data is available at least until it is + * sent out on the link (as it has to be ACKed by the remote + * party) we can safely use PBUF_ROM instead of PBUF_REF here. + */ + struct pbuf *p2; +#if TCP_OVERSIZE + LWIP_ASSERT("oversize == 0", oversize == 0); +#endif /* TCP_OVERSIZE */ + if ((p2 = pbuf_alloc(PBUF_TRANSPORT, seglen, PBUF_ROM)) == NULL) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for zero-copy pbuf\n")); goto memerr; } - queuelen += pbuf_clen(seg->p); - - /* Second, allocate a pbuf for holding the data. - * since the referenced data is available at least until it is sent out on the - * link (as it has to be ACKed by the remote party) we can safely use PBUF_ROM - * instead of PBUF_REF here. - */ - if (left > 0) { - if ((p = pbuf_alloc(PBUF_RAW, seglen, PBUF_ROM)) == NULL) { - /* If allocation fails, we have to deallocate the header pbuf as well. */ - pbuf_free(seg->p); - seg->p = NULL; - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_enqueue: could not allocate memory for zero-copy pbuf\n")); - goto memerr; - } - ++queuelen; - /* reference the non-volatile payload data */ - p->payload = ptr; - seg->dataptr = ptr; - - /* Concatenate the headers and data pbufs together. */ - pbuf_cat(seg->p/*header*/, p/*data*/); - p = NULL; +#if TCP_CHECKSUM_ON_COPY + /* calculate the checksum of nocopy-data */ + chksum = ~inet_chksum((u8_t*)arg + pos, seglen); +#endif /* TCP_CHECKSUM_ON_COPY */ + /* reference the non-volatile payload data */ + p2->payload = (u8_t*)arg + pos; + + /* Second, allocate a pbuf for the headers. */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + /* If allocation fails, we have to deallocate the data pbuf as + * well. */ + pbuf_free(p2); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: could not allocate memory for header pbuf\n")); + goto memerr; } + /* Concatenate the headers and data pbufs together. */ + pbuf_cat(p/*header*/, p2/*data*/); } + queuelen += pbuf_clen(p); + /* Now that there are more segments queued, we check again if the - length of the queue exceeds the configured maximum or overflows. */ + * length of the queue exceeds the configured maximum or + * overflows. */ if ((queuelen > TCP_SND_QUEUELEN) || (queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, - ("tcp_enqueue: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 2, ("tcp_write: queue too long %"U16_F" (%"U16_F")\n", queuelen, TCP_SND_QUEUELEN)); + pbuf_free(p); goto memerr; } - seg->len = seglen; - - /* build TCP header */ - if (pbuf_header(seg->p, TCP_HLEN)) { - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("tcp_enqueue: no room for TCP header in pbuf.\n")); - TCP_STATS_INC(tcp.err); + if ((seg = tcp_create_segment(pcb, p, 0, pcb->snd_lbb + pos, optflags)) == NULL) { goto memerr; } - seg->tcphdr = seg->p->payload; - seg->tcphdr->src = htons(pcb->local_port); - seg->tcphdr->dest = htons(pcb->remote_port); - seg->tcphdr->seqno = htonl(seqno); - seg->tcphdr->urgp = 0; - TCPH_FLAGS_SET(seg->tcphdr, flags); - /* don't fill in tcphdr->ackno and tcphdr->wnd until later */ - - seg->flags = optflags; - - /* Set the length of the header */ - TCPH_HDRLEN_SET(seg->tcphdr, (5 + optlen / 4)); - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_enqueue: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", +#if TCP_OVERSIZE_DBGCHECK + seg->oversize_left = oversize; +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + seg->chksum = chksum; + seg->chksum_swapped = chksum_swapped; + seg->flags |= TF_SEG_DATA_CHECKSUMMED; +#endif /* TCP_CHECKSUM_ON_COPY */ + + /* first segment of to-be-queued data? */ + if (queue == NULL) { + queue = seg; + } else { + /* Attach the segment to the end of the queued segments */ + LWIP_ASSERT("prev_seg != NULL", prev_seg != NULL); + prev_seg->next = seg; + } + /* remember last segment of to-be-queued data for next iteration */ + prev_seg = seg; + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, ("tcp_write: queueing %"U32_F":%"U32_F"\n", ntohl(seg->tcphdr->seqno), - ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), - (u16_t)flags)); + ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg))); - left -= seglen; - seqno += seglen; - ptr = (void *)((u8_t *)ptr + seglen); + pos += seglen; } - /* Now that the data to be enqueued has been broken up into TCP - segments in the queue variable, we add them to the end of the - pcb->unsent queue. */ - if (pcb->unsent == NULL) { - useg = NULL; - } - else { - for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); - } - /* { useg is last segment on the unsent queue, NULL if list is empty } */ - - /* If there is room in the last pbuf on the unsent queue, - chain the first pbuf on the queue together with that. */ - if (useg != NULL && - TCP_TCPLEN(useg) != 0 && - !(TCPH_FLAGS(useg->tcphdr) & (TCP_SYN | TCP_FIN)) && - (!(flags & (TCP_SYN | TCP_FIN)) || (flags == TCP_FIN)) && - /* fit within max seg size */ - (useg->len + queue->len <= pcb->mss) && - /* only concatenate segments with the same options */ - (useg->flags == queue->flags) && - /* segments are consecutive */ - (ntohl(useg->tcphdr->seqno) + useg->len == ntohl(queue->tcphdr->seqno)) ) { - /* Remove TCP header from first segment of our to-be-queued list */ - if(pbuf_header(queue->p, -(TCP_HLEN + optlen))) { - /* Can we cope with this failing? Just assert for now */ - LWIP_ASSERT("pbuf_header failed\n", 0); - TCP_STATS_INC(tcp.err); - goto memerr; - } - if (queue->p->len == 0) { - /* free the first (header-only) pbuf if it is now empty (contained only headers) */ - struct pbuf *old_q = queue->p; - queue->p = queue->p->next; - old_q->next = NULL; - queuelen--; - pbuf_free(old_q); - } - if (flags & TCP_FIN) { - /* the new segment contains only FIN, no data -> put the FIN into the last segment */ - LWIP_ASSERT("FIN enqueued together with data", queue->p == NULL && queue->len == 0); - TCPH_SET_FLAG(useg->tcphdr, TCP_FIN); - } else { - LWIP_ASSERT("zero-length pbuf", (queue->p != NULL) && (queue->p->len > 0)); - pbuf_cat(useg->p, queue->p); - useg->len += queue->len; - useg->next = queue->next; - } + /* + * All three segmentation phases were successful. We can commit the + * transaction. + */ - LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("tcp_enqueue: chaining segments, new len %"U16_F"\n", useg->len)); - if (seg == queue) { - seg = useg; - seglen = useg->len; + /* + * Phase 1: If data has been added to the preallocated tail of + * last_unsent, we update the length fields of the pbuf chain. + */ +#if TCP_OVERSIZE + if (oversize_used > 0) { + struct pbuf *p; + /* Bump tot_len of whole chain, len of tail */ + for (p = last_unsent->p; p; p = p->next) { + p->tot_len += oversize_used; + if (p->next == NULL) { + TCP_DATA_COPY((char *)p->payload + p->len, arg, oversize_used, last_unsent); + p->len += oversize_used; + } } - memp_free(MEMP_TCP_SEG, queue); + last_unsent->len += oversize_used; +#if TCP_OVERSIZE_DBGCHECK + last_unsent->oversize_left -= oversize_used; +#endif /* TCP_OVERSIZE_DBGCHECK */ } - else { - /* empty list */ - if (useg == NULL) { - /* initialize list with this segment */ - pcb->unsent = queue; - } - /* enqueue segment */ - else { - useg->next = queue; + pcb->unsent_oversize = oversize; +#endif /* TCP_OVERSIZE */ + + /* + * Phase 2: concat_p can be concatenated onto last_unsent->p + */ + if (concat_p != NULL) { + LWIP_ASSERT("tcp_write: cannot concatenate when pcb->unsent is empty", + (last_unsent != NULL)); + pbuf_cat(last_unsent->p, concat_p); + last_unsent->len += concat_p->tot_len; +#if TCP_CHECKSUM_ON_COPY + if (concat_chksummed) { + tcp_seg_add_chksum(concat_chksum, concat_chksummed, &last_unsent->chksum, + &last_unsent->chksum_swapped); + last_unsent->flags |= TF_SEG_DATA_CHECKSUMMED; } +#endif /* TCP_CHECKSUM_ON_COPY */ } - if ((flags & TCP_SYN) || (flags & TCP_FIN)) { - ++len; - } - if (flags & TCP_FIN) { - pcb->flags |= TF_FIN; + + /* + * Phase 3: Append queue to pcb->unsent. Queue may be NULL, but that + * is harmless + */ + if (last_unsent == NULL) { + pcb->unsent = queue; + } else { + last_unsent->next = queue; } - pcb->snd_lbb += len; + /* + * Finally update the pcb state. + */ + pcb->snd_lbb += len; pcb->snd_buf -= len; - - /* update number of segments on the queues */ pcb->snd_queuelen = queuelen; - LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_write: %"S16_F" (after enqueued)\n", + pcb->snd_queuelen)); if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_enqueue: valid queue length", - pcb->unacked != NULL || pcb->unsent != NULL); + LWIP_ASSERT("tcp_write: valid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); } - /* Set the PSH flag in the last segment that we enqueued, but only - if the segment has data (indicated by seglen > 0). */ - if (seg != NULL && seglen > 0 && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { + /* Set the PSH flag in the last segment that we enqueued. */ + if (seg != NULL && seg->tcphdr != NULL && ((apiflags & TCP_WRITE_FLAG_MORE)==0)) { TCPH_SET_FLAG(seg->tcphdr, TCP_PSH); } @@ -426,17 +687,130 @@ memerr: pcb->flags |= TF_NAGLEMEMERR; TCP_STATS_INC(tcp.memerr); + if (concat_p != NULL) { + pbuf_free(concat_p); + } if (queue != NULL) { tcp_segs_free(queue); } if (pcb->snd_queuelen != 0) { - LWIP_ASSERT("tcp_enqueue: valid queue length", pcb->unacked != NULL || + LWIP_ASSERT("tcp_write: valid queue length", pcb->unacked != NULL || pcb->unsent != NULL); } - LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_enqueue: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); + LWIP_DEBUGF(TCP_QLEN_DEBUG | LWIP_DBG_STATE, ("tcp_write: %"S16_F" (with mem err)\n", pcb->snd_queuelen)); return ERR_MEM; } +/** + * Enqueue TCP options for transmission. + * + * Called by tcp_connect(), tcp_listen_input(), and tcp_send_ctrl(). + * + * @param pcb Protocol control block for the TCP connection. + * @param flags TCP header flags to set in the outgoing segment. + * @param optdata pointer to TCP options, or NULL. + * @param optlen length of TCP options in bytes. + */ +err_t +tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags) +{ + struct pbuf *p; + struct tcp_seg *seg; + u8_t optflags = 0; + u8_t optlen = 0; + + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: queuelen: %"U16_F"\n", (u16_t)pcb->snd_queuelen)); + + LWIP_ASSERT("tcp_enqueue_flags: need either TCP_SYN or TCP_FIN in flags (programmer violates API)", + (flags & (TCP_SYN | TCP_FIN)) != 0); + + /* check for configured max queuelen and possible overflow */ + if ((pcb->snd_queuelen >= TCP_SND_QUEUELEN) || (pcb->snd_queuelen > TCP_SNDQUEUELEN_OVERFLOW)) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: too long queue %"U16_F" (max %"U16_F")\n", + pcb->snd_queuelen, TCP_SND_QUEUELEN)); + TCP_STATS_INC(tcp.memerr); + pcb->flags |= TF_NAGLEMEMERR; + return ERR_MEM; + } + + if (flags & TCP_SYN) { + optflags = TF_SEG_OPTS_MSS; + } +#if LWIP_TCP_TIMESTAMPS + if ((pcb->flags & TF_TIMESTAMP)) { + optflags |= TF_SEG_OPTS_TS; + } +#endif /* LWIP_TCP_TIMESTAMPS */ + optlen = LWIP_TCP_OPT_LENGTH(optflags); + + /* tcp_enqueue_flags is always called with either SYN or FIN in flags. + * We need one available snd_buf byte to do that. + * This means we can't send FIN while snd_buf==0. A better fix would be to + * not include SYN and FIN sequence numbers in the snd_buf count. */ + if (pcb->snd_buf == 0) { + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | 3, ("tcp_enqueue_flags: no send buffer available\n")); + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + + /* Allocate pbuf with room for TCP header + options */ + if ((p = pbuf_alloc(PBUF_TRANSPORT, optlen, PBUF_RAM)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("tcp_enqueue_flags: check that first pbuf can hold optlen", + (p->len >= optlen)); + + /* Allocate memory for tcp_seg, and fill in fields. */ + if ((seg = tcp_create_segment(pcb, p, flags, pcb->snd_lbb, optflags)) == NULL) { + pcb->flags |= TF_NAGLEMEMERR; + TCP_STATS_INC(tcp.memerr); + return ERR_MEM; + } + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); + LWIP_ASSERT("tcp_enqueue_flags: invalid segment length", seg->len == 0); + + LWIP_DEBUGF(TCP_OUTPUT_DEBUG | LWIP_DBG_TRACE, + ("tcp_enqueue_flags: queueing %"U32_F":%"U32_F" (0x%"X16_F")\n", + ntohl(seg->tcphdr->seqno), + ntohl(seg->tcphdr->seqno) + TCP_TCPLEN(seg), + (u16_t)flags)); + + /* Now append seg to pcb->unsent queue */ + if (pcb->unsent == NULL) { + pcb->unsent = seg; + } else { + struct tcp_seg *useg; + for (useg = pcb->unsent; useg->next != NULL; useg = useg->next); + useg->next = seg; + } +#if TCP_OVERSIZE + /* The new unsent tail has no space */ + pcb->unsent_oversize = 0; +#endif /* TCP_OVERSIZE */ + + /* SYN and FIN bump the sequence number */ + if ((flags & TCP_SYN) || (flags & TCP_FIN)) { + pcb->snd_lbb++; + /* optlen does not influence snd_buf */ + pcb->snd_buf--; + } + if (flags & TCP_FIN) { + pcb->flags |= TF_FIN; + } + + /* update number of segments on the queues */ + pcb->snd_queuelen += pbuf_clen(seg->p); + LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_enqueue_flags: %"S16_F" (after enqueued)\n", pcb->snd_queuelen)); + if (pcb->snd_queuelen != 0) { + LWIP_ASSERT("tcp_enqueue_flags: invalid queue length", + pcb->unacked != NULL || pcb->unsent != NULL); + } + + return ERR_OK; +} + #if LWIP_TCP_TIMESTAMPS /* Build a timestamp option (12 bytes long) at the specified options pointer) @@ -448,7 +822,7 @@ static void tcp_build_timestamp_option(struct tcp_pcb *pcb, u32_t *opts) { /* Pad with two NOP options to make everything nicely aligned */ - opts[0] = htonl(0x0101080A); + opts[0] = PP_HTONL(0x0101080A); opts[1] = htonl(sys_now()); opts[2] = htonl(pcb->ts_recent); } @@ -470,18 +844,18 @@ tcp_send_empty_ack(struct tcp_pcb *pcb) optlen = LWIP_TCP_OPT_LENGTH(TF_SEG_OPTS_TS); } #endif - p = pbuf_alloc(PBUF_IP, TCP_HLEN + optlen, PBUF_RAM); + + p = tcp_output_alloc_header(pcb, optlen, 0, htonl(pcb->snd_nxt)); if (p == NULL) { LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: (ACK) could not allocate pbuf\n")); return ERR_BUF; } + tcphdr = (struct tcp_hdr *)p->payload; LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: sending ACK for %"U32_F"\n", pcb->rcv_nxt)); /* remove ACK flags from the PCB, as we send an empty ACK now */ pcb->flags &= ~(TF_ACK_DELAY | TF_ACK_NOW); - tcphdr = tcp_output_set_header(pcb, p, optlen, htonl(pcb->snd_nxt)); - /* NB. MSS option is only sent on SYNs, so ignore it here */ #if LWIP_TCP_TIMESTAMPS pcb->ts_lastacksent = pcb->rcv_nxt; @@ -581,10 +955,10 @@ tcp_output(struct tcp_pcb *pcb) (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0); /* Stop sending if the nagle algorithm would prevent it * Don't stop: - * - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or + * - if tcp_write had a memory error before (prevent delayed ACK timeout) or * - if FIN was already enqueued for this PCB (SYN is always alone in a segment - * either seg->next != NULL or pcb->unacked == NULL; - * RST is no sent using tcp_enqueue/tcp_output. + * RST is no sent using tcp_write/tcp_output. */ if((tcp_do_output_nagle(pcb) == 0) && ((pcb->flags & (TF_NAGLEMEMERR | TF_FIN)) == 0)){ @@ -623,7 +997,7 @@ tcp_output(struct tcp_pcb *pcb) /* In the case of fast retransmit, the packet should not go to the tail * of the unacked queue, but rather somewhere before it. We need to check for * this case. -STJ Jul 27, 2004 */ - if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))){ + if (TCP_SEQ_LT(ntohl(seg->tcphdr->seqno), ntohl(useg->tcphdr->seqno))) { /* add segment to before tail of unacked list, keeping the list sorted */ struct tcp_seg **cur_seg = &(pcb->unacked); while (*cur_seg && @@ -644,6 +1018,12 @@ tcp_output(struct tcp_pcb *pcb) } seg = pcb->unsent; } +#if TCP_OVERSIZE + if (pcb->unsent == NULL) { + /* last unsent has been removed, reset unsent_oversize */ + pcb->unsent_oversize = 0; + } +#endif /* TCP_OVERSIZE */ if (seg != NULL && pcb->persist_backoff == 0 && ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len > pcb->snd_wnd) { @@ -683,7 +1063,8 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) /* Add any requested options. NB MSS option is only set on SYN packets, so ignore it here */ - opts = (u32_t *)(seg->tcphdr + 1); + LWIP_ASSERT("seg->tcphdr not aligned", ((mem_ptr_t)seg->tcphdr % MEM_ALIGNMENT) == 0); + opts = (u32_t *)(void *)(seg->tcphdr + 1); if (seg->flags & TF_SEG_OPTS_MSS) { TCP_BUILD_MSS_OPTION(*opts); opts += 1; @@ -697,6 +1078,12 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) } #endif + /* Set retransmission timer running if it is not currently enabled + This must be set before checking the route. */ + if (pcb->rtime == -1) { + pcb->rtime = 0; + } + /* If we don't have a local IP address, we get one by calling ip_route(). */ if (ip_addr_isany(&(pcb->local_ip))) { @@ -704,13 +1091,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) if (netif == NULL) { return; } - ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); + ip_addr_copy(pcb->local_ip, netif->ip_addr); } - /* Set retransmission timer running if it is not currently enabled */ - if(pcb->rtime == -1) - pcb->rtime = 0; - if (pcb->rttest == 0) { pcb->rttest = tcp_ticks; pcb->rtseq = ntohl(seg->tcphdr->seqno); @@ -730,11 +1113,45 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) seg->tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP - seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, - &(pcb->local_ip), +#if TCP_CHECKSUM_ON_COPY + { + u32_t acc; +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + u16_t chksum_slow = inet_chksum_pseudo(seg->p, &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + if ((seg->flags & TF_SEG_DATA_CHECKSUMMED) == 0) { + LWIP_ASSERT("data included but not checksummed", + seg->p->tot_len == (TCPH_HDRLEN(seg->tcphdr) * 4)); + } + + /* rebuild TCP header checksum (TCP header changes for retransmissions!) */ + acc = inet_chksum_pseudo_partial(seg->p, &(pcb->local_ip), &(pcb->remote_ip), - IP_PROTO_TCP, seg->p->tot_len); -#endif + IP_PROTO_TCP, seg->p->tot_len, TCPH_HDRLEN(seg->tcphdr) * 4); + /* add payload checksum */ + if (seg->chksum_swapped) { + seg->chksum = SWAP_BYTES_IN_WORD(seg->chksum); + seg->chksum_swapped = 0; + } + acc += (u16_t)~(seg->chksum); + seg->tcphdr->chksum = FOLD_U32T(acc); +#if TCP_CHECKSUM_ON_COPY_SANITY_CHECK + if (chksum_slow != seg->tcphdr->chksum) { + LWIP_DEBUGF(TCP_DEBUG | LWIP_DBG_LEVEL_WARNING, + ("tcp_output_segment: calculated checksum is %"X16_F" instead of %"X16_F"\n", + seg->tcphdr->chksum, chksum_slow)); + seg->tcphdr->chksum = chksum_slow; + } +#endif /* TCP_CHECKSUM_ON_COPY_SANITY_CHECK */ + } +#else /* TCP_CHECKSUM_ON_COPY */ + seg->tcphdr->chksum = inet_chksum_pseudo(seg->p, &(pcb->local_ip), + &(pcb->remote_ip), + IP_PROTO_TCP, seg->p->tot_len); +#endif /* TCP_CHECKSUM_ON_COPY */ +#endif /* CHECKSUM_GEN_TCP */ TCP_STATS_INC(tcp.xmit); #if LWIP_NETIF_HWADDRHINT @@ -768,7 +1185,7 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) */ void tcp_rst(u32_t seqno, u32_t ackno, - struct ip_addr *local_ip, struct ip_addr *remote_ip, + ip_addr_t *local_ip, ip_addr_t *remote_ip, u16_t local_port, u16_t remote_port) { struct pbuf *p; @@ -781,17 +1198,16 @@ tcp_rst(u32_t seqno, u32_t ackno, LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", (p->len >= sizeof(struct tcp_hdr))); - tcphdr = p->payload; + tcphdr = (struct tcp_hdr *)p->payload; tcphdr->src = htons(local_port); tcphdr->dest = htons(remote_port); tcphdr->seqno = htonl(seqno); tcphdr->ackno = htonl(ackno); - TCPH_FLAGS_SET(tcphdr, TCP_RST | TCP_ACK); - tcphdr->wnd = htons(TCP_WND); + TCPH_HDRLEN_FLAGS_SET(tcphdr, TCP_HLEN/4, TCP_RST | TCP_ACK); + tcphdr->wnd = PP_HTONS(TCP_WND); + tcphdr->chksum = 0; tcphdr->urgp = 0; - TCPH_HDRLEN_SET(tcphdr, 5); - tcphdr->chksum = 0; #if CHECKSUM_GEN_TCP tcphdr->chksum = inet_chksum_pseudo(p, local_ip, remote_ip, IP_PROTO_TCP, p->tot_len); @@ -900,10 +1316,11 @@ tcp_rexmit_fast(struct tcp_pcb *pcb) /* Set ssthresh to half of the minimum of the current * cwnd and the advertised window */ - if (pcb->cwnd > pcb->snd_wnd) + if (pcb->cwnd > pcb->snd_wnd) { pcb->ssthresh = pcb->snd_wnd / 2; - else + } else { pcb->ssthresh = pcb->cwnd / 2; + } /* The minimum value for ssthresh should be 2 MSS */ if (pcb->ssthresh < 2*pcb->mss) { @@ -935,23 +1352,19 @@ tcp_keepalive(struct tcp_pcb *pcb) struct tcp_hdr *tcphdr; LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: sending KEEPALIVE probe to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), - ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: tcp_ticks %"U32_F" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n", tcp_ticks, pcb->tmr, pcb->keep_cnt_sent)); - p = pbuf_alloc(PBUF_IP, TCP_HLEN, PBUF_RAM); - + p = tcp_output_alloc_header(pcb, 0, 0, htonl(pcb->snd_nxt - 1)); if(p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_keepalive: could not allocate memory for pbuf\n")); return; } - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= sizeof(struct tcp_hdr))); - - tcphdr = tcp_output_set_header(pcb, p, 0, htonl(pcb->snd_nxt - 1)); + tcphdr = (struct tcp_hdr *)p->payload; #if CHECKSUM_GEN_TCP tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip, @@ -994,8 +1407,8 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: sending ZERO WINDOW probe to %" U16_F".%"U16_F".%"U16_F".%"U16_F"\n", - ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), - ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip))); + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip))); LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: tcp_ticks %"U32_F @@ -1004,31 +1417,32 @@ tcp_zero_window_probe(struct tcp_pcb *pcb) seg = pcb->unacked; - if(seg == NULL) + if(seg == NULL) { seg = pcb->unsent; - - if(seg == NULL) + } + if(seg == NULL) { return; + } is_fin = ((TCPH_FLAGS(seg->tcphdr) & TCP_FIN) != 0) && (seg->len == 0); - len = is_fin ? TCP_HLEN : TCP_HLEN + 1; + /* we want to send one seqno: either FIN or data (no options) */ + len = is_fin ? 0 : 1; - p = pbuf_alloc(PBUF_IP, len, PBUF_RAM); + p = tcp_output_alloc_header(pcb, 0, len, seg->tcphdr->seqno); if(p == NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n")); return; } - LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr", - (p->len >= sizeof(struct tcp_hdr))); - - tcphdr = tcp_output_set_header(pcb, p, 0, seg->tcphdr->seqno); + tcphdr = (struct tcp_hdr *)p->payload; if (is_fin) { /* FIN segment, no data */ TCPH_FLAGS_SET(tcphdr, TCP_ACK | TCP_FIN); } else { /* Data segment, copy in one byte from the head of the unacked queue */ - *((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr; + struct tcp_hdr *thdr = (struct tcp_hdr *)seg->p->payload; + char *d = ((char *)p->payload + TCP_HLEN); + pbuf_copy_partial(seg->p, d, 1, TCPH_HDRLEN(thdr) * 4); } #if CHECKSUM_GEN_TCP diff --git a/core/lwip/src/core/timers.c b/core/lwip/src/core/timers.c new file mode 100644 index 00000000..4e94f0d1 --- /dev/null +++ b/core/lwip/src/core/timers.c @@ -0,0 +1,483 @@ +/** + * @file + * Stack-internal timers implementation. + * This file includes timer callbacks for stack-internal timers as well as + * functions to set up or stop timers and check for expired timers. + * + */ + +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * Simon Goldschmidt + * + */ + +#include "lwip/opt.h" + +#include "lwip/timers.h" +#include "lwip/tcp_impl.h" + +#if LWIP_TIMERS + +#include "lwip/def.h" +#include "lwip/memp.h" +#include "lwip/tcpip.h" + +#include "lwip/ip_frag.h" +#include "netif/etharp.h" +#include "lwip/dhcp.h" +#include "lwip/autoip.h" +#include "lwip/igmp.h" +#include "lwip/dns.h" + + +/** The one and only timeout list */ +static struct sys_timeo *next_timeout; +#if NO_SYS +static u32_t timeouts_last_time; +#endif /* NO_SYS */ + +#if LWIP_TCP +/** global variable that shows if the tcp timer is currently scheduled or not */ +static int tcpip_tcp_timer_active; + +/** + * Timer callback function that calls tcp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +tcpip_tcp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + /* call TCP timer handler */ + tcp_tmr(); + /* timer still needed? */ + if (tcp_active_pcbs || tcp_tw_pcbs) { + /* restart timer */ + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } else { + /* disable timer */ + tcpip_tcp_timer_active = 0; + } +} + +/** + * Called from TCP_REG when registering a new PCB: + * the reason is to have the TCP timer only running when + * there are active (or time-wait) PCBs. + */ +void +tcp_timer_needed(void) +{ + /* timer is off but needed again? */ + if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) { + /* enable and start timer */ + tcpip_tcp_timer_active = 1; + sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL); + } +} +#endif /* LWIP_TCP */ + +#if IP_REASSEMBLY +/** + * Timer callback function that calls ip_reass_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +ip_reass_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n")); + ip_reass_tmr(); + sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +} +#endif /* IP_REASSEMBLY */ + +#if LWIP_ARP +/** + * Timer callback function that calls etharp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +arp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n")); + etharp_tmr(); + undiarp_tmr(); + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +} +#endif /* LWIP_ARP */ + +#if LWIP_DHCP +/** + * Timer callback function that calls dhcp_coarse_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dhcp_timer_coarse(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n")); + dhcp_coarse_tmr(); + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); +} + +/** + * Timer callback function that calls dhcp_fine_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dhcp_timer_fine(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n")); + dhcp_fine_tmr(); + sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +} +#endif /* LWIP_DHCP */ + +#if LWIP_AUTOIP +/** + * Timer callback function that calls autoip_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +autoip_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n")); + autoip_tmr(); + sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +} +#endif /* LWIP_AUTOIP */ + +#if LWIP_IGMP +/** + * Timer callback function that calls igmp_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +igmp_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n")); + igmp_tmr(); + sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +} +#endif /* LWIP_IGMP */ + +#if LWIP_DNS +/** + * Timer callback function that calls dns_tmr() and reschedules itself. + * + * @param arg unused argument + */ +static void +dns_timer(void *arg) +{ + LWIP_UNUSED_ARG(arg); + LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n")); + dns_tmr(); + sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +} +#endif /* LWIP_DNS */ + +/** Initialize this module */ +void sys_timeouts_init(void) +{ +#if IP_REASSEMBLY + sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL); +#endif /* IP_REASSEMBLY */ +#if LWIP_ARP + sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL); +#endif /* LWIP_ARP */ +#if LWIP_DHCP + sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL); + sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL); +#endif /* LWIP_DHCP */ +#if LWIP_AUTOIP + sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL); +#endif /* LWIP_AUTOIP */ +#if LWIP_IGMP + sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL); +#endif /* LWIP_IGMP */ +#if LWIP_DNS + sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL); +#endif /* LWIP_DNS */ + +#if NO_SYS + /* Initialise timestamp for sys_check_timeouts */ + timeouts_last_time = sys_now(); +#endif +} + +/** + * Create a one-shot timer (aka timeout). Timeouts are processed in the + * following cases: + * - while waiting for a message using sys_timeouts_mbox_fetch() + * - by calling sys_check_timeouts() (NO_SYS==1 only) + * + * @param msecs time in milliseconds after that the timer should expire + * @param handler callback function to call when msecs have elapsed + * @param arg argument to pass to the callback function + */ +#if LWIP_DEBUG_TIMERNAMES +void +sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name) +#else /* LWIP_DEBUG_TIMERNAMES */ +void +sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg) +#endif /* LWIP_DEBUG_TIMERNAMES */ +{ + struct sys_timeo *timeout, *t; + + timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT); + if (timeout == NULL) { + LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL); + return; + } + timeout->next = NULL; + timeout->h = handler; + timeout->arg = arg; + timeout->time = msecs; +#if LWIP_DEBUG_TIMERNAMES + timeout->handler_name = handler_name; + LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n", + (void *)timeout, msecs, handler_name, (void *)arg)); +#endif /* LWIP_DEBUG_TIMERNAMES */ + + if (next_timeout == NULL) { + next_timeout = timeout; + return; + } + + if (next_timeout->time > msecs) { + next_timeout->time -= msecs; + timeout->next = next_timeout; + next_timeout = timeout; + } else { + for(t = next_timeout; t != NULL; t = t->next) { + timeout->time -= t->time; + if (t->next == NULL || t->next->time > timeout->time) { + if (t->next != NULL) { + t->next->time -= timeout->time; + } + timeout->next = t->next; + t->next = timeout; + break; + } + } + } +} + +/** + * Go through timeout list (for this task only) and remove the first matching + * entry, even though the timeout has not triggered yet. + * + * @note This function only works as expected if there is only one timeout + * calling 'handler' in the list of timeouts. + * + * @param handler callback function that would be called by the timeout + * @param arg callback argument that would be passed to handler +*/ +void +sys_untimeout(sys_timeout_handler handler, void *arg) +{ + struct sys_timeo *prev_t, *t; + + if (next_timeout == NULL) { + return; + } + + for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) { + if ((t->h == handler) && (t->arg == arg)) { + /* We have a match */ + /* Unlink from previous in list */ + if (prev_t == NULL) { + next_timeout = t->next; + } else { + prev_t->next = t->next; + } + /* If not the last one, add time of this one back to next */ + if (t->next != NULL) { + t->next->time += t->time; + } + memp_free(MEMP_SYS_TIMEOUT, t); + return; + } + } + return; +} + +#if NO_SYS + +/** Handle timeouts for NO_SYS==1 (i.e. without using + * tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout + * handler functions when timeouts expire. + * + * Must be called periodically from your main loop. + */ +void +sys_check_timeouts(void) +{ + struct sys_timeo *tmptimeout; + u32_t diff; + sys_timeout_handler handler; + void *arg; + int had_one; + u32_t now; + + now = sys_now(); + if (next_timeout) { + /* this cares for wraparounds */ + diff = LWIP_U32_DIFF(now, timeouts_last_time); + do + { + had_one = 0; + tmptimeout = next_timeout; + if (tmptimeout->time <= diff) { + /* timeout has expired */ + had_one = 1; + timeouts_last_time = now; + diff -= tmptimeout->time; + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n", + tmptimeout->handler_name, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { + handler(arg); + } + } + /* repeat until all expired timers have been called */ + }while(had_one); + } +} + +/** Set back the timestamp of the last call to sys_check_timeouts() + * This is necessary if sys_check_timeouts() hasn't been called for a long + * time (e.g. while saving energy) to prevent all timer functions of that + * period being called. + */ +void +sys_restart_timeouts(void) +{ + timeouts_last_time = sys_now(); +} + +#else /* NO_SYS */ + +/** + * Wait (forever) for a message to arrive in an mbox. + * While waiting, timeouts are processed. + * + * @param mbox the mbox to fetch the message from + * @param msg the place to store the message + */ +void +sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg) +{ + u32_t time_needed; + struct sys_timeo *tmptimeout; + sys_timeout_handler handler; + void *arg; + + again: + if (!next_timeout) { + time_needed = sys_arch_mbox_fetch(mbox, msg, 0); + } else { + if (next_timeout->time > 0) { + time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time); + } else { + time_needed = SYS_ARCH_TIMEOUT; + } + + if (time_needed == SYS_ARCH_TIMEOUT) { + /* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message + could be fetched. We should now call the timeout handler and + deallocate the memory allocated for the timeout. */ + tmptimeout = next_timeout; + next_timeout = tmptimeout->next; + handler = tmptimeout->h; + arg = tmptimeout->arg; +#if LWIP_DEBUG_TIMERNAMES + if (handler != NULL) { + LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n", + tmptimeout->handler_name, arg)); + } +#endif /* LWIP_DEBUG_TIMERNAMES */ + memp_free(MEMP_SYS_TIMEOUT, tmptimeout); + if (handler != NULL) { + /* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the + timeout handler function. */ + LOCK_TCPIP_CORE(); + handler(arg); + UNLOCK_TCPIP_CORE(); + } + LWIP_TCPIP_THREAD_ALIVE(); + + /* We try again to fetch a message from the mbox. */ + goto again; + } else { + /* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout + occured. The time variable is set to the number of + milliseconds we waited for the message. */ + if (time_needed < next_timeout->time) { + next_timeout->time -= time_needed; + } else { + next_timeout->time = 0; + } + } + } +} + +#endif /* NO_SYS */ + +#else /* LWIP_TIMERS */ +/* Satisfy the TCP code which calls this function */ +void +tcp_timer_needed(void) +{ +} +#endif /* LWIP_TIMERS */ diff --git a/core/lwip/src/core/udp.c b/core/lwip/src/core/udp.c index 96dab41b..4596ba2b 100644 --- a/core/lwip/src/core/udp.c +++ b/core/lwip/src/core/udp.c @@ -53,7 +53,6 @@ #include "lwip/udp.h" #include "lwip/def.h" #include "lwip/memp.h" -#include "lwip/inet.h" #include "lwip/inet_chksum.h" #include "lwip/ip_addr.h" #include "lwip/netif.h" @@ -96,7 +95,7 @@ udp_input(struct pbuf *p, struct netif *inp) UDP_STATS_INC(udp.recv); - iphdr = p->payload; + iphdr = (struct ip_hdr *)p->payload; /* Check minimum length (IP header + UDP header) * and move payload pointer to UDP header */ @@ -114,7 +113,7 @@ udp_input(struct pbuf *p, struct netif *inp) udphdr = (struct udp_hdr *)p->payload; /* is broadcast packet ? */ - broadcast = ip_addr_isbroadcast(&(iphdr->dest), inp); + broadcast = ip_addr_isbroadcast(¤t_iphdr_dest, inp); LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len)); @@ -128,10 +127,10 @@ udp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(UDP_DEBUG, ("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest), - ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest), - ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src), - ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src))); + ip4_addr1_16(&iphdr->dest), ip4_addr2_16(&iphdr->dest), + ip4_addr3_16(&iphdr->dest), ip4_addr4_16(&iphdr->dest), ntohs(udphdr->dest), + ip4_addr1_16(&iphdr->src), ip4_addr2_16(&iphdr->src), + ip4_addr3_16(&iphdr->src), ip4_addr4_16(&iphdr->src), ntohs(udphdr->src))); #if LWIP_DHCP pcb = NULL; @@ -145,7 +144,7 @@ udp_input(struct pbuf *p, struct netif *inp) (- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY! - inp->dhcp->pcb->remote == ANY or iphdr->src */ if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) || - ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) { + ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), ¤t_iphdr_src))) { pcb = inp->dhcp->pcb; } } @@ -166,17 +165,17 @@ udp_input(struct pbuf *p, struct netif *inp) LWIP_DEBUGF(UDP_DEBUG, ("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- " "(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n", - ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip), - ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port, - ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip), - ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port)); + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), pcb->local_port, + ip4_addr1_16(&pcb->remote_ip), ip4_addr2_16(&pcb->remote_ip), + ip4_addr3_16(&pcb->remote_ip), ip4_addr4_16(&pcb->remote_ip), pcb->remote_port)); /* compare PCB local addr+port to UDP destination addr+port */ if ((pcb->local_port == dest) && ((!broadcast && ip_addr_isany(&pcb->local_ip)) || - ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) || + ip_addr_cmp(&(pcb->local_ip), ¤t_iphdr_dest) || #if LWIP_IGMP - ip_addr_ismulticast(&(iphdr->dest)) || + ip_addr_ismulticast(¤t_iphdr_dest) || #endif /* LWIP_IGMP */ #if IP_SOF_BROADCAST_RECV (broadcast && (pcb->so_options & SOF_BROADCAST)))) { @@ -194,7 +193,7 @@ udp_input(struct pbuf *p, struct netif *inp) if ((local_match != 0) && (pcb->remote_port == src) && (ip_addr_isany(&pcb->remote_ip) || - ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) { + ip_addr_cmp(&(pcb->remote_ip), ¤t_iphdr_src))) { /* the first fully matching PCB */ if (prev != NULL) { /* move the pcb to the front of udp_pcbs so that is @@ -216,7 +215,7 @@ udp_input(struct pbuf *p, struct netif *inp) } /* Check checksum if this is a match or if it was directed at us. */ - if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) { + if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, ¤t_iphdr_dest)) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n")); #if LWIP_UDPLITE if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) { @@ -238,8 +237,7 @@ udp_input(struct pbuf *p, struct netif *inp) goto end; } } - if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src), - (struct ip_addr *)&(iphdr->dest), + if (inet_chksum_pseudo_partial(p, ¤t_iphdr_src, ¤t_iphdr_dest, IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP Lite datagram discarded due to failing checksum\n")); @@ -255,8 +253,7 @@ udp_input(struct pbuf *p, struct netif *inp) { #if CHECKSUM_CHECK_UDP if (udphdr->chksum != 0) { - if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src), - (struct ip_addr *)&(iphdr->dest), + if (inet_chksum_pseudo(p, ip_current_src_addr(), ip_current_dest_addr(), IP_PROTO_UDP, p->tot_len) != 0) { LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_input: UDP datagram discarded due to failing checksum\n")); @@ -279,10 +276,58 @@ udp_input(struct pbuf *p, struct netif *inp) } if (pcb != NULL) { snmp_inc_udpindatagrams(); +#if SO_REUSE && SO_REUSE_RXTOALL + if ((broadcast || ip_addr_ismulticast(¤t_iphdr_dest)) && + ((pcb->so_options & SOF_REUSEADDR) != 0)) { + /* pass broadcast- or multicast packets to all multicast pcbs + if SOF_REUSEADDR is set on the first match */ + struct udp_pcb *mpcb; + u8_t p_header_changed = 0; + for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) { + if (mpcb != pcb) { + /* compare PCB local addr+port to UDP destination addr+port */ + if ((mpcb->local_port == dest) && + ((!broadcast && ip_addr_isany(&mpcb->local_ip)) || + ip_addr_cmp(&(mpcb->local_ip), ¤t_iphdr_dest) || +#if LWIP_IGMP + ip_addr_ismulticast(¤t_iphdr_dest) || +#endif /* LWIP_IGMP */ +#if IP_SOF_BROADCAST_RECV + (broadcast && (mpcb->so_options & SOF_BROADCAST)))) { +#else /* IP_SOF_BROADCAST_RECV */ + (broadcast))) { +#endif /* IP_SOF_BROADCAST_RECV */ + /* pass a copy of the packet to all local matches */ + if (mpcb->recv != NULL) { + struct pbuf *q; + /* for that, move payload to IP header again */ + if (p_header_changed == 0) { + pbuf_header(p, (s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + p_header_changed = 1; + } + q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if (q != NULL) { + err_t err = pbuf_copy(q, p); + if (err == ERR_OK) { + /* move payload to UDP data */ + pbuf_header(q, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + mpcb->recv(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src); + } + } + } + } + } + } + if (p_header_changed) { + /* and move payload to UDP data again */ + pbuf_header(p, -(s16_t)((IPH_HL(iphdr) * 4) + UDP_HLEN)); + } + } +#endif /* SO_REUSE && SO_REUSE_RXTOALL */ /* callback */ if (pcb->recv != NULL) { /* now the recv function is responsible for freeing p */ - pcb->recv(pcb->recv_arg, pcb, p, &iphdr->src, src); + pcb->recv(pcb->recv_arg, pcb, p, ip_current_src_addr(), src); } else { /* no recv function registered? then we have to free the pbuf! */ pbuf_free(p); @@ -295,7 +340,7 @@ udp_input(struct pbuf *p, struct netif *inp) /* No match was found, send ICMP destination port unreachable unless destination address was broadcast/multicast. */ if (!broadcast && - !ip_addr_ismulticast(&iphdr->dest)) { + !ip_addr_ismulticast(¤t_iphdr_dest)) { /* move payload pointer back to ip header */ pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN); LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr)); @@ -339,6 +384,19 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port); } +#if LWIP_CHECKSUM_ON_COPY +/** Same as udp_send() but with checksum + */ +err_t +udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum) +{ + /* send to the packet using remote ip and port stored in the pcb */ + return udp_sendto_chksum(pcb, p, &pcb->remote_ip, pcb->remote_port, + have_chksum, chksum); +} +#endif /* LWIP_CHECKSUM_ON_COPY */ + /** * Send data to a specified address using UDP. * @@ -358,8 +416,18 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p) */ err_t udp_sendto(struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *dst_ip, u16_t dst_port) + ip_addr_t *dst_ip, u16_t dst_port) +{ +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0); +} + +/** Same as udp_sendto(), but with checksum */ +err_t +udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, u8_t have_chksum, u16_t chksum) { +#endif /* LWIP_CHECKSUM_ON_COPY */ struct netif *netif; LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n")); @@ -373,11 +441,16 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p, /* no outgoing network interface could be found? */ if (netif == NULL) { - LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr)); + LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(dst_ip), ip4_addr2_16(dst_ip), ip4_addr3_16(dst_ip), ip4_addr4_16(dst_ip))); UDP_STATS_INC(udp.rterr); return ERR_RTE; } +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum); +#else /* LWIP_CHECKSUM_ON_COPY */ return udp_sendto_if(pcb, p, dst_ip, dst_port, netif); +#endif /* LWIP_CHECKSUM_ON_COPY */ } /** @@ -401,10 +474,21 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p, */ err_t udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif) + ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif) { +#if LWIP_CHECKSUM_ON_COPY + return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0); +} + +/** Same as udp_sendto_if(), but with checksum */ +err_t +udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip, + u16_t dst_port, struct netif *netif, u8_t have_chksum, + u16_t chksum) +{ +#endif /* LWIP_CHECKSUM_ON_COPY */ struct udp_hdr *udphdr; - struct ip_addr *src_ip; + ip_addr_t *src_ip; err_t err; struct pbuf *q; /* q will be sent down the stack */ @@ -436,8 +520,10 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n")); return ERR_MEM; } - /* chain header q in front of given pbuf p */ - pbuf_chain(q, p); + if (p->tot_len != 0) { + /* chain header q in front of given pbuf p (only if p contains data) */ + pbuf_chain(q, p); + } /* first pbuf q points to header pbuf */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p)); @@ -450,12 +536,20 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, LWIP_ASSERT("check that first pbuf can hold struct udp_hdr", (q->len >= sizeof(struct udp_hdr))); /* q now represents the packet to be sent */ - udphdr = q->payload; + udphdr = (struct udp_hdr *)q->payload; udphdr->src = htons(pcb->local_port); udphdr->dest = htons(dst_port); /* in UDP, 0 checksum means 'no checksum' */ udphdr->chksum = 0x0000; + /* Multicast Loop? */ +#if LWIP_IGMP + if (ip_addr_ismulticast(dst_ip) && ((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0)) { + q->flags |= PBUF_FLAG_MCASTLOOP; + } +#endif /* LWIP_IGMP */ + + /* PCB local address is IP_ANY_ADDR? */ if (ip_addr_isany(&pcb->local_ip)) { /* use outgoing network interface IP address as source address */ @@ -503,11 +597,23 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, /* calculate checksum */ #if CHECKSUM_GEN_UDP udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, - IP_PROTO_UDPLITE, q->tot_len, chklen); + IP_PROTO_UDPLITE, q->tot_len, +#if !LWIP_CHECKSUM_ON_COPY + chklen); +#else /* !LWIP_CHECKSUM_ON_COPY */ + (have_chksum ? UDP_HLEN : chklen)); + if (have_chksum) { + u32_t acc; + acc = udphdr->chksum + (u16_t)~(chksum); + udphdr->chksum = FOLD_U32T(acc); + } +#endif /* !LWIP_CHECKSUM_ON_COPY */ + /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) + if (udphdr->chksum == 0x0000) { udphdr->chksum = 0xffff; -#endif /* CHECKSUM_CHECK_UDP */ + } +#endif /* CHECKSUM_GEN_UDP */ /* output to IP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n")); #if LWIP_NETIF_HWADDRHINT @@ -525,11 +631,27 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, /* calculate checksum */ #if CHECKSUM_GEN_UDP if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) { - udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); + u16_t udpchksum; +#if LWIP_CHECKSUM_ON_COPY + if (have_chksum) { + u32_t acc; + udpchksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip, IP_PROTO_UDP, + q->tot_len, UDP_HLEN); + acc = udpchksum + (u16_t)~(chksum); + udpchksum = FOLD_U32T(acc); + } else +#endif /* LWIP_CHECKSUM_ON_COPY */ + { + udpchksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len); + } + /* chksum zero must become 0xffff, as zero means 'no checksum' */ - if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff; + if (udpchksum == 0x0000) { + udpchksum = 0xffff; + } + udphdr->chksum = udpchksum; } -#endif /* CHECKSUM_CHECK_UDP */ +#endif /* CHECKSUM_GEN_UDP */ LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum)); LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n")); /* output to IP */ @@ -576,7 +698,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p, * @see udp_disconnect() */ err_t -udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; u8_t rebind; @@ -596,13 +718,16 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) rebind = 1; } - /* this code does not allow upper layer to share a UDP port for - listening to broadcast or multicast traffic (See SO_REUSE_ADDR and - SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR - combine with implementation of UDP PCB flags. Leon Woestenberg. */ -#ifdef LWIP_UDP_TODO - /* port matches that of PCB in list? */ - else + /* By default, we don't allow to bind to a port that any other udp + PCB is alread bound to, unless *all* PCBs with that port have tha + REUSEADDR flag set. */ +#if SO_REUSE + else if (((pcb->so_options & SOF_REUSEADDR) == 0) && + ((ipcb->so_options & SOF_REUSEADDR) == 0)) { +#else /* SO_REUSE */ + /* port matches that of PCB in list and REUSEADDR not set -> reject */ + else { +#endif /* SO_REUSE */ if ((ipcb->local_port == port) && /* IP address matches, or one is IP_ADDR_ANY? */ (ip_addr_isany(&(ipcb->local_ip)) || @@ -613,7 +738,7 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) ("udp_bind: local port %"U16_F" already bound by another pcb\n", port)); return ERR_USE; } -#endif + } } ip_addr_set(&pcb->local_ip, ipaddr); @@ -621,8 +746,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) /* no port specified? */ if (port == 0) { #ifndef UDP_LOCAL_PORT_RANGE_START -#define UDP_LOCAL_PORT_RANGE_START 4096 -#define UDP_LOCAL_PORT_RANGE_END 0x7fff +/* From http://www.iana.org/assignments/port-numbers: + "The Dynamic and/or Private Ports are those from 49152 through 65535" */ +#define UDP_LOCAL_PORT_RANGE_START 0xc000 +#define UDP_LOCAL_PORT_RANGE_END 0xffff #endif port = UDP_LOCAL_PORT_RANGE_START; ipcb = udp_pcbs; @@ -632,9 +759,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) port++; /* restart scanning all udp pcbs */ ipcb = udp_pcbs; - } else + } else { /* go on with next udp pcb */ ipcb = ipcb->next; + } } if (ipcb != NULL) { /* no more ports available in local range */ @@ -652,10 +780,9 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) } LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n", - (u16_t)((ntohl(pcb->local_ip.addr) >> 24) & 0xff), - (u16_t)((ntohl(pcb->local_ip.addr) >> 16) & 0xff), - (u16_t)((ntohl(pcb->local_ip.addr) >> 8) & 0xff), - (u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port)); + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), + pcb->local_port)); return ERR_OK; } /** @@ -676,14 +803,15 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) * @see udp_disconnect() */ err_t -udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) +udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port) { struct udp_pcb *ipcb; if (pcb->local_port == 0) { err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port); - if (err != ERR_OK) + if (err != ERR_OK) { return err; + } } ip_addr_set(&pcb->remote_ip, ipaddr); @@ -710,10 +838,9 @@ udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port) #endif LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n", - (u16_t)((ntohl(pcb->remote_ip.addr) >> 24) & 0xff), - (u16_t)((ntohl(pcb->remote_ip.addr) >> 16) & 0xff), - (u16_t)((ntohl(pcb->remote_ip.addr) >> 8) & 0xff), - (u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port)); + ip4_addr1_16(&pcb->local_ip), ip4_addr2_16(&pcb->local_ip), + ip4_addr3_16(&pcb->local_ip), ip4_addr4_16(&pcb->local_ip), + pcb->local_port)); /* Insert UDP PCB into the list of active UDP PCBs. */ for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) { @@ -737,7 +864,7 @@ void udp_disconnect(struct udp_pcb *pcb) { /* reset remote address association */ - ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY); + ip_addr_set_any(&pcb->remote_ip); pcb->remote_port = 0; /* mark PCB as unconnected */ pcb->flags &= ~UDP_FLAGS_CONNECTED; @@ -753,10 +880,7 @@ udp_disconnect(struct udp_pcb *pcb) * @param recv_arg additional argument to pass to the callback function */ void -udp_recv(struct udp_pcb *pcb, - void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p, - struct ip_addr *addr, u16_t port), - void *recv_arg) +udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg) { /* remember recv() callback and user data */ pcb->recv = recv; @@ -782,7 +906,7 @@ udp_remove(struct udp_pcb *pcb) /* make list start at 2nd pcb */ udp_pcbs = udp_pcbs->next; /* pcb not 1st in list */ - } else + } else { for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) { /* find pcb in udp_pcbs list */ if (pcb2->next != NULL && pcb2->next == pcb) { @@ -790,6 +914,7 @@ udp_remove(struct udp_pcb *pcb) pcb2->next = pcb->next; } } + } memp_free(MEMP_UDP_PCB, pcb); } @@ -805,7 +930,7 @@ struct udp_pcb * udp_new(void) { struct udp_pcb *pcb; - pcb = memp_malloc(MEMP_UDP_PCB); + pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB); /* could allocate UDP PCB? */ if (pcb != NULL) { /* UDP Lite: by initializing to all zeroes, chksum_len is set to 0 diff --git a/core/lwip/src/include/arch/sys_arch.h b/core/lwip/src/include/arch/sys_arch.h index 89126208..732a19c4 100644 --- a/core/lwip/src/include/arch/sys_arch.h +++ b/core/lwip/src/include/arch/sys_arch.h @@ -10,7 +10,12 @@ typedef struct semaphore *sys_sem_t; typedef struct mailbox *sys_mbox_t; typedef struct thread *sys_thread_t; -#define sys_sem_signal(x) sem_up(x) +static inline void sys_sem_signal(sys_sem_t *sem) +{ + if (!!sem) + sem_up(*sem); +} + #define sys_now ms_timer #define SYS_MBOX_NULL NULL diff --git a/core/lwip/src/include/ipv4/lwip/autoip.h b/core/lwip/src/include/ipv4/lwip/autoip.h index f2621658..23c264a1 100644 --- a/core/lwip/src/include/ipv4/lwip/autoip.h +++ b/core/lwip/src/include/ipv4/lwip/autoip.h @@ -80,7 +80,7 @@ extern "C" { struct autoip { - struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ + ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */ u8_t state; /* current AutoIP state machine state */ u8_t sent_num; /* sent number of probes or announces, dependent on state */ u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */ @@ -92,6 +92,9 @@ struct autoip /** Init srand, has to be called before entering mainloop */ void autoip_init(void); +/** Set a struct autoip allocated by the application to work with */ +void autoip_set_struct(struct netif *netif, struct autoip *autoip); + /** Start AutoIP client */ err_t autoip_start(struct netif *netif); diff --git a/core/lwip/src/include/ipv4/lwip/icmp.h b/core/lwip/src/include/ipv4/lwip/icmp.h index c73961c9..d47a7d8a 100644 --- a/core/lwip/src/include/ipv4/lwip/icmp.h +++ b/core/lwip/src/include/ipv4/lwip/icmp.h @@ -41,29 +41,29 @@ extern "C" { #endif -#define ICMP_ER 0 /* echo reply */ -#define ICMP_DUR 3 /* destination unreachable */ -#define ICMP_SQ 4 /* source quench */ -#define ICMP_RD 5 /* redirect */ +#define ICMP_ER 0 /* echo reply */ +#define ICMP_DUR 3 /* destination unreachable */ +#define ICMP_SQ 4 /* source quench */ +#define ICMP_RD 5 /* redirect */ #define ICMP_ECHO 8 /* echo */ -#define ICMP_TE 11 /* time exceeded */ -#define ICMP_PP 12 /* parameter problem */ -#define ICMP_TS 13 /* timestamp */ +#define ICMP_TE 11 /* time exceeded */ +#define ICMP_PP 12 /* parameter problem */ +#define ICMP_TS 13 /* timestamp */ #define ICMP_TSR 14 /* timestamp reply */ #define ICMP_IRQ 15 /* information request */ -#define ICMP_IR 16 /* information reply */ +#define ICMP_IR 16 /* information reply */ enum icmp_dur_type { - ICMP_DUR_NET = 0, /* net unreachable */ - ICMP_DUR_HOST = 1, /* host unreachable */ + ICMP_DUR_NET = 0, /* net unreachable */ + ICMP_DUR_HOST = 1, /* host unreachable */ ICMP_DUR_PROTO = 2, /* protocol unreachable */ - ICMP_DUR_PORT = 3, /* port unreachable */ - ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ - ICMP_DUR_SR = 5 /* source route failed */ + ICMP_DUR_PORT = 3, /* port unreachable */ + ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */ + ICMP_DUR_SR = 5 /* source route failed */ }; enum icmp_te_type { - ICMP_TE_TTL = 0, /* time to live exceeded in transit */ + ICMP_TE_TTL = 0, /* time to live exceeded in transit */ ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */ }; diff --git a/core/lwip/src/include/ipv4/lwip/igmp.h b/core/lwip/src/include/ipv4/lwip/igmp.h index 59c933f3..8aabac24 100644 --- a/core/lwip/src/include/ipv4/lwip/igmp.h +++ b/core/lwip/src/include/ipv4/lwip/igmp.h @@ -46,57 +46,20 @@ extern "C" { #endif -/* - * IGMP constants - */ -#define IP_PROTO_IGMP 2 -#define IGMP_TTL 1 -#define IGMP_MINLEN 8 -#define ROUTER_ALERT 0x9404 -#define ROUTER_ALERTLEN 4 - -/* - * IGMP message types, including version number. - */ -#define IGMP_MEMB_QUERY 0x11 /* Membership query */ -#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */ -#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */ -#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */ /* IGMP timer */ #define IGMP_TMR_INTERVAL 100 /* Milliseconds */ #define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL) #define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL) -/* MAC Filter Actions */ +/* MAC Filter Actions, these are passed to a netif's + * igmp_mac_filter callback function. */ #define IGMP_DEL_MAC_FILTER 0 #define IGMP_ADD_MAC_FILTER 1 -/* Group membership states */ -#define IGMP_GROUP_NON_MEMBER 0 -#define IGMP_GROUP_DELAYING_MEMBER 1 -#define IGMP_GROUP_IDLE_MEMBER 2 - -/* - * IGMP packet format. - */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct igmp_msg { - PACK_STRUCT_FIELD(u8_t igmp_msgtype); - PACK_STRUCT_FIELD(u8_t igmp_maxresp); - PACK_STRUCT_FIELD(u16_t igmp_checksum); - PACK_STRUCT_FIELD(struct ip_addr igmp_group_address); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif -/* - * now a group structure - there is +/** + * igmp group structure - there is * a list of groups for each interface * these should really be linked from the interface, but * if we keep them separate we will not affect the lwip original code @@ -106,53 +69,34 @@ PACK_STRUCT_END * will not run the state machine as it is used to kick off reports * from all the other groups */ - struct igmp_group { + /** next link */ struct igmp_group *next; - struct netif *interface; - struct ip_addr group_address; - u8_t last_reporter_flag; /* signifies we were the last person to report */ + /** interface on which the group is active */ + struct netif *netif; + /** multicast address */ + ip_addr_t group_address; + /** signifies we were the last person to report */ + u8_t last_reporter_flag; + /** current state of the group */ u8_t group_state; + /** timer for reporting, negative is OFF */ u16_t timer; - u8_t use; /* counter of simultaneous uses */ + /** counter of simultaneous uses */ + u8_t use; }; - /* Prototypes */ void igmp_init(void); - -err_t igmp_start( struct netif *netif); - -err_t igmp_stop( struct netif *netif); - -void igmp_report_groups( struct netif *netif); - -struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr); - -struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr); - -err_t igmp_remove_group( struct igmp_group *group); - -void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest); - -err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); - -err_t igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr); - +err_t igmp_start(struct netif *netif); +err_t igmp_stop(struct netif *netif); +void igmp_report_groups(struct netif *netif); +struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr); +void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest); +err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); +err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr); void igmp_tmr(void); -void igmp_timeout( struct igmp_group *group); - -void igmp_start_timer( struct igmp_group *group, u8_t max_time); - -void igmp_stop_timer( struct igmp_group *group); - -void igmp_delaying_member( struct igmp_group *group, u8_t maxresp); - -err_t igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif); - -void igmp_send( struct igmp_group *group, u8_t type); - #ifdef __cplusplus } #endif diff --git a/core/lwip/src/include/ipv4/lwip/inet.h b/core/lwip/src/include/ipv4/lwip/inet.h index 7e801308..0513c740 100644 --- a/core/lwip/src/include/ipv4/lwip/inet.h +++ b/core/lwip/src/include/ipv4/lwip/inet.h @@ -33,66 +33,70 @@ #define __LWIP_INET_H__ #include "lwip/opt.h" +#include "lwip/def.h" +#include "lwip/ip_addr.h" #ifdef __cplusplus extern "C" { #endif -/* For compatibility with BSD code */ +/** For compatibility with BSD code */ #include <netinet/in.h> -#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */ -#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */ -#define INADDR_ANY ((u32_t)0x00000000UL) /* 0.0.0.0 */ -#define INADDR_BROADCAST ((u32_t)0xffffffffUL) /* 255.255.255.255 */ - -u32_t inet_addr(const char *cp); -int inet_aton(const char *cp, struct in_addr *addr); -char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */ - -#ifdef htons -#undef htons -#endif /* htons */ -#ifdef htonl -#undef htonl -#endif /* htonl */ -#ifdef ntohs -#undef ntohs -#endif /* ntohs */ -#ifdef ntohl -#undef ntohl -#endif /* ntohl */ - -#ifndef LWIP_PLATFORM_BYTESWAP -#define LWIP_PLATFORM_BYTESWAP 0 -#endif +/** 255.255.255.255 */ +#define INADDR_NONE IPADDR_NONE +/** 127.0.0.1 */ +#define INADDR_LOOPBACK IPADDR_LOOPBACK +/** 0.0.0.0 */ +#define INADDR_ANY IPADDR_ANY +/** 255.255.255.255 */ +#define INADDR_BROADCAST IPADDR_BROADCAST + +/* Definitions of the bits in an Internet address integer. + + On subnets, host and network parts are found according to + the subnet mask, not these masks. */ +#define IN_CLASSA(a) IP_CLASSA(a) +#define IN_CLASSA_NET IP_CLASSA_NET +#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT +#define IN_CLASSA_HOST IP_CLASSA_HOST +#define IN_CLASSA_MAX IP_CLASSA_MAX + +#define IN_CLASSB(b) IP_CLASSB(b) +#define IN_CLASSB_NET IP_CLASSB_NET +#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT +#define IN_CLASSB_HOST IP_CLASSB_HOST +#define IN_CLASSB_MAX IP_CLASSB_MAX + +#define IN_CLASSC(c) IP_CLASSC(c) +#define IN_CLASSC_NET IP_CLASSC_NET +#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT +#define IN_CLASSC_HOST IP_CLASSC_HOST +#define IN_CLASSC_MAX IP_CLASSC_MAX + +#define IN_CLASSD(d) IP_CLASSD(d) +#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */ +#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */ +#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */ +#define IN_CLASSD_MAX IP_CLASSD_MAX + +#define IN_MULTICAST(a) IP_MULTICAST(a) + +#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a) +#define IN_BADCLASS(a) IP_BADCLASS(a) + +#define IN_LOOPBACKNET IP_LOOPBACKNET + +#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr)) +#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr)) +/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */ +#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr)) -#if BYTE_ORDER == BIG_ENDIAN -#define htons(x) (x) -#define ntohs(x) (x) -#define htonl(x) (x) -#define ntohl(x) (x) -#else /* BYTE_ORDER != BIG_ENDIAN */ -#ifdef LWIP_PREFIX_BYTEORDER_FUNCS -/* workaround for naming collisions on some platforms */ -#define htons lwip_htons -#define ntohs lwip_ntohs -#define htonl lwip_htonl -#define ntohl lwip_ntohl -#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ -#if LWIP_PLATFORM_BYTESWAP -#define htons(x) LWIP_PLATFORM_HTONS(x) -#define ntohs(x) LWIP_PLATFORM_HTONS(x) -#define htonl(x) LWIP_PLATFORM_HTONL(x) -#define ntohl(x) LWIP_PLATFORM_HTONL(x) -#else /* LWIP_PLATFORM_BYTESWAP */ -u16_t htons(u16_t x); -u16_t ntohs(u16_t x); -u32_t htonl(u32_t x); -u32_t ntohl(u32_t x); -#endif /* LWIP_PLATFORM_BYTESWAP */ - -#endif /* BYTE_ORDER == BIG_ENDIAN */ +/* directly map this to the lwip internal functions */ +#define inet_addr(cp) ipaddr_addr(cp) +#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr) +#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr)) +#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen) #ifdef __cplusplus } diff --git a/core/lwip/src/include/ipv4/lwip/inet_chksum.h b/core/lwip/src/include/ipv4/lwip/inet_chksum.h index 5cae59cb..79a2d90f 100644 --- a/core/lwip/src/include/ipv4/lwip/inet_chksum.h +++ b/core/lwip/src/include/ipv4/lwip/inet_chksum.h @@ -37,6 +37,35 @@ #include "lwip/pbuf.h" #include "lwip/ip_addr.h" +/** Swap the bytes in an u16_t: much like htons() for little-endian */ +#ifndef SWAP_BYTES_IN_WORD +#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) +/* little endian and PLATFORM_BYTESWAP defined */ +#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w) +#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */ +/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */ +#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8) +#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/ +#endif /* SWAP_BYTES_IN_WORD */ + +/** Split an u32_t in two u16_ts and add them up */ +#ifndef FOLD_U32T +#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL)) +#endif + +#if LWIP_CHECKSUM_ON_COPY +/** Function-like macro: same as MEMCPY but returns the checksum of copied data + as u16_t */ +#ifndef LWIP_CHKSUM_COPY +#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len) +#ifndef LWIP_CHKSUM_COPY_ALGORITHM +#define LWIP_CHKSUM_COPY_ALGORITHM 1 +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ +#endif /* LWIP_CHKSUM_COPY */ +#else /* LWIP_CHECKSUM_ON_COPY */ +#define LWIP_CHKSUM_COPY_ALGORITHM 0 +#endif /* LWIP_CHECKSUM_ON_COPY */ + #ifdef __cplusplus extern "C" { #endif @@ -44,13 +73,14 @@ extern "C" { u16_t inet_chksum(void *dataptr, u16_t len); u16_t inet_chksum_pbuf(struct pbuf *p); u16_t inet_chksum_pseudo(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, + ip_addr_t *src, ip_addr_t *dest, u8_t proto, u16_t proto_len); -#if LWIP_UDPLITE u16_t inet_chksum_pseudo_partial(struct pbuf *p, - struct ip_addr *src, struct ip_addr *dest, + ip_addr_t *src, ip_addr_t *dest, u8_t proto, u16_t proto_len, u16_t chksum_len); -#endif +#if LWIP_CHKSUM_COPY_ALGORITHM +u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len); +#endif /* LWIP_CHKSUM_COPY_ALGORITHM */ #ifdef __cplusplus } diff --git a/core/lwip/src/include/ipv4/lwip/ip.h b/core/lwip/src/include/ipv4/lwip/ip.h index fd84f304..74f501d1 100644 --- a/core/lwip/src/include/ipv4/lwip/ip.h +++ b/core/lwip/src/include/ipv4/lwip/ip.h @@ -50,6 +50,7 @@ extern "C" { #define IP_HLEN 20 #define IP_PROTO_ICMP 1 +#define IP_PROTO_IGMP 2 #define IP_PROTO_UDP 17 #define IP_PROTO_UDPLITE 136 #define IP_PROTO_TCP 6 @@ -74,10 +75,10 @@ extern "C" { having to change all PCB structs. */ #define IP_PCB \ /* ip addresses in network byte order */ \ - struct ip_addr local_ip; \ - struct ip_addr remote_ip; \ + ip_addr_t local_ip; \ + ip_addr_t remote_ip; \ /* Socket options */ \ - u16_t so_options; \ + u8_t so_options; \ /* Type Of Service */ \ u8_t tos; \ /* Time To Live */ \ @@ -93,16 +94,19 @@ struct ip_pcb { /* * Option flags per-socket. These are the same like SO_XXX. */ -#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */ -#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */ -#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */ -#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */ -#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */ -#define SOF_BROADCAST (u16_t)0x0020U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ -#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */ -#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */ -#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */ -#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */ +/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */ +#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */ +#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */ +#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */ +/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */ +#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ +/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */ +#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */ +/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */ +/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */ + +/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */ +#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/) #ifdef PACK_STRUCT_USE_INCLUDES @@ -118,17 +122,19 @@ struct ip_hdr { PACK_STRUCT_FIELD(u16_t _id); /* fragment offset field */ PACK_STRUCT_FIELD(u16_t _offset); -#define IP_RF 0x8000 /* reserved fragment flag */ -#define IP_DF 0x4000 /* dont fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - /* time to live / protocol*/ - PACK_STRUCT_FIELD(u16_t _ttl_proto); +#define IP_RF 0x8000U /* reserved fragment flag */ +#define IP_DF 0x4000U /* dont fragment flag */ +#define IP_MF 0x2000U /* more fragments flag */ +#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */ + /* time to live */ + PACK_STRUCT_FIELD(u8_t _ttl); + /* protocol*/ + PACK_STRUCT_FIELD(u8_t _proto); /* checksum */ PACK_STRUCT_FIELD(u16_t _chksum); /* source and destination IP addresses */ - PACK_STRUCT_FIELD(struct ip_addr src); - PACK_STRUCT_FIELD(struct ip_addr dest); + PACK_STRUCT_FIELD(ip_addr_p_t src); + PACK_STRUCT_FIELD(ip_addr_p_t dest); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES @@ -141,37 +147,41 @@ PACK_STRUCT_END #define IPH_LEN(hdr) ((hdr)->_len) #define IPH_ID(hdr) ((hdr)->_id) #define IPH_OFFSET(hdr) ((hdr)->_offset) -#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8) -#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff) +#define IPH_TTL(hdr) ((hdr)->_ttl) +#define IPH_PROTO(hdr) ((hdr)->_proto) #define IPH_CHKSUM(hdr) ((hdr)->_chksum) #define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos))) #define IPH_LEN_SET(hdr, len) (hdr)->_len = (len) #define IPH_ID_SET(hdr, id) (hdr)->_id = (id) #define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off) -#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8))) -#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8))) +#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl) +#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto) #define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum) /** The interface that provided the packet for the current callback invocation. */ extern struct netif *current_netif; /** Header of the input packet currently being processed. */ extern const struct ip_hdr *current_header; +/** Source IP address of current_header */ +extern ip_addr_t current_iphdr_src; +/** Destination IP address of current_header */ +extern ip_addr_t current_iphdr_dest; #define ip_init() /* Compatibility define, not init needed. */ -struct netif *ip_route(struct ip_addr *dest); +struct netif *ip_route(ip_addr_t *dest); err_t ip_input(struct pbuf *p, struct netif *inp); -err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto); -err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif); #if LWIP_NETIF_HWADDRHINT -err_t ip_output_hinted(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint); #endif /* LWIP_NETIF_HWADDRHINT */ #if IP_OPTIONS_SEND -err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, +err_t ip_output_if_opt(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest, u8_t ttl, u8_t tos, u8_t proto, struct netif *netif, void *ip_options, u16_t optlen); #endif /* IP_OPTIONS_SEND */ @@ -183,6 +193,11 @@ err_t ip_output_if_opt(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest * This function must only be called from a receive callback (udp_recv, * raw_recv, tcp_accept). It will return NULL otherwise. */ #define ip_current_header() (current_header) +/** Source IP address of current_header */ +#define ip_current_src_addr() (¤t_iphdr_src) +/** Destination IP address of current_header */ +#define ip_current_dest_addr() (¤t_iphdr_dest) + #if IP_DEBUG void ip_debug_print(struct pbuf *p); #else diff --git a/core/lwip/src/include/ipv4/lwip/ip_addr.h b/core/lwip/src/include/ipv4/lwip/ip_addr.h index 298e6576..77f84e02 100644 --- a/core/lwip/src/include/ipv4/lwip/ip_addr.h +++ b/core/lwip/src/include/ipv4/lwip/ip_addr.h @@ -33,18 +33,25 @@ #define __LWIP_IP_ADDR_H__ #include "lwip/opt.h" - -#include "lwip/inet.h" +#include "lwip/def.h" #ifdef __cplusplus extern "C" { #endif +/* This is the aligned version of ip_addr_t, + used as local variable, on the stack, etc. */ +struct ip_addr { + u32_t addr; +}; + +/* This is the packed version of ip_addr_t, + used in network headers that are itself packed */ #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN -struct ip_addr { +struct ip_addr_packed { PACK_STRUCT_FIELD(u32_t addr); } PACK_STRUCT_STRUCT; PACK_STRUCT_END @@ -52,6 +59,11 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif +/** ip_addr_t uses a struct for convenience only, so that the same defines can + * operate both on ip_addr_t as well as on ip_addr_p_t. */ +typedef struct ip_addr ip_addr_t; +typedef struct ip_addr_packed ip_addr_p_t; + /* * struct ipaddr2 is used in the definition of the ARP packet format in * order to support compilers that don't have structure packing. @@ -68,59 +80,109 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif +/* Forward declaration to not include netif.h */ struct netif; -extern const struct ip_addr ip_addr_any; -extern const struct ip_addr ip_addr_broadcast; +extern const ip_addr_t ip_addr_any; +extern const ip_addr_t ip_addr_broadcast; /** IP_ADDR_ can be used as a fixed IP address * for the wildcard and the broadcast address */ -#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any) -#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast) +#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any) +#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast) + +/** 255.255.255.255 */ +#define IPADDR_NONE ((u32_t)0xffffffffUL) +/** 127.0.0.1 */ +#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL) +/** 0.0.0.0 */ +#define IPADDR_ANY ((u32_t)0x00000000UL) +/** 255.255.255.255 */ +#define IPADDR_BROADCAST ((u32_t)0xffffffffUL) /* Definitions of the bits in an Internet address integer. On subnets, host and network parts are found according to the subnet mask, not these masks. */ +#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) +#define IP_CLASSA_NET 0xff000000 +#define IP_CLASSA_NSHIFT 24 +#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET) +#define IP_CLASSA_MAX 128 -#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) -#define IN_CLASSA_MAX 128 +#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) +#define IP_CLASSB_NET 0xffff0000 +#define IP_CLASSB_NSHIFT 16 +#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET) +#define IP_CLASSB_MAX 65536 -#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) -#define IN_CLASSB_MAX 65536 +#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) +#define IP_CLASSC_NET 0xffffff00 +#define IP_CLASSC_NSHIFT 8 +#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET) -#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) +#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) +#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */ +#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */ +#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */ +#define IP_MULTICAST(a) IP_CLASSD(a) -#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL) -#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */ -#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */ -#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */ -#define IN_MULTICAST(a) IN_CLASSD(a) +#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) -#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) -#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL) +#define IP_LOOPBACKNET 127 /* official! */ -#define IN_LOOPBACKNET 127 /* official! */ +#if BYTE_ORDER == BIG_ENDIAN +/** Set an IP address given by the four byte-parts */ +#define IP4_ADDR(ipaddr, a,b,c,d) \ + (ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \ + ((u32_t)((b) & 0xff) << 16) | \ + ((u32_t)((c) & 0xff) << 8) | \ + (u32_t)((d) & 0xff) +#else +/** Set an IP address given by the four byte-parts. + Little-endian version that prevents the use of htonl. */ #define IP4_ADDR(ipaddr, a,b,c,d) \ - (ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \ - ((u32_t)((b) & 0xff) << 16) | \ - ((u32_t)((c) & 0xff) << 8) | \ - (u32_t)((d) & 0xff)) - -#define ip_addr_set(dest, src) (dest)->addr = \ - ((src) == NULL? 0:\ - (src)->addr) + (ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \ + ((u32_t)((c) & 0xff) << 16) | \ + ((u32_t)((b) & 0xff) << 8) | \ + (u32_t)((a) & 0xff) +#endif + +/** MEMCPY-like copying of IP addresses where addresses are known to be + * 16-bit-aligned if the port is correctly configured (so a port could define + * this to copying 2 u16_t's) - no NULL-pointer-checking needed. */ +#ifndef IPADDR2_COPY +#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t)) +#endif + +/** Copy IP address - faster than ip_addr_set: no NULL check */ +#define ip_addr_copy(dest, src) ((dest).addr = (src).addr) +/** Safely copy one IP address to another (src may be NULL) */ +#define ip_addr_set(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0 : \ + (src)->addr)) +/** Set complete address to zero */ +#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0) +/** Set address to IPADDR_ANY (no need for htonl()) */ +#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY) +/** Set address to loopback address */ +#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK)) +/** Safely copy one IP address to another and change byte order + * from host- to network-order. */ +#define ip_addr_set_hton(dest, src) ((dest)->addr = \ + ((src) == NULL ? 0:\ + htonl((src)->addr))) +/** IPv4 only: set the IP address given as an u32_t */ +#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32)) +/** IPv4 only: get the IP address as an u32_t */ +#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr) + +/** Get the network address by combining host address with netmask */ +#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr)) + /** * Determine if two address are on the same network. * @@ -135,36 +197,45 @@ extern const struct ip_addr ip_addr_broadcast; (mask)->addr)) #define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr) -#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0) +#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY) -u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *); +#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif)) +u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif); -#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL)) +#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr) +u8_t ip4_addr_netmask_valid(u32_t netmask); -#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL)) +#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL)) -#define ip_addr_debug_print(debug, ipaddr) \ - LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ - ipaddr != NULL ? \ - (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \ - ipaddr != NULL ? \ - (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \ - ipaddr != NULL ? \ - (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \ - ipaddr != NULL ? \ - (u16_t)ntohl((ipaddr)->addr) & 0xff : 0)) +#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL)) +#define ip_addr_debug_print(debug, ipaddr) \ + LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \ + ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \ + ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0)) + +/* Get one byte from the 4-byte address */ +#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0]) +#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1]) +#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2]) +#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3]) /* These are cast to u16_t, with the intent that they are often arguments * to printf using the U16_F format from cc.h. */ -#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff) -#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff) -#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff) -#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff) - -/** - * Same as inet_ntoa() but takes a struct ip_addr* - */ -#define ip_ntoa(addr) ((addr != NULL) ? inet_ntoa(*((struct in_addr*)(addr))) : "NULL") +#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr)) +#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr)) +#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr)) +#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr)) + +/** For backwards compatibility */ +#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr) + +u32_t ipaddr_addr(const char *cp); +int ipaddr_aton(const char *cp, ip_addr_t *addr); +/** returns ptr to static buffer; not reentrant! */ +char *ipaddr_ntoa(const ip_addr_t *addr); +char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen); #ifdef __cplusplus } diff --git a/core/lwip/src/include/ipv4/lwip/ip_frag.h b/core/lwip/src/include/ipv4/lwip/ip_frag.h index 380e604d..77b5eb1e 100644 --- a/core/lwip/src/include/ipv4/lwip/ip_frag.h +++ b/core/lwip/src/include/ipv4/lwip/ip_frag.h @@ -66,7 +66,19 @@ struct pbuf * ip_reass(struct pbuf *p); #endif /* IP_REASSEMBLY */ #if IP_FRAG -err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest); +#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +/** A custom pbuf that holds a reference to another pbuf, which is freed + * when this custom pbuf is freed. This is used to create a custom PBUF_REF + * that points into the original pbuf. */ +struct pbuf_custom_ref { + /** 'base class' */ + struct pbuf_custom pc; + /** pointer to the original pbuf that is referenced */ + struct pbuf *original; +}; +#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ + +err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest); #endif /* IP_FRAG */ #ifdef __cplusplus diff --git a/core/lwip/src/include/lwip/api.h b/core/lwip/src/include/lwip/api.h index f6b1f743..91b9e5d2 100644 --- a/core/lwip/src/include/lwip/api.h +++ b/core/lwip/src/include/lwip/api.h @@ -51,16 +51,35 @@ extern "C" { * the same byte order as in the corresponding pcb. */ -/* Flags for netconn_write */ -#define NETCONN_NOFLAG 0x00 -#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ -#define NETCONN_COPY 0x01 -#define NETCONN_MORE 0x02 +/* Flags for netconn_write (u8_t) */ +#define NETCONN_NOFLAG 0x00 +#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */ +#define NETCONN_COPY 0x01 +#define NETCONN_MORE 0x02 +#define NETCONN_DONTBLOCK 0x04 + +/* Flags for struct netconn.flags (u8_t) */ +/** TCP: when data passed to netconn_write doesn't fit into the send buffer, + this temporarily stores whether to wake up the original application task + if data couldn't be sent in the first try. */ +#define NETCONN_FLAG_WRITE_DELAYED 0x01 +/** Should this netconn avoid blocking? */ +#define NETCONN_FLAG_NON_BLOCKING 0x02 +/** Was the last connect action a non-blocking one? */ +#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04 +/** If this is set, a TCP netconn must call netconn_recved() to update + the TCP receive window (done automatically if not set). */ +#define NETCONN_FLAG_NO_AUTO_RECVED 0x08 +/** If a nonblocking write has been rejected before, poll_tcp needs to + check if the netconn is writable again */ +#define NETCONN_FLAG_CHECK_WRITESPACE 0x10 + /* Helpers to process several netconn_types by the same code */ #define NETCONNTYPE_GROUP(t) (t&0xF0) #define NETCONNTYPE_DATAGRAM(t) (t&0xE0) +/** Protocol family and type of the netconn */ enum netconn_type { NETCONN_INVALID = 0, /* NETCONN_TCP Group */ @@ -73,6 +92,8 @@ enum netconn_type { NETCONN_RAW = 0x40 }; +/** Current state of the netconn. Non-TCP netconns are always + * in state NETCONN_NONE! */ enum netconn_state { NETCONN_NONE, NETCONN_WRITE, @@ -81,14 +102,17 @@ enum netconn_state { NETCONN_CLOSE }; +/** Use to inform the callback function about changes */ enum netconn_evt { NETCONN_EVT_RCVPLUS, NETCONN_EVT_RCVMINUS, NETCONN_EVT_SENDPLUS, - NETCONN_EVT_SENDMINUS + NETCONN_EVT_SENDMINUS, + NETCONN_EVT_ERROR }; #if LWIP_IGMP +/** Used for netconn_join_leave_group() */ enum netconn_igmp { NETCONN_JOIN, NETCONN_LEAVE @@ -101,6 +125,7 @@ struct tcp_pcb; struct udp_pcb; struct raw_pcb; struct netconn; +struct api_msg_msg; /** A callback prototype to inform about events for a netconn */ typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len); @@ -119,99 +144,136 @@ struct netconn { struct raw_pcb *raw; } pcb; /** the last error this netconn had */ - err_t err; + err_t last_err; /** sem that is used to synchroneously execute functions in the core context */ sys_sem_t op_completed; /** mbox where received packets are stored until they are fetched by the netconn application thread (can grow quite big) */ sys_mbox_t recvmbox; +#if LWIP_TCP /** mbox where new connections are stored until processed by the application thread */ sys_mbox_t acceptmbox; +#endif /* LWIP_TCP */ /** only used for socket layer */ +#if LWIP_SOCKET int socket; +#endif /* LWIP_SOCKET */ #if LWIP_SO_RCVTIMEO /** timeout to wait for new data to be received (or connections to arrive for listening netconns) */ int recv_timeout; #endif /* LWIP_SO_RCVTIMEO */ #if LWIP_SO_RCVBUF - /** maximum amount of bytes queued in recvmbox */ + /** maximum amount of bytes queued in recvmbox + not used for TCP: adjust TCP_WND instead! */ int recv_bufsize; -#endif /* LWIP_SO_RCVBUF */ + /** number of bytes currently in recvmbox to be received, + tested against recv_bufsize to limit bytes on recvmbox + for UDP and RAW, used for FIONREAD */ s16_t recv_avail; +#endif /* LWIP_SO_RCVBUF */ + /** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */ + u8_t flags; #if LWIP_TCP /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores the message. */ - struct api_msg_msg *write_msg; - /** TCP: when data passed to netconn_write doesn't fit into the send buffer, this temporarily stores how much is already sent. */ size_t write_offset; -#if LWIP_TCPIP_CORE_LOCKING /** TCP: when data passed to netconn_write doesn't fit into the send buffer, - this temporarily stores whether to wake up the original application task - if data couldn't be sent in the first try. */ - u8_t write_delayed; -#endif /* LWIP_TCPIP_CORE_LOCKING */ + this temporarily stores the message. + Also used during connect and close. */ + struct api_msg_msg *current_msg; #endif /* LWIP_TCP */ /** A callback function that is informed about events for this netconn */ netconn_callback callback; }; -/* Register an Network connection event */ +/** Register an Network connection event */ #define API_EVENT(c,e,l) if (c->callback) { \ (*c->callback)(c, e, l); \ } +/** Set conn->last_err to err but don't overwrite fatal errors */ +#define NETCONN_SET_SAFE_ERR(conn, err) do { \ + SYS_ARCH_DECL_PROTECT(lev); \ + SYS_ARCH_PROTECT(lev); \ + if (!ERR_IS_FATAL((conn)->last_err)) { \ + (conn)->last_err = err; \ + } \ + SYS_ARCH_UNPROTECT(lev); \ +} while(0); + /* Network connection functions: */ #define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL) #define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c) struct netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto, - netconn_callback callback); -err_t netconn_delete (struct netconn *conn); + netconn_callback callback); +err_t netconn_delete(struct netconn *conn); /** Get the type of a netconn (as enum netconn_type). */ #define netconn_type(conn) (conn->type) -err_t netconn_getaddr (struct netconn *conn, - struct ip_addr *addr, - u16_t *port, - u8_t local); +err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr, + u16_t *port, u8_t local); #define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0) #define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1) -err_t netconn_bind (struct netconn *conn, - struct ip_addr *addr, - u16_t port); -err_t netconn_connect (struct netconn *conn, - struct ip_addr *addr, - u16_t port); -err_t netconn_disconnect (struct netconn *conn); -err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); +err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port); +err_t netconn_disconnect (struct netconn *conn); +err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog); #define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG) -struct netconn * netconn_accept (struct netconn *conn); -struct netbuf * netconn_recv (struct netconn *conn); -err_t netconn_sendto (struct netconn *conn, - struct netbuf *buf, struct ip_addr *addr, u16_t port); -err_t netconn_send (struct netconn *conn, - struct netbuf *buf); -err_t netconn_write (struct netconn *conn, - const void *dataptr, size_t size, - u8_t apiflags); -err_t netconn_close (struct netconn *conn); +err_t netconn_accept(struct netconn *conn, struct netconn **new_conn); +err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf); +err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf); +void netconn_recved(struct netconn *conn, u32_t length); +err_t netconn_sendto(struct netconn *conn, struct netbuf *buf, + ip_addr_t *addr, u16_t port); +err_t netconn_send(struct netconn *conn, struct netbuf *buf); +err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size, + u8_t apiflags); +err_t netconn_close(struct netconn *conn); +err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx); #if LWIP_IGMP -err_t netconn_join_leave_group (struct netconn *conn, - struct ip_addr *multiaddr, - struct ip_addr *interface, - enum netconn_igmp join_or_leave); +err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr, + ip_addr_t *netif_addr, enum netconn_igmp join_or_leave); #endif /* LWIP_IGMP */ #if LWIP_DNS -err_t netconn_gethostbyname(const char *name, struct ip_addr *addr); +err_t netconn_gethostbyname(const char *name, ip_addr_t *addr); #endif /* LWIP_DNS */ -#define netconn_err(conn) ((conn)->err) -#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) +#define netconn_err(conn) ((conn)->last_err) +#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize) + +/** Set the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_set_nonblocking(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0) +/** Get the blocking status of netconn calls (@todo: write/send is missing) */ +#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0) + +/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_set_noautorecved(conn, val) do { if(val) { \ + (conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \ +} else { \ + (conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0) +/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */ +#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0) + +#if LWIP_SO_RCVTIMEO +/** Set the receive timeout in milliseconds */ +#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout)) +/** Get the receive timeout in milliseconds */ +#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout) +#endif /* LWIP_SO_RCVTIMEO */ +#if LWIP_SO_RCVBUF +/** Set the receive buffer in bytes */ +#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize)) +/** Get the receive buffer in bytes */ +#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize) +#endif /* LWIP_SO_RCVBUF*/ #ifdef __cplusplus } diff --git a/core/lwip/src/include/lwip/api_msg.h b/core/lwip/src/include/lwip/api_msg.h index d3b04568..f99d8c3b 100644 --- a/core/lwip/src/include/lwip/api_msg.h +++ b/core/lwip/src/include/lwip/api_msg.h @@ -48,6 +48,11 @@ extern "C" { #endif +/* For the netconn API, these values are use as a bitmask! */ +#define NETCONN_SHUT_RD 1 +#define NETCONN_SHUT_WR 2 +#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR) + /* IP addresses and port numbers are expected to be in * the same byte order as in the corresponding pcb. */ @@ -58,6 +63,8 @@ struct api_msg_msg { /** The netconn which to process - always needed: it includes the semaphore which is used to block the application thread until the function finished. */ struct netconn *conn; + /** The return value of the function executed in tcpip_thread. */ + err_t err; /** Depending on the executed function, one of these union members is used */ union { /** used for do_send */ @@ -68,12 +75,12 @@ struct api_msg_msg { } n; /** used for do_bind and do_connect */ struct { - struct ip_addr *ipaddr; + ip_addr_t *ipaddr; u16_t port; } bc; /** used for do_getaddr */ struct { - struct ip_addr *ipaddr; + ip_addr_t *ipaddr; u16_t *port; u8_t local; } ad; @@ -85,13 +92,17 @@ struct api_msg_msg { } w; /** used for do_recv */ struct { - u16_t len; + u32_t len; } r; + /** used for do_close (/shutdown) */ + struct { + u8_t shut; + } sd; #if LWIP_IGMP /** used for do_join_leave_group */ struct { - struct ip_addr *multiaddr; - struct ip_addr *interface; + ip_addr_t *multiaddr; + ip_addr_t *netif_addr; enum netconn_igmp join_or_leave; } jl; #endif /* LWIP_IGMP */ @@ -122,10 +133,10 @@ struct dns_api_msg { /** Hostname to query or dotted IP address string */ const char *name; /** Rhe resolved address is stored here */ - struct ip_addr *addr; + ip_addr_t *addr; /** This semaphore is posted when the name is resolved, the application thread should wait on it. */ - sys_sem_t sem; + sys_sem_t *sem; /** Errors are given back here */ err_t *err; }; @@ -142,6 +153,7 @@ void do_recv ( struct api_msg_msg *msg); void do_write ( struct api_msg_msg *msg); void do_getaddr ( struct api_msg_msg *msg); void do_close ( struct api_msg_msg *msg); +void do_shutdown ( struct api_msg_msg *msg); #if LWIP_IGMP void do_join_leave_group( struct api_msg_msg *msg); #endif /* LWIP_IGMP */ diff --git a/core/lwip/src/include/lwip/arch.h b/core/lwip/src/include/lwip/arch.h index 3a5a0e4f..524af6be 100644 --- a/core/lwip/src/include/lwip/arch.h +++ b/core/lwip/src/include/lwip/arch.h @@ -46,6 +46,11 @@ #ifndef SZT_F #define SZT_F U32_F #endif /* SZT_F */ +/** Temporary upgrade helper: define format string for u8_t as hex if not + defined in cc.h */ +#ifndef X8_F +#define X8_F "02x" +#endif /* X8_F */ #ifdef __cplusplus extern "C" { @@ -71,154 +76,154 @@ extern "C" { #ifdef LWIP_PROVIDE_ERRNO -#define EPERM 1 /* Operation not permitted */ -#define ENOENT 2 /* No such file or directory */ -#define ESRCH 3 /* No such process */ -#define EINTR 4 /* Interrupted system call */ -#define EIO 5 /* I/O error */ -#define ENXIO 6 /* No such device or address */ -#define E2BIG 7 /* Arg list too long */ -#define ENOEXEC 8 /* Exec format error */ -#define EBADF 9 /* Bad file number */ -#define ECHILD 10 /* No child processes */ -#define EAGAIN 11 /* Try again */ -#define ENOMEM 12 /* Out of memory */ -#define EACCES 13 /* Permission denied */ -#define EFAULT 14 /* Bad address */ -#define ENOTBLK 15 /* Block device required */ -#define EBUSY 16 /* Device or resource busy */ -#define EEXIST 17 /* File exists */ -#define EXDEV 18 /* Cross-device link */ -#define ENODEV 19 /* No such device */ -#define ENOTDIR 20 /* Not a directory */ -#define EISDIR 21 /* Is a directory */ -#define EINVAL 22 /* Invalid argument */ -#define ENFILE 23 /* File table overflow */ -#define EMFILE 24 /* Too many open files */ -#define ENOTTY 25 /* Not a typewriter */ -#define ETXTBSY 26 /* Text file busy */ -#define EFBIG 27 /* File too large */ -#define ENOSPC 28 /* No space left on device */ -#define ESPIPE 29 /* Illegal seek */ -#define EROFS 30 /* Read-only file system */ -#define EMLINK 31 /* Too many links */ -#define EPIPE 32 /* Broken pipe */ -#define EDOM 33 /* Math argument out of domain of func */ -#define ERANGE 34 /* Math result not representable */ -#define EDEADLK 35 /* Resource deadlock would occur */ -#define ENAMETOOLONG 36 /* File name too long */ -#define ENOLCK 37 /* No record locks available */ -#define ENOSYS 38 /* Function not implemented */ -#define ENOTEMPTY 39 /* Directory not empty */ -#define ELOOP 40 /* Too many symbolic links encountered */ +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ #define EWOULDBLOCK EAGAIN /* Operation would block */ -#define ENOMSG 42 /* No message of desired type */ -#define EIDRM 43 /* Identifier removed */ -#define ECHRNG 44 /* Channel number out of range */ -#define EL2NSYNC 45 /* Level 2 not synchronized */ -#define EL3HLT 46 /* Level 3 halted */ -#define EL3RST 47 /* Level 3 reset */ -#define ELNRNG 48 /* Link number out of range */ -#define EUNATCH 49 /* Protocol driver not attached */ -#define ENOCSI 50 /* No CSI structure available */ -#define EL2HLT 51 /* Level 2 halted */ -#define EBADE 52 /* Invalid exchange */ -#define EBADR 53 /* Invalid request descriptor */ -#define EXFULL 54 /* Exchange full */ -#define ENOANO 55 /* No anode */ -#define EBADRQC 56 /* Invalid request code */ -#define EBADSLT 57 /* Invalid slot */ - -#define EDEADLOCK EDEADLK - -#define EBFONT 59 /* Bad font file format */ -#define ENOSTR 60 /* Device not a stream */ -#define ENODATA 61 /* No data available */ -#define ETIME 62 /* Timer expired */ -#define ENOSR 63 /* Out of streams resources */ -#define ENONET 64 /* Machine is not on the network */ -#define ENOPKG 65 /* Package not installed */ -#define EREMOTE 66 /* Object is remote */ -#define ENOLINK 67 /* Link has been severed */ -#define EADV 68 /* Advertise error */ -#define ESRMNT 69 /* Srmount error */ -#define ECOMM 70 /* Communication error on send */ -#define EPROTO 71 /* Protocol error */ -#define EMULTIHOP 72 /* Multihop attempted */ -#define EDOTDOT 73 /* RFS specific error */ -#define EBADMSG 74 /* Not a data message */ -#define EOVERFLOW 75 /* Value too large for defined data type */ -#define ENOTUNIQ 76 /* Name not unique on network */ -#define EBADFD 77 /* File descriptor in bad state */ -#define EREMCHG 78 /* Remote address changed */ -#define ELIBACC 79 /* Can not access a needed shared library */ -#define ELIBBAD 80 /* Accessing a corrupted shared library */ -#define ELIBSCN 81 /* .lib section in a.out corrupted */ -#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ -#define ELIBEXEC 83 /* Cannot exec a shared library directly */ -#define EILSEQ 84 /* Illegal byte sequence */ -#define ERESTART 85 /* Interrupted system call should be restarted */ -#define ESTRPIPE 86 /* Streams pipe error */ -#define EUSERS 87 /* Too many users */ -#define ENOTSOCK 88 /* Socket operation on non-socket */ -#define EDESTADDRREQ 89 /* Destination address required */ -#define EMSGSIZE 90 /* Message too long */ -#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ + +#define EDEADLOCK EDEADLK + +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ #define ENOPROTOOPT 92 /* Protocol not available */ -#define EPROTONOSUPPORT 93 /* Protocol not supported */ -#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ -#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ -#define EPFNOSUPPORT 96 /* Protocol family not supported */ -#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ -#define EADDRINUSE 98 /* Address already in use */ -#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ -#define ENETDOWN 100 /* Network is down */ -#define ENETUNREACH 101 /* Network is unreachable */ -#define ENETRESET 102 /* Network dropped connection because of reset */ -#define ECONNABORTED 103 /* Software caused connection abort */ -#define ECONNRESET 104 /* Connection reset by peer */ -#define ENOBUFS 105 /* No buffer space available */ -#define EISCONN 106 /* Transport endpoint is already connected */ -#define ENOTCONN 107 /* Transport endpoint is not connected */ -#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ -#define ETOOMANYREFS 109 /* Too many references: cannot splice */ -#define ETIMEDOUT 110 /* Connection timed out */ -#define ECONNREFUSED 111 /* Connection refused */ -#define EHOSTDOWN 112 /* Host is down */ -#define EHOSTUNREACH 113 /* No route to host */ -#define EALREADY 114 /* Operation already in progress */ -#define EINPROGRESS 115 /* Operation now in progress */ -#define ESTALE 116 /* Stale NFS file handle */ -#define EUCLEAN 117 /* Structure needs cleaning */ -#define ENOTNAM 118 /* Not a XENIX named type file */ -#define ENAVAIL 119 /* No XENIX semaphores available */ -#define EISNAM 120 /* Is a named type file */ -#define EREMOTEIO 121 /* Remote I/O error */ -#define EDQUOT 122 /* Quota exceeded */ - -#define ENOMEDIUM 123 /* No medium found */ -#define EMEDIUMTYPE 124 /* Wrong medium type */ - - -#define ENSROK 0 /* DNS server returned answer with no data */ -#define ENSRNODATA 160 /* DNS server returned answer with no data */ -#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ -#define ENSRSERVFAIL 162 /* DNS server returned general failure */ -#define ENSRNOTFOUND 163 /* Domain name not found */ -#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ -#define ENSRREFUSED 165 /* DNS server refused query */ -#define ENSRBADQUERY 166 /* Misformatted DNS query */ -#define ENSRBADNAME 167 /* Misformatted domain name */ -#define ENSRBADFAMILY 168 /* Unsupported address family */ -#define ENSRBADRESP 169 /* Misformatted DNS reply */ -#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ -#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ -#define ENSROF 172 /* End of file */ -#define ENSRFILE 173 /* Error reading file */ -#define ENSRNOMEM 174 /* Out of memory */ -#define ENSRDESTRUCTION 175 /* Application terminated lookup */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +#define ENOMEDIUM 123 /* No medium found */ +#define EMEDIUMTYPE 124 /* Wrong medium type */ + + +#define ENSROK 0 /* DNS server returned answer with no data */ +#define ENSRNODATA 160 /* DNS server returned answer with no data */ +#define ENSRFORMERR 161 /* DNS server claims query was misformatted */ +#define ENSRSERVFAIL 162 /* DNS server returned general failure */ +#define ENSRNOTFOUND 163 /* Domain name not found */ +#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */ +#define ENSRREFUSED 165 /* DNS server refused query */ +#define ENSRBADQUERY 166 /* Misformatted DNS query */ +#define ENSRBADNAME 167 /* Misformatted domain name */ +#define ENSRBADFAMILY 168 /* Unsupported address family */ +#define ENSRBADRESP 169 /* Misformatted DNS reply */ +#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */ +#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */ +#define ENSROF 172 /* End of file */ +#define ENSRFILE 173 /* Error reading file */ +#define ENSRNOMEM 174 /* Out of memory */ +#define ENSRDESTRUCTION 175 /* Application terminated lookup */ #define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */ -#define ENSRCNAMELOOP 177 /* Domain name is too long */ +#define ENSRCNAMELOOP 177 /* Domain name is too long */ #ifndef errno extern int errno; diff --git a/core/lwip/src/include/lwip/def.h b/core/lwip/src/include/lwip/def.h index d2ed251d..9b6de6a8 100644 --- a/core/lwip/src/include/lwip/def.h +++ b/core/lwip/src/include/lwip/def.h @@ -32,8 +32,13 @@ #ifndef __LWIP_DEF_H__ #define __LWIP_DEF_H__ -/* this might define NULL already */ +/* arch.h might define NULL already */ #include "lwip/arch.h" +#include "lwip/opt.h" + +#ifdef __cplusplus +extern "C" { +#endif #define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y)) #define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y)) @@ -42,6 +47,81 @@ #define NULL ((void *)0) #endif +/** Get the absolute difference between 2 u32_t values (correcting overflows) + * 'a' is expected to be 'higher' (without overflow) than 'b'. */ +#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1))) + +/* Endianess-optimized shifting of two u8_t to create one u16_t */ +#if BYTE_ORDER == LITTLE_ENDIAN +#define LWIP_MAKE_U16(a, b) ((a << 8) | b) +#else +#define LWIP_MAKE_U16(a, b) ((b << 8) | a) +#endif + +#ifndef LWIP_PLATFORM_BYTESWAP +#define LWIP_PLATFORM_BYTESWAP 0 +#endif + +#ifndef LWIP_PREFIX_BYTEORDER_FUNCS +/* workaround for naming collisions on some platforms */ + +#ifdef htons +#undef htons +#endif /* htons */ +#ifdef htonl +#undef htonl +#endif /* htonl */ +#ifdef ntohs +#undef ntohs +#endif /* ntohs */ +#ifdef ntohl +#undef ntohl +#endif /* ntohl */ + +#define htons(x) lwip_htons(x) +#define ntohs(x) lwip_ntohs(x) +#define htonl(x) lwip_htonl(x) +#define ntohl(x) lwip_ntohl(x) +#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */ + +#if BYTE_ORDER == BIG_ENDIAN +#define lwip_htons(x) (x) +#define lwip_ntohs(x) (x) +#define lwip_htonl(x) (x) +#define lwip_ntohl(x) (x) +#define PP_HTONS(x) (x) +#define PP_NTOHS(x) (x) +#define PP_HTONL(x) (x) +#define PP_NTOHL(x) (x) +#else /* BYTE_ORDER != BIG_ENDIAN */ +#if LWIP_PLATFORM_BYTESWAP +#define lwip_htons(x) LWIP_PLATFORM_HTONS(x) +#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x) +#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x) +#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x) +#else /* LWIP_PLATFORM_BYTESWAP */ +u16_t lwip_htons(u16_t x); +u16_t lwip_ntohs(u16_t x); +u32_t lwip_htonl(u32_t x); +u32_t lwip_ntohl(u32_t x); +#endif /* LWIP_PLATFORM_BYTESWAP */ + +/* These macros should be calculated by the preprocessor and are used + with compile-time constants only (so that there is no little-endian + overhead at runtime). */ +#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8)) +#define PP_NTOHS(x) PP_HTONS(x) +#define PP_HTONL(x) ((((x) & 0xff) << 24) | \ + (((x) & 0xff00) << 8) | \ + (((x) & 0xff0000UL) >> 8) | \ + (((x) & 0xff000000UL) >> 24)) +#define PP_NTOHL(x) PP_HTONL(x) + +#endif /* BYTE_ORDER == BIG_ENDIAN */ + +#ifdef __cplusplus +} +#endif #endif /* __LWIP_DEF_H__ */ diff --git a/core/lwip/src/include/lwip/dhcp.h b/core/lwip/src/include/lwip/dhcp.h index db37e884..32d93381 100644 --- a/core/lwip/src/include/lwip/dhcp.h +++ b/core/lwip/src/include/lwip/dhcp.h @@ -22,6 +22,10 @@ extern "C" { /** period (in milliseconds) of the application calling dhcp_fine_tmr() */ #define DHCP_FINE_TIMER_MSECS 500 +#define DHCP_CHADDR_LEN 16U +#define DHCP_SNAME_LEN 64U +#define DHCP_FILE_LEN 128U + struct dhcp { /** transaction identifier of last sent request */ @@ -30,14 +34,14 @@ struct dhcp struct udp_pcb *pcb; /** incoming msg */ struct dhcp_msg *msg_in; - /** incoming msg options */ - void *options_in; - /** ingoing msg options length */ - u16_t options_in_len; /** current DHCP state machine state */ u8_t state; /** retries of current request */ u8_t tries; +#if LWIP_DHCP_AUTOIP_COOP + u8_t autoip_coop_state; +#endif + u8_t subnet_mask_given; struct pbuf *p_out; /* pbuf of outcoming msg */ struct dhcp_msg *msg_out; /* outgoing msg */ @@ -45,28 +49,20 @@ struct dhcp u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */ u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */ u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */ - struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */ - struct ip_addr offered_ip_addr; - struct ip_addr offered_sn_mask; - struct ip_addr offered_gw_addr; - struct ip_addr offered_bc_addr; -#define DHCP_MAX_DNS 2 - u32_t dns_count; /* actual number of DNS servers obtained */ - struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */ + ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */ + ip_addr_t offered_ip_addr; + ip_addr_t offered_sn_mask; + ip_addr_t offered_gw_addr; u32_t offered_t0_lease; /* lease period (in seconds) */ u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */ u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */ -#if LWIP_DHCP_AUTOIP_COOP - u8_t autoip_coop_state; -#endif -/** Patch #1308 - * TODO: See dhcp.c "TODO"s - */ -#if 0 - struct ip_addr offered_si_addr; - u8_t *boot_file_name; -#endif + /* @todo: LWIP_DHCP_BOOTP_FILE configuration option? + integrate with possible TFTP-client for booting? */ +#if LWIP_DHCP_BOOTP_FILE + ip_addr_t offered_si_addr; + char boot_file_name[DHCP_FILE_LEN]; +#endif /* LWIP_DHCP_BOOTPFILE */ }; /* MUST be compiled with "pack structs" or equivalent! */ @@ -84,15 +80,12 @@ struct dhcp_msg PACK_STRUCT_FIELD(u32_t xid); PACK_STRUCT_FIELD(u16_t secs); PACK_STRUCT_FIELD(u16_t flags); - PACK_STRUCT_FIELD(struct ip_addr ciaddr); - PACK_STRUCT_FIELD(struct ip_addr yiaddr); - PACK_STRUCT_FIELD(struct ip_addr siaddr); - PACK_STRUCT_FIELD(struct ip_addr giaddr); -#define DHCP_CHADDR_LEN 16U + PACK_STRUCT_FIELD(ip_addr_p_t ciaddr); + PACK_STRUCT_FIELD(ip_addr_p_t yiaddr); + PACK_STRUCT_FIELD(ip_addr_p_t siaddr); + PACK_STRUCT_FIELD(ip_addr_p_t giaddr); PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]); -#define DHCP_SNAME_LEN 64U PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]); -#define DHCP_FILE_LEN 128U PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]); PACK_STRUCT_FIELD(u32_t cookie); #define DHCP_MIN_OPTIONS_LEN 68U @@ -112,6 +105,10 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif +void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp); +/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */ +#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0) +void dhcp_cleanup(struct netif *netif); /** start DHCP configuration */ err_t dhcp_start(struct netif *netif); /** enforce early lease renewal (not needed normally)*/ @@ -127,7 +124,7 @@ void dhcp_network_changed(struct netif *netif); /** if enabled, check whether the offered IP address is not in use, using ARP */ #if DHCP_DOES_ARP_CHECK -void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr); +void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr); #endif /** to be called every minute */ @@ -136,66 +133,66 @@ void dhcp_coarse_tmr(void); void dhcp_fine_tmr(void); /** DHCP message item offsets and length */ -#define DHCP_MSG_OFS (UDP_DATA_OFS) - #define DHCP_OP_OFS (DHCP_MSG_OFS + 0) - #define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1) - #define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2) - #define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3) - #define DHCP_XID_OFS (DHCP_MSG_OFS + 4) - #define DHCP_SECS_OFS (DHCP_MSG_OFS + 8) - #define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10) - #define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12) - #define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16) - #define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20) - #define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24) - #define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28) - #define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44) - #define DHCP_FILE_OFS (DHCP_MSG_OFS + 108) -#define DHCP_MSG_LEN 236 - -#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN) -#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4) - -#define DHCP_CLIENT_PORT 68 -#define DHCP_SERVER_PORT 67 +#define DHCP_OP_OFS 0 +#define DHCP_HTYPE_OFS 1 +#define DHCP_HLEN_OFS 2 +#define DHCP_HOPS_OFS 3 +#define DHCP_XID_OFS 4 +#define DHCP_SECS_OFS 8 +#define DHCP_FLAGS_OFS 10 +#define DHCP_CIADDR_OFS 12 +#define DHCP_YIADDR_OFS 16 +#define DHCP_SIADDR_OFS 20 +#define DHCP_GIADDR_OFS 24 +#define DHCP_CHADDR_OFS 28 +#define DHCP_SNAME_OFS 44 +#define DHCP_FILE_OFS 108 +#define DHCP_MSG_LEN 236 + +#define DHCP_COOKIE_OFS DHCP_MSG_LEN +#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4) + +#define DHCP_CLIENT_PORT 68 +#define DHCP_SERVER_PORT 67 /** DHCP client states */ -#define DHCP_REQUESTING 1 -#define DHCP_INIT 2 -#define DHCP_REBOOTING 3 -#define DHCP_REBINDING 4 -#define DHCP_RENEWING 5 -#define DHCP_SELECTING 6 -#define DHCP_INFORMING 7 -#define DHCP_CHECKING 8 -#define DHCP_PERMANENT 9 -#define DHCP_BOUND 10 +#define DHCP_OFF 0 +#define DHCP_REQUESTING 1 +#define DHCP_INIT 2 +#define DHCP_REBOOTING 3 +#define DHCP_REBINDING 4 +#define DHCP_RENEWING 5 +#define DHCP_SELECTING 6 +#define DHCP_INFORMING 7 +#define DHCP_CHECKING 8 +#define DHCP_PERMANENT 9 +#define DHCP_BOUND 10 /** not yet implemented #define DHCP_RELEASING 11 */ -#define DHCP_BACKING_OFF 12 -#define DHCP_OFF 13 +#define DHCP_BACKING_OFF 12 /** AUTOIP cooperatation flags */ -#define DHCP_AUTOIP_COOP_STATE_OFF 0 -#define DHCP_AUTOIP_COOP_STATE_ON 1 +#define DHCP_AUTOIP_COOP_STATE_OFF 0 +#define DHCP_AUTOIP_COOP_STATE_ON 1 -#define DHCP_BOOTREQUEST 1 -#define DHCP_BOOTREPLY 2 +#define DHCP_BOOTREQUEST 1 +#define DHCP_BOOTREPLY 2 +/** DHCP message types */ #define DHCP_DISCOVER 1 -#define DHCP_OFFER 2 -#define DHCP_REQUEST 3 -#define DHCP_DECLINE 4 -#define DHCP_ACK 5 -#define DHCP_NAK 6 -#define DHCP_RELEASE 7 -#define DHCP_INFORM 8 - +#define DHCP_OFFER 2 +#define DHCP_REQUEST 3 +#define DHCP_DECLINE 4 +#define DHCP_ACK 5 +#define DHCP_NAK 6 +#define DHCP_RELEASE 7 +#define DHCP_INFORM 8 + +/** DHCP hardware type, currently only ethernet is supported */ #define DHCP_HTYPE_ETH 1 -#define DHCP_HLEN_ETH 6 +#define DHCP_MAGIC_COOKIE 0x63825363UL -#define DHCP_BROADCAST_FLAG 15 -#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST) +/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */ /** BootP options */ #define DHCP_OPTION_PAD 0 @@ -217,7 +214,6 @@ void dhcp_fine_tmr(void); #define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */ #define DHCP_OPTION_MESSAGE_TYPE_LEN 1 - #define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */ #define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */ diff --git a/core/lwip/src/include/lwip/dns.h b/core/lwip/src/include/lwip/dns.h index e5f4b7a3..6c7d9b07 100644 --- a/core/lwip/src/include/lwip/dns.h +++ b/core/lwip/src/include/lwip/dns.h @@ -38,6 +38,10 @@ #if LWIP_DNS /* don't build if not configured for use in lwipopts.h */ +#ifdef __cplusplus +extern "C" { +#endif + /** DNS timer period */ #define DNS_TMR_INTERVAL 1000 @@ -66,32 +70,55 @@ #define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */ #define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */ +/* The size used for the next line is rather a hack, but it prevents including socket.h in all files + that include memp.h, and that would possibly break portability (since socket.h defines some types + and constants possibly already define by the OS). + Calculation rule: + sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */ +#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1) + +#if DNS_LOCAL_HOSTLIST +/** struct used for local host-list */ +struct local_hostlist_entry { + /** static hostname */ + const char *name; + /** static host address in network byteorder */ + ip_addr_t addr; + struct local_hostlist_entry *next; +}; +#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC +#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN +#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH +#endif +#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1)) +#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#endif /* DNS_LOCAL_HOSTLIST */ + /** Callback which is invoked when a hostname is found. * A function of this type must be implemented by the application using the DNS resolver. * @param name pointer to the name that was looked up. - * @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname, + * @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname, * or NULL if the name could not be found (or on any other error). * @param callback_arg a user-specified callback argument passed to dns_gethostbyname */ -typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg); - +typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg); void dns_init(void); - void dns_tmr(void); - -void dns_setserver(u8_t numdns, struct ip_addr *dnsserver); - -struct ip_addr dns_getserver(u8_t numdns); - -err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr, +void dns_setserver(u8_t numdns, ip_addr_t *dnsserver); +ip_addr_t dns_getserver(u8_t numdns); +err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr, dns_found_callback found, void *callback_arg); #if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC -int dns_local_removehost(const char *hostname, const struct ip_addr *addr); -err_t dns_local_addhost(const char *hostname, const struct ip_addr *addr); +int dns_local_removehost(const char *hostname, const ip_addr_t *addr); +err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr); #endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#ifdef __cplusplus +} +#endif + #endif /* LWIP_DNS */ #endif /* __LWIP_DNS_H__ */ diff --git a/core/lwip/src/include/lwip/err.h b/core/lwip/src/include/lwip/err.h index 69676445..ac907729 100644 --- a/core/lwip/src/include/lwip/err.h +++ b/core/lwip/src/include/lwip/err.h @@ -44,7 +44,7 @@ extern "C" { #ifdef LWIP_ERR_T typedef LWIP_ERR_T err_t; #else /* LWIP_ERR_T */ - typedef s8_t err_t; +typedef s8_t err_t; #endif /* LWIP_ERR_T*/ /* Definitions for error constants. */ @@ -54,24 +54,22 @@ typedef LWIP_ERR_T err_t; #define ERR_BUF -2 /* Buffer error. */ #define ERR_TIMEOUT -3 /* Timeout. */ #define ERR_RTE -4 /* Routing problem. */ +#define ERR_INPROGRESS -5 /* Operation in progress */ +#define ERR_VAL -6 /* Illegal value. */ +#define ERR_WOULDBLOCK -7 /* Operation would block. */ +#define ERR_USE -8 /* Address in use. */ +#define ERR_ISCONN -9 /* Already connected. */ -#define ERR_IS_FATAL(e) ((e) < ERR_RTE) +#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN) -#define ERR_ABRT -5 /* Connection aborted. */ -#define ERR_RST -6 /* Connection reset. */ -#define ERR_CLSD -7 /* Connection closed. */ -#define ERR_CONN -8 /* Not connected. */ +#define ERR_ABRT -10 /* Connection aborted. */ +#define ERR_RST -11 /* Connection reset. */ +#define ERR_CLSD -12 /* Connection closed. */ +#define ERR_CONN -13 /* Not connected. */ -#define ERR_VAL -9 /* Illegal value. */ +#define ERR_ARG -14 /* Illegal argument. */ -#define ERR_ARG -10 /* Illegal argument. */ - -#define ERR_USE -11 /* Address in use. */ - -#define ERR_IF -12 /* Low-level netif error */ -#define ERR_ISCONN -13 /* Already connected. */ - -#define ERR_INPROGRESS -14 /* Operation in progress */ +#define ERR_IF -15 /* Low-level netif error */ #ifdef LWIP_DEBUG diff --git a/core/lwip/src/include/lwip/init.h b/core/lwip/src/include/lwip/init.h index c1455f5a..77dcdfc7 100644 --- a/core/lwip/src/include/lwip/init.h +++ b/core/lwip/src/include/lwip/init.h @@ -41,9 +41,9 @@ extern "C" { /** X.x.x: Major version of the stack */ #define LWIP_VERSION_MAJOR 1U /** x.X.x: Minor version of the stack */ -#define LWIP_VERSION_MINOR 3U +#define LWIP_VERSION_MINOR 4U /** x.x.X: Revision of the stack */ -#define LWIP_VERSION_REVISION 2U +#define LWIP_VERSION_REVISION 0U /** For release candidates, this is set to 1..254 * For official releases, this is set to 255 (LWIP_RC_RELEASE) * For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */ diff --git a/core/lwip/src/include/lwip/mem.h b/core/lwip/src/include/lwip/mem.h index aeac0a81..4dbf2f64 100644 --- a/core/lwip/src/include/lwip/mem.h +++ b/core/lwip/src/include/lwip/mem.h @@ -58,44 +58,59 @@ typedef size_t mem_size_t; #ifndef mem_calloc #define mem_calloc calloc #endif -#ifndef mem_realloc -static inline void *mem_realloc(void *mem, mem_size_t size) -{ - LWIP_UNUSED_ARG(size); - return mem; -} +/* Since there is no C library allocation function to shrink memory without + moving it, define this to nothing. */ +#ifndef mem_trim +#define mem_trim(mem, size) (mem) #endif #else /* MEM_LIBC_MALLOC */ /* MEM_SIZE would have to be aligned, but using 64000 here instead of * 65535 leaves some room for alignment... */ -#if MEM_SIZE > 64000l +#if MEM_SIZE > 64000L typedef u32_t mem_size_t; +#define MEM_SIZE_F U32_F #else typedef u16_t mem_size_t; +#define MEM_SIZE_F U16_F #endif /* MEM_SIZE > 64000 */ #if MEM_USE_POOLS /** lwip_mem_init is not used when using pools instead of a heap */ #define lwip_mem_init() -/** mem_realloc is not used when using pools instead of a heap: +/** mem_trim is not used when using pools instead of a heap: we can't free part of a pool element and don't want to copy the rest */ -#define mem_realloc(mem, size) (mem) +#define mem_trim(mem, size) (mem) #else /* MEM_USE_POOLS */ /* lwIP alternative malloc */ void lwip_mem_init(void); -void *mem_realloc(void *mem, mem_size_t size); +void *mem_trim(void *mem, mem_size_t size); #endif /* MEM_USE_POOLS */ void *mem_malloc(mem_size_t size); void *mem_calloc(mem_size_t count, mem_size_t size); void mem_free(void *mem); #endif /* MEM_LIBC_MALLOC */ +/** Calculate memory size for an aligned buffer - returns the next highest + * multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and + * LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). + */ #ifndef LWIP_MEM_ALIGN_SIZE #define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) #endif +/** Calculate safe memory size for an aligned buffer when using an unaligned + * type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the + * start (e.g. if buffer is u8_t[] and actual data will be u32_t*) + */ +#ifndef LWIP_MEM_ALIGN_BUFFER +#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1)) +#endif + +/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT + * so that ADDR % MEM_ALIGNMENT == 0 + */ #ifndef LWIP_MEM_ALIGN #define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) #endif diff --git a/core/lwip/src/include/lwip/memp_std.h b/core/lwip/src/include/lwip/memp_std.h index 34469032..6ce408fb 100644 --- a/core/lwip/src/include/lwip/memp_std.h +++ b/core/lwip/src/include/lwip/memp_std.h @@ -47,6 +47,9 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg), #if IP_REASSEMBLY LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA") #endif /* IP_REASSEMBLY */ +#if IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF +LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF") +#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */ #if LWIP_NETCONN LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF") @@ -55,7 +58,9 @@ LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn), #if NO_SYS==0 LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API") +#if !LWIP_TCPIP_CORE_LOCKING_INPUT LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT") +#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */ #endif /* NO_SYS==0 */ #if ARP_QUEUEING @@ -66,10 +71,25 @@ LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_en LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP") #endif /* LWIP_IGMP */ -#if NO_SYS==0 +#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */ LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT") -#endif /* NO_SYS==0 */ - +#endif /* LWIP_TIMERS */ + +#if LWIP_SNMP +LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE") +LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE") +LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND") +LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE") +#endif /* LWIP_SNMP */ +#if LWIP_DNS && LWIP_SOCKET +LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB") +#endif /* LWIP_DNS && LWIP_SOCKET */ +#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC +LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST") +#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */ +#if PPP_SUPPORT && PPPOE_SUPPORT +LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF") +#endif /* PPP_SUPPORT && PPPOE_SUPPORT */ /* * A list of pools of pbuf's used by LWIP. diff --git a/core/lwip/src/include/lwip/netbuf.h b/core/lwip/src/include/lwip/netbuf.h index 0dfb367a..7d247d71 100644 --- a/core/lwip/src/include/lwip/netbuf.h +++ b/core/lwip/src/include/lwip/netbuf.h @@ -40,14 +40,24 @@ extern "C" { #endif +/** This netbuf has dest-addr/port set */ +#define NETBUF_FLAG_DESTADDR 0x01 +/** This netbuf includes a checksum */ +#define NETBUF_FLAG_CHKSUM 0x02 + struct netbuf { struct pbuf *p, *ptr; - struct ip_addr *addr; + ip_addr_t addr; u16_t port; +#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY +#if LWIP_CHECKSUM_ON_COPY + u8_t flags; +#endif /* LWIP_CHECKSUM_ON_COPY */ + u16_t toport_chksum; #if LWIP_NETBUF_RECVINFO - struct ip_addr *toaddr; - u16_t toport; + ip_addr_t toaddr; #endif /* LWIP_NETBUF_RECVINFO */ +#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */ }; /* Network buffer functions: */ @@ -56,13 +66,12 @@ void netbuf_delete (struct netbuf *buf); void * netbuf_alloc (struct netbuf *buf, u16_t size); void netbuf_free (struct netbuf *buf); err_t netbuf_ref (struct netbuf *buf, - const void *dataptr, u16_t size); + const void *dataptr, u16_t size); void netbuf_chain (struct netbuf *head, struct netbuf *tail); -u16_t netbuf_len (struct netbuf *buf); err_t netbuf_data (struct netbuf *buf, - void **dataptr, u16_t *len); + void **dataptr, u16_t *len); s8_t netbuf_next (struct netbuf *buf); void netbuf_first (struct netbuf *buf); @@ -72,12 +81,18 @@ void netbuf_first (struct netbuf *buf); #define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0) #define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len) #define netbuf_len(buf) ((buf)->p->tot_len) -#define netbuf_fromaddr(buf) ((buf)->addr) +#define netbuf_fromaddr(buf) (&((buf)->addr)) +#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set((&(buf)->addr), fromaddr) #define netbuf_fromport(buf) ((buf)->port) #if LWIP_NETBUF_RECVINFO -#define netbuf_destaddr(buf) ((buf)->toaddr) -#define netbuf_destport(buf) ((buf)->toport) +#define netbuf_destaddr(buf) (&((buf)->toaddr)) +#define netbuf_set_destaddr(buf, destaddr) ip_addr_set((&(buf)->addr), destaddr) +#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0) #endif /* LWIP_NETBUF_RECVINFO */ +#if LWIP_CHECKSUM_ON_COPY +#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \ + (buf)->toport_chksum = chksum; } while(0) +#endif /* LWIP_CHECKSUM_ON_COPY */ #ifdef __cplusplus } diff --git a/core/lwip/src/include/lwip/netdb.h b/core/lwip/src/include/lwip/netdb.h index 29c9847c..7587e2f2 100644 --- a/core/lwip/src/include/lwip/netdb.h +++ b/core/lwip/src/include/lwip/netdb.h @@ -26,6 +26,8 @@ * Author: Simon Goldschmidt * */ +#ifndef __LWIP_NETDB_H__ +#define __LWIP_NETDB_H__ #include "lwip/opt.h" @@ -33,8 +35,13 @@ #include <stddef.h> /* for size_t */ +#include "lwip/inet.h" #include "lwip/sockets.h" +#ifdef __cplusplus +extern "C" { +#endif + /* some rarely used options */ #ifndef LWIP_DNS_API_DECLARE_H_ERRNO #define LWIP_DNS_API_DECLARE_H_ERRNO 1 @@ -108,4 +115,10 @@ int lwip_getaddrinfo(const char *nodename, lwip_getaddrinfo(nodname, servname, hints, res) #endif /* LWIP_COMPAT_SOCKETS */ +#ifdef __cplusplus +} +#endif + #endif /* LWIP_DNS && LWIP_SOCKET */ + +#endif /* __LWIP_NETDB_H__ */ diff --git a/core/lwip/src/include/lwip/netif.h b/core/lwip/src/include/lwip/netif.h index 462d3497..8e799295 100644 --- a/core/lwip/src/include/lwip/netif.h +++ b/core/lwip/src/include/lwip/netif.h @@ -40,7 +40,7 @@ #include "lwip/ip_addr.h" -#include "lwip/inet.h" +#include "lwip/def.h" #include "lwip/pbuf.h" #if LWIP_DHCP struct dhcp; @@ -60,61 +60,108 @@ extern "C" { across all types of interfaces in use */ #define NETIF_MAX_HWADDR_LEN 32U -/** TODO: define the use (where, when, whom) of netif flags */ - -/** whether the network interface is 'up'. this is +/** Whether the network interface is 'up'. This is * a software flag used to control whether this network * interface is enabled and processes traffic. + * It is set by the startup code (for static IP configuration) or + * by dhcp/autoip when an address has been assigned. */ #define NETIF_FLAG_UP 0x01U -/** if set, the netif has broadcast capability */ +/** If set, the netif has broadcast capability. + * Set by the netif driver in its init function. */ #define NETIF_FLAG_BROADCAST 0x02U -/** if set, the netif is one end of a point-to-point connection */ +/** If set, the netif is one end of a point-to-point connection. + * Set by the netif driver in its init function. */ #define NETIF_FLAG_POINTTOPOINT 0x04U -/** if set, the interface is configured using DHCP */ +/** If set, the interface is configured using DHCP. + * Set by the DHCP code when starting or stopping DHCP. */ #define NETIF_FLAG_DHCP 0x08U -/** if set, the interface has an active link - * (set by the network interface driver) */ +/** If set, the interface has an active link + * (set by the network interface driver). + * Either set by the netif driver in its init function (if the link + * is up at that time) or at a later point once the link comes up + * (if link detection is supported by the hardware). */ #define NETIF_FLAG_LINK_UP 0x10U -/** if set, the netif is an device using ARP */ +/** If set, the netif is an ethernet device using ARP. + * Set by the netif driver in its init function. + * Used to check input packet types and use of DHCP. */ #define NETIF_FLAG_ETHARP 0x20U -/** if set, the netif has IGMP capability */ -#define NETIF_FLAG_IGMP 0x40U +/** If set, the netif is an ethernet device. It might not use + * ARP or TCP/IP if it is used for PPPoE only. + */ +#define NETIF_FLAG_ETHERNET 0x40U +/** If set, the netif has IGMP capability. + * Set by the netif driver in its init function. */ +#define NETIF_FLAG_IGMP 0x80U + +/** Function prototype for netif init functions. Set up flags and output/linkoutput + * callback functions in this function. + * + * @param netif The netif to initialize + */ +typedef err_t (*netif_init_fn)(struct netif *netif); +/** Function prototype for netif->input functions. This function is saved as 'input' + * callback function in the netif struct. Call it when a packet has been received. + * + * @param p The received packet, copied into a pbuf + * @param inp The netif which received the packet + */ +typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp); +/** Function prototype for netif->output functions. Called by lwIP when a packet + * shall be sent. For ethernet netif, set this to 'etharp_output' and set + * 'linkoutput'. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (p->payload points to IP header) + * @param ipaddr The IP address to which the packet shall be sent + */ +typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p, + ip_addr_t *ipaddr); +/** Function prototype for netif->linkoutput functions. Only used for ethernet + * netifs. This function is called by ARP when a packet shall be sent. + * + * @param netif The netif which shall send a packet + * @param p The packet to send (raw ethernet packet) + */ +typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p); +/** Function prototype for netif status- or link-callback functions. */ +typedef void (*netif_status_callback_fn)(struct netif *netif); +/** Function prototype for netif igmp_mac_filter functions */ +typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif, + ip_addr_t *group, u8_t action); /** Generic data structure used for all lwIP network interfaces. * The following fields should be filled in by the initialization * function for the device driver: hwaddr_len, hwaddr[], mtu, flags */ - struct netif { /** pointer to next in linked list */ struct netif *next; /** IP address configuration in network byte order */ - struct ip_addr ip_addr; - struct ip_addr netmask; - struct ip_addr gw; + ip_addr_t ip_addr; + ip_addr_t netmask; + ip_addr_t gw; /** This function is called by the network device driver * to pass a packet up the TCP/IP stack. */ - err_t (* input)(struct pbuf *p, struct netif *inp); + netif_input_fn input; /** This function is called by the IP module when it wants * to send a packet on the interface. This function typically * first resolves the hardware address, then sends the packet. */ - err_t (* output)(struct netif *netif, struct pbuf *p, - struct ip_addr *ipaddr); + netif_output_fn output; /** This function is called by the ARP module when it wants * to send a packet on the interface. This function outputs * the pbuf as-is on the link medium. */ - err_t (* linkoutput)(struct netif *netif, struct pbuf *p); + netif_linkoutput_fn linkoutput; #if LWIP_NETIF_STATUS_CALLBACK /** This function is called when the netif state is set to up or down */ - void (* status_callback)(struct netif *netif); + netif_status_callback_fn status_callback; #endif /* LWIP_NETIF_STATUS_CALLBACK */ #if LWIP_NETIF_LINK_CALLBACK /** This function is called when the netif link is set to up or down */ - void (* link_callback)(struct netif *netif); + netif_status_callback_fn link_callback; #endif /* LWIP_NETIF_LINK_CALLBACK */ /** This field can be set by the device driver and could point * to state information for the device. */ @@ -161,8 +208,9 @@ struct netif { u32_t ifoutdiscards; #endif /* LWIP_SNMP */ #if LWIP_IGMP - /* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/ - err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action); + /** This function could be called to add or delete a entry in the multicast + filter table of the ethernet MAC.*/ + netif_igmp_mac_filter_fn igmp_mac_filter; #endif /* LWIP_IGMP */ #if LWIP_NETIF_HWADDRHINT u8_t *addr_hint; @@ -180,18 +228,18 @@ struct netif { #if LWIP_SNMP #define NETIF_INIT_SNMP(netif, type, speed) \ /* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \ - netif->link_type = type; \ + (netif)->link_type = (type); \ /* your link speed here (units: bits per second) */ \ - netif->link_speed = speed; \ - netif->ts = 0; \ - netif->ifinoctets = 0; \ - netif->ifinucastpkts = 0; \ - netif->ifinnucastpkts = 0; \ - netif->ifindiscards = 0; \ - netif->ifoutoctets = 0; \ - netif->ifoutucastpkts = 0; \ - netif->ifoutnucastpkts = 0; \ - netif->ifoutdiscards = 0 + (netif)->link_speed = (speed); \ + (netif)->ts = 0; \ + (netif)->ifinoctets = 0; \ + (netif)->ifinucastpkts = 0; \ + (netif)->ifinnucastpkts = 0; \ + (netif)->ifindiscards = 0; \ + (netif)->ifoutoctets = 0; \ + (netif)->ifoutucastpkts = 0; \ + (netif)->ifoutnucastpkts = 0; \ + (netif)->ifoutdiscards = 0 #else /* LWIP_SNMP */ #define NETIF_INIT_SNMP(netif, type, speed) #endif /* LWIP_SNMP */ @@ -202,17 +250,14 @@ extern struct netif *netif_list; /** The default network interface. */ extern struct netif *netif_default; -#define netif_init() /* Compatibility define, not init needed. */ +void netif_init(void); -struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask, - struct ip_addr *gw, - void *state, - err_t (* init)(struct netif *netif), - err_t (* input)(struct pbuf *p, struct netif *netif)); +struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input); void -netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask, - struct ip_addr *gw); +netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask, + ip_addr_t *gw); void netif_remove(struct netif * netif); /* Returns a network interface given its name. The name is of the form @@ -223,41 +268,48 @@ struct netif *netif_find(char *name); void netif_set_default(struct netif *netif); -void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr); -void netif_set_netmask(struct netif *netif, struct ip_addr *netmask); -void netif_set_gw(struct netif *netif, struct ip_addr *gw); +void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr); +void netif_set_netmask(struct netif *netif, ip_addr_t *netmask); +void netif_set_gw(struct netif *netif, ip_addr_t *gw); void netif_set_up(struct netif *netif); void netif_set_down(struct netif *netif); -u8_t netif_is_up(struct netif *netif); +/** Ask if an interface is up */ +#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0) #if LWIP_NETIF_STATUS_CALLBACK -/* - * Set callback to be called when interface is brought up/down - */ -void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif)); +void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback); #endif /* LWIP_NETIF_STATUS_CALLBACK */ -#if LWIP_NETIF_LINK_CALLBACK void netif_set_link_up(struct netif *netif); void netif_set_link_down(struct netif *netif); -u8_t netif_is_link_up(struct netif *netif); -/* - * Set callback to be called when link is brought up/down - */ -void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif)); +/** Ask if a link is up */ +#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0) + +#if LWIP_NETIF_LINK_CALLBACK +void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback); #endif /* LWIP_NETIF_LINK_CALLBACK */ -#ifdef __cplusplus -} -#endif +#if LWIP_NETIF_HOSTNAME +#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0) +#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL) +#endif /* LWIP_NETIF_HOSTNAME */ + +#if LWIP_IGMP +#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0) +#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL) +#endif /* LWIP_IGMP */ #if ENABLE_LOOPBACK -err_t netif_loop_output(struct netif *netif, struct pbuf *p, struct ip_addr *dest_ip); +err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip); void netif_poll(struct netif *netif); #if !LWIP_NETIF_LOOPBACK_MULTITHREADING void netif_poll_all(void); #endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ #endif /* ENABLE_LOOPBACK */ +#ifdef __cplusplus +} +#endif + #endif /* __LWIP_NETIF_H__ */ diff --git a/core/lwip/src/include/lwip/netifapi.h b/core/lwip/src/include/lwip/netifapi.h index 4145dd74..33318efa 100644 --- a/core/lwip/src/include/lwip/netifapi.h +++ b/core/lwip/src/include/lwip/netifapi.h @@ -41,6 +41,9 @@ extern "C" { #endif +typedef void (*netifapi_void_fn)(struct netif *netif); +typedef err_t (*netifapi_errt_fn)(struct netif *netif); + struct netifapi_msg_msg { #if !LWIP_TCPIP_CORE_LOCKING sys_sem_t sem; @@ -49,16 +52,16 @@ struct netifapi_msg_msg { struct netif *netif; union { struct { - struct ip_addr *ipaddr; - struct ip_addr *netmask; - struct ip_addr *gw; + ip_addr_t *ipaddr; + ip_addr_t *netmask; + ip_addr_t *gw; void *state; - err_t (* init) (struct netif *netif); - err_t (* input)(struct pbuf *p, struct netif *netif); + netif_init_fn init; + netif_input_fn input; } add; struct { - void (* voidfunc)(struct netif *netif); - err_t (* errtfunc)(struct netif *netif); + netifapi_void_fn voidfunc; + netifapi_errt_fn errtfunc; } common; } msg; }; @@ -71,21 +74,21 @@ struct netifapi_msg { /* API for application */ err_t netifapi_netif_add ( struct netif *netif, - struct ip_addr *ipaddr, - struct ip_addr *netmask, - struct ip_addr *gw, + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw, void *state, - err_t (* init)(struct netif *netif), - err_t (* input)(struct pbuf *p, struct netif *netif) ); + netif_init_fn init, + netif_input_fn input); err_t netifapi_netif_set_addr ( struct netif *netif, - struct ip_addr *ipaddr, - struct ip_addr *netmask, - struct ip_addr *gw ); + ip_addr_t *ipaddr, + ip_addr_t *netmask, + ip_addr_t *gw ); err_t netifapi_netif_common ( struct netif *netif, - void (* voidfunc)(struct netif *netif), - err_t (* errtfunc)(struct netif *netif) ); + netifapi_void_fn voidfunc, + netifapi_errt_fn errtfunc); #define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL) #define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL) diff --git a/core/lwip/src/include/lwip/opt.h b/core/lwip/src/include/lwip/opt.h index eb99a778..a1b87658 100644 --- a/core/lwip/src/include/lwip/opt.h +++ b/core/lwip/src/include/lwip/opt.h @@ -69,6 +69,14 @@ #endif /** + * NO_SYS_NO_TIMERS==1: Drop support for sys_timeout when NO_SYS==1 + * Mainly for compatibility to old versions. + */ +#ifndef NO_SYS_NO_TIMERS +#define NO_SYS_NO_TIMERS 0 +#endif + +/** * MEMCPY: override this if you have a faster implementation at hand than the * one included in your C library */ @@ -125,6 +133,15 @@ #endif /** + * MEMP_SEPARATE_POOLS: if defined to 1, each pool is placed in its own array. + * This can be used to individually change the location of each pool. + * Default is one big array for all pools + */ +#ifndef MEMP_SEPARATE_POOLS +#define MEMP_SEPARATE_POOLS 0 +#endif + +/** * MEMP_OVERFLOW_CHECK: memp overflow protection reserves a configurable * amount of bytes before and after each memp element in every pool and fills * it with a prominent default value. @@ -251,7 +268,7 @@ #endif /** - * MEMP_NUM_REASSDATA: the number of simultaneously IP packets queued for + * MEMP_NUM_REASSDATA: the number of IP packets simultaneously queued for * reassembly (whole packets, not fragments!) */ #ifndef MEMP_NUM_REASSDATA @@ -259,6 +276,17 @@ #endif /** + * MEMP_NUM_FRAG_PBUF: the number of IP fragments simultaneously sent + * (fragments, not whole packets!). + * This is only used with IP_FRAG_USES_STATIC_BUF==0 and + * LWIP_NETIF_TX_SINGLE_PBUF==0 and only has to be > 1 with DMA-enabled MACs + * where the packet is not yet sent when netif->output returns. + */ +#ifndef MEMP_NUM_FRAG_PBUF +#define MEMP_NUM_FRAG_PBUF 15 +#endif + +/** * MEMP_NUM_ARP_QUEUE: the number of simulateously queued outgoing * packets (pbufs) that are waiting for an ARP request (to resolve * their destination address) to finish. @@ -321,6 +349,63 @@ #endif /** + * MEMP_NUM_SNMP_NODE: the number of leafs in the SNMP tree. + */ +#ifndef MEMP_NUM_SNMP_NODE +#define MEMP_NUM_SNMP_NODE 50 +#endif + +/** + * MEMP_NUM_SNMP_ROOTNODE: the number of branches in the SNMP tree. + * Every branch has one leaf (MEMP_NUM_SNMP_NODE) at least! + */ +#ifndef MEMP_NUM_SNMP_ROOTNODE +#define MEMP_NUM_SNMP_ROOTNODE 30 +#endif + +/** + * MEMP_NUM_SNMP_VARBIND: the number of concurrent requests (does not have to + * be changed normally) - 2 of these are used per request (1 for input, + * 1 for output) + */ +#ifndef MEMP_NUM_SNMP_VARBIND +#define MEMP_NUM_SNMP_VARBIND 2 +#endif + +/** + * MEMP_NUM_SNMP_VALUE: the number of OID or values concurrently used + * (does not have to be changed normally) - 3 of these are used per request + * (1 for the value read and 2 for OIDs - input and output) + */ +#ifndef MEMP_NUM_SNMP_VALUE +#define MEMP_NUM_SNMP_VALUE 3 +#endif + +/** + * MEMP_NUM_NETDB: the number of concurrently running lwip_addrinfo() calls + * (before freeing the corresponding memory using lwip_freeaddrinfo()). + */ +#ifndef MEMP_NUM_NETDB +#define MEMP_NUM_NETDB 1 +#endif + +/** + * MEMP_NUM_LOCALHOSTLIST: the number of host entries in the local host list + * if DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1. + */ +#ifndef MEMP_NUM_LOCALHOSTLIST +#define MEMP_NUM_LOCALHOSTLIST 1 +#endif + +/** + * MEMP_NUM_PPPOE_INTERFACES: the number of concurrently active PPPoE + * interfaces (only used with PPPOE_SUPPORT==1) + */ +#ifndef MEMP_NUM_PPPOE_INTERFACES +#define MEMP_NUM_PPPOE_INTERFACES 1 +#endif + +/** * PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */ #ifndef PBUF_POOL_SIZE @@ -347,11 +432,14 @@ #endif /** - * ARP_QUEUEING==1: Outgoing packets are queued during hardware address - * resolution. + * ARP_QUEUEING==1: Multiple outgoing packets are queued during hardware address + * resolution. By default, only the most recent packet is queued per IP address. + * This is sufficient for most protocols and mainly reduces TCP connection + * startup time. Set this to 1 if you know your application sends more than one + * packet in a row to an IP address that is not in the ARP cache. */ #ifndef ARP_QUEUEING -#define ARP_QUEUEING 1 +#define ARP_QUEUEING 0 #endif /** @@ -361,9 +449,11 @@ * correct addresses, or as a limited approach to attempt to handle * spoofing. If disabled, lwIP will need to make a new ARP request if * the peer is not already in the ARP table, adding a little latency. + * The peer *is* in the ARP table if it requested our address before. + * Also notice that this slows down input processing of every IP packet! */ #ifndef ETHARP_TRUST_IP_MAC -#define ETHARP_TRUST_IP_MAC 1 +#define ETHARP_TRUST_IP_MAC 0 #endif /** @@ -376,6 +466,30 @@ #define ETHARP_SUPPORT_VLAN 0 #endif +/** LWIP_ETHERNET==1: enable ethernet support for PPPoE even though ARP + * might be disabled + */ +#ifndef LWIP_ETHERNET +#define LWIP_ETHERNET (LWIP_ARP || PPPOE_SUPPORT) +#endif + +/** ETH_PAD_SIZE: number of bytes added before the ethernet header to ensure + * alignment of payload after that header. Since the header is 14 bytes long, + * without this padding e.g. addresses in the IP header will not be aligned + * on a 32-bit boundary, so setting this to 2 can speed up 32-bit-platforms. + */ +#ifndef ETH_PAD_SIZE +#define ETH_PAD_SIZE 0 +#endif + +/** ETHARP_SUPPORT_STATIC_ENTRIES==1: enable code to support static ARP table + * entries (using etharp_add_static_entry/etharp_remove_static_entry). + */ +#ifndef ETHARP_SUPPORT_STATIC_ENTRIES +#define ETHARP_SUPPORT_STATIC_ENTRIES 0 +#endif + + /* -------------------------------- ---------- IP options ---------- @@ -439,10 +553,12 @@ /** * IP_FRAG_USES_STATIC_BUF==1: Use a static MTU-sized buffer for IP * fragmentation. Otherwise pbufs are allocated and reference the original - * packet data to be fragmented. + * packet data to be fragmented (or with LWIP_NETIF_TX_SINGLE_PBUF==1, + * new PBUF_RAM pbufs are used for fragments). + * ATTENTION: IP_FRAG_USES_STATIC_BUF==1 may not be used for DMA-enabled MACs! */ #ifndef IP_FRAG_USES_STATIC_BUF -#define IP_FRAG_USES_STATIC_BUF 1 +#define IP_FRAG_USES_STATIC_BUF 0 #endif /** @@ -595,7 +711,8 @@ /** * SNMP_CONCURRENT_REQUESTS: Number of concurrent requests the module will - * allow. At least one request buffer is required. + * allow. At least one request buffer is required. + * Does not have to be changed unless external MIBs answer request asynchronously */ #ifndef SNMP_CONCURRENT_REQUESTS #define SNMP_CONCURRENT_REQUESTS 1 @@ -611,6 +728,8 @@ /** * SNMP_PRIVATE_MIB: + * When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ #ifndef SNMP_PRIVATE_MIB #define SNMP_PRIVATE_MIB 0 @@ -625,6 +744,31 @@ #define SNMP_SAFE_REQUESTS 1 #endif +/** + * The maximum length of strings used. This affects the size of + * MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_OCTET_STRING_LEN +#define SNMP_MAX_OCTET_STRING_LEN 127 +#endif + +/** + * The maximum depth of the SNMP tree. + * With private MIBs enabled, this depends on your MIB! + * This affects the size of MEMP_SNMP_VALUE elements. + */ +#ifndef SNMP_MAX_TREE_DEPTH +#define SNMP_MAX_TREE_DEPTH 15 +#endif + +/** + * The size of the MEMP_SNMP_VALUE elements, normally calculated from + * SNMP_MAX_OCTET_STRING_LEN and SNMP_MAX_TREE_DEPTH. + */ +#ifndef SNMP_MAX_VALUE_SIZE +#define SNMP_MAX_VALUE_SIZE LWIP_MAX((SNMP_MAX_OCTET_STRING_LEN)+1, sizeof(s32_t)*(SNMP_MAX_TREE_DEPTH)) +#endif + /* ---------------------------------- ---------- IGMP options ---------- @@ -670,13 +814,6 @@ #define DNS_DOES_NAME_CHECK 1 #endif -/** DNS use a local buffer if DNS_USES_STATIC_BUF=0, a static one if - DNS_USES_STATIC_BUF=1, or a dynamic one if DNS_USES_STATIC_BUF=2. - The buffer will be of size DNS_MSG_SIZE */ -#ifndef DNS_USES_STATIC_BUF -#define DNS_USES_STATIC_BUF 1 -#endif - /** DNS message max. size. Default value is RFC compliant. */ #ifndef DNS_MSG_SIZE #define DNS_MSG_SIZE 512 @@ -820,19 +957,28 @@ * as much as (2 * TCP_SND_BUF/TCP_MSS) for things to work. */ #ifndef TCP_SND_QUEUELEN -#define TCP_SND_QUEUELEN (4 * (TCP_SND_BUF)/(TCP_MSS)) +#define TCP_SND_QUEUELEN ((4 * (TCP_SND_BUF) + (TCP_MSS - 1))/(TCP_MSS)) #endif /** - * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than or equal - * to TCP_SND_BUF. It is the amount of space which must be available in the - * TCP snd_buf for select to return writable. + * TCP_SNDLOWAT: TCP writable space (bytes). This must be less than + * TCP_SND_BUF. It is the amount of space which must be available in the + * TCP snd_buf for select to return writable (combined with TCP_SNDQUEUELOWAT). */ #ifndef TCP_SNDLOWAT #define TCP_SNDLOWAT ((TCP_SND_BUF)/2) #endif /** + * TCP_SNDQUEUELOWAT: TCP writable bufs (pbuf count). This must be grater + * than TCP_SND_QUEUELEN. If the number of pbufs queued on a pcb drops below + * this number, select returns writable (combined with TCP_SNDLOWAT). + */ +#ifndef TCP_SNDQUEUELOWAT +#define TCP_SNDQUEUELOWAT ((TCP_SND_QUEUELEN)/2) +#endif + +/** * TCP_LISTEN_BACKLOG: Enable the backlog option for tcp listen pcb. */ #ifndef TCP_LISTEN_BACKLOG @@ -849,6 +995,24 @@ #endif /** + * TCP_OVERSIZE: The maximum number of bytes that tcp_write may + * allocate ahead of time in an attempt to create shorter pbuf chains + * for transmission. The meaningful range is 0 to TCP_MSS. Some + * suggested values are: + * + * 0: Disable oversized allocation. Each tcp_write() allocates a new + pbuf (old behaviour). + * 1: Allocate size-aligned pbufs with minimal excess. Use this if your + * scatter-gather DMA requires aligned fragments. + * 128: Limit the pbuf/memory overhead to 20%. + * TCP_MSS: Try to create unfragmented TCP packets. + * TCP_MSS/4: Try to create 4 fragments or less per TCP packet. + */ +#ifndef TCP_OVERSIZE +#define TCP_OVERSIZE TCP_MSS +#endif + +/** * LWIP_TCP_TIMESTAMPS==1: support the TCP timestamp option. */ #ifndef LWIP_TCP_TIMESTAMPS @@ -890,7 +1054,7 @@ * Ethernet. */ #ifndef PBUF_LINK_HLEN -#define PBUF_LINK_HLEN 14 +#define PBUF_LINK_HLEN (14 + ETH_PAD_SIZE) #endif /** @@ -1084,14 +1248,14 @@ #endif /** - * PPP_THREAD_NAME: The name assigned to the pppMain thread. + * PPP_THREAD_NAME: The name assigned to the pppInputThread. */ #ifndef PPP_THREAD_NAME -#define PPP_THREAD_NAME "pppMain" +#define PPP_THREAD_NAME "pppInputThread" #endif /** - * PPP_THREAD_STACKSIZE: The stack size used by the pppMain thread. + * PPP_THREAD_STACKSIZE: The stack size used by the pppInputThread. * The stack size value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ @@ -1100,7 +1264,7 @@ #endif /** - * PPP_THREAD_PRIO: The priority assigned to the pppMain thread. + * PPP_THREAD_PRIO: The priority assigned to the pppInputThread. * The priority value itself is platform-dependent, but is passed to * sys_thread_new() when the thread is created. */ @@ -1183,12 +1347,27 @@ #endif /** + * LWIP_TCPIP_CORE_LOCKING_INPUT: (EXPERIMENTAL!) + * Don't use it if you're not an active lwIP project member + */ +#ifndef LWIP_TCPIP_CORE_LOCKING_INPUT +#define LWIP_TCPIP_CORE_LOCKING_INPUT 0 +#endif + +/** * LWIP_NETCONN==1: Enable Netconn API (require to use api_lib.c) */ #ifndef LWIP_NETCONN #define LWIP_NETCONN 1 #endif +/** LWIP_TCPIP_TIMEOUT==1: Enable tcpip_timeout/tcpip_untimeout tod create + * timers running in tcpip_thread from another thread. + */ +#ifndef LWIP_TCPIP_TIMEOUT +#define LWIP_TCPIP_TIMEOUT 1 +#endif + /* ------------------------------------ ---------- Socket options ---------- @@ -1249,12 +1428,21 @@ #endif /** - * SO_REUSE==1: Enable SO_REUSEADDR and SO_REUSEPORT options. DO NOT USE! + * SO_REUSE==1: Enable SO_REUSEADDR option. */ #ifndef SO_REUSE #define SO_REUSE 0 #endif +/** + * SO_REUSE_RXTOALL==1: Pass a copy of incoming broadcast/multicast packets + * to all local matches if SO_REUSEADDR is turned on. + * WARNING: Adds a memcpy for every packet if passing to more than one pcb! + */ +#ifndef SO_REUSE_RXTOALL +#define SO_REUSE_RXTOALL 0 +#endif + /* ---------------------------------------- ---------- Statistics options ---------- @@ -1583,6 +1771,14 @@ #define CHECKSUM_CHECK_TCP 1 #endif +/** + * LWIP_CHECKSUM_ON_COPY==1: Calculate checksum when copying data from + * application buffers to pbufs. + */ +#ifndef LWIP_CHECKSUM_ON_COPY +#define LWIP_CHECKSUM_ON_COPY 0 +#endif + /* --------------------------------------- ---------- Debugging options ---------- @@ -1711,6 +1907,13 @@ #endif /** + * TIMERS_DEBUG: Enable debugging in timers.c. + */ +#ifndef TIMERS_DEBUG +#define TIMERS_DEBUG LWIP_DBG_OFF +#endif + +/** * TCP_DEBUG: Enable debugging for TCP. */ #ifndef TCP_DEBUG diff --git a/core/lwip/src/include/lwip/pbuf.h b/core/lwip/src/include/lwip/pbuf.h index 8380f65d..3b1d608b 100644 --- a/core/lwip/src/include/lwip/pbuf.h +++ b/core/lwip/src/include/lwip/pbuf.h @@ -40,6 +40,10 @@ extern "C" { #endif +/** Currently, the pbuf_custom code is only needed for one specific configuration + * of IP_FRAG */ +#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) + #define PBUF_TRANSPORT_HLEN 20 #define PBUF_IP_HLEN 20 @@ -59,7 +63,12 @@ typedef enum { /** indicates this packet's data should be immediately passed to the application */ -#define PBUF_FLAG_PUSH 0x01U +#define PBUF_FLAG_PUSH 0x01U +/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a + a pbuf differently */ +#define PBUF_FLAG_IS_CUSTOM 0x02U +/** indicates this pbuf is UDP multicast to be looped back */ +#define PBUF_FLAG_MCASTLOOP 0x04U struct pbuf { /** next pbuf in singly linked pbuf chain */ @@ -67,7 +76,7 @@ struct pbuf { /** pointer to the actual data in the buffer */ void *payload; - + /** * total length of this buffer and all next buffers in chain * belonging to the same packet. @@ -76,9 +85,9 @@ struct pbuf { * p->tot_len == p->len + (p->next? p->next->tot_len: 0) */ u16_t tot_len; - + /** length of this buffer */ - u16_t len; + u16_t len; /** pbuf_type as u8_t instead of enum to save space */ u8_t /*pbuf_type*/ type; @@ -92,17 +101,33 @@ struct pbuf { * the stack itself, or pbuf->next pointers from a chain. */ u16_t ref; - }; +#if LWIP_SUPPORT_CUSTOM_PBUF +/** Prototype for a function to free a custom pbuf */ +typedef void (*pbuf_free_custom_fn)(struct pbuf *p); + +/** A custom pbuf: like a pbuf, but following a function pointer to free it. */ +struct pbuf_custom { + /** The actual pbuf */ + struct pbuf pbuf; + /** This function is called when pbuf_free deallocates this pbuf(_custom) */ + pbuf_free_custom_fn custom_free_function; +}; +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ + /* Initializes the pbuf module. This call is empty for now, but may not be in future. */ #define pbuf_init() -struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type); +struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type); +#if LWIP_SUPPORT_CUSTOM_PBUF +struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type, + struct pbuf_custom *p, void *payload_mem, + u16_t payload_mem_len); +#endif /* LWIP_SUPPORT_CUSTOM_PBUF */ void pbuf_realloc(struct pbuf *p, u16_t size); u8_t pbuf_header(struct pbuf *p, s16_t header_size); void pbuf_ref(struct pbuf *p); -void pbuf_ref_chain(struct pbuf *p); u8_t pbuf_free(struct pbuf *p); u8_t pbuf_clen(struct pbuf *p); void pbuf_cat(struct pbuf *head, struct pbuf *tail); @@ -112,6 +137,15 @@ err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from); u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset); err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len); struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer); +#if LWIP_CHECKSUM_ON_COPY +err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr, + u16_t len, u16_t *chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ + +u8_t pbuf_get_at(struct pbuf* p, u16_t offset); +u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n); +u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset); +u16_t pbuf_strstr(struct pbuf* p, const char* substr); #ifdef __cplusplus } diff --git a/core/lwip/src/include/lwip/raw.h b/core/lwip/src/include/lwip/raw.h index 20b0a11b..17d0a1c5 100644 --- a/core/lwip/src/include/lwip/raw.h +++ b/core/lwip/src/include/lwip/raw.h @@ -37,7 +37,7 @@ #if LWIP_RAW /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" -#include "lwip/inet.h" +#include "lwip/def.h" #include "lwip/ip.h" #include "lwip/ip_addr.h" @@ -45,26 +45,31 @@ extern "C" { #endif +struct raw_pcb; + +/** Function prototype for raw pcb receive callback functions. + * @param arg user supplied argument (raw_pcb.recv_arg) + * @param pcb the raw_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @return 1 if the packet was 'eaten' (aka. deleted), + * 0 if the packet lives on + * If returning 1, the callback is responsible for freeing the pbuf + * if it's not used any more. + */ +typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p, + ip_addr_t *addr); + struct raw_pcb { -/* Common members of all PCB types */ + /* Common members of all PCB types */ IP_PCB; struct raw_pcb *next; u8_t protocol; - /* receive callback function - * @param arg user supplied argument (raw_pcb.recv_arg) - * @param pcb the raw_pcb which received data - * @param p the packet buffer that was received - * @param addr the remote IP address from which the packet was received - * @return 1 if the packet was 'eaten' (aka. deleted), - * 0 if the packet lives on - * If returning 1, the callback is responsible for freeing the pbuf - * if it's not used any more. - */ - u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p, - struct ip_addr *addr); + /** receive callback function */ + raw_recv_fn recv; /* user-supplied argument for the recv callback */ void *recv_arg; }; @@ -73,15 +78,11 @@ struct raw_pcb { RAW code. */ struct raw_pcb * raw_new (u8_t proto); void raw_remove (struct raw_pcb *pcb); -err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr); -err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr); - -void raw_recv (struct raw_pcb *pcb, - u8_t (* recv)(void *arg, struct raw_pcb *pcb, - struct pbuf *p, - struct ip_addr *addr), - void *recv_arg); -err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr); +err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr); +err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr); + +void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg); +err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr); err_t raw_send (struct raw_pcb *pcb, struct pbuf *p); /* The following functions are the lower layer interface to RAW. */ diff --git a/core/lwip/src/include/lwip/snmp.h b/core/lwip/src/include/lwip/snmp.h index dd03d5d7..2ed043dd 100644 --- a/core/lwip/src/include/lwip/snmp.h +++ b/core/lwip/src/include/lwip/snmp.h @@ -34,13 +34,16 @@ #define __LWIP_SNMP_H__ #include "lwip/opt.h" -#include "lwip/netif.h" -#include "lwip/udp.h" #ifdef __cplusplus extern "C" { #endif +#include "lwip/ip_addr.h" + +struct udp_pcb; +struct netif; + /** * @see RFC1213, "MIB-II, 6. Definitions" */ @@ -118,8 +121,8 @@ void snmp_inc_iflist(void); void snmp_dec_iflist(void); /* ARP (for atTable and ipNetToMediaTable) */ -void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip); -void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip); +void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip); +void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip); /* IP */ void snmp_inc_ipinreceives(void); diff --git a/core/lwip/src/include/lwip/snmp_asn1.h b/core/lwip/src/include/lwip/snmp_asn1.h index 8a602881..605fa3f1 100644 --- a/core/lwip/src/include/lwip/snmp_asn1.h +++ b/core/lwip/src/include/lwip/snmp_asn1.h @@ -46,12 +46,12 @@ extern "C" { #endif -#define SNMP_ASN1_UNIV (!0x80 | !0x40) -#define SNMP_ASN1_APPLIC (!0x80 | 0x40) -#define SNMP_ASN1_CONTXT ( 0x80 | !0x40) +#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */ +#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */ +#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */ -#define SNMP_ASN1_CONSTR (0x20) -#define SNMP_ASN1_PRIMIT (!0x20) +#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */ +#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */ /* universal tags */ #define SNMP_ASN1_INTEG 2 @@ -87,10 +87,10 @@ void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed); void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed); err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type); err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length); -err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value); -err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value); +err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value); +err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value); err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident); -err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw); +err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw); #ifdef __cplusplus } diff --git a/core/lwip/src/include/lwip/snmp_msg.h b/core/lwip/src/include/lwip/snmp_msg.h index b2f69c4b..1183e3a9 100644 --- a/core/lwip/src/include/lwip/snmp_msg.h +++ b/core/lwip/src/include/lwip/snmp_msg.h @@ -38,10 +38,14 @@ #include "lwip/opt.h" #include "lwip/snmp.h" #include "lwip/snmp_structs.h" +#include "lwip/ip_addr.h" +#include "lwip/err.h" #if LWIP_SNMP #if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ #include "private_mib.h" #endif @@ -219,7 +223,7 @@ struct snmp_msg_pstat /* lwIP local port (161) binding */ struct udp_pcb *pcb; /* source IP address */ - struct ip_addr sip; + ip_addr_t sip; /* source UDP port */ u16_t sp; /* request type */ @@ -258,7 +262,7 @@ struct snmp_msg_trap /* lwIP local port (161) binding */ struct udp_pcb *pcb; /* destination IP address in network order */ - struct ip_addr dip; + ip_addr_t dip; /* source enterprise ID (sysObjectID) */ struct snmp_obj_id *enterprise; @@ -286,7 +290,7 @@ extern struct snmp_msg_trap trap_msg; /** Agent setup, start listening to port 161. */ void snmp_init(void); void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable); -void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst); +void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst); /** Varbind-list functions. */ struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len); diff --git a/core/lwip/src/include/lwip/snmp_structs.h b/core/lwip/src/include/lwip/snmp_structs.h index 9f3f8a94..0d3b46a9 100644 --- a/core/lwip/src/include/lwip/snmp_structs.h +++ b/core/lwip/src/include/lwip/snmp_structs.h @@ -44,6 +44,8 @@ #include "lwip/snmp.h" #if SNMP_PRIVATE_MIB +/* When using a private MIB, you have to create a file 'private_mib.h' that contains + * a 'struct mib_array_node mib_private' which contains your MIB. */ #include "private_mib.h" #endif @@ -56,11 +58,15 @@ extern "C" { #define MIB_OBJECT_SCALAR 1 #define MIB_OBJECT_TAB 2 +/* MIB access types */ +#define MIB_ACCESS_READ 1 +#define MIB_ACCESS_WRITE 2 + /* MIB object access */ -#define MIB_OBJECT_READ_ONLY 0 -#define MIB_OBJECT_READ_WRITE 1 -#define MIB_OBJECT_WRITE_ONLY 2 -#define MIB_OBJECT_NOT_ACCESSIBLE 3 +#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ +#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE) +#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE +#define MIB_OBJECT_NOT_ACCESSIBLE 0 /** object definition returned by (get_object_def)() */ struct obj_def @@ -109,9 +115,9 @@ struct mib_node /** sets object value, only to be called when set_test() */ void (*set_value)(struct obj_def *od, u16_t len, void *value); /** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */ - const u8_t node_type; + u8_t node_type; /* array or max list length */ - const u16_t maxlength; + u16_t maxlength; }; /** derived node for scalars .0 index */ @@ -122,15 +128,15 @@ typedef struct mib_node mib_scalar_node; struct mib_array_node { /* inherited "base class" members */ - void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); - void (* const get_value)(struct obj_def *od, u16_t len, void *value); + void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od); + void (*get_value)(struct obj_def *od, u16_t len, void *value); u8_t (*set_test)(struct obj_def *od, u16_t len, void *value); void (*set_value)(struct obj_def *od, u16_t len, void *value); - const u8_t node_type; - const u16_t maxlength; + u8_t node_type; + u16_t maxlength; - /* aditional struct members */ + /* additional struct members */ const s32_t *objid; struct mib_node* const *nptr; }; @@ -174,7 +180,7 @@ struct mib_list_rootnode u8_t node_type; u16_t maxlength; - /* aditional struct members */ + /* additional struct members */ struct mib_list_node *head; struct mib_list_node *tail; /* counts list nodes in list */ @@ -194,8 +200,8 @@ struct mib_external_node u8_t node_type; u16_t maxlength; - /* aditional struct members */ - /** points to an extenal (in memory) record of some sort of addressing + /* additional struct members */ + /** points to an external (in memory) record of some sort of addressing information, passed to and interpreted by the funtions below */ void* addr_inf; /** tree levels under this node */ @@ -234,8 +240,8 @@ void noleafs_get_value(struct obj_def *od, u16_t len, void *value); u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value); void noleafs_set_value(struct obj_def *od, u16_t len, void *value); -void snmp_oidtoip(s32_t *ident, struct ip_addr *ip); -void snmp_iptooid(struct ip_addr *ip, s32_t *ident); +void snmp_oidtoip(s32_t *ident, ip_addr_t *ip); +void snmp_iptooid(ip_addr_t *ip, s32_t *ident); void snmp_ifindextonetif(s32_t ifindex, struct netif **netif); void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx); diff --git a/core/lwip/src/include/lwip/sockets.h b/core/lwip/src/include/lwip/sockets.h index 7b52e151..3c8fed24 100644 --- a/core/lwip/src/include/lwip/sockets.h +++ b/core/lwip/src/include/lwip/sockets.h @@ -72,11 +72,11 @@ struct sockaddr { #define SOCK_RAW 3 /* - * Option flags per-socket. These must match the SOF_ flags in ip.h! + * Option flags per-socket. These must match the SOF_ flags in ip.h (checked in init.c) */ #define SO_DEBUG 0x0001 /* Unimplemented: turn on debugging info recording */ #define SO_ACCEPTCONN 0x0002 /* socket has had listen() */ -#define SO_REUSEADDR 0x0004 /* Unimplemented: allow local address reuse */ +#define SO_REUSEADDR 0x0004 /* Allow local address reuse */ #define SO_KEEPALIVE 0x0008 /* keep connections alive */ #define SO_DONTROUTE 0x0010 /* Unimplemented: just use interface addresses */ #define SO_BROADCAST 0x0020 /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */ @@ -262,9 +262,27 @@ typedef struct ip_mreq { #define SIOCATMARK _IOR('s', 7, unsigned long) /* at oob mark? */ #endif -/* Socket flags: */ +/* commands for fnctl */ +#ifndef F_GETFL +#define F_GETFL 3 +#endif +#ifndef F_SETFL +#define F_SETFL 4 +#endif + +/* File status flags and file access modes for fnctl, + these are bits in an int. */ #ifndef O_NONBLOCK -#define O_NONBLOCK 04000U +#define O_NONBLOCK 1 /* nonblocking I/O */ +#endif +#ifndef O_NDELAY +#define O_NDELAY 1 /* same as O_NONBLOCK, for compatibility */ +#endif + +#ifndef SHUT_RD + #define SHUT_RD 0 + #define SHUT_WR 1 + #define SHUT_RDWR 2 #endif /* FD_SET used for lwip_select */ @@ -320,6 +338,7 @@ int lwip_write(int s, const void *dataptr, size_t size); int lwip_select(int maxfdp1, fd_set *readset, fd_set *writeset, fd_set *exceptset, struct timeval *timeout); int lwip_ioctl(int s, long cmd, void *argp); +int lwip_fcntl(int s, int cmd, int val); #if LWIP_COMPAT_SOCKETS #define accept(a,b,c) lwip_accept(a,b,c) diff --git a/core/lwip/src/include/lwip/stats.h b/core/lwip/src/include/lwip/stats.h index aa179f5c..015b7ce7 100644 --- a/core/lwip/src/include/lwip/stats.h +++ b/core/lwip/src/include/lwip/stats.h @@ -71,18 +71,26 @@ struct stats_proto { }; struct stats_igmp { - STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER xmit; /* Transmitted packets. */ + STAT_COUNTER recv; /* Received packets. */ + STAT_COUNTER drop; /* Dropped packets. */ STAT_COUNTER chkerr; /* Checksum error. */ - STAT_COUNTER v1_rxed; /* */ - STAT_COUNTER join_sent; /* */ - STAT_COUNTER leave_sent; /* */ - STAT_COUNTER unicast_query; /* */ - STAT_COUNTER report_sent; /* */ - STAT_COUNTER report_rxed; /* */ - STAT_COUNTER group_query_rxed; /* */ + STAT_COUNTER lenerr; /* Invalid length error. */ + STAT_COUNTER memerr; /* Out of memory error. */ + STAT_COUNTER proterr; /* Protocol error. */ + STAT_COUNTER rx_v1; /* Received v1 frames. */ + STAT_COUNTER rx_group; /* Received group-specific queries. */ + STAT_COUNTER rx_general; /* Received general queries. */ + STAT_COUNTER rx_report; /* Received reports. */ + STAT_COUNTER tx_join; /* Sent joins. */ + STAT_COUNTER tx_leave; /* Sent leaves. */ + STAT_COUNTER tx_report; /* Sent reports. */ }; struct stats_mem { +#ifdef LWIP_DEBUG + const char *name; +#endif /* LWIP_DEBUG */ mem_size_t avail; mem_size_t used; mem_size_t max; @@ -98,6 +106,7 @@ struct stats_syselem { struct stats_sys { struct stats_syselem sem; + struct stats_syselem mutex; struct stats_syselem mbox; }; @@ -139,14 +148,20 @@ struct stats_ { extern struct stats_ lwip_stats; -#define stats_init() /* Compatibility define, not init needed. */ +void stats_init(void); #define STATS_INC(x) ++lwip_stats.x #define STATS_DEC(x) --lwip_stats.x -#else +#define STATS_INC_USED(x, y) do { lwip_stats.x.used += y; \ + if (lwip_stats.x.max < lwip_stats.x.used) { \ + lwip_stats.x.max = lwip_stats.x.used; \ + } \ + } while(0) +#else /* LWIP_STATS */ #define stats_init() #define STATS_INC(x) #define STATS_DEC(x) +#define STATS_INC_USED(x) #endif /* LWIP_STATS */ #if TCP_STATS @@ -216,11 +231,7 @@ extern struct stats_ lwip_stats; #if MEM_STATS #define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y #define MEM_STATS_INC(x) STATS_INC(mem.x) -#define MEM_STATS_INC_USED(x, y) do { lwip_stats.mem.used += y; \ - if (lwip_stats.mem.max < lwip_stats.mem.used) { \ - lwip_stats.mem.max = lwip_stats.mem.used; \ - } \ - } while(0) +#define MEM_STATS_INC_USED(x, y) STATS_INC_USED(mem, y) #define MEM_STATS_DEC_USED(x, y) lwip_stats.mem.x -= y #define MEM_STATS_DISPLAY() stats_display_mem(&lwip_stats.mem, "HEAP") #else @@ -235,11 +246,7 @@ extern struct stats_ lwip_stats; #define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y #define MEMP_STATS_INC(x, i) STATS_INC(memp[i].x) #define MEMP_STATS_DEC(x, i) STATS_DEC(memp[i].x) -#define MEMP_STATS_INC_USED(x, i) do { ++lwip_stats.memp[i].used; \ - if (lwip_stats.memp[i].max < lwip_stats.memp[i].used) { \ - lwip_stats.memp[i].max = lwip_stats.memp[i].used; \ - } \ - } while(0) +#define MEMP_STATS_INC_USED(x, i) STATS_INC_USED(memp[i], 1) #define MEMP_STATS_DISPLAY(i) stats_display_memp(&lwip_stats.memp[i], i) #else #define MEMP_STATS_AVAIL(x, i, y) @@ -252,10 +259,12 @@ extern struct stats_ lwip_stats; #if SYS_STATS #define SYS_STATS_INC(x) STATS_INC(sys.x) #define SYS_STATS_DEC(x) STATS_DEC(sys.x) +#define SYS_STATS_INC_USED(x) STATS_INC_USED(sys.x, 1) #define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys) #else #define SYS_STATS_INC(x) #define SYS_STATS_DEC(x) +#define SYS_STATS_INC_USED(x) #define SYS_STATS_DISPLAY() #endif @@ -267,7 +276,7 @@ void stats_display_igmp(struct stats_igmp *igmp); void stats_display_mem(struct stats_mem *mem, char *name); void stats_display_memp(struct stats_mem *mem, int index); void stats_display_sys(struct stats_sys *sys); -#else +#else /* LWIP_STATS_DISPLAY */ #define stats_display() #define stats_display_proto(proto, name) #define stats_display_igmp(igmp) diff --git a/core/lwip/src/include/lwip/sys.h b/core/lwip/src/include/lwip/sys.h index 0cc84ddf..9f62c754 100644 --- a/core/lwip/src/include/lwip/sys.h +++ b/core/lwip/src/include/lwip/sys.h @@ -43,19 +43,19 @@ extern "C" { /* For a totally minimal and standalone system, we provide null definitions of the sys_ functions. */ typedef u8_t sys_sem_t; +typedef u8_t sys_mutex_t; typedef u8_t sys_mbox_t; -struct sys_timeo {u8_t dummy;}; -#define sys_init() -#define sys_timeout(m,h,a) -#define sys_untimeout(m,a) -#define sys_sem_new(c) c +#define sys_sem_new(s, c) ERR_OK #define sys_sem_signal(s) #define sys_sem_wait(s) -#define sys_sem_wait_timeout(s,t) #define sys_arch_sem_wait(s,t) #define sys_sem_free(s) -#define sys_mbox_new(s) 0 +#define sys_mutex_new(mu) ERR_OK +#define sys_mutex_lock(mu) +#define sys_mutex_unlock(mu) +#define sys_mutex_free(mu) +#define sys_mbox_new(m, s) ERR_OK #define sys_mbox_fetch(m,d) #define sys_mbox_tryfetch(m,d) #define sys_mbox_post(m,d) @@ -64,12 +64,14 @@ struct sys_timeo {u8_t dummy;}; #define sys_thread_new(n,t,a,s,p) +#define sys_msleep(t) + #else /* NO_SYS */ /** Return code for timeouts from sys_arch_mbox_fetch and sys_arch_sem_wait */ #define SYS_ARCH_TIMEOUT 0xffffffffUL -/* sys_mbox_tryfetch returns SYS_MBOX_EMPTY if appropriate. +/** sys_mbox_tryfetch() returns SYS_MBOX_EMPTY if appropriate. * For now we use the same magic value, but we allow this to change in future. */ #define SYS_MBOX_EMPTY SYS_ARCH_TIMEOUT @@ -77,70 +79,156 @@ struct sys_timeo {u8_t dummy;}; #include "lwip/err.h" #include "arch/sys_arch.h" -typedef void (* sys_timeout_handler)(void *arg); - -struct sys_timeo { - struct sys_timeo *next; - u32_t time; - sys_timeout_handler h; - void *arg; -}; - -struct sys_timeouts { - struct sys_timeo *next; -}; - -/* sys_init() must be called before anthing else. */ -void sys_init(void); - -/* - * sys_timeout(): - * - * Schedule a timeout a specified amount of milliseconds in the - * future. When the timeout occurs, the specified timeout handler will - * be called. The handler will be passed the "arg" argument when - * called. - * - */ -void sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg); -void sys_untimeout(sys_timeout_handler h, void *arg); -struct sys_timeouts *sys_arch_timeouts(void); - -/* Semaphore functions. */ -sys_sem_t sys_sem_new(u8_t count); -void sys_sem_signal(sys_sem_t sem); -u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout); -void sys_sem_free(sys_sem_t sem); -void sys_sem_wait(sys_sem_t sem); -int sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout); +/** Function prototype for thread functions */ +typedef void (*lwip_thread_fn)(void *arg); + +/* Function prototypes for functions to be implemented by platform ports + (in sys_arch.c) */ + +/* Mutex functions: */ + +/** Define LWIP_COMPAT_MUTEX if the port has no mutexes and binary semaphores + should be used instead */ +#if LWIP_COMPAT_MUTEX +/* for old ports that don't have mutexes: define them to binary semaphores */ +#define sys_mutex_t sys_sem_t +#define sys_mutex_new(mutex) sys_sem_new(mutex, 1) +#define sys_mutex_lock(mutex) sys_sem_wait(mutex) +#define sys_mutex_unlock(mutex) sys_sem_signal(mutex) +#define sys_mutex_free(mutex) sys_sem_free(mutex) +#define sys_mutex_valid(mutex) sys_sem_valid(mutex) +#define sys_mutex_set_invalid(mutex) sys_sem_set_invalid(mutex) + +#else /* LWIP_COMPAT_MUTEX */ + +/** Create a new mutex + * @param mutex pointer to the mutex to create + * @return a new mutex */ +err_t sys_mutex_new(sys_mutex_t *mutex); +/** Lock a mutex + * @param mutex the mutex to lock */ +void sys_mutex_lock(sys_mutex_t *mutex); +/** Unlock a mutex + * @param mutex the mutex to unlock */ +void sys_mutex_unlock(sys_mutex_t *mutex); +/** Delete a semaphore + * @param mutex the mutex to delete */ +void sys_mutex_free(sys_mutex_t *mutex); +#ifndef sys_mutex_valid +/** Check if a mutex is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mutex_valid(sys_mutex_t *mutex); +#endif +#ifndef sys_mutex_set_invalid +/** Set a mutex invalid so that sys_mutex_valid returns 0 */ +void sys_mutex_set_invalid(sys_mutex_t *mutex); +#endif +#endif /* LWIP_COMPAT_MUTEX */ + +/* Semaphore functions: */ + +/** Create a new semaphore + * @param sem pointer to the semaphore to create + * @param count initial count of the semaphore + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_sem_new(sys_sem_t *sem, u8_t count); +/** Signals a semaphore + * @param sem the semaphore to signal */ +void sys_sem_signal(sys_sem_t *sem); +/** Wait for a semaphore for the specified timeout + * @param sem the semaphore to wait for + * @param timeout timeout in milliseconds to wait (0 = wait forever) + * @return time (in milliseconds) waited for the semaphore + * or SYS_ARCH_TIMEOUT on timeout */ +u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout); +/** Delete a semaphore + * @param sem semaphore to delete */ +void sys_sem_free(sys_sem_t *sem); +/** Wait for a semaphore - forever/no timeout */ +#define sys_sem_wait(sem) sys_arch_sem_wait(sem, 0) +#ifndef sys_sem_valid +/** Check if a sempahore is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_sem_valid(sys_sem_t *sem); +#endif +#ifndef sys_sem_set_invalid +/** Set a semaphore invalid so that sys_sem_valid returns 0 */ +void sys_sem_set_invalid(sys_sem_t *sem); +#endif /* Time functions. */ #ifndef sys_msleep void sys_msleep(u32_t ms); /* only has a (close to) 1 jiffy resolution. */ #endif -#ifndef sys_jiffies -u32_t sys_jiffies(void); /* since power up. */ -#endif /* Mailbox functions. */ -sys_mbox_t sys_mbox_new(int size); -void sys_mbox_post(sys_mbox_t mbox, void *msg); -err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg); -u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout); -#ifndef sys_arch_mbox_tryfetch /* Allow port to override with a macro */ -u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg); + +/** Create a new mbox of specified size + * @param mbox pointer to the mbox to create + * @param size (miminum) number of messages in this mbox + * @return ERR_OK if successful, another err_t otherwise */ +err_t sys_mbox_new(sys_mbox_t *mbox, int size); +/** Post a message to an mbox - may not fail + * -> blocks if full, only used from tasks not from ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +void sys_mbox_post(sys_mbox_t *mbox, void *msg); +/** Try to post a message to an mbox - may fail if full or ISR + * @param mbox mbox to posts the message + * @param msg message to post (ATTENTION: can be NULL) */ +err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg); +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return time (in milliseconds) waited for a message, may be 0 if not waited + or SYS_ARCH_TIMEOUT on timeout + * The returned time has to be accurate to prevent timer jitter! */ +u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout); +/* Allow port to override with a macro, e.g. special timout for sys_arch_mbox_fetch() */ +#ifndef sys_arch_mbox_tryfetch +/** Wait for a new message to arrive in the mbox + * @param mbox mbox to get a message from + * @param msg pointer where the message is stored + * @param timeout maximum time (in milliseconds) to wait for a message + * @return 0 (milliseconds) if a message has been received + * or SYS_MBOX_EMPTY if the mailbox is empty */ +u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg); #endif -/* For now, we map straight to sys_arch implementation. */ +/** For now, we map straight to sys_arch implementation. */ #define sys_mbox_tryfetch(mbox, msg) sys_arch_mbox_tryfetch(mbox, msg) -void sys_mbox_free(sys_mbox_t mbox); -void sys_mbox_fetch(sys_mbox_t mbox, void **msg); +/** Delete an mbox + * @param mbox mbox to delete */ +void sys_mbox_free(sys_mbox_t *mbox); +#define sys_mbox_fetch(mbox, msg) sys_arch_mbox_fetch(mbox, msg, 0) +#ifndef sys_mbox_valid +/** Check if an mbox is valid/allocated: return 1 for valid, 0 for invalid */ +int sys_mbox_valid(sys_mbox_t *mbox); +#endif +#ifndef sys_mbox_set_invalid +/** Set an mbox invalid so that sys_mbox_valid returns 0 */ +void sys_mbox_set_invalid(sys_mbox_t *mbox); +#endif -/* Thread functions. */ -sys_thread_t sys_thread_new(char *name, void (* thread)(void *arg), void *arg, int stacksize, int prio); +/** The only thread function: + * Creates a new thread + * @param name human-readable name for the thread (used for debugging purposes) + * @param thread thread-function + * @param arg parameter passed to 'thread' + * @param stacksize stack size in bytes for the new thread (may be ignored by ports) + * @param prio priority of the new thread (may be ignored by ports) */ +sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio); #endif /* NO_SYS */ -/** Returns the current time in milliseconds. */ +/* sys_init() must be called before anthing else. */ +void sys_init(void); + +#ifndef sys_jiffies +/** Ticks/jiffies since power up. */ +u32_t sys_jiffies(void); +#endif + +/** Returns the current time in milliseconds, + * may be the same as sys_jiffies or at least based on it. */ u32_t sys_now(void); /* Critical Region Protection */ diff --git a/core/lwip/src/include/lwip/tcp.h b/core/lwip/src/include/lwip/tcp.h index c88d25d7..07dcd10e 100644 --- a/core/lwip/src/include/lwip/tcp.h +++ b/core/lwip/src/include/lwip/tcp.h @@ -49,198 +49,80 @@ extern "C" { struct tcp_pcb; -/* Functions for interfacing with TCP: */ - -/* Lower layer interface to TCP: */ -#define tcp_init() /* Compatibility define, not init needed. */ -void tcp_tmr (void); /* Must be called every - TCP_TMR_INTERVAL - ms. (Typically 250 ms). */ -/* Application program's interface: */ -struct tcp_pcb * tcp_new (void); -struct tcp_pcb * tcp_alloc (u8_t prio); - -void tcp_arg (struct tcp_pcb *pcb, void *arg); -void tcp_accept (struct tcp_pcb *pcb, - err_t (* accept)(void *arg, struct tcp_pcb *newpcb, - err_t err)); -void tcp_recv (struct tcp_pcb *pcb, - err_t (* recv)(void *arg, struct tcp_pcb *tpcb, - struct pbuf *p, err_t err)); -void tcp_sent (struct tcp_pcb *pcb, - err_t (* sent)(void *arg, struct tcp_pcb *tpcb, - u16_t len)); -void tcp_poll (struct tcp_pcb *pcb, - err_t (* poll)(void *arg, struct tcp_pcb *tpcb), - u8_t interval); -void tcp_err (struct tcp_pcb *pcb, - void (* err)(void *arg, err_t err)); - -#define tcp_mss(pcb) ((pcb)->mss) -#define tcp_sndbuf(pcb) ((pcb)->snd_buf) -#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) -#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) -#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) - -#if TCP_LISTEN_BACKLOG -#define tcp_accepted(pcb) (((struct tcp_pcb_listen *)(pcb))->accepts_pending--) -#else /* TCP_LISTEN_BACKLOG */ -#define tcp_accepted(pcb) -#endif /* TCP_LISTEN_BACKLOG */ - -void tcp_recved (struct tcp_pcb *pcb, u16_t len); -err_t tcp_bind (struct tcp_pcb *pcb, struct ip_addr *ipaddr, - u16_t port); -err_t tcp_connect (struct tcp_pcb *pcb, struct ip_addr *ipaddr, - u16_t port, err_t (* connected)(void *arg, - struct tcp_pcb *tpcb, - err_t err)); - -struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); -#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) - -void tcp_abandon (struct tcp_pcb *pcb, int reset); -#define tcp_abort(pcb) tcp_abandon((pcb), 1) -err_t tcp_close (struct tcp_pcb *pcb); - -/* Flags for "apiflags" parameter in tcp_write and tcp_enqueue */ -#define TCP_WRITE_FLAG_COPY 0x01 -#define TCP_WRITE_FLAG_MORE 0x02 - -err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, - u8_t apiflags); - -void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); - -#define TCP_PRIO_MIN 1 -#define TCP_PRIO_NORMAL 64 -#define TCP_PRIO_MAX 127 - -/* It is also possible to call these two functions at the right - intervals (instead of calling tcp_tmr()). */ -void tcp_slowtmr (void); -void tcp_fasttmr (void); - - -/* Only used by IP to pass a TCP segment to TCP: */ -void tcp_input (struct pbuf *p, struct netif *inp); -/* Used within the TCP code only: */ -err_t tcp_send_empty_ack(struct tcp_pcb *pcb); -err_t tcp_output (struct tcp_pcb *pcb); -void tcp_rexmit (struct tcp_pcb *pcb); -void tcp_rexmit_rto (struct tcp_pcb *pcb); -void tcp_rexmit_fast (struct tcp_pcb *pcb); -u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); - -/** - * This is the Nagle algorithm: try to combine user data to send as few TCP - * segments as possible. Only send if - * - no previously transmitted data on the connection remains unacknowledged or - * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or - * - the only unsent segment is at least pcb->mss bytes long (or there is more - * than one unsent segment - with lwIP, this can happen although unsent->len < mss) - * - or if we are in fast-retransmit (TF_INFR) +/** Function prototype for tcp accept callback functions. Called when a new + * connection can be accepted on a listening pcb. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param newpcb The new connection pcb + * @param err An error code if there has been an error accepting. + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! */ -#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ - ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ - (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ - ((tpcb)->unsent->len >= (tpcb)->mss))) \ - ) ? 1 : 0) -#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) - - -#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) -#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) -#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) -#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) -/* is b<=a<=c? */ -#if 0 /* see bug #10548 */ -#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) -#endif -#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) -#define TCP_FIN 0x01U -#define TCP_SYN 0x02U -#define TCP_RST 0x04U -#define TCP_PSH 0x08U -#define TCP_ACK 0x10U -#define TCP_URG 0x20U -#define TCP_ECE 0x40U -#define TCP_CWR 0x80U - -#define TCP_FLAGS 0x3fU - -/* Length of the TCP header, excluding options. */ -#define TCP_HLEN 20 +typedef err_t (*tcp_accept_fn)(void *arg, struct tcp_pcb *newpcb, err_t err); -#ifndef TCP_TMR_INTERVAL -#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ -#endif /* TCP_TMR_INTERVAL */ - -#ifndef TCP_FAST_INTERVAL -#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ -#endif /* TCP_FAST_INTERVAL */ - -#ifndef TCP_SLOW_INTERVAL -#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ -#endif /* TCP_SLOW_INTERVAL */ - -#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ -#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ - -#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ - -#ifndef TCP_MSL -#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ -#endif - -/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ -#ifndef TCP_KEEPIDLE_DEFAULT -#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ -#endif - -#ifndef TCP_KEEPINTVL_DEFAULT -#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ -#endif - -#ifndef TCP_KEEPCNT_DEFAULT -#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ -#endif - -#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ +/** Function prototype for tcp receive callback functions. Called when data has + * been received. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which received data + * @param p The received data (or NULL when the connection has been closed!) + * @param err An error code if there has been an error receiving + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_recv_fn)(void *arg, struct tcp_pcb *tpcb, + struct pbuf *p, err_t err); -/* Fields are (of course) in network byte order. - * Some fields are converted to host byte order in tcp_input(). +/** Function prototype for tcp sent callback functions. Called when sent data has + * been acknowledged by the remote side. Use it to free corresponding resources. + * This also means that the pcb has now space available to send new data. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb for which data has been acknowledged + * @param len The amount of bytes acknowledged + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! */ -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/bpstruct.h" -#endif -PACK_STRUCT_BEGIN -struct tcp_hdr { - PACK_STRUCT_FIELD(u16_t src); - PACK_STRUCT_FIELD(u16_t dest); - PACK_STRUCT_FIELD(u32_t seqno); - PACK_STRUCT_FIELD(u32_t ackno); - PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); - PACK_STRUCT_FIELD(u16_t wnd); - PACK_STRUCT_FIELD(u16_t chksum); - PACK_STRUCT_FIELD(u16_t urgp); -} PACK_STRUCT_STRUCT; -PACK_STRUCT_END -#ifdef PACK_STRUCT_USE_INCLUDES -# include "arch/epstruct.h" -#endif +typedef err_t (*tcp_sent_fn)(void *arg, struct tcp_pcb *tpcb, + u16_t len); -#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) -#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) -#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) +/** Function prototype for tcp poll callback functions. Called periodically as + * specified by @see tcp_poll. + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb tcp pcb + * @return ERR_OK: try to send some data by calling tcp_output + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + */ +typedef err_t (*tcp_poll_fn)(void *arg, struct tcp_pcb *tpcb); -#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) -#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) -#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & htons((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) -#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) -#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) +/** Function prototype for tcp error callback functions. Called when the pcb + * receives a RST or is unexpectedly closed for any other reason. + * + * @note The corresponding pcb is already freed when this callback is called! + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param err Error code to indicate why the pcb has been closed + * ERR_ABRT: aborted through tcp_abort or by a TCP timer + * ERR_RST: the connection was reset by the remote host + */ +typedef void (*tcp_err_fn)(void *arg, err_t err); -#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) +/** Function prototype for tcp connected callback functions. Called when a pcb + * is connected to the remote side after initiating a connection attempt by + * calling tcp_connect(). + * + * @param arg Additional argument to pass to the callback function (@see tcp_arg()) + * @param tpcb The connection pcb which is connected + * @param err An unused error code, always ERR_OK currently ;-) TODO! + * Only return ERR_ABRT if you have called tcp_abort from within the + * callback function! + * + * @note When a connection attempt fails, the error callback is currently called! + */ +typedef err_t (*tcp_connected_fn)(void *arg, struct tcp_pcb *tpcb, err_t err); enum tcp_state { CLOSED = 0, @@ -256,13 +138,6 @@ enum tcp_state { TIME_WAIT = 10 }; -/** Flags used on input processing, not on pcb->flags -*/ -#define TF_RESET (u8_t)0x08U /* Connection was reset. */ -#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ -#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ - - #if LWIP_CALLBACK_API /* Function to call when a listener has been connected. * @param arg user-supplied argument (tcp_pcb.callback_arg) @@ -271,7 +146,7 @@ enum tcp_state { * @return ERR_OK: accept the new connection, * any other err_t abortsthe new connection */ -#define DEF_ACCEPT_CALLBACK err_t (* accept)(void *arg, struct tcp_pcb *newpcb, err_t err) +#define DEF_ACCEPT_CALLBACK tcp_accept_fn accept; #else /* LWIP_CALLBACK_API */ #define DEF_ACCEPT_CALLBACK #endif /* LWIP_CALLBACK_API */ @@ -284,10 +159,10 @@ enum tcp_state { enum tcp_state state; /* TCP state */ \ u8_t prio; \ void *callback_arg; \ - /* ports are in host byte order */ \ - u16_t local_port; \ /* the accept callback for listen- and normal pcbs, if LWIP_CALLBACK_API */ \ - DEF_ACCEPT_CALLBACK + DEF_ACCEPT_CALLBACK \ + /* ports are in host byte order */ \ + u16_t local_port /* the TCP protocol control block */ @@ -305,6 +180,7 @@ struct tcp_pcb { #define TF_ACK_NOW ((u8_t)0x02U) /* Immediate ACK. */ #define TF_INFR ((u8_t)0x04U) /* In fast recovery. */ #define TF_TIMESTAMP ((u8_t)0x08U) /* Timestamp option enabled */ +#define TF_RXCLOSED ((u8_t)0x10U) /* rx closed by tcp_shutdown */ #define TF_FIN ((u8_t)0x20U) /* Connection was closed locally (FIN segment enqueued). */ #define TF_NODELAY ((u8_t)0x40U) /* Disable Nagle algorithm */ #define TF_NAGLEMEMERR ((u8_t)0x80U) /* nagle enabled, memerr, try to output to prevent delayed ACK to happen */ @@ -352,10 +228,14 @@ struct tcp_pcb { u16_t acked; u16_t snd_buf; /* Available buffer space for sending (in bytes). */ -#define TCP_SNDQUEUELEN_OVERFLOW (0xffff-3) +#define TCP_SNDQUEUELEN_OVERFLOW (0xffffU-3) u16_t snd_queuelen; /* Available buffer space for sending (in tcp_segs). */ - - + +#if TCP_OVERSIZE + /* Extra bytes available at the end of the last pbuf in unsent. */ + u16_t unsent_oversize; +#endif /* TCP_OVERSIZE */ + /* These are ordered by sequence number: */ struct tcp_seg *unsent; /* Unsent (queued) segments. */ struct tcp_seg *unacked; /* Sent but unacknowledged segments. */ @@ -366,49 +246,16 @@ struct tcp_pcb { struct pbuf *refused_data; /* Data previously received but not yet taken by upper layer */ #if LWIP_CALLBACK_API - /* Function to be called when more send buffer space is available. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb the tcp_pcb which has send buffer space available - * @param space the amount of bytes available - * @return ERR_OK: try to send some data by calling tcp_output - */ - err_t (* sent)(void *arg, struct tcp_pcb *pcb, u16_t space); - - /* Function to be called when (in-sequence) data has arrived. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb the tcp_pcb for which data has arrived - * @param p the packet buffer which arrived - * @param err an error argument (TODO: that is current always ERR_OK?) - * @return ERR_OK: try to send some data by calling tcp_output - */ - err_t (* recv)(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); - - /* Function to be called when a connection has been set up. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb the tcp_pcb that now is connected - * @param err an error argument (TODO: that is current always ERR_OK?) - * @return value is currently ignored - */ - err_t (* connected)(void *arg, struct tcp_pcb *pcb, err_t err); - - /* Function which is called periodically. - * The period can be adjusted in multiples of the TCP slow timer interval - * by changing tcp_pcb.polltmr. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param pcb the tcp_pcb to poll for - * @return ERR_OK: try to send some data by calling tcp_output - */ - err_t (* poll)(void *arg, struct tcp_pcb *pcb); - - /* Function to be called whenever a fatal error occurs. - * There is no pcb parameter since most of the times, the pcb is - * already deallocated (or there is no pcb) when this function is called. - * @param arg user-supplied argument (tcp_pcb.callback_arg) - * @param err an indication why the error callback is called: - * ERR_ABRT: aborted through tcp_abort or by a TCP timer - * ERR_RST: the connection was reset by the remote host - */ - void (* errf)(void *arg, err_t err); + /* Function to be called when more send buffer space is available. */ + tcp_sent_fn sent; + /* Function to be called when (in-sequence) data has arrived. */ + tcp_recv_fn recv; + /* Function to be called when a connection has been set up. */ + tcp_connected_fn connected; + /* Function which is called periodically. */ + tcp_poll_fn poll; + /* Function to be called whenever a fatal error occurs. */ + tcp_err_fn errf; #endif /* LWIP_CALLBACK_API */ #if LWIP_TCP_TIMESTAMPS @@ -461,242 +308,65 @@ err_t lwip_tcp_event(void *arg, struct tcp_pcb *pcb, u16_t size, err_t err); -#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_ACCEPT, NULL, 0, err) -#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_SENT, NULL, space, ERR_OK) -#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_RECV, (p), 0, (err)) -#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_CONNECTED, NULL, 0, (err)) -#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ - LWIP_EVENT_POLL, NULL, 0, ERR_OK) -#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ - LWIP_EVENT_ERR, NULL, 0, (err)) -#else /* LWIP_EVENT_API */ - -#define TCP_EVENT_ACCEPT(pcb,err,ret) \ - do { \ - if((pcb)->accept != NULL) \ - (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_SENT(pcb,space,ret) \ - do { \ - if((pcb)->sent != NULL) \ - (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_RECV(pcb,p,err,ret) \ - do { \ - if((pcb)->recv != NULL) { \ - (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err)); \ - } else { \ - (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ - } \ - } while (0) - -#define TCP_EVENT_CONNECTED(pcb,err,ret) \ - do { \ - if((pcb)->connected != NULL) \ - (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_POLL(pcb,ret) \ - do { \ - if((pcb)->poll != NULL) \ - (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ - else (ret) = ERR_OK; \ - } while (0) - -#define TCP_EVENT_ERR(errf,arg,err) \ - do { \ - if((errf) != NULL) \ - (errf)((arg),(err)); \ - } while (0) - #endif /* LWIP_EVENT_API */ -/* This structure represents a TCP segment on the unsent and unacked queues */ -struct tcp_seg { - struct tcp_seg *next; /* used when putting segements on a queue */ - struct pbuf *p; /* buffer containing data + TCP header */ - void *dataptr; /* pointer to the TCP data in the pbuf */ - u16_t len; /* the TCP length of this segment */ - u8_t flags; -#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ -#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ - struct tcp_hdr *tcphdr; /* the TCP header */ -}; +/* Application program's interface: */ +struct tcp_pcb * tcp_new (void); -#define LWIP_TCP_OPT_LENGTH(flags) \ - (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ - (flags & TF_SEG_OPTS_TS ? 12 : 0) - -/** This returns a TCP header option for MSS in an u32_t */ -#define TCP_BUILD_MSS_OPTION(x) (x) = htonl(((u32_t)2 << 24) | \ - ((u32_t)4 << 16) | \ - (((u32_t)TCP_MSS / 256) << 8) | \ - (TCP_MSS & 255)) - -/* Internal functions and global variables: */ -struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); -void tcp_pcb_purge(struct tcp_pcb *pcb); -void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); - -u8_t tcp_segs_free(struct tcp_seg *seg); -u8_t tcp_seg_free(struct tcp_seg *seg); -struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); - -#define tcp_ack(pcb) \ - do { \ - if((pcb)->flags & TF_ACK_DELAY) { \ - (pcb)->flags &= ~TF_ACK_DELAY; \ - (pcb)->flags |= TF_ACK_NOW; \ - tcp_output(pcb); \ - } \ - else { \ - (pcb)->flags |= TF_ACK_DELAY; \ - } \ - } while (0) - -#define tcp_ack_now(pcb) \ - do { \ - (pcb)->flags |= TF_ACK_NOW; \ - tcp_output(pcb); \ - } while (0) - -err_t tcp_send_ctrl(struct tcp_pcb *pcb, u8_t flags); -err_t tcp_enqueue(struct tcp_pcb *pcb, void *dataptr, u16_t len, - u8_t flags, u8_t apiflags, u8_t optflags); - -void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); - -void tcp_rst(u32_t seqno, u32_t ackno, - struct ip_addr *local_ip, struct ip_addr *remote_ip, - u16_t local_port, u16_t remote_port); - -u32_t tcp_next_iss(void); - -void tcp_keepalive(struct tcp_pcb *pcb); -void tcp_zero_window_probe(struct tcp_pcb *pcb); - -#if TCP_CALCULATE_EFF_SEND_MSS -u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr); -#endif /* TCP_CALCULATE_EFF_SEND_MSS */ +void tcp_arg (struct tcp_pcb *pcb, void *arg); +void tcp_accept (struct tcp_pcb *pcb, tcp_accept_fn accept); +void tcp_recv (struct tcp_pcb *pcb, tcp_recv_fn recv); +void tcp_sent (struct tcp_pcb *pcb, tcp_sent_fn sent); +void tcp_poll (struct tcp_pcb *pcb, tcp_poll_fn poll, u8_t interval); +void tcp_err (struct tcp_pcb *pcb, tcp_err_fn err); + +#define tcp_mss(pcb) (((pcb)->flags & TF_TIMESTAMP) ? ((pcb)->mss - 12) : (pcb)->mss) +#define tcp_sndbuf(pcb) ((pcb)->snd_buf) +#define tcp_sndqueuelen(pcb) ((pcb)->snd_queuelen) +#define tcp_nagle_disable(pcb) ((pcb)->flags |= TF_NODELAY) +#define tcp_nagle_enable(pcb) ((pcb)->flags &= ~TF_NODELAY) +#define tcp_nagle_disabled(pcb) (((pcb)->flags & TF_NODELAY) != 0) -#if LWIP_CALLBACK_API -err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); -#endif /* LWIP_CALLBACK_API */ +#if TCP_LISTEN_BACKLOG +#define tcp_accepted(pcb) do { \ + LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", pcb->state == LISTEN); \ + (((struct tcp_pcb_listen *)(pcb))->accepts_pending--); } while(0) +#else /* TCP_LISTEN_BACKLOG */ +#define tcp_accepted(pcb) LWIP_ASSERT("pcb->state == LISTEN (called for wrong pcb?)", \ + pcb->state == LISTEN) +#endif /* TCP_LISTEN_BACKLOG */ + +void tcp_recved (struct tcp_pcb *pcb, u16_t len); +err_t tcp_bind (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port); +err_t tcp_connect (struct tcp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port, tcp_connected_fn connected); + +struct tcp_pcb * tcp_listen_with_backlog(struct tcp_pcb *pcb, u8_t backlog); +#define tcp_listen(pcb) tcp_listen_with_backlog(pcb, TCP_DEFAULT_LISTEN_BACKLOG) + +void tcp_abort (struct tcp_pcb *pcb); +err_t tcp_close (struct tcp_pcb *pcb); +err_t tcp_shutdown(struct tcp_pcb *pcb, int shut_rx, int shut_tx); + +/* Flags for "apiflags" parameter in tcp_write */ +#define TCP_WRITE_FLAG_COPY 0x01 +#define TCP_WRITE_FLAG_MORE 0x02 + +err_t tcp_write (struct tcp_pcb *pcb, const void *dataptr, u16_t len, + u8_t apiflags); + +void tcp_setprio (struct tcp_pcb *pcb, u8_t prio); + +#define TCP_PRIO_MIN 1 +#define TCP_PRIO_NORMAL 64 +#define TCP_PRIO_MAX 127 + +err_t tcp_output (struct tcp_pcb *pcb); -extern struct tcp_pcb *tcp_input_pcb; -extern u32_t tcp_ticks; const char* tcp_debug_state_str(enum tcp_state s); -#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG -void tcp_debug_print(struct tcp_hdr *tcphdr); -void tcp_debug_print_flags(u8_t flags); -void tcp_debug_print_state(enum tcp_state s); -void tcp_debug_print_pcbs(void); -s16_t tcp_pcbs_sane(void); -#else -# define tcp_debug_print(tcphdr) -# define tcp_debug_print_flags(flags) -# define tcp_debug_print_state(s) -# define tcp_debug_print_pcbs() -# define tcp_pcbs_sane() 1 -#endif /* TCP_DEBUG */ - -#if NO_SYS -#define tcp_timer_needed() -#else -void tcp_timer_needed(void); -#endif -/* The TCP PCB lists. */ -union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ - struct tcp_pcb_listen *listen_pcbs; - struct tcp_pcb *pcbs; -}; -extern union tcp_listen_pcbs_t tcp_listen_pcbs; -extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a - state in which they accept or send - data. */ -extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ - -extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ - -/* Axioms about the above lists: - 1) Every TCP PCB that is not CLOSED is in one of the lists. - 2) A PCB is only in one of the lists. - 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. - 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. -*/ - -/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB - with a PCB list or removes a PCB from a list, respectively. */ -#if 0 -#define TCP_REG(pcbs, npcb) do {\ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", npcb, npcb->local_port)); \ - for(tcp_tmp_pcb = *pcbs; \ - tcp_tmp_pcb != NULL; \ - tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != npcb); \ - } \ - LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", npcb->state != CLOSED); \ - npcb->next = *pcbs; \ - LWIP_ASSERT("TCP_REG: npcb->next != npcb", npcb->next != npcb); \ - *(pcbs) = npcb; \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - tcp_timer_needed(); \ - } while(0) -#define TCP_RMV(pcbs, npcb) do { \ - LWIP_ASSERT("TCP_RMV: pcbs != NULL", *pcbs != NULL); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", npcb, *pcbs)); \ - if(*pcbs == npcb) { \ - *pcbs = (*pcbs)->next; \ - } else for(tcp_tmp_pcb = *pcbs; tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next == npcb) { \ - tcp_tmp_pcb->next = npcb->next; \ - break; \ - } \ - } \ - npcb->next = NULL; \ - LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ - LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", npcb, *pcbs)); \ - } while(0) - -#else /* LWIP_DEBUG */ - -#define TCP_REG(pcbs, npcb) \ - do { \ - npcb->next = *pcbs; \ - *(pcbs) = npcb; \ - tcp_timer_needed(); \ - } while (0) - -#define TCP_RMV(pcbs, npcb) \ - do { \ - if(*(pcbs) == npcb) { \ - (*(pcbs)) = (*pcbs)->next; \ - } \ - else { \ - for(tcp_tmp_pcb = *pcbs; \ - tcp_tmp_pcb != NULL; \ - tcp_tmp_pcb = tcp_tmp_pcb->next) { \ - if(tcp_tmp_pcb->next == npcb) { \ - tcp_tmp_pcb->next = npcb->next; \ - break; \ - } \ - } \ - } \ - npcb->next = NULL; \ - } while(0) - -#endif /* LWIP_DEBUG */ #ifdef __cplusplus } diff --git a/core/lwip/src/include/lwip/tcp_impl.h b/core/lwip/src/include/lwip/tcp_impl.h new file mode 100644 index 00000000..b4feec0d --- /dev/null +++ b/core/lwip/src/include/lwip/tcp_impl.h @@ -0,0 +1,471 @@ +/* + * Copyright (c) 2001-2004 Swedish Institute of Computer Science. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * 3. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT + * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT + * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * This file is part of the lwIP TCP/IP stack. + * + * Author: Adam Dunkels <adam@sics.se> + * + */ +#ifndef __LWIP_TCP_IMPL_H__ +#define __LWIP_TCP_IMPL_H__ + +#include "lwip/opt.h" + +#if LWIP_TCP /* don't build if not configured for use in lwipopts.h */ + +#include "lwip/tcp.h" +#include "lwip/sys.h" +#include "lwip/mem.h" +#include "lwip/pbuf.h" +#include "lwip/ip.h" +#include "lwip/icmp.h" +#include "lwip/err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* Functions for interfacing with TCP: */ + +/* Lower layer interface to TCP: */ +#define tcp_init() /* Compatibility define, no init needed. */ +void tcp_tmr (void); /* Must be called every + TCP_TMR_INTERVAL + ms. (Typically 250 ms). */ +/* It is also possible to call these two functions at the right + intervals (instead of calling tcp_tmr()). */ +void tcp_slowtmr (void); +void tcp_fasttmr (void); + + +/* Only used by IP to pass a TCP segment to TCP: */ +void tcp_input (struct pbuf *p, struct netif *inp); +/* Used within the TCP code only: */ +struct tcp_pcb * tcp_alloc (u8_t prio); +void tcp_abandon (struct tcp_pcb *pcb, int reset); +err_t tcp_send_empty_ack(struct tcp_pcb *pcb); +void tcp_rexmit (struct tcp_pcb *pcb); +void tcp_rexmit_rto (struct tcp_pcb *pcb); +void tcp_rexmit_fast (struct tcp_pcb *pcb); +u32_t tcp_update_rcv_ann_wnd(struct tcp_pcb *pcb); + +/** + * This is the Nagle algorithm: try to combine user data to send as few TCP + * segments as possible. Only send if + * - no previously transmitted data on the connection remains unacknowledged or + * - the TF_NODELAY flag is set (nagle algorithm turned off for this pcb) or + * - the only unsent segment is at least pcb->mss bytes long (or there is more + * than one unsent segment - with lwIP, this can happen although unsent->len < mss) + * - or if we are in fast-retransmit (TF_INFR) + */ +#define tcp_do_output_nagle(tpcb) ((((tpcb)->unacked == NULL) || \ + ((tpcb)->flags & (TF_NODELAY | TF_INFR)) || \ + (((tpcb)->unsent != NULL) && (((tpcb)->unsent->next != NULL) || \ + ((tpcb)->unsent->len >= (tpcb)->mss))) \ + ) ? 1 : 0) +#define tcp_output_nagle(tpcb) (tcp_do_output_nagle(tpcb) ? tcp_output(tpcb) : ERR_OK) + + +#define TCP_SEQ_LT(a,b) ((s32_t)((a)-(b)) < 0) +#define TCP_SEQ_LEQ(a,b) ((s32_t)((a)-(b)) <= 0) +#define TCP_SEQ_GT(a,b) ((s32_t)((a)-(b)) > 0) +#define TCP_SEQ_GEQ(a,b) ((s32_t)((a)-(b)) >= 0) +/* is b<=a<=c? */ +#if 0 /* see bug #10548 */ +#define TCP_SEQ_BETWEEN(a,b,c) ((c)-(b) >= (a)-(b)) +#endif +#define TCP_SEQ_BETWEEN(a,b,c) (TCP_SEQ_GEQ(a,b) && TCP_SEQ_LEQ(a,c)) +#define TCP_FIN 0x01U +#define TCP_SYN 0x02U +#define TCP_RST 0x04U +#define TCP_PSH 0x08U +#define TCP_ACK 0x10U +#define TCP_URG 0x20U +#define TCP_ECE 0x40U +#define TCP_CWR 0x80U + +#define TCP_FLAGS 0x3fU + +/* Length of the TCP header, excluding options. */ +#define TCP_HLEN 20 + +#ifndef TCP_TMR_INTERVAL +#define TCP_TMR_INTERVAL 250 /* The TCP timer interval in milliseconds. */ +#endif /* TCP_TMR_INTERVAL */ + +#ifndef TCP_FAST_INTERVAL +#define TCP_FAST_INTERVAL TCP_TMR_INTERVAL /* the fine grained timeout in milliseconds */ +#endif /* TCP_FAST_INTERVAL */ + +#ifndef TCP_SLOW_INTERVAL +#define TCP_SLOW_INTERVAL (2*TCP_TMR_INTERVAL) /* the coarse grained timeout in milliseconds */ +#endif /* TCP_SLOW_INTERVAL */ + +#define TCP_FIN_WAIT_TIMEOUT 20000 /* milliseconds */ +#define TCP_SYN_RCVD_TIMEOUT 20000 /* milliseconds */ + +#define TCP_OOSEQ_TIMEOUT 6U /* x RTO */ + +#ifndef TCP_MSL +#define TCP_MSL 60000UL /* The maximum segment lifetime in milliseconds */ +#endif + +/* Keepalive values, compliant with RFC 1122. Don't change this unless you know what you're doing */ +#ifndef TCP_KEEPIDLE_DEFAULT +#define TCP_KEEPIDLE_DEFAULT 7200000UL /* Default KEEPALIVE timer in milliseconds */ +#endif + +#ifndef TCP_KEEPINTVL_DEFAULT +#define TCP_KEEPINTVL_DEFAULT 75000UL /* Default Time between KEEPALIVE probes in milliseconds */ +#endif + +#ifndef TCP_KEEPCNT_DEFAULT +#define TCP_KEEPCNT_DEFAULT 9U /* Default Counter for KEEPALIVE probes */ +#endif + +#define TCP_MAXIDLE TCP_KEEPCNT_DEFAULT * TCP_KEEPINTVL_DEFAULT /* Maximum KEEPALIVE probe time */ + +/* Fields are (of course) in network byte order. + * Some fields are converted to host byte order in tcp_input(). + */ +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/bpstruct.h" +#endif +PACK_STRUCT_BEGIN +struct tcp_hdr { + PACK_STRUCT_FIELD(u16_t src); + PACK_STRUCT_FIELD(u16_t dest); + PACK_STRUCT_FIELD(u32_t seqno); + PACK_STRUCT_FIELD(u32_t ackno); + PACK_STRUCT_FIELD(u16_t _hdrlen_rsvd_flags); + PACK_STRUCT_FIELD(u16_t wnd); + PACK_STRUCT_FIELD(u16_t chksum); + PACK_STRUCT_FIELD(u16_t urgp); +} PACK_STRUCT_STRUCT; +PACK_STRUCT_END +#ifdef PACK_STRUCT_USE_INCLUDES +# include "arch/epstruct.h" +#endif + +#define TCPH_OFFSET(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 8) +#define TCPH_HDRLEN(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) >> 12) +#define TCPH_FLAGS(phdr) (ntohs((phdr)->_hdrlen_rsvd_flags) & TCP_FLAGS) + +#define TCPH_OFFSET_SET(phdr, offset) (phdr)->_hdrlen_rsvd_flags = htons(((offset) << 8) | TCPH_FLAGS(phdr)) +#define TCPH_HDRLEN_SET(phdr, len) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | TCPH_FLAGS(phdr)) +#define TCPH_FLAGS_SET(phdr, flags) (phdr)->_hdrlen_rsvd_flags = (((phdr)->_hdrlen_rsvd_flags & PP_HTONS((u16_t)(~(u16_t)(TCP_FLAGS)))) | htons(flags)) +#define TCPH_HDRLEN_FLAGS_SET(phdr, len, flags) (phdr)->_hdrlen_rsvd_flags = htons(((len) << 12) | (flags)) + +#define TCPH_SET_FLAG(phdr, flags ) (phdr)->_hdrlen_rsvd_flags = ((phdr)->_hdrlen_rsvd_flags | htons(flags)) +#define TCPH_UNSET_FLAG(phdr, flags) (phdr)->_hdrlen_rsvd_flags = htons(ntohs((phdr)->_hdrlen_rsvd_flags) | (TCPH_FLAGS(phdr) & ~(flags)) ) + +#define TCP_TCPLEN(seg) ((seg)->len + ((TCPH_FLAGS((seg)->tcphdr) & (TCP_FIN | TCP_SYN)) != 0)) + +/** Flags used on input processing, not on pcb->flags +*/ +#define TF_RESET (u8_t)0x08U /* Connection was reset. */ +#define TF_CLOSED (u8_t)0x10U /* Connection was sucessfully closed. */ +#define TF_GOT_FIN (u8_t)0x20U /* Connection was closed by the remote end. */ + + +#if LWIP_EVENT_API + +#define TCP_EVENT_ACCEPT(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_ACCEPT, NULL, 0, err) +#define TCP_EVENT_SENT(pcb,space,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_SENT, NULL, space, ERR_OK) +#define TCP_EVENT_RECV(pcb,p,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, (p), 0, (err)) +#define TCP_EVENT_CLOSED(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_RECV, NULL, 0, ERR_OK) +#define TCP_EVENT_CONNECTED(pcb,err,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_CONNECTED, NULL, 0, (err)) +#define TCP_EVENT_POLL(pcb,ret) ret = lwip_tcp_event((pcb)->callback_arg, (pcb),\ + LWIP_EVENT_POLL, NULL, 0, ERR_OK) +#define TCP_EVENT_ERR(errf,arg,err) lwip_tcp_event((arg), NULL, \ + LWIP_EVENT_ERR, NULL, 0, (err)) + +#else /* LWIP_EVENT_API */ + +#define TCP_EVENT_ACCEPT(pcb,err,ret) \ + do { \ + if((pcb)->accept != NULL) \ + (ret) = (pcb)->accept((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_ARG; \ + } while (0) + +#define TCP_EVENT_SENT(pcb,space,ret) \ + do { \ + if((pcb)->sent != NULL) \ + (ret) = (pcb)->sent((pcb)->callback_arg,(pcb),(space)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_RECV(pcb,p,err,ret) \ + do { \ + if((pcb)->recv != NULL) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),(p),(err));\ + } else { \ + (ret) = tcp_recv_null(NULL, (pcb), (p), (err)); \ + } \ + } while (0) + +#define TCP_EVENT_CLOSED(pcb,ret) \ + do { \ + if(((pcb)->recv != NULL)) { \ + (ret) = (pcb)->recv((pcb)->callback_arg,(pcb),NULL,ERR_OK);\ + } else { \ + (ret) = ERR_OK; \ + } \ + } while (0) + +#define TCP_EVENT_CONNECTED(pcb,err,ret) \ + do { \ + if((pcb)->connected != NULL) \ + (ret) = (pcb)->connected((pcb)->callback_arg,(pcb),(err)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_POLL(pcb,ret) \ + do { \ + if((pcb)->poll != NULL) \ + (ret) = (pcb)->poll((pcb)->callback_arg,(pcb)); \ + else (ret) = ERR_OK; \ + } while (0) + +#define TCP_EVENT_ERR(errf,arg,err) \ + do { \ + if((errf) != NULL) \ + (errf)((arg),(err)); \ + } while (0) + +#endif /* LWIP_EVENT_API */ + +/** Enabled extra-check for TCP_OVERSIZE if LWIP_DEBUG is enabled */ +#if TCP_OVERSIZE && defined(LWIP_DEBUG) +#define TCP_OVERSIZE_DBGCHECK 1 +#else +#define TCP_OVERSIZE_DBGCHECK 0 +#endif + +/** Don't generate checksum on copy if CHECKSUM_GEN_TCP is disabled */ +#define TCP_CHECKSUM_ON_COPY (LWIP_CHECKSUM_ON_COPY && CHECKSUM_GEN_TCP) + +/* This structure represents a TCP segment on the unsent, unacked and ooseq queues */ +struct tcp_seg { + struct tcp_seg *next; /* used when putting segements on a queue */ + struct pbuf *p; /* buffer containing data + TCP header */ + u16_t len; /* the TCP length of this segment */ +#if TCP_OVERSIZE_DBGCHECK + u16_t oversize_left; /* Extra bytes available at the end of the last + pbuf in unsent (used for asserting vs. + tcp_pcb.unsent_oversized only) */ +#endif /* TCP_OVERSIZE_DBGCHECK */ +#if TCP_CHECKSUM_ON_COPY + u16_t chksum; + u8_t chksum_swapped; +#endif /* TCP_CHECKSUM_ON_COPY */ + u8_t flags; +#define TF_SEG_OPTS_MSS (u8_t)0x01U /* Include MSS option. */ +#define TF_SEG_OPTS_TS (u8_t)0x02U /* Include timestamp option. */ +#define TF_SEG_DATA_CHECKSUMMED (u8_t)0x04U /* ALL data (not the header) is + checksummed into 'chksum' */ + struct tcp_hdr *tcphdr; /* the TCP header */ +}; + +#define LWIP_TCP_OPT_LENGTH(flags) \ + (flags & TF_SEG_OPTS_MSS ? 4 : 0) + \ + (flags & TF_SEG_OPTS_TS ? 12 : 0) + +/** This returns a TCP header option for MSS in an u32_t */ +#define TCP_BUILD_MSS_OPTION(x) (x) = PP_HTONL(((u32_t)2 << 24) | \ + ((u32_t)4 << 16) | \ + (((u32_t)TCP_MSS / 256) << 8) | \ + (TCP_MSS & 255)) + +/* Global variables: */ +extern struct tcp_pcb *tcp_input_pcb; +extern u32_t tcp_ticks; + +/* The TCP PCB lists. */ +union tcp_listen_pcbs_t { /* List of all TCP PCBs in LISTEN state. */ + struct tcp_pcb_listen *listen_pcbs; + struct tcp_pcb *pcbs; +}; +extern struct tcp_pcb *tcp_bound_pcbs; +extern union tcp_listen_pcbs_t tcp_listen_pcbs; +extern struct tcp_pcb *tcp_active_pcbs; /* List of all TCP PCBs that are in a + state in which they accept or send + data. */ +extern struct tcp_pcb *tcp_tw_pcbs; /* List of all TCP PCBs in TIME-WAIT. */ + +extern struct tcp_pcb *tcp_tmp_pcb; /* Only used for temporary storage. */ + +/* Axioms about the above lists: + 1) Every TCP PCB that is not CLOSED is in one of the lists. + 2) A PCB is only in one of the lists. + 3) All PCBs in the tcp_listen_pcbs list is in LISTEN state. + 4) All PCBs in the tcp_tw_pcbs list is in TIME-WAIT state. +*/ +/* Define two macros, TCP_REG and TCP_RMV that registers a TCP PCB + with a PCB list or removes a PCB from a list, respectively. */ +#ifndef TCP_DEBUG_PCB_LISTS +#define TCP_DEBUG_PCB_LISTS 0 +#endif +#if TCP_DEBUG_PCB_LISTS +#define TCP_REG(pcbs, npcb) do {\ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_REG %p local port %d\n", (npcb), (npcb)->local_port)); \ + for(tcp_tmp_pcb = *(pcbs); \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + LWIP_ASSERT("TCP_REG: already registered\n", tcp_tmp_pcb != (npcb)); \ + } \ + LWIP_ASSERT("TCP_REG: pcb->state != CLOSED", ((pcbs) == &tcp_bound_pcbs) || ((npcb)->state != CLOSED)); \ + (npcb)->next = *(pcbs); \ + LWIP_ASSERT("TCP_REG: npcb->next != npcb", (npcb)->next != (npcb)); \ + *(pcbs) = (npcb); \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + tcp_timer_needed(); \ + } while(0) +#define TCP_RMV(pcbs, npcb) do { \ + LWIP_ASSERT("TCP_RMV: pcbs != NULL", *(pcbs) != NULL); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removing %p from %p\n", (npcb), *(pcbs))); \ + if(*(pcbs) == (npcb)) { \ + *(pcbs) = (*pcbs)->next; \ + } else for(tcp_tmp_pcb = *(pcbs); tcp_tmp_pcb != NULL; tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + (npcb)->next = NULL; \ + LWIP_ASSERT("TCP_RMV: tcp_pcbs sane", tcp_pcbs_sane()); \ + LWIP_DEBUGF(TCP_DEBUG, ("TCP_RMV: removed %p from %p\n", (npcb), *(pcbs))); \ + } while(0) + +#else /* LWIP_DEBUG */ + +#define TCP_REG(pcbs, npcb) \ + do { \ + (npcb)->next = *pcbs; \ + *(pcbs) = (npcb); \ + tcp_timer_needed(); \ + } while (0) + +#define TCP_RMV(pcbs, npcb) \ + do { \ + if(*(pcbs) == (npcb)) { \ + (*(pcbs)) = (*pcbs)->next; \ + } \ + else { \ + for(tcp_tmp_pcb = *pcbs; \ + tcp_tmp_pcb != NULL; \ + tcp_tmp_pcb = tcp_tmp_pcb->next) { \ + if(tcp_tmp_pcb->next == (npcb)) { \ + tcp_tmp_pcb->next = (npcb)->next; \ + break; \ + } \ + } \ + } \ + (npcb)->next = NULL; \ + } while(0) + +#endif /* LWIP_DEBUG */ + + +/* Internal functions: */ +struct tcp_pcb *tcp_pcb_copy(struct tcp_pcb *pcb); +void tcp_pcb_purge(struct tcp_pcb *pcb); +void tcp_pcb_remove(struct tcp_pcb **pcblist, struct tcp_pcb *pcb); + +void tcp_segs_free(struct tcp_seg *seg); +void tcp_seg_free(struct tcp_seg *seg); +struct tcp_seg *tcp_seg_copy(struct tcp_seg *seg); + +#define tcp_ack(pcb) \ + do { \ + if((pcb)->flags & TF_ACK_DELAY) { \ + (pcb)->flags &= ~TF_ACK_DELAY; \ + (pcb)->flags |= TF_ACK_NOW; \ + } \ + else { \ + (pcb)->flags |= TF_ACK_DELAY; \ + } \ + } while (0) + +#define tcp_ack_now(pcb) \ + do { \ + (pcb)->flags |= TF_ACK_NOW; \ + } while (0) + +err_t tcp_send_fin(struct tcp_pcb *pcb); +err_t tcp_enqueue_flags(struct tcp_pcb *pcb, u8_t flags); + +void tcp_rexmit_seg(struct tcp_pcb *pcb, struct tcp_seg *seg); + +void tcp_rst(u32_t seqno, u32_t ackno, + ip_addr_t *local_ip, ip_addr_t *remote_ip, + u16_t local_port, u16_t remote_port); + +u32_t tcp_next_iss(void); + +void tcp_keepalive(struct tcp_pcb *pcb); +void tcp_zero_window_probe(struct tcp_pcb *pcb); + +#if TCP_CALCULATE_EFF_SEND_MSS +u16_t tcp_eff_send_mss(u16_t sendmss, ip_addr_t *addr); +#endif /* TCP_CALCULATE_EFF_SEND_MSS */ + +#if LWIP_CALLBACK_API +err_t tcp_recv_null(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err); +#endif /* LWIP_CALLBACK_API */ + +#if TCP_DEBUG || TCP_INPUT_DEBUG || TCP_OUTPUT_DEBUG +void tcp_debug_print(struct tcp_hdr *tcphdr); +void tcp_debug_print_flags(u8_t flags); +void tcp_debug_print_state(enum tcp_state s); +void tcp_debug_print_pcbs(void); +s16_t tcp_pcbs_sane(void); +#else +# define tcp_debug_print(tcphdr) +# define tcp_debug_print_flags(flags) +# define tcp_debug_print_state(s) +# define tcp_debug_print_pcbs() +# define tcp_pcbs_sane() 1 +#endif /* TCP_DEBUG */ + +/** External function (implemented in timers.c), called when TCP detects + * that a timer is needed (i.e. active- or time-wait-pcb found). */ +void tcp_timer_needed(void); + + +#ifdef __cplusplus +} +#endif + +#endif /* LWIP_TCP */ + +#endif /* __LWIP_TCP_H__ */ diff --git a/core/lwip/src/include/lwip/tcpip.h b/core/lwip/src/include/lwip/tcpip.h index 75393ee9..995ba8ad 100644 --- a/core/lwip/src/include/lwip/tcpip.h +++ b/core/lwip/src/include/lwip/tcpip.h @@ -41,31 +41,43 @@ #include "lwip/pbuf.h" #include "lwip/api.h" #include "lwip/sys.h" +#include "lwip/timers.h" #include "lwip/netif.h" #ifdef __cplusplus extern "C" { #endif +/** Define this to something that triggers a watchdog. This is called from + * tcpip_thread after processing a message. */ +#ifndef LWIP_TCPIP_THREAD_ALIVE +#define LWIP_TCPIP_THREAD_ALIVE() +#endif + #if LWIP_TCPIP_CORE_LOCKING /** The global semaphore to lock the stack. */ -extern sys_sem_t lock_tcpip_core; -#define LOCK_TCPIP_CORE() sys_sem_wait(lock_tcpip_core) -#define UNLOCK_TCPIP_CORE() sys_sem_signal(lock_tcpip_core) +extern sys_mutex_t lock_tcpip_core; +#define LOCK_TCPIP_CORE() sys_mutex_lock(&lock_tcpip_core) +#define UNLOCK_TCPIP_CORE() sys_mutex_unlock(&lock_tcpip_core) #define TCPIP_APIMSG(m) tcpip_apimsg_lock(m) #define TCPIP_APIMSG_ACK(m) #define TCPIP_NETIFAPI(m) tcpip_netifapi_lock(m) #define TCPIP_NETIFAPI_ACK(m) -#else +#else /* LWIP_TCPIP_CORE_LOCKING */ #define LOCK_TCPIP_CORE() #define UNLOCK_TCPIP_CORE() #define TCPIP_APIMSG(m) tcpip_apimsg(m) -#define TCPIP_APIMSG_ACK(m) sys_sem_signal(m->conn->op_completed) +#define TCPIP_APIMSG_ACK(m) sys_sem_signal(&m->conn->op_completed) #define TCPIP_NETIFAPI(m) tcpip_netifapi(m) -#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(m->sem) +#define TCPIP_NETIFAPI_ACK(m) sys_sem_signal(&m->sem) #endif /* LWIP_TCPIP_CORE_LOCKING */ -void tcpip_init(void (* tcpip_init_done)(void *), void *arg); +/** Function prototype for the init_done function passed to tcpip_init */ +typedef void (*tcpip_init_done_fn)(void *arg); +/** Function prototype for functions passed to tcpip_callback() */ +typedef void (*tcpip_callback_fn)(void *ctx); + +void tcpip_init(tcpip_init_done_fn tcpip_init_done, void *arg); #if LWIP_NETCONN err_t tcpip_apimsg(struct api_msg *apimsg); @@ -83,15 +95,17 @@ err_t tcpip_netifapi_lock(struct netifapi_msg *netifapimsg); #endif /* LWIP_TCPIP_CORE_LOCKING */ #endif /* LWIP_NETIF_API */ -err_t tcpip_callback_with_block(void (*f)(void *ctx), void *ctx, u8_t block); +err_t tcpip_callback_with_block(tcpip_callback_fn function, void *ctx, u8_t block); #define tcpip_callback(f, ctx) tcpip_callback_with_block(f, ctx, 1) /* free pbufs or heap memory from another context without blocking */ err_t pbuf_free_callback(struct pbuf *p); err_t mem_free_callback(void *m); +#if LWIP_TCPIP_TIMEOUT err_t tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg); err_t tcpip_untimeout(sys_timeout_handler h, void *arg); +#endif /* LWIP_TCPIP_TIMEOUT */ enum tcpip_msg_type { #if LWIP_NETCONN @@ -101,9 +115,11 @@ enum tcpip_msg_type { #if LWIP_NETIF_API TCPIP_MSG_NETIFAPI, #endif /* LWIP_NETIF_API */ - TCPIP_MSG_CALLBACK, +#if LWIP_TCPIP_TIMEOUT TCPIP_MSG_TIMEOUT, - TCPIP_MSG_UNTIMEOUT + TCPIP_MSG_UNTIMEOUT, +#endif /* LWIP_TCPIP_TIMEOUT */ + TCPIP_MSG_CALLBACK }; struct tcpip_msg { @@ -121,14 +137,16 @@ struct tcpip_msg { struct netif *netif; } inp; struct { - void (*f)(void *ctx); + tcpip_callback_fn function; void *ctx; } cb; +#if LWIP_TCPIP_TIMEOUT struct { u32_t msecs; sys_timeout_handler h; void *arg; } tmo; +#endif /* LWIP_TCPIP_TIMEOUT */ } msg; }; diff --git a/core/lwip/src/include/netif/loopif.h b/core/lwip/src/include/lwip/timers.h index 304af4b3..fb92b4b4 100644 --- a/core/lwip/src/include/netif/loopif.h +++ b/core/lwip/src/include/lwip/timers.h @@ -27,27 +27,72 @@ * This file is part of the lwIP TCP/IP stack. * * Author: Adam Dunkels <adam@sics.se> + * Simon Goldschmidt * */ -#ifndef __NETIF_LOOPIF_H__ -#define __NETIF_LOOPIF_H__ +#ifndef __LWIP_TIMERS_H__ +#define __LWIP_TIMERS_H__ #include "lwip/opt.h" -#include "lwip/netif.h" + +/* Timers are not supported when NO_SYS==1 and NO_SYS_NO_TIMERS==1 */ +#define LWIP_TIMERS (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) + +#if LWIP_TIMERS + #include "lwip/err.h" +#include "lwip/sys.h" #ifdef __cplusplus extern "C" { #endif -#if !LWIP_NETIF_LOOPBACK_MULTITHREADING -#define loopif_poll netif_poll -#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */ +#ifndef LWIP_DEBUG_TIMERNAMES +#ifdef LWIP_DEBUG +#define LWIP_DEBUG_TIMERNAMES SYS_DEBUG +#else /* LWIP_DEBUG */ +#define LWIP_DEBUG_TIMERNAMES 0 +#endif /* LWIP_DEBUG*/ +#endif + +/** Function prototype for a timeout callback function. Register such a function + * using sys_timeout(). + * + * @param arg Additional argument to pass to the function - set up by sys_timeout() + */ +typedef void (* sys_timeout_handler)(void *arg); + +struct sys_timeo { + struct sys_timeo *next; + u32_t time; + sys_timeout_handler h; + void *arg; +#if LWIP_DEBUG_TIMERNAMES + const char* handler_name; +#endif /* LWIP_DEBUG_TIMERNAMES */ +}; + +void sys_timeouts_init(void); + +#if LWIP_DEBUG_TIMERNAMES +void sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name); +#define sys_timeout(msecs, handler, arg) sys_timeout_debug(msecs, handler, arg, #handler) +#else /* LWIP_DEBUG_TIMERNAMES */ +void sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg); +#endif /* LWIP_DEBUG_TIMERNAMES */ + +void sys_untimeout(sys_timeout_handler handler, void *arg); +#if NO_SYS +void sys_check_timeouts(void); +void sys_restart_timeouts(void); +#else /* NO_SYS */ +void sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg); +#endif /* NO_SYS */ -err_t loopif_init(struct netif *netif); #ifdef __cplusplus } #endif -#endif /* __NETIF_LOOPIF_H__ */ +#endif /* LWIP_TIMERS */ +#endif /* __LWIP_TIMERS_H__ */ diff --git a/core/lwip/src/include/lwip/udp.h b/core/lwip/src/include/lwip/udp.h index 08d1817b..c98c1b3e 100644 --- a/core/lwip/src/include/lwip/udp.h +++ b/core/lwip/src/include/lwip/udp.h @@ -63,9 +63,30 @@ PACK_STRUCT_END # include "arch/epstruct.h" #endif -#define UDP_FLAGS_NOCHKSUM 0x01U -#define UDP_FLAGS_UDPLITE 0x02U -#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_NOCHKSUM 0x01U +#define UDP_FLAGS_UDPLITE 0x02U +#define UDP_FLAGS_CONNECTED 0x04U +#define UDP_FLAGS_MULTICAST_LOOP 0x08U + +struct udp_pcb; + +/** Function prototype for udp pcb receive callback functions + * addr and port are in same byte order as in the pcb + * The callback is responsible for freeing the pbuf + * if it's not used any more. + * + * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf + * makes 'addr' invalid, too. + * + * @param arg user supplied argument (udp_pcb.recv_arg) + * @param pcb the udp_pcb which received data + * @param p the packet buffer that was received + * @param addr the remote IP address from which the packet was received + * @param port the remote port from which the packet was received + */ +typedef void (*udp_recv_fn)(void *arg, struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *addr, u16_t port); + struct udp_pcb { /* Common members of all PCB types */ @@ -76,36 +97,22 @@ struct udp_pcb { struct udp_pcb *next; u8_t flags; - /* ports are in host byte order */ + /** ports are in host byte order */ u16_t local_port, remote_port; #if LWIP_IGMP - /* outgoing network interface for multicast packets */ - struct ip_addr multicast_ip; + /** outgoing network interface for multicast packets */ + ip_addr_t multicast_ip; #endif /* LWIP_IGMP */ #if LWIP_UDPLITE - /* used for UDP_LITE only */ + /** used for UDP_LITE only */ u16_t chksum_len_rx, chksum_len_tx; #endif /* LWIP_UDPLITE */ - /* receive callback function - * addr and port are in same byte order as in the pcb - * The callback is responsible for freeing the pbuf - * if it's not used any more. - * - * ATTENTION: Be aware that 'addr' points into the pbuf 'p' so freeing this pbuf - * makes 'addr' invalid, too. - * - * @param arg user supplied argument (udp_pcb.recv_arg) - * @param pcb the udp_pcb which received data - * @param p the packet buffer that was received - * @param addr the remote IP address from which the packet was received - * @param port the remote port from which the packet was received - */ - void (* recv)(void *arg, struct udp_pcb *pcb, struct pbuf *p, - struct ip_addr *addr, u16_t port); - /* user-supplied argument for the recv callback */ + /** receive callback function */ + udp_recv_fn recv; + /** user-supplied argument for the recv callback */ void *recv_arg; }; /* udp_pcbs export for exernal reference (e.g. SNMP agent) */ @@ -115,22 +122,33 @@ extern struct udp_pcb *udp_pcbs; UDP code. */ struct udp_pcb * udp_new (void); void udp_remove (struct udp_pcb *pcb); -err_t udp_bind (struct udp_pcb *pcb, struct ip_addr *ipaddr, - u16_t port); -err_t udp_connect (struct udp_pcb *pcb, struct ip_addr *ipaddr, - u16_t port); -void udp_disconnect (struct udp_pcb *pcb); -void udp_recv (struct udp_pcb *pcb, - void (* recv)(void *arg, struct udp_pcb *upcb, - struct pbuf *p, - struct ip_addr *addr, - u16_t port), - void *recv_arg); -err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif); -err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *dst_ip, u16_t dst_port); +err_t udp_bind (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port); +err_t udp_connect (struct udp_pcb *pcb, ip_addr_t *ipaddr, + u16_t port); +void udp_disconnect (struct udp_pcb *pcb); +void udp_recv (struct udp_pcb *pcb, udp_recv_fn recv, + void *recv_arg); +err_t udp_sendto_if (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif); +err_t udp_sendto (struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port); err_t udp_send (struct udp_pcb *pcb, struct pbuf *p); -#define udp_flags(pcb) ((pcb)->flags) +#if LWIP_CHECKSUM_ON_COPY +err_t udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + struct netif *netif, u8_t have_chksum, + u16_t chksum); +err_t udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, + ip_addr_t *dst_ip, u16_t dst_port, + u8_t have_chksum, u16_t chksum); +err_t udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p, + u8_t have_chksum, u16_t chksum); +#endif /* LWIP_CHECKSUM_ON_COPY */ + +#define udp_flags(pcb) ((pcb)->flags) #define udp_setflags(pcb, f) ((pcb)->flags = (f)) /* The following functions are the lower layer interface to UDP. */ diff --git a/core/lwip/src/include/lwipopts.h b/core/lwip/src/include/lwipopts.h index 2f0ba032..e0d39b89 100644 --- a/core/lwip/src/include/lwipopts.h +++ b/core/lwip/src/include/lwipopts.h @@ -2,6 +2,7 @@ #define __LWIPOPTS_H__ #include <byteswap.h> +#include <netinet/in.h> #define SYS_LIGHTWEIGHT_PROT 1 #define LWIP_NETIF_API 1 @@ -65,5 +66,8 @@ #define LWIP_PLATFORM_HTONS(x) bswap_16(x) #define LWIP_PLATFORM_HTONL(x) bswap_32(x) +#define LWIP_PREFIX_BYTEORDER_FUNCS 0 +#define LWIP_COMPAT_MUTEX 1 + void undiarp_tmr(void); #endif /* __LWIPOPTS_H__ */ diff --git a/core/lwip/src/include/netif/etharp.h b/core/lwip/src/include/netif/etharp.h index 72b8d79f..691575fa 100644 --- a/core/lwip/src/include/netif/etharp.h +++ b/core/lwip/src/include/netif/etharp.h @@ -37,7 +37,7 @@ #include "lwip/opt.h" -#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ +#if LWIP_ARP || LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */ #include "lwip/pbuf.h" #include "lwip/ip_addr.h" @@ -48,10 +48,6 @@ extern "C" { #endif -#ifndef ETH_PAD_SIZE -#define ETH_PAD_SIZE 0 -#endif - #ifndef ETHARP_HWADDR_LEN #define ETHARP_HWADDR_LEN 6 #endif @@ -72,6 +68,7 @@ PACK_STRUCT_END # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN +/** Ethernet header */ struct eth_hdr { #if ETH_PAD_SIZE PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]); @@ -93,9 +90,12 @@ PACK_STRUCT_END # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN +/** VLAN header inserted between ethernet header and payload + * if 'type' in ethernet header is ETHTYPE_VLAN. + * See IEEE802.Q */ struct eth_vlan_hdr { - PACK_STRUCT_FIELD(u16_t tpid); PACK_STRUCT_FIELD(u16_t prio_vid); + PACK_STRUCT_FIELD(u16_t tpid); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES @@ -111,11 +111,12 @@ PACK_STRUCT_END # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN -/** the ARP message */ +/** the ARP message, see RFC 826 ("Packet format") */ struct etharp_hdr { PACK_STRUCT_FIELD(u16_t hwtype); PACK_STRUCT_FIELD(u16_t proto); - PACK_STRUCT_FIELD(u16_t _hwlen_protolen); + PACK_STRUCT_FIELD(u8_t hwlen); + PACK_STRUCT_FIELD(u8_t protolen); PACK_STRUCT_FIELD(u16_t opcode); PACK_STRUCT_FIELD(struct eth_addr shwaddr); PACK_STRUCT_FIELD(struct ip_addr2 sipaddr); @@ -133,16 +134,40 @@ PACK_STRUCT_END /** 5 seconds period */ #define ARP_TMR_INTERVAL 5000 -#define ETHTYPE_ARP 0x0806 -#define ETHTYPE_IP 0x0800 -#define ETHTYPE_VLAN 0x8100 -#define ETHTYPE_PPPOEDISC 0x8863 /* PPP Over Ethernet Discovery Stage */ -#define ETHTYPE_PPPOE 0x8864 /* PPP Over Ethernet Session Stage */ +#define ETHTYPE_ARP 0x0806U +#define ETHTYPE_IP 0x0800U +#define ETHTYPE_VLAN 0x8100U +#define ETHTYPE_PPPOEDISC 0x8863U /* PPP Over Ethernet Discovery Stage */ +#define ETHTYPE_PPPOE 0x8864U /* PPP Over Ethernet Session Stage */ + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are local variables + * or known to be 32-bit aligned within the protocol header. */ +#ifndef ETHADDR32_COPY +#define ETHADDR32_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +/** MEMCPY-like macro to copy to/from struct eth_addr's that are no local + * variables and known to be 16-bit aligned within the protocol header. */ +#ifndef ETHADDR16_COPY +#define ETHADDR16_COPY(src, dst) SMEMCPY(src, dst, ETHARP_HWADDR_LEN) +#endif + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ /** ARP message types (opcodes) */ #define ARP_REQUEST 1 #define ARP_REPLY 2 +/** Define this to 1 and define LWIP_ARP_FILTER_NETIF_FN(pbuf, netif, type) + * to a filter function that returns the correct netif when using multiple + * netifs on one hardware interface where the netif's low-level receive + * routine cannot decide for the correct netif (e.g. when mapping multiple + * IP addresses to one hardware interface). + */ +#ifndef LWIP_ARP_FILTER_NETIF +#define LWIP_ARP_FILTER_NETIF 0 +#endif + #if ARP_QUEUEING /** struct for queueing outgoing packets for unknown address * defined here to be accessed by memp.h @@ -155,38 +180,42 @@ struct etharp_q_entry { #define etharp_init() /* Compatibility define, not init needed. */ void etharp_tmr(void); -s8_t etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, - struct eth_addr **eth_ret, struct ip_addr **ip_ret); -void etharp_ip_input(struct netif *netif, struct pbuf *p); -void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, - struct pbuf *p); -err_t etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr); -err_t etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q); -err_t etharp_request(struct netif *netif, struct ip_addr *ipaddr); +s8_t etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret); +err_t etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr); +err_t etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q); +err_t etharp_request(struct netif *netif, ip_addr_t *ipaddr); /** For Ethernet network interfaces, we might want to send "gratuitous ARP"; * this is an ARP packet sent by a node in order to spontaneously cause other * nodes to update an entry in their ARP cache. * From RFC 3220 "IP Mobility Support for IPv4" section 4.6. */ #define etharp_gratuitous(netif) etharp_request((netif), &(netif)->ip_addr) -err_t ethernet_input(struct pbuf *p, struct netif *netif); +#if ETHARP_SUPPORT_STATIC_ENTRIES +err_t etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr); +err_t etharp_remove_static_entry(ip_addr_t *ipaddr); +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ #if LWIP_AUTOIP err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, - const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, const u16_t opcode); #endif /* LWIP_AUTOIP */ +#endif /* LWIP_ARP */ + +err_t ethernet_input(struct pbuf *p, struct netif *netif); + #define eth_addr_cmp(addr1, addr2) (memcmp((addr1)->addr, (addr2)->addr, ETHARP_HWADDR_LEN) == 0) extern const struct eth_addr ethbroadcast, ethzero; +#endif /* LWIP_ARP || LWIP_ETHERNET */ + #ifdef __cplusplus } #endif -#endif /* LWIP_ARP */ - #endif /* __NETIF_ARP_H__ */ diff --git a/core/lwip/src/include/netif/ppp_oe.h b/core/lwip/src/include/netif/ppp_oe.h index 3aa55aec..e1cdfa51 100644 --- a/core/lwip/src/include/netif/ppp_oe.h +++ b/core/lwip/src/include/netif/ppp_oe.h @@ -74,15 +74,17 @@ #if PPPOE_SUPPORT > 0 +#include "netif/etharp.h" + #ifdef PACK_STRUCT_USE_INCLUDES # include "arch/bpstruct.h" #endif PACK_STRUCT_BEGIN struct pppoehdr { - PACK_STRUCT_FIELD(u8_t vertype); - PACK_STRUCT_FIELD(u8_t code); - PACK_STRUCT_FIELD(u16_t session); - PACK_STRUCT_FIELD(u16_t plen); + PACK_STRUCT_FIELD(u8_t vertype); + PACK_STRUCT_FIELD(u8_t code); + PACK_STRUCT_FIELD(u16_t session); + PACK_STRUCT_FIELD(u16_t plen); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES @@ -94,8 +96,8 @@ PACK_STRUCT_END #endif PACK_STRUCT_BEGIN struct pppoetag { - PACK_STRUCT_FIELD(u16_t tag); - PACK_STRUCT_FIELD(u16_t len); + PACK_STRUCT_FIELD(u16_t tag); + PACK_STRUCT_FIELD(u16_t len); } PACK_STRUCT_STRUCT; PACK_STRUCT_END #ifdef PACK_STRUCT_USE_INCLUDES @@ -103,45 +105,71 @@ PACK_STRUCT_END #endif -#define PPPOE_STATE_INITIAL 0 -#define PPPOE_STATE_PADI_SENT 1 -#define PPPOE_STATE_PADR_SENT 2 -#define PPPOE_STATE_SESSION 3 -#define PPPOE_STATE_CLOSING 4 +#define PPPOE_STATE_INITIAL 0 +#define PPPOE_STATE_PADI_SENT 1 +#define PPPOE_STATE_PADR_SENT 2 +#define PPPOE_STATE_SESSION 3 +#define PPPOE_STATE_CLOSING 4 /* passive */ -#define PPPOE_STATE_PADO_SENT 1 - -#define PPPOE_HEADERLEN sizeof(struct pppoehdr) -#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ - -#define PPPOE_TAG_EOL 0x0000 /* end of list */ -#define PPPOE_TAG_SNAME 0x0101 /* service name */ -#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ -#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ -#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ -#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ -#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ -#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ -#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ -#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ - -#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ -#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ -#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ -#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ -#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ +#define PPPOE_STATE_PADO_SENT 1 + +#define PPPOE_HEADERLEN sizeof(struct pppoehdr) +#define PPPOE_VERTYPE 0x11 /* VER=1, TYPE = 1 */ + +#define PPPOE_TAG_EOL 0x0000 /* end of list */ +#define PPPOE_TAG_SNAME 0x0101 /* service name */ +#define PPPOE_TAG_ACNAME 0x0102 /* access concentrator name */ +#define PPPOE_TAG_HUNIQUE 0x0103 /* host unique */ +#define PPPOE_TAG_ACCOOKIE 0x0104 /* AC cookie */ +#define PPPOE_TAG_VENDOR 0x0105 /* vendor specific */ +#define PPPOE_TAG_RELAYSID 0x0110 /* relay session id */ +#define PPPOE_TAG_SNAME_ERR 0x0201 /* service name error */ +#define PPPOE_TAG_ACSYS_ERR 0x0202 /* AC system error */ +#define PPPOE_TAG_GENERIC_ERR 0x0203 /* gerneric error */ + +#define PPPOE_CODE_PADI 0x09 /* Active Discovery Initiation */ +#define PPPOE_CODE_PADO 0x07 /* Active Discovery Offer */ +#define PPPOE_CODE_PADR 0x19 /* Active Discovery Request */ +#define PPPOE_CODE_PADS 0x65 /* Active Discovery Session confirmation */ +#define PPPOE_CODE_PADT 0xA7 /* Active Discovery Terminate */ #ifndef ETHERMTU #define ETHERMTU 1500 #endif /* two byte PPP protocol discriminator, then IP data */ -#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2) +#define PPPOE_MAXMTU (ETHERMTU-PPPOE_HEADERLEN-2) + +#ifndef PPPOE_MAX_AC_COOKIE_LEN +#define PPPOE_MAX_AC_COOKIE_LEN 64 +#endif -struct pppoe_softc; +struct pppoe_softc { + struct pppoe_softc *next; + struct netif *sc_ethif; /* ethernet interface we are using */ + int sc_pd; /* ppp unit number */ + void (*sc_linkStatusCB)(int pd, int up); + + int sc_state; /* discovery phase or session connected */ + struct eth_addr sc_dest; /* hardware address of concentrator */ + u16_t sc_session; /* PPPoE session id */ + +#ifdef PPPOE_TODO + char *sc_service_name; /* if != NULL: requested name of service */ + char *sc_concentrator_name; /* if != NULL: requested concentrator id */ +#endif /* PPPOE_TODO */ + u8_t sc_ac_cookie[PPPOE_MAX_AC_COOKIE_LEN]; /* content of AC cookie we must echo back */ + size_t sc_ac_cookie_len; /* length of cookie data */ +#ifdef PPPOE_SERVER + u8_t *sc_hunique; /* content of host unique we must echo back */ + size_t sc_hunique_len; /* length of host unique */ +#endif + int sc_padi_retried; /* number of PADI retries already done */ + int sc_padr_retried; /* number of PADR retries already done */ +}; -void pppoe_init(void); +#define pppoe_init() /* compatibility define, no initialization needed */ err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr); err_t pppoe_destroy(struct netif *ifp); @@ -154,7 +182,8 @@ void pppoe_data_input(struct netif *netif, struct pbuf *p); err_t pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb); -extern int pppoe_hdrlen; +/** used in ppp.c */ +#define PPPOE_HDRLEN (sizeof(struct eth_hdr) + PPPOE_HEADERLEN) #endif /* PPPOE_SUPPORT */ diff --git a/core/lwip/src/netif/etharp.c b/core/lwip/src/netif/etharp.c index 8f6872fa..b60dadd0 100644 --- a/core/lwip/src/netif/etharp.c +++ b/core/lwip/src/netif/etharp.c @@ -45,9 +45,10 @@ #include "lwip/opt.h" -#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ +#if LWIP_ARP || LWIP_ETHERNET -#include "lwip/inet.h" +#include "lwip/ip_addr.h" +#include "lwip/def.h" #include "lwip/ip.h" #include "lwip/stats.h" #include "lwip/snmp.h" @@ -61,6 +62,11 @@ #include <string.h> +const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; +const struct eth_addr ethzero = {{0,0,0,0,0,0}}; + +#if LWIP_ARP /* don't build if not configured for use in lwipopts.h */ + /** the time an ARP entry stays valid after its last update, * for ARP_TMR_INTERVAL = 5000, this is * (240 * 5) seconds = 20 minutes. @@ -77,12 +83,6 @@ #define HWTYPE_ETHERNET 1 -#define ARPH_HWLEN(hdr) (ntohs((hdr)->_hwlen_protolen) >> 8) -#define ARPH_PROTOLEN(hdr) (ntohs((hdr)->_hwlen_protolen) & 0xff) - -#define ARPH_HWLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons(ARPH_PROTOLEN(hdr) | ((len) << 8)) -#define ARPH_PROTOLEN_SET(hdr, len) (hdr)->_hwlen_protolen = htons((len) | (ARPH_HWLEN(hdr) << 8)) - enum etharp_state { ETHARP_STATE_EMPTY = 0, ETHARP_STATE_PENDING, @@ -91,45 +91,49 @@ enum etharp_state { struct etharp_entry { #if ARP_QUEUEING - /** - * Pointer to queue of pending outgoing packets on this ARP entry. - */ + /** Pointer to queue of pending outgoing packets on this ARP entry. */ struct etharp_q_entry *q; -#endif - struct ip_addr ipaddr; +#else /* ARP_QUEUEING */ + /** Pointer to a single pending outgoing packet on this ARP entry. */ + struct pbuf *q; +#endif /* ARP_QUEUEING */ + ip_addr_t ipaddr; struct eth_addr ethaddr; - enum etharp_state state; - u8_t ctime; +#if LWIP_SNMP struct netif *netif; +#endif /* LWIP_SNMP */ + u8_t state; + u8_t ctime; +#if ETHARP_SUPPORT_STATIC_ENTRIES + u8_t static_entry; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ }; -const struct eth_addr ethbroadcast = {{0xff,0xff,0xff,0xff,0xff,0xff}}; -const struct eth_addr ethzero = {{0,0,0,0,0,0}}; static struct etharp_entry arp_table[ARP_TABLE_SIZE]; + #if !LWIP_NETIF_HWADDRHINT static u8_t etharp_cached_entry; -#endif +#endif /* !LWIP_NETIF_HWADDRHINT */ -/** - * Try hard to create a new entry - we want the IP address to appear in - * the cache (even if this means removing an active entry or so). */ -#define ETHARP_TRY_HARD 1 -#define ETHARP_FIND_ONLY 2 +/** Try hard to create a new entry - we want the IP address to appear in + the cache (even if this means removing an active entry or so). */ +#define ETHARP_FLAG_TRY_HARD 1 +#define ETHARP_FLAG_FIND_ONLY 2 +#define ETHARP_FLAG_STATIC_ENTRY 4 #if LWIP_NETIF_HWADDRHINT -#define NETIF_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ +#define ETHARP_SET_HINT(netif, hint) if (((netif) != NULL) && ((netif)->addr_hint != NULL)) \ *((netif)->addr_hint) = (hint); -static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif); #else /* LWIP_NETIF_HWADDRHINT */ -static s8_t find_entry(struct ip_addr *ipaddr, u8_t flags); +#define ETHARP_SET_HINT(netif, hint) (etharp_cached_entry = (hint)) #endif /* LWIP_NETIF_HWADDRHINT */ -static err_t update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags); +static err_t update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags); /* Some checks, instead of etharp_init(): */ #if (LWIP_ARP && (ARP_TABLE_SIZE > 0x7f)) - #error "If you want to use ARP, ARP_TABLE_SIZE must fit in an s8_t, so, you have to reduce it in your lwipopts.h" + #error "ARP_TABLE_SIZE must fit in an s8_t, you have to reduce it in your lwipopts.h" #endif @@ -153,12 +157,46 @@ free_etharp_q(struct etharp_q_entry *q) memp_free(MEMP_ARP_QUEUE, r); } } -#endif +#else /* ARP_QUEUEING */ + +/** Compatibility define: free the queued pbuf */ +#define free_etharp_q(q) pbuf_free(q) + +#endif /* ARP_QUEUEING */ + +/** Clean up ARP table entries */ +static void +free_entry(int i) +{ + /* remove from SNMP ARP index tree */ + snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); + /* and empty packet queue */ + if (arp_table[i].q != NULL) { + /* remove all queued packets */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); + free_etharp_q(arp_table[i].q); + arp_table[i].q = NULL; + } + /* recycle entry for re-use */ + arp_table[i].state = ETHARP_STATE_EMPTY; +#if ETHARP_SUPPORT_STATIC_ENTRIES + arp_table[i].static_entry = 0; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ +#ifdef LWIP_DEBUG + /* for debugging, clean out the complete entry */ + arp_table[i].ctime = 0; +#if LWIP_SNMP + arp_table[i].netif = NULL; +#endif /* LWIP_SNMP */ + ip_addr_set_zero(&arp_table[i].ipaddr); + arp_table[i].ethaddr = ethzero; +#endif /* LWIP_DEBUG */ +} /** * Clears expired entries in the ARP table. * - * This function should be called every ETHARP_TMR_INTERVAL microseconds (5 seconds), + * This function should be called every ETHARP_TMR_INTERVAL milliseconds (5 seconds), * in order to expire entries in the ARP table. */ void @@ -169,35 +207,29 @@ etharp_tmr(void) LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer\n")); /* remove expired entries from the ARP table */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { - arp_table[i].ctime++; - if (((arp_table[i].state == ETHARP_STATE_STABLE) && - (arp_table[i].ctime >= ARP_MAXAGE)) || - ((arp_table[i].state == ETHARP_STATE_PENDING) && - (arp_table[i].ctime >= ARP_MAXPENDING))) { - /* pending or stable entry has become old! */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", - arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); - /* clean up entries that have just been expired */ - /* remove from SNMP ARP index tree */ - snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); -#if ARP_QUEUEING - /* and empty packet queue */ - if (arp_table[i].q != NULL) { - /* remove all queued packets */ - LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: freeing entry %"U16_F", packet queue %p.\n", (u16_t)i, (void *)(arp_table[i].q))); - free_etharp_q(arp_table[i].q); - arp_table[i].q = NULL; + u8_t state = arp_table[i].state; + if (state != ETHARP_STATE_EMPTY +#if ETHARP_SUPPORT_STATIC_ENTRIES + && (arp_table[i].static_entry == 0) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + ) { + arp_table[i].ctime++; + if ((arp_table[i].ctime >= ARP_MAXAGE) || + ((arp_table[i].state == ETHARP_STATE_PENDING) && + (arp_table[i].ctime >= ARP_MAXPENDING))) { + /* pending or stable entry has become old! */ + LWIP_DEBUGF(ETHARP_DEBUG, ("etharp_timer: expired %s entry %"U16_F".\n", + arp_table[i].state == ETHARP_STATE_STABLE ? "stable" : "pending", (u16_t)i)); + /* clean up entries that have just been expired */ + free_entry(i); } -#endif - /* recycle entry for re-use */ - arp_table[i].state = ETHARP_STATE_EMPTY; - } #if ARP_QUEUEING - /* still pending entry? (not expired) */ - if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* still pending entry? (not expired) */ + if (arp_table[i].state == ETHARP_STATE_PENDING) { /* resend an ARP query here? */ + } +#endif /* ARP_QUEUEING */ } -#endif } } @@ -212,62 +244,26 @@ etharp_tmr(void) * If ipaddr is NULL, return a initialized new entry in state ETHARP_EMPTY. * * In all cases, attempt to create new entries from an empty entry. If no - * empty entries are available and ETHARP_TRY_HARD flag is set, recycle + * empty entries are available and ETHARP_FLAG_TRY_HARD flag is set, recycle * old entries. Heuristic choose the least important entry for recycling. * * @param ipaddr IP address to find in ARP cache, or to add if not found. - * @param flags - * - ETHARP_TRY_HARD: Try hard to create a entry by allowing recycling of - * active (stable or pending) entries. + * @param flags @see definition of ETHARP_FLAG_* + * @param netif netif related to this address (used for NETIF_HWADDRHINT) * * @return The ARP entry index that matched or is created, ERR_MEM if no * entry is found or could be recycled. */ static s8_t -#if LWIP_NETIF_HWADDRHINT -find_entry(struct ip_addr *ipaddr, u8_t flags, struct netif *netif) -#else /* LWIP_NETIF_HWADDRHINT */ -find_entry(struct ip_addr *ipaddr, u8_t flags) -#endif /* LWIP_NETIF_HWADDRHINT */ +find_entry(ip_addr_t *ipaddr, u8_t flags) { s8_t old_pending = ARP_TABLE_SIZE, old_stable = ARP_TABLE_SIZE; s8_t empty = ARP_TABLE_SIZE; u8_t i = 0, age_pending = 0, age_stable = 0; -#if ARP_QUEUEING /* oldest entry with packets on queue */ s8_t old_queue = ARP_TABLE_SIZE; /* its age */ u8_t age_queue = 0; -#endif - - /* First, test if the last call to this function asked for the - * same address. If so, we're really fast! */ - if (ipaddr) { - /* ipaddr to search for was given */ -#if LWIP_NETIF_HWADDRHINT - if ((netif != NULL) && (netif->addr_hint != NULL)) { - /* per-pcb cached entry was given */ - u8_t per_pcb_cache = *(netif->addr_hint); - if ((per_pcb_cache < ARP_TABLE_SIZE) && arp_table[per_pcb_cache].state == ETHARP_STATE_STABLE) { - /* the per-pcb-cached entry is stable */ - if (ip_addr_cmp(ipaddr, &arp_table[per_pcb_cache].ipaddr)) { - /* per-pcb cached entry was the right one! */ - ETHARP_STATS_INC(etharp.cachehit); - return per_pcb_cache; - } - } - } -#else /* #if LWIP_NETIF_HWADDRHINT */ - if (arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) { - /* the cached entry is stable */ - if (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr)) { - /* cached entry was the right one! */ - ETHARP_STATS_INC(etharp.cachehit); - return etharp_cached_entry; - } - } -#endif /* #if LWIP_NETIF_HWADDRHINT */ - } /** * a) do a search through the cache, remember candidates @@ -285,65 +281,59 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) */ for (i = 0; i < ARP_TABLE_SIZE; ++i) { + u8_t state = arp_table[i].state; /* no empty entry found yet and now we do find one? */ - if ((empty == ARP_TABLE_SIZE) && (arp_table[i].state == ETHARP_STATE_EMPTY)) { + if ((empty == ARP_TABLE_SIZE) && (state == ETHARP_STATE_EMPTY)) { LWIP_DEBUGF(ETHARP_DEBUG, ("find_entry: found empty entry %"U16_F"\n", (u16_t)i)); /* remember first empty entry */ empty = i; - } - /* pending entry? */ - else if (arp_table[i].state == ETHARP_STATE_PENDING) { + } else if (state != ETHARP_STATE_EMPTY) { + LWIP_ASSERT("state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE", + state == ETHARP_STATE_PENDING || state == ETHARP_STATE_STABLE); /* if given, does IP address match IP address in ARP entry? */ if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching pending entry %"U16_F"\n", (u16_t)i)); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching entry %"U16_F"\n", (u16_t)i)); /* found exact IP address match, simply bail out */ -#if LWIP_NETIF_HWADDRHINT - NETIF_SET_HINT(netif, i); -#else /* #if LWIP_NETIF_HWADDRHINT */ - etharp_cached_entry = i; -#endif /* #if LWIP_NETIF_HWADDRHINT */ return i; -#if ARP_QUEUEING - /* pending with queued packets? */ - } else if (arp_table[i].q != NULL) { - if (arp_table[i].ctime >= age_queue) { - old_queue = i; - age_queue = arp_table[i].ctime; + } + /* pending entry? */ + if (state == ETHARP_STATE_PENDING) { + /* pending with queued packets? */ + if (arp_table[i].q != NULL) { + if (arp_table[i].ctime >= age_queue) { + old_queue = i; + age_queue = arp_table[i].ctime; + } + } else + /* pending without queued packets? */ + { + if (arp_table[i].ctime >= age_pending) { + old_pending = i; + age_pending = arp_table[i].ctime; + } } -#endif - /* pending without queued packets? */ - } else { - if (arp_table[i].ctime >= age_pending) { - old_pending = i; - age_pending = arp_table[i].ctime; + /* stable entry? */ + } else if (state == ETHARP_STATE_STABLE) { +#if ETHARP_SUPPORT_STATIC_ENTRIES + /* don't record old_stable for static entries since they never expire */ + if (arp_table[i].static_entry == 0) +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + { + /* remember entry with oldest stable entry in oldest, its age in maxtime */ + if (arp_table[i].ctime >= age_stable) { + old_stable = i; + age_stable = arp_table[i].ctime; + } } - } - } - /* stable entry? */ - else if (arp_table[i].state == ETHARP_STATE_STABLE) { - /* if given, does IP address match IP address in ARP entry? */ - if (ipaddr && ip_addr_cmp(ipaddr, &arp_table[i].ipaddr)) { - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: found matching stable entry %"U16_F"\n", (u16_t)i)); - /* found exact IP address match, simply bail out */ -#if LWIP_NETIF_HWADDRHINT - NETIF_SET_HINT(netif, i); -#else /* #if LWIP_NETIF_HWADDRHINT */ - etharp_cached_entry = i; -#endif /* #if LWIP_NETIF_HWADDRHINT */ - return i; - /* remember entry with oldest stable entry in oldest, its age in maxtime */ - } else if (arp_table[i].ctime >= age_stable) { - old_stable = i; - age_stable = arp_table[i].ctime; } } } /* { we have no match } => try to create a new entry */ - /* no empty entry found and not allowed to recycle? */ - if (((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_TRY_HARD) == 0)) - /* or don't create new entry, only search? */ - || ((flags & ETHARP_FIND_ONLY) != 0)) { + /* don't create new entry, only search? */ + if (((flags & ETHARP_FLAG_FIND_ONLY) != 0) || + /* or no empty entry found and not allowed to recycle? */ + ((empty == ARP_TABLE_SIZE) && ((flags & ETHARP_FLAG_TRY_HARD) == 0))) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty entry found and not allowed to recycle\n")); return (s8_t)ERR_MEM; } @@ -354,63 +344,55 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) * 3) oldest pending entry without queued packets * 4) oldest pending entry with queued packets * - * { ETHARP_TRY_HARD is set at this point } + * { ETHARP_FLAG_TRY_HARD is set at this point } */ /* 1) empty entry available? */ if (empty < ARP_TABLE_SIZE) { i = empty; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting empty entry %"U16_F"\n", (u16_t)i)); - } - /* 2) found recyclable stable entry? */ - else if (old_stable < ARP_TABLE_SIZE) { - /* recycle oldest stable*/ - i = old_stable; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); -#if ARP_QUEUEING - /* no queued packets should exist on stable entries */ - LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); -#endif - /* 3) found recyclable pending entry without queued packets? */ - } else if (old_pending < ARP_TABLE_SIZE) { - /* recycle oldest pending */ - i = old_pending; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); -#if ARP_QUEUEING - /* 4) found recyclable pending entry with queued packets? */ - } else if (old_queue < ARP_TABLE_SIZE) { - /* recycle oldest pending */ - i = old_queue; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); - free_etharp_q(arp_table[i].q); - arp_table[i].q = NULL; -#endif - /* no empty or recyclable entries found */ } else { - return (s8_t)ERR_MEM; + /* 2) found recyclable stable entry? */ + if (old_stable < ARP_TABLE_SIZE) { + /* recycle oldest stable*/ + i = old_stable; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest stable entry %"U16_F"\n", (u16_t)i)); + /* no queued packets should exist on stable entries */ + LWIP_ASSERT("arp_table[i].q == NULL", arp_table[i].q == NULL); + /* 3) found recyclable pending entry without queued packets? */ + } else if (old_pending < ARP_TABLE_SIZE) { + /* recycle oldest pending */ + i = old_pending; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F" (without queue)\n", (u16_t)i)); + /* 4) found recyclable pending entry with queued packets? */ + } else if (old_queue < ARP_TABLE_SIZE) { + /* recycle oldest pending (queued packets are free in free_entry) */ + i = old_queue; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: selecting oldest pending entry %"U16_F", freeing packet queue %p\n", (u16_t)i, (void *)(arp_table[i].q))); + /* no empty or recyclable entries found */ + } else { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("find_entry: no empty or recyclable entries found\n")); + return (s8_t)ERR_MEM; + } + + /* { empty or recyclable entry found } */ + LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); + free_entry(i); } - /* { empty or recyclable entry found } */ LWIP_ASSERT("i < ARP_TABLE_SIZE", i < ARP_TABLE_SIZE); - - if (arp_table[i].state != ETHARP_STATE_EMPTY) - { - snmp_delete_arpidx_tree(arp_table[i].netif, &arp_table[i].ipaddr); - } - /* recycle entry (no-op for an already empty entry) */ - arp_table[i].state = ETHARP_STATE_EMPTY; + LWIP_ASSERT("arp_table[i].state == ETHARP_STATE_EMPTY", + arp_table[i].state == ETHARP_STATE_EMPTY); /* IP address given? */ if (ipaddr != NULL) { /* set IP address */ - ip_addr_set(&arp_table[i].ipaddr, ipaddr); + ip_addr_copy(arp_table[i].ipaddr, *ipaddr); } arp_table[i].ctime = 0; -#if LWIP_NETIF_HWADDRHINT - NETIF_SET_HINT(netif, i); -#else /* #if LWIP_NETIF_HWADDRHINT */ - etharp_cached_entry = i; -#endif /* #if LWIP_NETIF_HWADDRHINT */ +#if ETHARP_SUPPORT_STATIC_ENTRIES + arp_table[i].static_entry = 0; +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ return (err_t)i; } @@ -427,18 +409,13 @@ find_entry(struct ip_addr *ipaddr, u8_t flags) static err_t etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst) { - struct eth_hdr *ethhdr = p->payload; - u8_t k; + struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload; LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); - k = ETHARP_HWADDR_LEN; - while(k > 0) { - k--; - ethhdr->dest.addr[k] = dst->addr[k]; - ethhdr->src.addr[k] = src->addr[k]; - } - ethhdr->type = htons(ETHTYPE_IP); + ETHADDR32_COPY(ðhdr->dest, dst); + ETHADDR16_COPY(ðhdr->src, src); + ethhdr->type = PP_HTONS(ETHTYPE_IP); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_send_ip: sending packet %p\n", (void *)p)); /* send the packet */ return netif->linkoutput(netif, p); @@ -450,30 +427,27 @@ etharp_send_ip(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct * If a pending entry is resolved, any queued packets will be sent * at this point. * + * @param netif netif related to this entry (used for NETIF_ADDRHINT) * @param ipaddr IP address of the inserted ARP entry. * @param ethaddr Ethernet address of the inserted ARP entry. - * @param flags Defines behaviour: - * - ETHARP_TRY_HARD Allows ARP to insert this as a new item. If not specified, - * only existing ARP entries will be updated. + * @param flags @see definition of ETHARP_FLAG_* * * @return * - ERR_OK Succesfully updated ARP cache. - * - ERR_MEM If we could not add a new ARP entry when ETHARP_TRY_HARD was set. + * - ERR_MEM If we could not add a new ARP entry when ETHARP_FLAG_TRY_HARD was set. * - ERR_ARG Non-unicast address given, those will not appear in ARP cache. * * @see pbuf_free() */ static err_t -update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *ethaddr, u8_t flags) +update_arp_entry(struct netif *netif, ip_addr_t *ipaddr, struct eth_addr *ethaddr, u8_t flags) { s8_t i; - u8_t k; - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry()\n")); LWIP_ASSERT("netif->hwaddr_len == ETHARP_HWADDR_LEN", netif->hwaddr_len == ETHARP_HWADDR_LEN); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", - ip4_addr1(ipaddr), ip4_addr2(ipaddr), ip4_addr3(ipaddr), ip4_addr4(ipaddr), - ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], - ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], + ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); /* non-unicast address? */ if (ip_addr_isany(ipaddr) || ip_addr_isbroadcast(ipaddr, netif) || @@ -482,34 +456,36 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e return ERR_ARG; } /* find or create ARP entry */ -#if LWIP_NETIF_HWADDRHINT - i = find_entry(ipaddr, flags, netif); -#else /* LWIP_NETIF_HWADDRHINT */ i = find_entry(ipaddr, flags); -#endif /* LWIP_NETIF_HWADDRHINT */ /* bail out if no entry could be found */ - if (i < 0) + if (i < 0) { return (err_t)i; - + } + +#if ETHARP_SUPPORT_STATIC_ENTRIES + if (flags & ETHARP_FLAG_STATIC_ENTRY) { + /* record static type */ + arp_table[i].static_entry = 1; + } +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + /* mark it stable */ arp_table[i].state = ETHARP_STATE_STABLE; + +#if LWIP_SNMP /* record network interface */ arp_table[i].netif = netif; - +#endif /* LWIP_SNMP */ /* insert in SNMP ARP index tree */ snmp_insert_arpidx_tree(netif, &arp_table[i].ipaddr); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("update_arp_entry: updating stable entry %"S16_F"\n", (s16_t)i)); /* update address */ - k = ETHARP_HWADDR_LEN; - while (k > 0) { - k--; - arp_table[i].ethaddr.addr[k] = ethaddr->addr[k]; - } + ETHADDR32_COPY(&arp_table[i].ethaddr, ethaddr); /* reset time stamp */ arp_table[i].ctime = 0; -#if ARP_QUEUEING /* this is where we will send out queued packets! */ +#if ARP_QUEUEING while (arp_table[i].q != NULL) { struct pbuf *p; /* remember remainder of queue */ @@ -520,15 +496,78 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e p = q->p; /* now queue entry can be freed */ memp_free(MEMP_ARP_QUEUE, q); +#else /* ARP_QUEUEING */ + if (arp_table[i].q != NULL) { + struct pbuf *p = arp_table[i].q; + arp_table[i].q = NULL; +#endif /* ARP_QUEUEING */ /* send the queued IP packet */ etharp_send_ip(netif, p, (struct eth_addr*)(netif->hwaddr), ethaddr); /* free the queued IP packet */ pbuf_free(p); } -#endif return ERR_OK; } +#if ETHARP_SUPPORT_STATIC_ENTRIES +/** Add a new static entry to the ARP table. If an entry exists for the + * specified IP address, this entry is overwritten. + * If packets are queued for the specified IP address, they are sent out. + * + * @param ipaddr IP address for the new static entry + * @param ethaddr ethernet address for the new static entry + * @return @see return values of etharp_add_static_entry + */ +err_t +etharp_add_static_entry(ip_addr_t *ipaddr, struct eth_addr *ethaddr) +{ + struct netif *netif; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_add_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F" - %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr), + ethaddr->addr[0], ethaddr->addr[1], ethaddr->addr[2], + ethaddr->addr[3], ethaddr->addr[4], ethaddr->addr[5])); + + netif = ip_route(ipaddr); + if (netif == NULL) { + return ERR_RTE; + } + + return update_arp_entry(netif, ipaddr, ethaddr, ETHARP_FLAG_TRY_HARD | ETHARP_FLAG_STATIC_ENTRY); +} + +/** Remove a static entry from the ARP table previously added with a call to + * etharp_add_static_entry. + * + * @param ipaddr IP address of the static entry to remove + * @return ERR_OK: entry removed + * ERR_MEM: entry wasn't found + * ERR_ARG: entry wasn't a static entry but a dynamic one + */ +err_t +etharp_remove_static_entry(ip_addr_t *ipaddr) +{ + s8_t i; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_remove_static_entry: %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n", + ip4_addr1_16(ipaddr), ip4_addr2_16(ipaddr), ip4_addr3_16(ipaddr), ip4_addr4_16(ipaddr))); + + /* find or create ARP entry */ + i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); + /* bail out if no entry could be found */ + if (i < 0) { + return (err_t)i; + } + + if ((arp_table[i].state != ETHARP_STATE_STABLE) || + (arp_table[i].static_entry == 0)) { + /* entry wasn't a static entry, cannot remove it */ + return ERR_ARG; + } + /* entry found, free it */ + free_entry(i); + return ERR_OK; +} +#endif /* ETHARP_SUPPORT_STATIC_ENTRIES */ + /** * Finds (stable) ethernet/IP address pair from ARP table * using interface and IP address index. @@ -541,18 +580,17 @@ update_arp_entry(struct netif *netif, struct ip_addr *ipaddr, struct eth_addr *e * @return table index if found, -1 otherwise */ s8_t -etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, - struct eth_addr **eth_ret, struct ip_addr **ip_ret) +etharp_find_addr(struct netif *netif, ip_addr_t *ipaddr, + struct eth_addr **eth_ret, ip_addr_t **ip_ret) { s8_t i; + LWIP_ASSERT("eth_ret != NULL && ip_ret != NULL", + eth_ret != NULL && ip_ret != NULL); + LWIP_UNUSED_ARG(netif); -#if LWIP_NETIF_HWADDRHINT - i = find_entry(ipaddr, ETHARP_FIND_ONLY, NULL); -#else /* LWIP_NETIF_HWADDRHINT */ - i = find_entry(ipaddr, ETHARP_FIND_ONLY); -#endif /* LWIP_NETIF_HWADDRHINT */ + i = find_entry(ipaddr, ETHARP_FLAG_FIND_ONLY); if((i >= 0) && arp_table[i].state == ETHARP_STATE_STABLE) { *eth_ret = &arp_table[i].ethaddr; *ip_ret = &arp_table[i].ipaddr; @@ -561,6 +599,7 @@ etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, return -1; } +#if ETHARP_TRUST_IP_MAC /** * Updates the ARP table using the given IP packet. * @@ -576,35 +615,39 @@ etharp_find_addr(struct netif *netif, struct ip_addr *ipaddr, * * @see pbuf_free() */ -void +static void etharp_ip_input(struct netif *netif, struct pbuf *p) { struct eth_hdr *ethhdr; struct ip_hdr *iphdr; + ip_addr_t iphdr_src; LWIP_ERROR("netif != NULL", (netif != NULL), return;); + /* Only insert an entry if the source IP address of the incoming IP packet comes from a host on the local network. */ - ethhdr = p->payload; + ethhdr = (struct eth_hdr *)p->payload; iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); #if ETHARP_SUPPORT_VLAN - if (ethhdr->type == ETHTYPE_VLAN) { + if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { iphdr = (struct ip_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); } #endif /* ETHARP_SUPPORT_VLAN */ + ip_addr_copy(iphdr_src, iphdr->src); + /* source is not on the local network? */ - if (!ip_addr_netcmp(&(iphdr->src), &(netif->ip_addr), &(netif->netmask))) { + if (!ip_addr_netcmp(&iphdr_src, &(netif->ip_addr), &(netif->netmask))) { /* do nothing */ return; } LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_ip_input: updating ETHARP table.\n")); - /* update ARP table */ - /* @todo We could use ETHARP_TRY_HARD if we think we are going to talk + /* update the source IP address in the cache, if present */ + /* @todo We could use ETHARP_FLAG_TRY_HARD if we think we are going to talk * back soon (for example, if the destination IP address is ours. */ - update_arp_entry(netif, &(iphdr->src), &(ethhdr->src), 0); + update_arp_entry(netif, &iphdr_src, &(ethhdr->src), ETHARP_FLAG_FIND_ONLY); } - +#endif /* ETHARP_TRUST_IP_MAC */ /** * Responds to ARP requests to us. Upon ARP replies to us, add entry to cache @@ -621,21 +664,20 @@ etharp_ip_input(struct netif *netif, struct pbuf *p) * * @see pbuf_free() */ -void +static void etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) { struct etharp_hdr *hdr; struct eth_hdr *ethhdr; /* these are aligned properly, whereas the ARP header fields might not be */ - struct ip_addr sipaddr, dipaddr; - u8_t i; + ip_addr_t sipaddr, dipaddr; u8_t for_us; #if LWIP_AUTOIP const u8_t * ethdst_hwaddr; #endif /* LWIP_AUTOIP */ LWIP_ERROR("netif != NULL", (netif != NULL), return;); - + /* drop short ARP packets: we have to check for p->len instead of p->tot_len here since a struct etharp_hdr is pointed to p->payload, so it musn't be chained! */ if (p->len < SIZEOF_ETHARP_PACKET) { @@ -648,22 +690,22 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) return; } - ethhdr = p->payload; + ethhdr = (struct eth_hdr *)p->payload; hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); #if ETHARP_SUPPORT_VLAN - if (ethhdr->type == ETHTYPE_VLAN) { + if (ethhdr->type == PP_HTONS(ETHTYPE_VLAN)) { hdr = (struct etharp_hdr *)(((u8_t*)ethhdr) + SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR); } #endif /* ETHARP_SUPPORT_VLAN */ /* RFC 826 "Packet Reception": */ - if ((hdr->hwtype != htons(HWTYPE_ETHERNET)) || - (hdr->_hwlen_protolen != htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr))) || - (hdr->proto != htons(ETHTYPE_IP)) || - (ethhdr->type != htons(ETHTYPE_ARP))) { + if ((hdr->hwtype != PP_HTONS(HWTYPE_ETHERNET)) || + (hdr->hwlen != ETHARP_HWADDR_LEN) || + (hdr->protolen != sizeof(ip_addr_t)) || + (hdr->proto != PP_HTONS(ETHTYPE_IP))) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, - ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", - hdr->hwtype, ARPH_HWLEN(hdr), hdr->proto, ARPH_PROTOLEN(hdr), ethhdr->type)); + ("etharp_arp_input: packet dropped, wrong hw type, hwlen, proto, protolen or ethernet type (%"U16_F"/%"U16_F"/%"U16_F"/%"U16_F")\n", + hdr->hwtype, hdr->hwlen, hdr->proto, hdr->protolen)); ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); pbuf_free(p); @@ -680,32 +722,29 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without * structure packing (not using structure copy which breaks strict-aliasing rules). */ - SMEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr)); - SMEMCPY(&dipaddr, &hdr->dipaddr, sizeof(dipaddr)); + IPADDR2_COPY(&sipaddr, &hdr->sipaddr); + IPADDR2_COPY(&dipaddr, &hdr->dipaddr); /* this interface is not configured? */ - if (netif->ip_addr.addr == 0) { + if (ip_addr_isany(&netif->ip_addr)) { for_us = 0; } else { /* ARP packet directed to us? */ - for_us = ip_addr_cmp(&dipaddr, &(netif->ip_addr)); + for_us = (u8_t)ip_addr_cmp(&dipaddr, &(netif->ip_addr)); } - /* ARP message directed to us? */ - if (for_us) { - /* add IP address in ARP cache; assume requester wants to talk to us. - * can result in directly sending the queued packets for this host. */ - update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), ETHARP_TRY_HARD); - /* ARP message not directed to us? */ - } else { - /* update the source IP address in the cache, if present */ - update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), 0); - } + /* ARP message directed to us? + -> add IP address in ARP cache; assume requester wants to talk to us, + can result in directly sending the queued packets for this host. + ARP message not directed to us? + -> update the source IP address in the cache, if present */ + update_arp_entry(netif, &sipaddr, &(hdr->shwaddr), + for_us ? ETHARP_FLAG_TRY_HARD : ETHARP_FLAG_FIND_ONLY); /* now act on the message itself */ - switch (htons(hdr->opcode)) { + switch (hdr->opcode) { /* ARP request? */ - case ARP_REQUEST: + case PP_HTONS(ARP_REQUEST): /* ARP request. If it asked for our address, we send out a * reply. In any case, we time-stamp any existing ARP entry, * and possiby send out an IP packet that was queued on it. */ @@ -720,29 +759,26 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) that would allocate a new pbuf. */ hdr->opcode = htons(ARP_REPLY); - hdr->dipaddr = hdr->sipaddr; - SMEMCPY(&hdr->sipaddr, &netif->ip_addr, sizeof(hdr->sipaddr)); + IPADDR2_COPY(&hdr->dipaddr, &hdr->sipaddr); + IPADDR2_COPY(&hdr->sipaddr, &netif->ip_addr); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); - i = ETHARP_HWADDR_LEN; #if LWIP_AUTOIP - /* If we are using Link-Local, ARP packets must be broadcast on the - * link layer. (See RFC3927 Section 2.5) */ - ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + ethdst_hwaddr = ip_addr_islinklocal(&netif->ip_addr) ? (u8_t*)(ethbroadcast.addr) : hdr->shwaddr.addr; #endif /* LWIP_AUTOIP */ - while(i > 0) { - i--; - hdr->dhwaddr.addr[i] = hdr->shwaddr.addr[i]; + ETHADDR16_COPY(&hdr->dhwaddr, &hdr->shwaddr); #if LWIP_AUTOIP - ethhdr->dest.addr[i] = ethdst_hwaddr[i]; + ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); #else /* LWIP_AUTOIP */ - ethhdr->dest.addr[i] = hdr->shwaddr.addr[i]; + ETHADDR16_COPY(ðhdr->dest, &hdr->shwaddr); #endif /* LWIP_AUTOIP */ - hdr->shwaddr.addr[i] = ethaddr->addr[i]; - ethhdr->src.addr[i] = ethaddr->addr[i]; - } + ETHADDR16_COPY(&hdr->shwaddr, ethaddr); + ETHADDR16_COPY(ðhdr->src, ethaddr); /* hwtype, hwaddr_len, proto, protolen and the type in the ethernet header are already correct, we tested that before */ @@ -750,7 +786,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) /* return ARP reply */ netif->linkoutput(netif, p); /* we are not configured? */ - } else if (netif->ip_addr.addr == 0) { + } else if (ip_addr_isany(&netif->ip_addr)) { /* { for_us == 0 and netif->ip_addr.addr == 0 } */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: we are unconfigured, ARP request ignored.\n")); /* request was not directed to us */ @@ -759,7 +795,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP request was not for us.\n")); } break; - case ARP_REPLY: + case PP_HTONS(ARP_REPLY): /* ARP reply. We already updated the ARP cache earlier. */ LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: incoming ARP reply\n")); #if (LWIP_DHCP && DHCP_DOES_ARP_CHECK) @@ -768,7 +804,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) * want to take a duplicate IP address on a single network. * @todo How should we handle redundant (fail-over) interfaces? */ dhcp_arp_reply(netif, &sipaddr); -#endif +#endif /* (LWIP_DHCP && DHCP_DOES_ARP_CHECK) */ break; default: LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_arp_input: ARP unknown opcode type %"S16_F"\n", htons(hdr->opcode))); @@ -798,7 +834,7 @@ etharp_arp_input(struct netif *netif, struct eth_addr *ethaddr, struct pbuf *p) * or the return type of either etharp_query() or etharp_send_ip(). */ err_t -etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) +etharp_output(struct netif *netif, struct pbuf *q, ip_addr_t *ipaddr) { struct eth_addr *dest, mcastaddr; @@ -834,17 +870,46 @@ etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) /* unicast destination IP address? */ } else { /* outside local network? */ - if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask))) { - /* interface has default gateway? */ - if (netif->gw.addr != 0) { - /* send to hardware address of default gateway IP address */ - ipaddr = &(netif->gw); - /* no default gateway available */ - } else { - /* no route to destination error (default gateway missing) */ - return ERR_RTE; + if (!ip_addr_netcmp(ipaddr, &(netif->ip_addr), &(netif->netmask)) && + !ip_addr_islinklocal(ipaddr)) { +#if LWIP_AUTOIP + struct ip_hdr *iphdr = (struct ip_hdr*)((u8_t*)q->payload + + sizeof(struct eth_hdr)); + /* According to RFC 3297, chapter 2.6.2 (Forwarding Rules), a packet with + a link-local source address must always be "directly to its destination + on the same physical link. The host MUST NOT send the packet to any + router for forwarding". */ + if (!ip_addr_islinklocal(&iphdr->src)) +#endif /* LWIP_AUTOIP */ + { + /* interface has default gateway? */ + if (!ip_addr_isany(&netif->gw)) { + /* send to hardware address of default gateway IP address */ + ipaddr = &(netif->gw); + /* no default gateway available */ + } else { + /* no route to destination error (default gateway missing) */ + return ERR_RTE; + } + } + } +#if LWIP_NETIF_HWADDRHINT + if (netif->addr_hint != NULL) { + /* per-pcb cached entry was given */ + u8_t etharp_cached_entry = *(netif->addr_hint); + if (etharp_cached_entry < ARP_TABLE_SIZE) { +#endif /* LWIP_NETIF_HWADDRHINT */ + if ((arp_table[etharp_cached_entry].state == ETHARP_STATE_STABLE) && + (ip_addr_cmp(ipaddr, &arp_table[etharp_cached_entry].ipaddr))) { + /* the per-pcb-cached entry is stable and the right one! */ + ETHARP_STATS_INC(etharp.cachehit); + return etharp_send_ip(netif, q, (struct eth_addr*)(netif->hwaddr), + &arp_table[etharp_cached_entry].ethaddr); + } +#if LWIP_NETIF_HWADDRHINT } } +#endif /* LWIP_NETIF_HWADDRHINT */ /* queue on destination Ethernet address belonging to ipaddr */ return etharp_query(netif, ipaddr, q); } @@ -889,7 +954,7 @@ etharp_output(struct netif *netif, struct pbuf *q, struct ip_addr *ipaddr) * */ err_t -etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) +etharp_query(struct netif *netif, ip_addr_t *ipaddr, struct pbuf *q) { struct eth_addr * srcaddr = (struct eth_addr *)netif->hwaddr; err_t result = ERR_MEM; @@ -904,11 +969,7 @@ etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) } /* find entry in ARP cache, ask to create entry if queueing packet */ -#if LWIP_NETIF_HWADDRHINT - i = find_entry(ipaddr, ETHARP_TRY_HARD, netif); -#else /* LWIP_NETIF_HWADDRHINT */ - i = find_entry(ipaddr, ETHARP_TRY_HARD); -#endif /* LWIP_NETIF_HWADDRHINT */ + i = find_entry(ipaddr, ETHARP_FLAG_TRY_HARD); /* could not find or create entry? */ if (i < 0) { @@ -940,85 +1001,94 @@ etharp_query(struct netif *netif, struct ip_addr *ipaddr, struct pbuf *q) since this failure could be temporary, and the next packet calling etharp_query again could lead to sending the queued packets. */ } + if (q == NULL) { + return result; + } } - + /* packet given? */ - if (q != NULL) { - /* stable entry? */ - if (arp_table[i].state == ETHARP_STATE_STABLE) { - /* we have a valid IP->Ethernet address mapping */ - /* send the packet */ - result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); - /* pending entry? (either just created or already pending */ - } else if (arp_table[i].state == ETHARP_STATE_PENDING) { -#if ARP_QUEUEING /* queue the given q packet */ - struct pbuf *p; - int copy_needed = 0; - /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but - * to copy the whole queue into a new PBUF_RAM (see bug #11400) - * PBUF_ROMs can be left as they are, since ROM must not get changed. */ - p = q; - while (p) { - LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); - if(p->type != PBUF_ROM) { - copy_needed = 1; - break; - } - p = p->next; + LWIP_ASSERT("q != NULL", q != NULL); + /* stable entry? */ + if (arp_table[i].state == ETHARP_STATE_STABLE) { + /* we have a valid IP->Ethernet address mapping */ + ETHARP_SET_HINT(netif, i); + /* send the packet */ + result = etharp_send_ip(netif, q, srcaddr, &(arp_table[i].ethaddr)); + /* pending entry? (either just created or already pending */ + } else if (arp_table[i].state == ETHARP_STATE_PENDING) { + /* entry is still pending, queue the given packet 'q' */ + struct pbuf *p; + int copy_needed = 0; + /* IF q includes a PBUF_REF, PBUF_POOL or PBUF_RAM, we have no choice but + * to copy the whole queue into a new PBUF_RAM (see bug #11400) + * PBUF_ROMs can be left as they are, since ROM must not get changed. */ + p = q; + while (p) { + LWIP_ASSERT("no packet queues allowed!", (p->len != p->tot_len) || (p->next == 0)); + if(p->type != PBUF_ROM) { + copy_needed = 1; + break; } - if(copy_needed) { - /* copy the whole packet into new pbufs */ - p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); - if(p != NULL) { - if (pbuf_copy(p, q) != ERR_OK) { - pbuf_free(p); - p = NULL; - } + p = p->next; + } + if(copy_needed) { + /* copy the whole packet into new pbufs */ + p = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); + if(p != NULL) { + if (pbuf_copy(p, q) != ERR_OK) { + pbuf_free(p); + p = NULL; } - } else { - /* referencing the old pbuf is enough */ - p = q; - pbuf_ref(p); } - /* packet could be taken over? */ - if (p != NULL) { - /* queue packet ... */ - struct etharp_q_entry *new_entry; - /* allocate a new arp queue entry */ - new_entry = memp_malloc(MEMP_ARP_QUEUE); - if (new_entry != NULL) { - new_entry->next = 0; - new_entry->p = p; - if(arp_table[i].q != NULL) { - /* queue was already existent, append the new entry to the end */ - struct etharp_q_entry *r; - r = arp_table[i].q; - while (r->next != NULL) { - r = r->next; - } - r->next = new_entry; - } else { - /* queue did not exist, first item in queue */ - arp_table[i].q = new_entry; + } else { + /* referencing the old pbuf is enough */ + p = q; + pbuf_ref(p); + } + /* packet could be taken over? */ + if (p != NULL) { + /* queue packet ... */ +#if ARP_QUEUEING + struct etharp_q_entry *new_entry; + /* allocate a new arp queue entry */ + new_entry = (struct etharp_q_entry *)memp_malloc(MEMP_ARP_QUEUE); + if (new_entry != NULL) { + new_entry->next = 0; + new_entry->p = p; + if(arp_table[i].q != NULL) { + /* queue was already existent, append the new entry to the end */ + struct etharp_q_entry *r; + r = arp_table[i].q; + while (r->next != NULL) { + r = r->next; } - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); - result = ERR_OK; + r->next = new_entry; } else { - /* the pool MEMP_ARP_QUEUE is empty */ - pbuf_free(p); - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - /* { result == ERR_MEM } through initialization */ + /* queue did not exist, first item in queue */ + arp_table[i].q = new_entry; } + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + result = ERR_OK; } else { - ETHARP_STATS_INC(etharp.memerr); + /* the pool MEMP_ARP_QUEUE is empty */ + pbuf_free(p); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); - /* { result == ERR_MEM } through initialization */ + result = ERR_MEM; } -#else /* ARP_QUEUEING == 0 */ - /* q && state == PENDING && ARP_QUEUEING == 0 => result = ERR_MEM */ - /* { result == ERR_MEM } through initialization */ - LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: Ethernet destination address unknown, queueing disabled, packet %p dropped\n", (void *)q)); -#endif +#else /* ARP_QUEUEING */ + /* always queue one packet per ARP request only, freeing a previously queued packet */ + if (arp_table[i].q != NULL) { + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: dropped previously queued packet %p for ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); + pbuf_free(arp_table[i].q); + } + arp_table[i].q = p; + result = ERR_OK; + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: queued packet %p on ARP entry %"S16_F"\n", (void *)q, (s16_t)i)); +#endif /* ARP_QUEUEING */ + } else { + ETHARP_STATS_INC(etharp.memerr); + LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_query: could not queue a copy of PBUF_REF packet %p (out of memory)\n", (void *)q)); + result = ERR_MEM; } } return result; @@ -1045,13 +1115,12 @@ static err_t etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, const struct eth_addr *ethdst_addr, - const struct eth_addr *hwsrc_addr, const struct ip_addr *ipsrc_addr, - const struct eth_addr *hwdst_addr, const struct ip_addr *ipdst_addr, + const struct eth_addr *hwsrc_addr, const ip_addr_t *ipsrc_addr, + const struct eth_addr *hwdst_addr, const ip_addr_t *ipdst_addr, const u16_t opcode) { struct pbuf *p; err_t result = ERR_OK; - u8_t k; /* ARP entry index */ struct eth_hdr *ethhdr; struct etharp_hdr *hdr; #if LWIP_AUTOIP @@ -1070,42 +1139,41 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, LWIP_ASSERT("check that first pbuf can hold struct etharp_hdr", (p->len >= SIZEOF_ETHARP_PACKET)); - ethhdr = p->payload; + ethhdr = (struct eth_hdr *)p->payload; hdr = (struct etharp_hdr *)((u8_t*)ethhdr + SIZEOF_ETH_HDR); LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_raw: sending raw ARP packet.\n")); hdr->opcode = htons(opcode); LWIP_ASSERT("netif->hwaddr_len must be the same as ETHARP_HWADDR_LEN for etharp!", (netif->hwaddr_len == ETHARP_HWADDR_LEN)); - k = ETHARP_HWADDR_LEN; #if LWIP_AUTOIP - /* If we are using Link-Local, ARP packets must be broadcast on the - * link layer. (See RFC3927 Section 2.5) */ - ethdst_hwaddr = ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; + /* If we are using Link-Local, all ARP packets that contain a Link-Local + * 'sender IP address' MUST be sent using link-layer broadcast instead of + * link-layer unicast. (See RFC3927 Section 2.5, last paragraph) */ + ethdst_hwaddr = ip_addr_islinklocal(ipsrc_addr) ? (u8_t*)(ethbroadcast.addr) : ethdst_addr->addr; #endif /* LWIP_AUTOIP */ - /* Write MAC-Addresses (combined loop for both headers) */ - while(k > 0) { - k--; - /* Write the ARP MAC-Addresses */ - hdr->shwaddr.addr[k] = hwsrc_addr->addr[k]; - hdr->dhwaddr.addr[k] = hwdst_addr->addr[k]; - /* Write the Ethernet MAC-Addresses */ + /* Write the ARP MAC-Addresses */ + ETHADDR16_COPY(&hdr->shwaddr, hwsrc_addr); + ETHADDR16_COPY(&hdr->dhwaddr, hwdst_addr); + /* Write the Ethernet MAC-Addresses */ #if LWIP_AUTOIP - ethhdr->dest.addr[k] = ethdst_hwaddr[k]; + ETHADDR16_COPY(ðhdr->dest, ethdst_hwaddr); #else /* LWIP_AUTOIP */ - ethhdr->dest.addr[k] = ethdst_addr->addr[k]; + ETHADDR16_COPY(ðhdr->dest, ethdst_addr); #endif /* LWIP_AUTOIP */ - ethhdr->src.addr[k] = ethsrc_addr->addr[k]; - } - hdr->sipaddr = *(struct ip_addr2 *)ipsrc_addr; - hdr->dipaddr = *(struct ip_addr2 *)ipdst_addr; + ETHADDR16_COPY(ðhdr->src, ethsrc_addr); + /* Copy struct ip_addr2 to aligned ip_addr, to support compilers without + * structure packing. */ + IPADDR2_COPY(&hdr->sipaddr, ipsrc_addr); + IPADDR2_COPY(&hdr->dipaddr, ipdst_addr); - hdr->hwtype = htons(HWTYPE_ETHERNET); - hdr->proto = htons(ETHTYPE_IP); - /* set hwlen and protolen together */ - hdr->_hwlen_protolen = htons((ETHARP_HWADDR_LEN << 8) | sizeof(struct ip_addr)); + hdr->hwtype = PP_HTONS(HWTYPE_ETHERNET); + hdr->proto = PP_HTONS(ETHTYPE_IP); + /* set hwlen and protolen */ + hdr->hwlen = ETHARP_HWADDR_LEN; + hdr->protolen = sizeof(ip_addr_t); - ethhdr->type = htons(ETHTYPE_ARP); + ethhdr->type = PP_HTONS(ETHTYPE_ARP); /* send ARP query */ result = netif->linkoutput(netif, p); ETHARP_STATS_INC(etharp.xmit); @@ -1127,13 +1195,14 @@ etharp_raw(struct netif *netif, const struct eth_addr *ethsrc_addr, * any other err_t on failure */ err_t -etharp_request(struct netif *netif, struct ip_addr *ipaddr) +etharp_request(struct netif *netif, ip_addr_t *ipaddr) { LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("etharp_request: sending ARP request.\n")); return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, ðbroadcast, (struct eth_addr *)netif->hwaddr, &netif->ip_addr, ðzero, ipaddr, ARP_REQUEST); } +#endif /* LWIP_ARP */ /** * Process received ethernet frames. Using this function instead of directly @@ -1148,21 +1217,35 @@ ethernet_input(struct pbuf *p, struct netif *netif) { struct eth_hdr* ethhdr; u16_t type; + s16_t ip_hdr_offset = SIZEOF_ETH_HDR; + + if (p->len <= SIZEOF_ETH_HDR) { + /* a packet with only an ethernet header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } /* points to packet payload, which starts with an Ethernet header */ - ethhdr = p->payload; + ethhdr = (struct eth_hdr *)p->payload; LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, - ("ethernet_input: dest:%02x:%02x:%02x:%02x:%02x:%02x, src:%02x:%02x:%02x:%02x:%02x:%02x, type:%2hx\n", + ("ethernet_input: dest:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", src:%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F":%"X8_F", type:%"X16_F"\n", (unsigned)ethhdr->dest.addr[0], (unsigned)ethhdr->dest.addr[1], (unsigned)ethhdr->dest.addr[2], (unsigned)ethhdr->dest.addr[3], (unsigned)ethhdr->dest.addr[4], (unsigned)ethhdr->dest.addr[5], (unsigned)ethhdr->src.addr[0], (unsigned)ethhdr->src.addr[1], (unsigned)ethhdr->src.addr[2], (unsigned)ethhdr->src.addr[3], (unsigned)ethhdr->src.addr[4], (unsigned)ethhdr->src.addr[5], (unsigned)htons(ethhdr->type))); - type = htons(ethhdr->type); + type = ethhdr->type; #if ETHARP_SUPPORT_VLAN - if (type == ETHTYPE_VLAN) { + if (type == PP_HTONS(ETHTYPE_VLAN)) { struct eth_vlan_hdr *vlan = (struct eth_vlan_hdr*)(((char*)ethhdr) + SIZEOF_ETH_HDR); + if (p->len <= SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR) { + /* a packet with only an ethernet/vlan header (or less) is not valid for us */ + ETHARP_STATS_INC(etharp.proterr); + ETHARP_STATS_INC(etharp.drop); + goto free_and_return; + } #ifdef ETHARP_VLAN_CHECK /* if not, allow all VLANs */ if (VLAN_ID(vlan) != ETHARP_VLAN_CHECK) { /* silently ignore this packet: not for our VLAN */ @@ -1170,39 +1253,50 @@ ethernet_input(struct pbuf *p, struct netif *netif) return ERR_OK; } #endif /* ETHARP_VLAN_CHECK */ - type = htons(vlan->tpid); + type = vlan->tpid; + ip_hdr_offset = SIZEOF_ETH_HDR + SIZEOF_VLAN_HDR; } #endif /* ETHARP_SUPPORT_VLAN */ +#if LWIP_ARP_FILTER_NETIF + netif = LWIP_ARP_FILTER_NETIF_FN(p, netif, htons(type)); +#endif /* LWIP_ARP_FILTER_NETIF*/ + switch (type) { +#if LWIP_ARP /* IP packet? */ - case ETHTYPE_IP: + case PP_HTONS(ETHTYPE_IP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } #if ETHARP_TRUST_IP_MAC /* update ARP table */ etharp_ip_input(netif, p); #endif /* ETHARP_TRUST_IP_MAC */ /* skip Ethernet header */ - if(pbuf_header(p, -(s16_t)SIZEOF_ETH_HDR)) { + if(pbuf_header(p, -ip_hdr_offset)) { LWIP_ASSERT("Can't move over header in packet", 0); - pbuf_free(p); - p = NULL; + goto free_and_return; } else { /* pass to IP layer */ ip_input(p, netif); } break; - case ETHTYPE_ARP: + case PP_HTONS(ETHTYPE_ARP): + if (!(netif->flags & NETIF_FLAG_ETHARP)) { + goto free_and_return; + } /* pass p to ARP module */ etharp_arp_input(netif, (struct eth_addr*)(netif->hwaddr), p); break; - +#endif /* LWIP_ARP */ #if PPPOE_SUPPORT - case ETHTYPE_PPPOEDISC: /* PPP Over Ethernet Discovery Stage */ + case PP_HTONS(ETHTYPE_PPPOEDISC): /* PPP Over Ethernet Discovery Stage */ pppoe_disc_input(netif, p); break; - case ETHTYPE_PPPOE: /* PPP Over Ethernet Session Stage */ + case PP_HTONS(ETHTYPE_PPPOE): /* PPP Over Ethernet Session Stage */ pppoe_data_input(netif, p); break; #endif /* PPPOE_SUPPORT */ @@ -1210,13 +1304,15 @@ ethernet_input(struct pbuf *p, struct netif *netif) default: ETHARP_STATS_INC(etharp.proterr); ETHARP_STATS_INC(etharp.drop); - pbuf_free(p); - p = NULL; - break; + goto free_and_return; } /* This means the pbuf is freed or consumed, so the caller doesn't have to free it again */ return ERR_OK; + +free_and_return: + pbuf_free(p); + return ERR_OK; } -#endif /* LWIP_ARP */ +#endif /* LWIP_ARP || LWIP_ETHERNET */ diff --git a/core/lwip/src/netif/loopif.c b/core/lwip/src/netif/loopif.c deleted file mode 100644 index 1e1f28cf..00000000 --- a/core/lwip/src/netif/loopif.c +++ /dev/null @@ -1,66 +0,0 @@ -/** - * @file - * Loop Interface - * - */ - -/* - * Copyright (c) 2001-2004 Swedish Institute of Computer Science. - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, - * this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * 3. The name of the author may not be used to endorse or promote products - * derived from this software without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT - * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT - * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING - * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY - * OF SUCH DAMAGE. - * - * This file is part of the lwIP TCP/IP stack. - * - * Author: Adam Dunkels <adam@sics.se> - * - */ -#include "lwip/opt.h" - -#if LWIP_HAVE_LOOPIF - -#include "netif/loopif.h" -#include "lwip/snmp.h" - -/** - * Initialize a lwip network interface structure for a loopback interface - * - * @param netif the lwip network interface structure for this loopif - * @return ERR_OK if the loopif is initialized - * ERR_MEM if private data couldn't be allocated - */ -err_t -loopif_init(struct netif *netif) -{ - /* initialize the snmp variables and counters inside the struct netif - * ifSpeed: no assumption can be made! - */ - NETIF_INIT_SNMP(netif, snmp_ifType_softwareLoopback, 0); - - netif->name[0] = 'l'; - netif->name[1] = 'o'; - netif->output = netif_loop_output; - return ERR_OK; -} - -#endif /* LWIP_HAVE_LOOPIF */ diff --git a/core/lwip/src/netif/ppp/auth.c b/core/lwip/src/netif/ppp/auth.c index cbd3eb21..c3c49d22 100644 --- a/core/lwip/src/netif/ppp/auth.c +++ b/core/lwip/src/netif/ppp/auth.c @@ -82,11 +82,104 @@ #include "cbcp.h" #endif /* CBCP_SUPPORT */ +#include "lwip/inet.h" + #include <string.h> -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ +#if 0 /* UNUSED */ +/* Bits in scan_authfile return value */ +#define NONWILD_SERVER 1 +#define NONWILD_CLIENT 2 + +#define ISWILD(word) (word[0] == '*' && word[1] == 0) +#endif /* UNUSED */ + +#if PAP_SUPPORT || CHAP_SUPPORT +/* The name by which the peer authenticated itself to us. */ +static char peer_authname[MAXNAMELEN]; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +/* Records which authentication operations haven't completed yet. */ +static int auth_pending[NUM_PPP]; + +/* Set if we have successfully called plogin() */ +static int logged_in; + +/* Set if we have run the /etc/ppp/auth-up script. */ +static int did_authup; /* @todo, we don't need this in lwip*/ + +/* List of addresses which the peer may use. */ +static struct wordlist *addresses[NUM_PPP]; + +#if 0 /* UNUSED */ +/* Wordlist giving addresses which the peer may use + without authenticating itself. */ +static struct wordlist *noauth_addrs; + +/* Extra options to apply, from the secrets file entry for the peer. */ +static struct wordlist *extra_options; +#endif /* UNUSED */ + +/* Number of network protocols which we have opened. */ +static int num_np_open; + +/* Number of network protocols which have come up. */ +static int num_np_up; + +#if PAP_SUPPORT || CHAP_SUPPORT +/* Set if we got the contents of passwd[] from the pap-secrets file. */ +static int passwd_from_file; +#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + +#if 0 /* UNUSED */ +/* Set if we require authentication only because we have a default route. */ +static bool default_auth; + +/* Hook to enable a plugin to control the idle time limit */ +int (*idle_time_hook) __P((struct ppp_idle *)) = NULL; + +/* Hook for a plugin to say whether we can possibly authenticate any peer */ +int (*pap_check_hook) __P((void)) = NULL; + +/* Hook for a plugin to check the PAP user and password */ +int (*pap_auth_hook) __P((char *user, char *passwd, char **msgp, + struct wordlist **paddrs, + struct wordlist **popts)) = NULL; + +/* Hook for a plugin to know about the PAP user logout */ +void (*pap_logout_hook) __P((void)) = NULL; + +/* Hook for a plugin to get the PAP password for authenticating us */ +int (*pap_passwd_hook) __P((char *user, char *passwd)) = NULL; + +/* + * This is used to ensure that we don't start an auth-up/down + * script while one is already running. + */ +enum script_state { + s_down, + s_up +}; + +static enum script_state auth_state = s_down; +static enum script_state auth_script_state = s_down; +static pid_t auth_script_pid = 0; + +/* + * Option variables. + * lwip: some of these are present in the ppp_settings structure + */ +bool uselogin = 0; /* Use /etc/passwd for checking PAP */ +bool cryptpap = 0; /* Passwords in pap-secrets are encrypted */ +bool refuse_pap = 0; /* Don't wanna auth. ourselves with PAP */ +bool refuse_chap = 0; /* Don't wanna auth. ourselves with CHAP */ +bool usehostname = 0; /* Use hostname for our_name */ +bool auth_required = 0; /* Always require authentication from peer */ +bool allow_any_ip = 0; /* Allow peer to use any IP address */ +bool explicit_remote = 0; /* User specified explicit remote name */ +char remote_name[MAXNAMELEN]; /* Peer's name for authentication */ + +#endif /* UNUSED */ /* Bits in auth_pending[] */ #define PAP_WITHPEER 1 @@ -94,10 +187,7 @@ #define CHAP_WITHPEER 4 #define CHAP_PEER 8 - -/************************/ -/*** LOCAL DATA TYPES ***/ -/************************/ +/* @todo, move this somewhere */ /* Used for storing a sequence of words. Usually malloced. */ struct wordlist { struct wordlist *next; @@ -105,9 +195,6 @@ struct wordlist { }; -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ extern char *crypt (const char *, const char *); /* Prototypes for procedures local to this file. */ @@ -116,63 +203,172 @@ static void network_phase (int); static void check_idle (void *); static void connect_time_expired (void *); #if 0 -static int login (char *, char *, char **, int *); +static int plogin (char *, char *, char **, int *); #endif -static void logout (void); +static void plogout (void); static int null_login (int); static int get_pap_passwd (int, char *, char *); static int have_pap_secret (void); static int have_chap_secret (char *, char *, u32_t); static int ip_addr_check (u32_t, struct wordlist *); + #if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ -static void set_allowed_addrs(int unit, struct wordlist *addrs); +static int scan_authfile (FILE *, char *, char *, char *, + struct wordlist **, struct wordlist **, + char *); static void free_wordlist (struct wordlist *); +static void auth_script (char *); +static void auth_script_done (void *); +static void set_allowed_addrs (int unit, struct wordlist *addrs); +static int some_ip_ok (struct wordlist *); +static int setupapfile (char **); +static int privgroup (char **); +static int set_noauth_addr (char **); +static void check_access (FILE *, char *); #endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ -#if CBCP_SUPPORT -static void callback_phase (int); -#endif /* CBCP_SUPPORT */ - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ - - -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ -#if PAP_SUPPORT || CHAP_SUPPORT -/* The name by which the peer authenticated itself to us. */ -static char peer_authname[MAXNAMELEN]; -#endif /* PAP_SUPPORT || CHAP_SUPPORT */ - -/* Records which authentication operations haven't completed yet. */ -static int auth_pending[NUM_PPP]; - -/* Set if we have successfully called login() */ -static int logged_in; +#if 0 /* UNUSED */ +/* + * Authentication-related options. + */ +option_t auth_options[] = { + { "require-pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", 1, &auth_required }, + { "+pap", o_bool, &lcp_wantoptions[0].neg_upap, + "Require PAP authentication from peer", 1, &auth_required }, + { "refuse-pap", o_bool, &refuse_pap, + "Don't agree to auth to peer with PAP", 1 }, + { "-pap", o_bool, &refuse_pap, + "Don't allow PAP authentication with peer", 1 }, + { "require-chap", o_bool, &lcp_wantoptions[0].neg_chap, + "Require CHAP authentication from peer", 1, &auth_required }, + { "+chap", o_bool, &lcp_wantoptions[0].neg_chap, + "Require CHAP authentication from peer", 1, &auth_required }, + { "refuse-chap", o_bool, &refuse_chap, + "Don't agree to auth to peer with CHAP", 1 }, + { "-chap", o_bool, &refuse_chap, + "Don't allow CHAP authentication with peer", 1 }, + { "name", o_string, our_name, + "Set local name for authentication", + OPT_PRIV|OPT_STATIC, NULL, MAXNAMELEN }, + { "user", o_string, user, + "Set name for auth with peer", OPT_STATIC, NULL, MAXNAMELEN }, + { "usehostname", o_bool, &usehostname, + "Must use hostname for authentication", 1 }, + { "remotename", o_string, remote_name, + "Set remote name for authentication", OPT_STATIC, + &explicit_remote, MAXNAMELEN }, + { "auth", o_bool, &auth_required, + "Require authentication from peer", 1 }, + { "noauth", o_bool, &auth_required, + "Don't require peer to authenticate", OPT_PRIV, &allow_any_ip }, + { "login", o_bool, &uselogin, + "Use system password database for PAP", 1 }, + { "papcrypt", o_bool, &cryptpap, + "PAP passwords are encrypted", 1 }, + { "+ua", o_special, (void *)setupapfile, + "Get PAP user and password from file" }, + { "password", o_string, passwd, + "Password for authenticating us to the peer", OPT_STATIC, + NULL, MAXSECRETLEN }, + { "privgroup", o_special, (void *)privgroup, + "Allow group members to use privileged options", OPT_PRIV }, + { "allow-ip", o_special, (void *)set_noauth_addr, + "Set IP address(es) which can be used without authentication", + OPT_PRIV }, + { NULL } +}; +#endif /* UNUSED */ +#if 0 /* UNUSED */ +/* + * setupapfile - specifies UPAP info for authenticating with peer. + */ +static int +setupapfile(char **argv) +{ + FILE * ufile; + int l; + + lcp_allowoptions[0].neg_upap = 1; + + /* open user info file */ + seteuid(getuid()); + ufile = fopen(*argv, "r"); + seteuid(0); + if (ufile == NULL) { + option_error("unable to open user login data file %s", *argv); + return 0; + } + check_access(ufile, *argv); -/* Set if we have run the /etc/ppp/auth-up script. */ -static int did_authup; + /* get username */ + if (fgets(user, MAXNAMELEN - 1, ufile) == NULL + || fgets(passwd, MAXSECRETLEN - 1, ufile) == NULL){ + option_error("unable to read user login data file %s", *argv); + return 0; + } + fclose(ufile); -/* List of addresses which the peer may use. */ -static struct wordlist *addresses[NUM_PPP]; + /* get rid of newlines */ + l = strlen(user); + if (l > 0 && user[l-1] == '\n') + user[l-1] = 0; + l = strlen(passwd); + if (l > 0 && passwd[l-1] == '\n') + passwd[l-1] = 0; -/* Number of network protocols which we have opened. */ -static int num_np_open; + return (1); +} +#endif /* UNUSED */ -/* Number of network protocols which have come up. */ -static int num_np_up; +#if 0 /* UNUSED */ +/* + * privgroup - allow members of the group to have privileged access. + */ +static int +privgroup(char **argv) +{ + struct group *g; + int i; -#if PAP_SUPPORT || CHAP_SUPPORT -/* Set if we got the contents of passwd[] from the pap-secrets file. */ -static int passwd_from_file; -#endif /* PAP_SUPPORT || CHAP_SUPPORT */ + g = getgrnam(*argv); + if (g == 0) { + option_error("group %s is unknown", *argv); + return 0; + } + for (i = 0; i < ngroups; ++i) { + if (groups[i] == g->gr_gid) { + privileged = 1; + break; + } + } + return 1; +} +#endif +#if 0 /* UNUSED */ +/* + * set_noauth_addr - set address(es) that can be used without authentication. + * Equivalent to specifying an entry like `"" * "" addr' in pap-secrets. + */ +static int +set_noauth_addr(char **argv) +{ + char *addr = *argv; + int l = strlen(addr); + struct wordlist *wp; + + wp = (struct wordlist *) malloc(sizeof(struct wordlist) + l + 1); + if (wp == NULL) + novm("allow-ip argument"); + wp->word = (char *) (wp + 1); + wp->next = noauth_addrs; + BCOPY(addr, wp->word, l); + noauth_addrs = wp; + return 1; +} +#endif /* UNUSED */ -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ /* * An Open on LCP has requested a change from Dead to Establish phase. * Do what's necessary to bring the physical layer up. @@ -182,7 +378,7 @@ link_required(int unit) { LWIP_UNUSED_ARG(unit); - AUTHDEBUG((LOG_INFO, "link_required: %d\n", unit)); + AUTHDEBUG(LOG_INFO, ("link_required: %d\n", unit)); } /* @@ -192,15 +388,15 @@ link_required(int unit) void link_terminated(int unit) { - AUTHDEBUG((LOG_INFO, "link_terminated: %d\n", unit)); + AUTHDEBUG(LOG_INFO, ("link_terminated: %d\n", unit)); if (lcp_phase[unit] == PHASE_DEAD) { return; } if (logged_in) { - logout(); + plogout(); } lcp_phase[unit] = PHASE_DEAD; - AUTHDEBUG((LOG_NOTICE, "Connection terminated.\n")); + AUTHDEBUG(LOG_NOTICE, ("Connection terminated.\n")); pppLinkTerminated(unit); } @@ -212,8 +408,9 @@ link_down(int unit) { int i; struct protent *protp; - - AUTHDEBUG((LOG_INFO, "link_down: %d\n", unit)); + + AUTHDEBUG(LOG_INFO, ("link_down: %d\n", unit)); + if (did_authup) { /* XXX Do link down processing. */ did_authup = 0; @@ -229,8 +426,9 @@ link_down(int unit) (*protp->close)(unit, "LCP down"); } } - num_np_open = 0; - num_np_up = 0; + num_np_open = 0; /* number of network protocols we have opened */ + num_np_up = 0; /* Number of network protocols which have come up */ + if (lcp_phase[unit] != PHASE_DEAD) { lcp_phase[unit] = PHASE_TERMINATE; } @@ -253,7 +451,7 @@ link_established(int unit) lcp_options *ho = &lcp_hisoptions[unit]; #endif /* PAP_SUPPORT || CHAP_SUPPORT */ - AUTHDEBUG((LOG_INFO, "link_established: %d\n", unit)); + AUTHDEBUG(LOG_INFO, ("link_established: unit %d; Lowering up all protocols...\n", unit)); /* * Tell higher-level protocols that LCP is up. */ @@ -269,12 +467,12 @@ link_established(int unit) * of "" and a password of "". If that's not OK, boot it out. */ if (!wo->neg_upap || !null_login(unit)) { - AUTHDEBUG((LOG_WARNING, "peer refused to authenticate\n")); + AUTHDEBUG(LOG_WARNING, ("peer refused to authenticate\n")); lcp_close(unit, "peer refused to authenticate"); return; } } - + lcp_phase[unit] = PHASE_AUTHENTICATE; auth = 0; #if CHAP_SUPPORT @@ -306,7 +504,7 @@ link_established(int unit) if (ppp_settings.passwd[0] == 0) { passwd_from_file = 1; if (!get_pap_passwd(unit, ppp_settings.user, ppp_settings.passwd)) { - AUTHDEBUG((LOG_ERR, "No secret found for PAP login\n")); + AUTHDEBUG(LOG_ERR, ("No secret found for PAP login\n")); } } upap_authwithpeer(unit, ppp_settings.user, ppp_settings.passwd); @@ -321,6 +519,52 @@ link_established(int unit) } /* + * Proceed to the network phase. + */ +static void +network_phase(int unit) +{ + int i; + struct protent *protp; + lcp_options *go = &lcp_gotoptions[unit]; + + /* + * If the peer had to authenticate, run the auth-up script now. + */ + if ((go->neg_chap || go->neg_upap) && !did_authup) { + /* XXX Do setup for peer authentication. */ + did_authup = 1; + } + +#if CBCP_SUPPORT + /* + * If we negotiated callback, do it now. + */ + if (go->neg_cbcp) { + lcp_phase[unit] = PHASE_CALLBACK; + (*cbcp_protent.open)(unit); + return; + } +#endif /* CBCP_SUPPORT */ + + lcp_phase[unit] = PHASE_NETWORK; + for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { + if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { + (*protp->open)(unit); + if (protp->protocol != PPP_CCP) { + ++num_np_open; + } + } + } + + if (num_np_open == 0) { + /* nothing to do */ + lcp_close(0, "No network protocols running"); + } +} +/* @todo: add void start_networks(void) here (pppd 2.3.11) */ + +/* * The peer has failed to authenticate himself using `protocol'. */ void @@ -328,7 +572,7 @@ auth_peer_fail(int unit, u16_t protocol) { LWIP_UNUSED_ARG(protocol); - AUTHDEBUG((LOG_INFO, "auth_peer_fail: %d proto=%X\n", unit, protocol)); + AUTHDEBUG(LOG_INFO, ("auth_peer_fail: %d proto=%X\n", unit, protocol)); /* * Authentication failure: take the link down */ @@ -344,8 +588,8 @@ void auth_peer_success(int unit, u16_t protocol, char *name, int namelen) { int pbit; - - AUTHDEBUG((LOG_INFO, "auth_peer_success: %d proto=%X\n", unit, protocol)); + + AUTHDEBUG(LOG_INFO, ("auth_peer_success: %d proto=%X\n", unit, protocol)); switch (protocol) { case PPP_CHAP: pbit = CHAP_PEER; @@ -354,14 +598,14 @@ auth_peer_success(int unit, u16_t protocol, char *name, int namelen) pbit = PAP_PEER; break; default: - AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); + AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); return; } - + /* * Save the authenticated name of the peer for later. */ - if (namelen > sizeof(peer_authname) - 1) { + if (namelen > (int)sizeof(peer_authname) - 1) { namelen = sizeof(peer_authname) - 1; } BCOPY(name, peer_authname, namelen); @@ -383,25 +627,21 @@ void auth_withpeer_fail(int unit, u16_t protocol) { int errCode = PPPERR_AUTHFAIL; - + LWIP_UNUSED_ARG(protocol); - AUTHDEBUG((LOG_INFO, "auth_withpeer_fail: %d proto=%X\n", unit, protocol)); + AUTHDEBUG(LOG_INFO, ("auth_withpeer_fail: %d proto=%X\n", unit, protocol)); if (passwd_from_file) { BZERO(ppp_settings.passwd, MAXSECRETLEN); } - /* - * XXX Warning: the unit number indicates the interface which is - * not necessarily the PPP connection. It works here as long - * as we are only supporting PPP interfaces. - */ - pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); /* * We've failed to authenticate ourselves to our peer. * He'll probably take the link down, and there's not much * we can do except wait for that. */ + pppIOCtl(unit, PPPCTLS_ERRCODE, &errCode); + lcp_close(unit, "Failed to authenticate ourselves to peer"); } /* @@ -411,8 +651,8 @@ void auth_withpeer_success(int unit, u16_t protocol) { int pbit; - - AUTHDEBUG((LOG_INFO, "auth_withpeer_success: %d proto=%X\n", unit, protocol)); + + AUTHDEBUG(LOG_INFO, ("auth_withpeer_success: %d proto=%X\n", unit, protocol)); switch (protocol) { case PPP_CHAP: pbit = CHAP_WITHPEER; @@ -424,10 +664,10 @@ auth_withpeer_success(int unit, u16_t protocol) pbit = PAP_WITHPEER; break; default: - AUTHDEBUG((LOG_WARNING, "auth_peer_success: unknown protocol %x\n", protocol)); + AUTHDEBUG(LOG_WARNING, ("auth_peer_success: unknown protocol %x\n", protocol)); pbit = 0; } - + /* * If there is no more authentication still being done, * proceed to the network (or callback) phase. @@ -448,16 +688,16 @@ np_up(int unit, u16_t proto) LWIP_UNUSED_ARG(unit); LWIP_UNUSED_ARG(proto); - AUTHDEBUG((LOG_INFO, "np_up: %d proto=%X\n", unit, proto)); + AUTHDEBUG(LOG_INFO, ("np_up: %d proto=%X\n", unit, proto)); if (num_np_up == 0) { - AUTHDEBUG((LOG_INFO, "np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); + AUTHDEBUG(LOG_INFO, ("np_up: maxconnect=%d idle_time_limit=%d\n",ppp_settings.maxconnect,ppp_settings.idle_time_limit)); /* * At this point we consider that the link has come up successfully. */ if (ppp_settings.idle_time_limit > 0) { TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit); } - + /* * Set a timeout to close the connection once the maximum * connect time has expired. @@ -478,7 +718,7 @@ np_down(int unit, u16_t proto) LWIP_UNUSED_ARG(unit); LWIP_UNUSED_ARG(proto); - AUTHDEBUG((LOG_INFO, "np_down: %d proto=%X\n", unit, proto)); + AUTHDEBUG(LOG_INFO, ("np_down: %d proto=%X\n", unit, proto)); if (--num_np_up == 0 && ppp_settings.idle_time_limit > 0) { UNTIMEOUT(check_idle, NULL); } @@ -493,7 +733,7 @@ np_finished(int unit, u16_t proto) LWIP_UNUSED_ARG(unit); LWIP_UNUSED_ARG(proto); - AUTHDEBUG((LOG_INFO, "np_finished: %d proto=%X\n", unit, proto)); + AUTHDEBUG(LOG_INFO, ("np_finished: %d proto=%X\n", unit, proto)); if (--num_np_open <= 0) { /* no further use for the link: shut up shop. */ lcp_close(0, "No network protocols running"); @@ -501,6 +741,85 @@ np_finished(int unit, u16_t proto) } /* + * check_idle - check whether the link has been idle for long + * enough that we can shut it down. + */ +static void +check_idle(void *arg) +{ + struct ppp_idle idle; + u_short itime; + + LWIP_UNUSED_ARG(arg); + if (!get_idle_time(0, &idle)) { + return; + } + itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); + if (itime >= ppp_settings.idle_time_limit) { + /* link is idle: shut it down. */ + AUTHDEBUG(LOG_INFO, ("Terminating connection due to lack of activity.\n")); + lcp_close(0, "Link inactive"); + } else { + TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); + } +} + +/* + * connect_time_expired - log a message and close the connection. + */ +static void +connect_time_expired(void *arg) +{ + LWIP_UNUSED_ARG(arg); + + AUTHDEBUG(LOG_INFO, ("Connect time expired\n")); + lcp_close(0, "Connect time expired"); /* Close connection */ +} + +#if 0 /* UNUSED */ +/* + * auth_check_options - called to check authentication options. + */ +void +auth_check_options(void) +{ + lcp_options *wo = &lcp_wantoptions[0]; + int can_auth; + ipcp_options *ipwo = &ipcp_wantoptions[0]; + u32_t remote; + + /* Default our_name to hostname, and user to our_name */ + if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { + strcpy(ppp_settings.our_name, ppp_settings.hostname); + } + + if (ppp_settings.user[0] == 0) { + strcpy(ppp_settings.user, ppp_settings.our_name); + } + + /* If authentication is required, ask peer for CHAP or PAP. */ + if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { + wo->neg_chap = 1; + wo->neg_upap = 1; + } + + /* + * Check whether we have appropriate secrets to use + * to authenticate the peer. + */ + can_auth = wo->neg_upap && have_pap_secret(); + if (!can_auth && wo->neg_chap) { + remote = ipwo->accept_remote? 0: ipwo->hisaddr; + can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); + } + + if (ppp_settings.auth_required && !can_auth) { + ppp_panic("No auth secret"); + } +} +#endif /* UNUSED */ + +/* * auth_reset - called when LCP is starting negotiations to recheck * authentication options, i.e. whether we have appropriate secrets * to use for authenticating ourselves and/or the peer. @@ -513,7 +832,7 @@ auth_reset(int unit) ipcp_options *ipwo = &ipcp_wantoptions[0]; u32_t remote; - AUTHDEBUG((LOG_INFO, "auth_reset: %d\n", unit)); + AUTHDEBUG(LOG_INFO, ("auth_reset: %d\n", unit)); ao->neg_upap = !ppp_settings.refuse_pap && (ppp_settings.passwd[0] != 0 || get_pap_passwd(unit, NULL, NULL)); ao->neg_chap = !ppp_settings.refuse_chap && ppp_settings.passwd[0] != 0 /*have_chap_secret(ppp_settings.user, ppp_settings.remote_name, (u32_t)0)*/; @@ -539,10 +858,10 @@ auth_reset(int unit) * UPAP_AUTHACK: Authentication succeeded. * In either case, msg points to an appropriate message. */ -int +u_char check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, char **msg, int *msglen) { -#if 1 +#if 1 /* XXX Assume all entries OK. */ LWIP_UNUSED_ARG(unit); LWIP_UNUSED_ARG(auser); LWIP_UNUSED_ARG(userlen); @@ -552,7 +871,7 @@ check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, *msg = (char *) 0; return UPAP_AUTHACK; /* XXX Assume all entries OK. */ #else - int ret = 0; + u_char ret = 0; struct wordlist *addrs = NULL; char passwd[256], user[256]; char secret[MAXWORDLEN]; @@ -581,11 +900,14 @@ check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, * On 10'th, drop the connection. */ if (attempts++ >= 10) { - AUTHDEBUG((LOG_WARNING, "%d LOGIN FAILURES BY %s\n", attempts, user)); + AUTHDEBUG(LOG_WARNING, ("%d LOGIN FAILURES BY %s\n", attempts, user)); /*ppp_panic("Excess Bad Logins");*/ } if (attempts > 3) { - sys_msleep((attempts - 3) * 5); + /* @todo: this was sleep(), i.e. seconds, not milliseconds + * I don't think we really need this in lwIP - we would block tcpip_thread! + */ + /*sys_msleep((attempts - 3) * 5);*/ } if (addrs != NULL) { free_wordlist(addrs); @@ -607,247 +929,70 @@ check_passwd( int unit, char *auser, int userlen, char *apasswd, int passwdlen, } #endif /* PAP_SUPPORT */ - -/* - * auth_ip_addr - check whether the peer is authorized to use - * a given IP address. Returns 1 if authorized, 0 otherwise. - */ -int -auth_ip_addr(int unit, u32_t addr) -{ - return ip_addr_check(addr, addresses[unit]); -} - -/* - * bad_ip_adrs - return 1 if the IP address is one we don't want - * to use, such as an address in the loopback net or a multicast address. - * addr is in network byte order. - */ -int -bad_ip_adrs(u32_t addr) -{ - addr = ntohl(addr); - return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET - || IN_MULTICAST(addr) || IN_BADCLASS(addr); -} - - -#if CHAP_SUPPORT +#if 0 /* UNUSED */ /* - * get_secret - open the CHAP secret file and return the secret - * for authenticating the given client on the given server. - * (We could be either client or server). + * This function is needed for PAM. */ -int get_secret( int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) -{ -#if 1 - int len; - struct wordlist *addrs; - LWIP_UNUSED_ARG(unit); - LWIP_UNUSED_ARG(server); - LWIP_UNUSED_ARG(save_addrs); +#ifdef USE_PAM - addrs = NULL; +/* lwip does not support PAM*/ - if(!client || !client[0] || strcmp(client, ppp_settings.user)) { - return 0; - } +#endif /* USE_PAM */ - len = strlen(ppp_settings.passwd); - if (len > MAXSECRETLEN) { - AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); - len = MAXSECRETLEN; - } +#endif /* UNUSED */ - BCOPY(ppp_settings.passwd, secret, len); - *secret_len = len; - return 1; -#else - int ret = 0, len; - struct wordlist *addrs; - char secbuf[MAXWORDLEN]; - - addrs = NULL; - secbuf[0] = 0; +#if 0 /* UNUSED */ +/* + * plogin - Check the user name and password against the system + * password database, and login the user if OK. + * + * returns: + * UPAP_AUTHNAK: Login failed. + * UPAP_AUTHACK: Login succeeded. + * In either case, msg points to an appropriate message. + */ +static int +plogin(char *user, char *passwd, char **msg, int *msglen) +{ - /* XXX Find secret. */ - if (ret < 0) { - return 0; - } + LWIP_UNUSED_ARG(user); + LWIP_UNUSED_ARG(passwd); + LWIP_UNUSED_ARG(msg); + LWIP_UNUSED_ARG(msglen); - if (save_addrs) { - set_allowed_addrs(unit, addrs); - } - len = strlen(secbuf); - if (len > MAXSECRETLEN) { - AUTHDEBUG((LOG_ERR, "Secret for %s on %s is too long\n", client, server)); - len = MAXSECRETLEN; - } + /* The new lines are here align the file when + * compared against the pppd 2.3.11 code */ - BCOPY(secbuf, secret, len); - BZERO(secbuf, sizeof(secbuf)); - *secret_len = len; - return 1; -#endif -} -#endif /* CHAP_SUPPORT */ -#if 0 /* UNUSED */ -/* - * auth_check_options - called to check authentication options. - */ -void -auth_check_options(void) -{ - lcp_options *wo = &lcp_wantoptions[0]; - int can_auth; - ipcp_options *ipwo = &ipcp_wantoptions[0]; - u32_t remote; - /* Default our_name to hostname, and user to our_name */ - if (ppp_settings.our_name[0] == 0 || ppp_settings.usehostname) { - strcpy(ppp_settings.our_name, ppp_settings.hostname); - } - if (ppp_settings.user[0] == 0) { - strcpy(ppp_settings.user, ppp_settings.our_name); - } - /* If authentication is required, ask peer for CHAP or PAP. */ - if (ppp_settings.auth_required && !wo->neg_chap && !wo->neg_upap) { - wo->neg_chap = 1; - wo->neg_upap = 1; - } - - /* - * Check whether we have appropriate secrets to use - * to authenticate the peer. - */ - can_auth = wo->neg_upap && have_pap_secret(); - if (!can_auth && wo->neg_chap) { - remote = ipwo->accept_remote? 0: ipwo->hisaddr; - can_auth = have_chap_secret(ppp_settings.remote_name, ppp_settings.our_name, remote); - } - if (ppp_settings.auth_required && !can_auth) { - ppp_panic("No auth secret"); - } -} -#endif -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ -/* - * Proceed to the network phase. - */ -static void -network_phase(int unit) -{ - int i; - struct protent *protp; - lcp_options *go = &lcp_gotoptions[unit]; - - /* - * If the peer had to authenticate, run the auth-up script now. - */ - if ((go->neg_chap || go->neg_upap) && !did_authup) { - /* XXX Do setup for peer authentication. */ - did_authup = 1; - } -#if CBCP_SUPPORT - /* - * If we negotiated callback, do it now. - */ - if (go->neg_cbcp) { - lcp_phase[unit] = PHASE_CALLBACK; - (*cbcp_protent.open)(unit); - return; - } -#endif /* CBCP_SUPPORT */ - lcp_phase[unit] = PHASE_NETWORK; - for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { - if (protp->protocol < 0xC000 && protp->enabled_flag && protp->open != NULL) { - (*protp->open)(unit); - if (protp->protocol != PPP_CCP) { - ++num_np_open; - } - } - } - if (num_np_open == 0) { - /* nothing to do */ - lcp_close(0, "No network protocols running"); - } -} - -/* - * check_idle - check whether the link has been idle for long - * enough that we can shut it down. - */ -static void -check_idle(void *arg) -{ - struct ppp_idle idle; - u_short itime; - - LWIP_UNUSED_ARG(arg); - if (!get_idle_time(0, &idle)) { - return; - } - itime = LWIP_MIN(idle.xmit_idle, idle.recv_idle); - if (itime >= ppp_settings.idle_time_limit) { - /* link is idle: shut it down. */ - AUTHDEBUG((LOG_INFO, "Terminating connection due to lack of activity.\n")); - lcp_close(0, "Link inactive"); - } else { - TIMEOUT(check_idle, NULL, ppp_settings.idle_time_limit - itime); - } -} -/* - * connect_time_expired - log a message and close the connection. - */ -static void -connect_time_expired(void *arg) -{ - LWIP_UNUSED_ARG(arg); - AUTHDEBUG((LOG_INFO, "Connect time expired\n")); - lcp_close(0, "Connect time expired"); /* Close connection */ -} -#if 0 -/* - * login - Check the user name and password against the system - * password database, and login the user if OK. - * - * returns: - * UPAP_AUTHNAK: Login failed. - * UPAP_AUTHACK: Login succeeded. - * In either case, msg points to an appropriate message. - */ -static int -login(char *user, char *passwd, char **msg, int *msglen) -{ /* XXX Fail until we decide that we want to support logins. */ return (UPAP_AUTHNAK); } #endif + + /* - * logout - Logout the user. + * plogout - Logout the user. */ static void -logout(void) +plogout(void) { logged_in = 0; } @@ -865,6 +1010,7 @@ null_login(int unit) return 0; } + /* * get_pap_passwd - get a password for authenticating ourselves with * our peer using PAP. Returns 1 on success, 0 if no suitable password @@ -878,6 +1024,8 @@ get_pap_passwd(int unit, char *user, char *passwd) but this causes problems with some providers (like CHT in Taiwan) who incorrectly request PAP and expect a bogus/empty password, so always provide a default user/passwd of "none"/"none" + + @todo: This should be configured by the user, instead of being hardcoded here! */ if(user) { strcpy(user, "none"); @@ -911,9 +1059,76 @@ have_chap_secret(char *client, char *server, u32_t remote) LWIP_UNUSED_ARG(client); LWIP_UNUSED_ARG(server); LWIP_UNUSED_ARG(remote); + /* XXX Fail until we set up our passwords. */ return 0; } +#if CHAP_SUPPORT + +/* + * get_secret - open the CHAP secret file and return the secret + * for authenticating the given client on the given server. + * (We could be either client or server). + */ +int +get_secret(int unit, char *client, char *server, char *secret, int *secret_len, int save_addrs) +{ +#if 1 + int len; + struct wordlist *addrs; + + LWIP_UNUSED_ARG(unit); + LWIP_UNUSED_ARG(server); + LWIP_UNUSED_ARG(save_addrs); + + addrs = NULL; + + if(!client || !client[0] || strcmp(client, ppp_settings.user)) { + return 0; + } + + len = (int)strlen(ppp_settings.passwd); + if (len > MAXSECRETLEN) { + AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); + len = MAXSECRETLEN; + } + + BCOPY(ppp_settings.passwd, secret, len); + *secret_len = len; + + return 1; +#else + int ret = 0, len; + struct wordlist *addrs; + char secbuf[MAXWORDLEN]; + + addrs = NULL; + secbuf[0] = 0; + + /* XXX Find secret. */ + if (ret < 0) { + return 0; + } + + if (save_addrs) { + set_allowed_addrs(unit, addrs); + } + + len = strlen(secbuf); + if (len > MAXSECRETLEN) { + AUTHDEBUG(LOG_ERR, ("Secret for %s on %s is too long\n", client, server)); + len = MAXSECRETLEN; + } + + BCOPY(secbuf, secret, len); + BZERO(secbuf, sizeof(secbuf)); + *secret_len = len; + + return 1; +#endif +} +#endif /* CHAP_SUPPORT */ + #if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ /* @@ -954,7 +1169,17 @@ set_allowed_addrs(int unit, struct wordlist *addrs) } #endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ -static int +/* + * auth_ip_addr - check whether the peer is authorized to use + * a given IP address. Returns 1 if authorized, 0 otherwise. + */ +int +auth_ip_addr(int unit, u32_t addr) +{ + return ip_addr_check(addr, addresses[unit]); +} + +static int /* @todo: integrate this funtion into auth_ip_addr()*/ ip_addr_check(u32_t addr, struct wordlist *addrs) { /* don't allow loopback or multicast address */ @@ -970,7 +1195,71 @@ ip_addr_check(u32_t addr, struct wordlist *addrs) return 1; } -#if 0 /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * bad_ip_adrs - return 1 if the IP address is one we don't want + * to use, such as an address in the loopback net or a multicast address. + * addr is in network byte order. + */ +int +bad_ip_adrs(u32_t addr) +{ + addr = ntohl(addr); + return (addr >> IN_CLASSA_NSHIFT) == IN_LOOPBACKNET + || IN_MULTICAST(addr) || IN_BADCLASS(addr); +} + +#if 0 /* UNUSED */ /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * some_ip_ok - check a wordlist to see if it authorizes any + * IP address(es). + */ +static int +some_ip_ok(struct wordlist *addrs) +{ + for (; addrs != 0; addrs = addrs->next) { + if (addrs->word[0] == '-') + break; + if (addrs->word[0] != '!') + return 1; /* some IP address is allowed */ + } + return 0; +} + +/* + * check_access - complain if a secret file has too-liberal permissions. + */ +static void +check_access(FILE *f, char *filename) +{ + struct stat sbuf; + + if (fstat(fileno(f), &sbuf) < 0) { + warn("cannot stat secret file %s: %m", filename); + } else if ((sbuf.st_mode & (S_IRWXG | S_IRWXO)) != 0) { + warn("Warning - secret file %s has world and/or group access", + filename); + } +} + + +/* + * scan_authfile - Scan an authorization file for a secret suitable + * for authenticating `client' on `server'. The return value is -1 + * if no secret is found, otherwise >= 0. The return value has + * NONWILD_CLIENT set if the secret didn't have "*" for the client, and + * NONWILD_SERVER set if the secret didn't have "*" for the server. + * Any following words on the line up to a "--" (i.e. address authorization + * info) are placed in a wordlist and returned in *addrs. Any + * following words (extra options) are placed in a wordlist and + * returned in *opts. + * We assume secret is NULL or points to MAXWORDLEN bytes of space. + */ +static int +scan_authfile(FILE *f, char *client, char *server, char *secret, struct wordlist **addrs, struct wordlist **opts, char *filename) +{ + /* We do not (currently) need this in lwip */ + return 0; /* dummy */ +} /* * free_wordlist - release memory allocated for a wordlist. */ @@ -978,13 +1267,68 @@ static void free_wordlist(struct wordlist *wp) { struct wordlist *next; - + while (wp != NULL) { next = wp->next; free(wp); wp = next; } } -#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ +/* + * auth_script_done - called when the auth-up or auth-down script + * has finished. + */ +static void +auth_script_done(void *arg) +{ + auth_script_pid = 0; + switch (auth_script_state) { + case s_up: + if (auth_state == s_down) { + auth_script_state = s_down; + auth_script(_PATH_AUTHDOWN); + } + break; + case s_down: + if (auth_state == s_up) { + auth_script_state = s_up; + auth_script(_PATH_AUTHUP); + } + break; + } +} + +/* + * auth_script - execute a script with arguments + * interface-name peer-name real-user tty speed + */ +static void +auth_script(char *script) +{ + char strspeed[32]; + struct passwd *pw; + char struid[32]; + char *user_name; + char *argv[8]; + + if ((pw = getpwuid(getuid())) != NULL && pw->pw_name != NULL) + user_name = pw->pw_name; + else { + slprintf(struid, sizeof(struid), "%d", getuid()); + user_name = struid; + } + slprintf(strspeed, sizeof(strspeed), "%d", baud_rate); + + argv[0] = script; + argv[1] = ifname; + argv[2] = peer_authname; + argv[3] = user_name; + argv[4] = devnam; + argv[5] = strspeed; + argv[6] = NULL; + + auth_script_pid = run_program(script, argv, 0, auth_script_done, NULL); +} +#endif /* 0 */ /* PAP_SUPPORT || CHAP_SUPPORT */ #endif /* PPP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/auth.h b/core/lwip/src/netif/ppp/auth.h index 86ff0494..a8069ec4 100644 --- a/core/lwip/src/netif/ppp/auth.h +++ b/core/lwip/src/netif/ppp/auth.h @@ -97,7 +97,7 @@ void auth_check_options (void); void auth_reset (int); /* Check peer-supplied username/password */ -int check_passwd (int, char *, int, char *, int, char **, int *); +u_char check_passwd (int, char *, int, char *, int, char **, int *); /* get "secret" for chap */ int get_secret (int, char *, char *, char *, int *, int); diff --git a/core/lwip/src/netif/ppp/chap.c b/core/lwip/src/netif/ppp/chap.c index b3ea6b22..3a49ff8a 100644 --- a/core/lwip/src/netif/ppp/chap.c +++ b/core/lwip/src/netif/ppp/chap.c @@ -84,19 +84,25 @@ #include <string.h> -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ - - -/************************/ -/*** LOCAL DATA TYPES ***/ -/************************/ - +#if 0 /* UNUSED */ +/* + * Command-line options. + */ +static option_t chap_option_list[] = { + { "chap-restart", o_int, &chap[0].timeouttime, + "Set timeout for CHAP" }, + { "chap-max-challenge", o_int, &chap[0].max_transmits, + "Set max #xmits for challenge" }, + { "chap-interval", o_int, &chap[0].chal_interval, + "Set interval for rechallenge" }, +#ifdef MSLANMAN + { "ms-lanman", o_bool, &ms_lanman, + "Use LanMan passwd when using MS-CHAP", 1 }, +#endif + { NULL } +}; +#endif /* UNUSED */ -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ /* * Protocol entry points. */ @@ -105,28 +111,10 @@ static void ChapLowerUp (int); static void ChapLowerDown (int); static void ChapInput (int, u_char *, int); static void ChapProtocolReject (int); -#if 0 +#if PPP_ADDITIONAL_CALLBACKS static int ChapPrintPkt (u_char *, int, void (*) (void *, char *, ...), void *); #endif -static void ChapChallengeTimeout (void *); -static void ChapResponseTimeout (void *); -static void ChapReceiveChallenge (chap_state *, u_char *, int, int); -static void ChapRechallenge (void *); -static void ChapReceiveResponse (chap_state *, u_char *, int, int); -static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len); -static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len); -static void ChapSendStatus (chap_state *, int); -static void ChapSendChallenge (chap_state *); -static void ChapSendResponse (chap_state *); -static void ChapGenChallenge (chap_state *); - - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ -chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ - struct protent chap_protent = { PPP_CHAP, ChapInit, @@ -136,29 +124,57 @@ struct protent chap_protent = { ChapLowerDown, NULL, NULL, -#if 0 +#if PPP_ADDITIONAL_CALLBACKS ChapPrintPkt, NULL, -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ 1, "CHAP", -#if 0 +#if PPP_ADDITIONAL_CALLBACKS NULL, NULL, NULL -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ }; +chap_state chap[NUM_PPP]; /* CHAP state; one for each unit */ + +static void ChapChallengeTimeout (void *); +static void ChapResponseTimeout (void *); +static void ChapReceiveChallenge (chap_state *, u_char *, u_char, int); +static void ChapRechallenge (void *); +static void ChapReceiveResponse (chap_state *, u_char *, int, int); +static void ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len); +static void ChapSendStatus (chap_state *, int); +static void ChapSendChallenge (chap_state *); +static void ChapSendResponse (chap_state *); +static void ChapGenChallenge (chap_state *); + +/* + * ChapInit - Initialize a CHAP unit. + */ +static void +ChapInit(int unit) +{ + chap_state *cstate = &chap[unit]; + + BZERO(cstate, sizeof(*cstate)); + cstate->unit = unit; + cstate->clientstate = CHAPCS_INITIAL; + cstate->serverstate = CHAPSS_INITIAL; + cstate->timeouttime = CHAP_DEFTIMEOUT; + cstate->max_transmits = CHAP_DEFTRANSMITS; + /* random number generator is initialized in magic_init */ +} + -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ /* * ChapAuthWithPeer - Authenticate us with our peer (start client). * */ void -ChapAuthWithPeer(int unit, char *our_name, int digest) +ChapAuthWithPeer(int unit, char *our_name, u_char digest) { chap_state *cstate = &chap[unit]; @@ -185,7 +201,7 @@ ChapAuthWithPeer(int unit, char *our_name, int digest) * ChapAuthPeer - Authenticate our peer (start server). */ void -ChapAuthPeer(int unit, char *our_name, int digest) +ChapAuthPeer(int unit, char *our_name, u_char digest) { chap_state *cstate = &chap[unit]; @@ -205,27 +221,6 @@ ChapAuthPeer(int unit, char *our_name, int digest) } -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ -/* - * ChapInit - Initialize a CHAP unit. - */ -static void -ChapInit(int unit) -{ - chap_state *cstate = &chap[unit]; - - BZERO(cstate, sizeof(*cstate)); - cstate->unit = unit; - cstate->clientstate = CHAPCS_INITIAL; - cstate->serverstate = CHAPSS_INITIAL; - cstate->timeouttime = CHAP_DEFTIMEOUT; - cstate->max_transmits = CHAP_DEFTRANSMITS; - /* random number generator is initialized in magic_init */ -} - - /* * ChapChallengeTimeout - Timeout expired on sending challenge. */ @@ -243,7 +238,7 @@ ChapChallengeTimeout(void *arg) if (cstate->chal_transmits >= cstate->max_transmits) { /* give up on peer */ - CHAPDEBUG((LOG_ERR, "Peer failed to respond to CHAP challenge\n")); + CHAPDEBUG(LOG_ERR, ("Peer failed to respond to CHAP challenge\n")); cstate->serverstate = CHAPSS_BADAUTH; auth_peer_fail(cstate->unit, PPP_CHAP); return; @@ -355,7 +350,7 @@ ChapProtocolReject(int unit) } if (cstate->clientstate != CHAPCS_INITIAL && cstate->clientstate != CHAPCS_CLOSED) { - auth_withpeer_fail(unit, PPP_CHAP); + auth_withpeer_fail(unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */ } ChapLowerDown(unit); /* shutdown chap */ } @@ -378,18 +373,18 @@ ChapInput(int unit, u_char *inpacket, int packet_len) */ inp = inpacket; if (packet_len < CHAP_HEADERLEN) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short header.\n")); + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short header.\n")); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); if (len < CHAP_HEADERLEN) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd illegal length.\n")); + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd illegal length.\n")); return; } if (len > packet_len) { - CHAPDEBUG((LOG_INFO, "ChapInput: rcvd short packet.\n")); + CHAPDEBUG(LOG_INFO, ("ChapInput: rcvd short packet.\n")); return; } len -= CHAP_HEADERLEN; @@ -415,7 +410,7 @@ ChapInput(int unit, u_char *inpacket, int packet_len) break; default: /* Need code reject? */ - CHAPDEBUG((LOG_WARNING, "Unknown CHAP code (%d) received.\n", code)); + CHAPDEBUG(LOG_WARNING, ("Unknown CHAP code (%d) received.\n", code)); break; } } @@ -425,7 +420,7 @@ ChapInput(int unit, u_char *inpacket, int packet_len) * ChapReceiveChallenge - Receive Challenge and send Response. */ static void -ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len) +ChapReceiveChallenge(chap_state *cstate, u_char *inp, u_char id, int len) { int rchallenge_len; u_char *rchallenge; @@ -434,48 +429,52 @@ ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len) char rhostname[256]; MD5_CTX mdContext; u_char hash[MD5_SIGNATURE_SIZE]; - - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: Rcvd id %d.\n", id)); + + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: Rcvd id %d.\n", id)); if (cstate->clientstate == CHAPCS_CLOSED || cstate->clientstate == CHAPCS_PENDING) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: in state %d\n", + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: in state %d\n", cstate->clientstate)); return; } if (len < 2) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n")); return; } GETCHAR(rchallenge_len, inp); len -= sizeof (u_char) + rchallenge_len; /* now name field length */ if (len < 0) { - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: rcvd short packet.\n")); + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: rcvd short packet.\n")); return; } rchallenge = inp; INCPTR(rchallenge_len, inp); - if (len >= sizeof(rhostname)) { + if (len >= (int)sizeof(rhostname)) { len = sizeof(rhostname) - 1; } BCOPY(inp, rhostname, len); rhostname[len] = '\000'; - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: received name field '%s'\n", rhostname)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: received name field '%s'\n", + rhostname)); /* Microsoft doesn't send their name back in the PPP packet */ if (ppp_settings.remote_name[0] != 0 && (ppp_settings.explicit_remote || rhostname[0] == 0)) { strncpy(rhostname, ppp_settings.remote_name, sizeof(rhostname)); rhostname[sizeof(rhostname) - 1] = 0; - CHAPDEBUG((LOG_INFO, "ChapReceiveChallenge: using '%s' as remote name\n", rhostname)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveChallenge: using '%s' as remote name\n", + rhostname)); } /* get secret for authenticating ourselves with the specified host */ - if (!get_secret(cstate->unit, cstate->resp_name, rhostname, secret, &secret_len, 0)) { + if (!get_secret(cstate->unit, cstate->resp_name, rhostname, + secret, &secret_len, 0)) { secret_len = 0; /* assume null secret if can't find one */ - CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating us to %s\n", rhostname)); + CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating us to %s\n", + rhostname)); } /* cancel response send timeout if necessary */ @@ -499,14 +498,14 @@ ChapReceiveChallenge(chap_state *cstate, u_char *inp, int id, int len) cstate->resp_length = MD5_SIGNATURE_SIZE; break; -#ifdef CHAPMS +#if MSCHAP_SUPPORT case CHAP_MICROSOFT: ChapMS(cstate, rchallenge, rchallenge_len, secret, secret_len); break; #endif default: - CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->resp_type)); + CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->resp_type)); return; } @@ -528,12 +527,12 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) MD5_CTX mdContext; char secret[MAXSECRETLEN]; u_char hash[MD5_SIGNATURE_SIZE]; - - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: Rcvd id %d.\n", id)); + + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: Rcvd id %d.\n", id)); if (cstate->serverstate == CHAPSS_CLOSED || cstate->serverstate == CHAPSS_PENDING) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: in state %d\n", + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: in state %d\n", cstate->serverstate)); return; } @@ -557,7 +556,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) } if (len < 2) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n")); return; } GETCHAR(remmd_len, inp); /* get length of MD */ @@ -566,29 +565,30 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) len -= sizeof (u_char) + remmd_len; if (len < 0) { - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: rcvd short packet.\n")); + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: rcvd short packet.\n")); return; } UNTIMEOUT(ChapChallengeTimeout, cstate); - if (len >= sizeof(rhostname)) { + if (len >= (int)sizeof(rhostname)) { len = sizeof(rhostname) - 1; } BCOPY(inp, rhostname, len); rhostname[len] = '\000'; - CHAPDEBUG((LOG_INFO, "ChapReceiveResponse: received name field: %s\n", rhostname)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveResponse: received name field: %s\n", + rhostname)); /* * Get secret for authenticating them with us, * do the hash ourselves, and compare the result. */ code = CHAP_FAILURE; - if (!get_secret(cstate->unit, rhostname, cstate->chal_name, secret, &secret_len, 1)) { - /* CHAPDEBUG((LOG_WARNING, TL_CHAP, "No CHAP secret found for authenticating %s\n", rhostname)); */ - CHAPDEBUG((LOG_WARNING, "No CHAP secret found for authenticating %s\n", - rhostname)); + if (!get_secret(cstate->unit, rhostname, cstate->chal_name, + secret, &secret_len, 1)) { + CHAPDEBUG(LOG_WARNING, ("No CHAP secret found for authenticating %s\n", + rhostname)); } else { /* generate MD based on negotiated type */ switch (cstate->chal_type) { @@ -610,7 +610,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) break; default: - CHAPDEBUG((LOG_INFO, "unknown digest type %d\n", cstate->chal_type)); + CHAPDEBUG(LOG_INFO, ("unknown digest type %d\n", cstate->chal_type)); } } @@ -627,7 +627,7 @@ ChapReceiveResponse(chap_state *cstate, u_char *inp, int id, int len) TIMEOUT(ChapRechallenge, cstate, cstate->chal_interval); } } else { - CHAPDEBUG((LOG_ERR, "CHAP peer authentication failed\n")); + CHAPDEBUG(LOG_ERR, ("CHAP peer authentication failed\n")); cstate->serverstate = CHAPSS_BADAUTH; auth_peer_fail(cstate->unit, PPP_CHAP); } @@ -642,7 +642,7 @@ ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len) LWIP_UNUSED_ARG(id); LWIP_UNUSED_ARG(inp); - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: Rcvd id %d.\n", id)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: Rcvd id %d.\n", id)); if (cstate->clientstate == CHAPCS_OPEN) { /* presumably an answer to a duplicate response */ @@ -651,7 +651,8 @@ ChapReceiveSuccess(chap_state *cstate, u_char *inp, u_char id, int len) if (cstate->clientstate != CHAPCS_RESPONSE) { /* don't know what this is */ - CHAPDEBUG((LOG_INFO, "ChapReceiveSuccess: in state %d\n", cstate->clientstate)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveSuccess: in state %d\n", + cstate->clientstate)); return; } @@ -679,11 +680,12 @@ ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len) LWIP_UNUSED_ARG(id); LWIP_UNUSED_ARG(inp); - CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: Rcvd id %d.\n", id)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: Rcvd id %d.\n", id)); if (cstate->clientstate != CHAPCS_RESPONSE) { /* don't know what this is */ - CHAPDEBUG((LOG_INFO, "ChapReceiveFailure: in state %d\n", cstate->clientstate)); + CHAPDEBUG(LOG_INFO, ("ChapReceiveFailure: in state %d\n", + cstate->clientstate)); return; } @@ -696,8 +698,8 @@ ChapReceiveFailure(chap_state *cstate, u_char *inp, u_char id, int len) PRINTMSG(inp, len); } - CHAPDEBUG((LOG_ERR, "CHAP authentication failed\n")); - auth_withpeer_fail(cstate->unit, PPP_CHAP); + CHAPDEBUG(LOG_ERR, ("CHAP authentication failed\n")); + auth_withpeer_fail(cstate->unit, PPP_CHAP); /* lwip: just sets the PPP error code on this unit to PPPERR_AUTHFAIL */ } @@ -712,25 +714,25 @@ ChapSendChallenge(chap_state *cstate) int outlen; chal_len = cstate->chal_len; - name_len = strlen(cstate->chal_name); + name_len = (int)strlen(cstate->chal_name); outlen = CHAP_HEADERLEN + sizeof (u_char) + chal_len + name_len; outp = outpacket_buf[cstate->unit]; - + MAKEHEADER(outp, PPP_CHAP); /* paste in a CHAP header */ - + PUTCHAR(CHAP_CHALLENGE, outp); PUTCHAR(cstate->chal_id, outp); PUTSHORT(outlen, outp); - + PUTCHAR(chal_len, outp); /* put length of challenge */ BCOPY(cstate->challenge, outp, chal_len); INCPTR(chal_len, outp); - + BCOPY(cstate->chal_name, outp, name_len); /* append hostname */ pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); - - CHAPDEBUG((LOG_INFO, "ChapSendChallenge: Sent id %d.\n", cstate->chal_id)); + + CHAPDEBUG(LOG_INFO, ("ChapSendChallenge: Sent id %d.\n", cstate->chal_id)); TIMEOUT(ChapChallengeTimeout, cstate, cstate->timeouttime); ++cstate->chal_transmits; @@ -745,18 +747,18 @@ ChapSendStatus(chap_state *cstate, int code) { u_char *outp; int outlen, msglen; - char msg[256]; - + char msg[256]; /* @todo: this can be a char*, no strcpy needed */ + if (code == CHAP_SUCCESS) { strcpy(msg, "Welcome!"); } else { strcpy(msg, "I don't like you. Go 'way."); } - msglen = strlen(msg); - + msglen = (int)strlen(msg); + outlen = CHAP_HEADERLEN + msglen; outp = outpacket_buf[cstate->unit]; - + MAKEHEADER(outp, PPP_CHAP); /* paste in a header */ PUTCHAR(code, outp); @@ -764,8 +766,9 @@ ChapSendStatus(chap_state *cstate, int code) PUTSHORT(outlen, outp); BCOPY(msg, outp, msglen); pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); - - CHAPDEBUG((LOG_INFO, "ChapSendStatus: Sent code %d, id %d.\n", code, cstate->chal_id)); + + CHAPDEBUG(LOG_INFO, ("ChapSendStatus: Sent code %d, id %d.\n", code, + cstate->chal_id)); } /* @@ -781,17 +784,18 @@ ChapGenChallenge(chap_state *cstate) int chal_len; u_char *ptr = cstate->challenge; int i; - + /* pick a random challenge length between MIN_CHALLENGE_LENGTH and MAX_CHALLENGE_LENGTH */ chal_len = (unsigned) ((((magic() >> 16) * (MAX_CHALLENGE_LENGTH - MIN_CHALLENGE_LENGTH)) >> 16) + MIN_CHALLENGE_LENGTH); - cstate->chal_len = chal_len; + LWIP_ASSERT("chal_len <= 0xff", chal_len <= 0xffff); + cstate->chal_len = (u_char)chal_len; cstate->chal_id = ++cstate->id; cstate->chal_transmits = 0; - + /* generate a random string */ for (i = 0; i < chal_len; i++ ) { *ptr++ = (char) (magic() & 0xff); @@ -808,12 +812,12 @@ ChapSendResponse(chap_state *cstate) { u_char *outp; int outlen, md_len, name_len; - + md_len = cstate->resp_length; - name_len = strlen(cstate->resp_name); + name_len = (int)strlen(cstate->resp_name); outlen = CHAP_HEADERLEN + sizeof (u_char) + md_len + name_len; outp = outpacket_buf[cstate->unit]; - + MAKEHEADER(outp, PPP_CHAP); PUTCHAR(CHAP_RESPONSE, outp); /* we are a response */ @@ -823,18 +827,18 @@ ChapSendResponse(chap_state *cstate) PUTCHAR(md_len, outp); /* length of MD */ BCOPY(cstate->response, outp, md_len); /* copy MD to buffer */ INCPTR(md_len, outp); - + BCOPY(cstate->resp_name, outp, name_len); /* append our name */ - + /* send the packet */ pppWrite(cstate->unit, outpacket_buf[cstate->unit], outlen + PPP_HDRLEN); - + cstate->clientstate = CHAPCS_RESPONSE; TIMEOUT(ChapResponseTimeout, cstate, cstate->timeouttime); ++cstate->resp_transmits; } -#if 0 +#if PPP_ADDITIONAL_CALLBACKS static char *ChapCodenames[] = { "Challenge", "Response", "Success", "Failure" }; @@ -847,7 +851,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void * int code, id, len; int clen, nlen; u_char x; - + if (plen < CHAP_HEADERLEN) { return 0; } @@ -857,6 +861,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void * if (len < CHAP_HEADERLEN || len > plen) { return 0; } + if (code >= 1 && code <= sizeof(ChapCodenames) / sizeof(char *)) { printer(arg, " %s", ChapCodenames[code-1]); } else { @@ -896,7 +901,7 @@ ChapPrintPkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void * return len + CHAP_HEADERLEN; } -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ #endif /* CHAP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/chap.h b/core/lwip/src/netif/ppp/chap.h index 83dafd73..fedcab8d 100644 --- a/core/lwip/src/netif/ppp/chap.h +++ b/core/lwip/src/netif/ppp/chap.h @@ -62,16 +62,12 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: chap.h,v 1.4 2007/12/19 20:47:22 fbernon Exp $ + * $Id: chap.h,v 1.6 2010/01/24 13:19:34 goldsimon Exp $ */ #ifndef CHAP_H #define CHAP_H -/************************* -*** PUBLIC DEFINITIONS *** -*************************/ - /* Code + ID + length */ #define CHAP_HEADERLEN 4 @@ -97,31 +93,6 @@ #define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 or MS-CHAP */ /* - * Client (peer) states. - */ -#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */ -#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */ -#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */ -#define CHAPCS_LISTEN 3 /* Listening for a challenge */ -#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */ -#define CHAPCS_OPEN 5 /* We've received Success */ - -/* - * Server (authenticator) states. - */ -#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */ -#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */ -#define CHAPSS_PENDING 2 /* Auth peer when lower up */ -#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */ -#define CHAPSS_OPEN 4 /* We've sent a Success msg */ -#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */ -#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */ - -/************************ -*** PUBLIC DATA TYPES *** -************************/ - -/* * Each interface is described by a chap structure. */ @@ -148,19 +119,32 @@ typedef struct chap_state { } chap_state; -/****************** -*** PUBLIC DATA *** -******************/ -extern chap_state chap[]; +/* + * Client (peer) states. + */ +#define CHAPCS_INITIAL 0 /* Lower layer down, not opened */ +#define CHAPCS_CLOSED 1 /* Lower layer up, not opened */ +#define CHAPCS_PENDING 2 /* Auth us to peer when lower up */ +#define CHAPCS_LISTEN 3 /* Listening for a challenge */ +#define CHAPCS_RESPONSE 4 /* Sent response, waiting for status */ +#define CHAPCS_OPEN 5 /* We've received Success */ -extern struct protent chap_protent; +/* + * Server (authenticator) states. + */ +#define CHAPSS_INITIAL 0 /* Lower layer down, not opened */ +#define CHAPSS_CLOSED 1 /* Lower layer up, not opened */ +#define CHAPSS_PENDING 2 /* Auth peer when lower up */ +#define CHAPSS_INITIAL_CHAL 3 /* We've sent the first challenge */ +#define CHAPSS_OPEN 4 /* We've sent a Success msg */ +#define CHAPSS_RECHALLENGE 5 /* We've sent another challenge */ +#define CHAPSS_BADAUTH 6 /* We've sent a Failure msg */ +extern chap_state chap[]; -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ +void ChapAuthWithPeer (int, char *, u_char); +void ChapAuthPeer (int, char *, u_char); -void ChapAuthWithPeer (int, char *, int); -void ChapAuthPeer (int, char *, int); +extern struct protent chap_protent; #endif /* CHAP_H */ diff --git a/core/lwip/src/netif/ppp/chpms.c b/core/lwip/src/netif/ppp/chpms.c index 582cfd2d..83acefce 100644 --- a/core/lwip/src/netif/ppp/chpms.c +++ b/core/lwip/src/netif/ppp/chpms.c @@ -85,6 +85,8 @@ #include "chap.h" #include "chpms.h" +#include <string.h> + /*************************/ /*** LOCAL DEFINITIONS ***/ @@ -137,49 +139,12 @@ static u_char Get7Bits( int startBit ); - -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ -void -ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len) -{ - MS_ChapResponse response; -#ifdef MSLANMAN - extern int ms_lanman; -#endif - -#if 0 - CHAPDEBUG((LOG_INFO, "ChapMS: secret is '%.*s'\n", secret_len, secret)); -#endif - BZERO(&response, sizeof(response)); - - /* Calculate both always */ - ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); - -#ifdef MSLANMAN - ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); - - /* prefered method is set by option */ - response.UseNT = !ms_lanman; -#else - response.UseNT = 1; -#endif - - BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); - cstate->resp_length = MS_CHAP_RESPONSE_LEN; -} - - -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ static void ChallengeResponse( u_char *challenge, /* IN 8 octets */ u_char *pwHash, /* IN 16 octets */ u_char *response /* OUT 24 octets */) { - char ZPasswordHash[21]; + u_char ZPasswordHash[21]; BZERO(ZPasswordHash, sizeof(ZPasswordHash)); BCOPY(pwHash, ZPasswordHash, 16); @@ -211,19 +176,19 @@ DesEncrypt( u_char *clear, /* IN 8 octets */ MakeKey(key, des_key); Expand(des_key, crypt_key); - setkey(crypt_key); + setkey((char*)crypt_key); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); #endif Expand(clear, des_input); - encrypt(des_input, 0); + encrypt((char*)des_input, 0); Collapse(des_input, cipher); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); #endif } @@ -243,14 +208,14 @@ DesEncrypt( u_char *clear, /* IN 8 octets */ des_set_key(&des_key, key_schedule); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet input : %02X%02X%02X%02X%02X%02X%02X%02X\n", clear[0], clear[1], clear[2], clear[3], clear[4], clear[5], clear[6], clear[7])); #endif des_ecb_encrypt((des_cblock *)clear, (des_cblock *)cipher, key_schedule, 1); #if 0 - CHAPDEBUG((LOG_INFO, "DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("DesEncrypt: 8 octet output: %02X%02X%02X%02X%02X%02X%02X%02X\n", cipher[0], cipher[1], cipher[2], cipher[3], cipher[4], cipher[5], cipher[6], cipher[7])); #endif } @@ -329,9 +294,9 @@ MakeKey( u_char *key, /* IN 56 bit DES key missing parity bits */ #endif #if 0 - CHAPDEBUG((LOG_INFO, "MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("MakeKey: 56-bit input : %02X%02X%02X%02X%02X%02X%02X\n", key[0], key[1], key[2], key[3], key[4], key[5], key[6])); - CHAPDEBUG((LOG_INFO, "MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n", + CHAPDEBUG(LOG_INFO, ("MakeKey: 64-bit output: %02X%02X%02X%02X%02X%02X%02X%02X\n", des_key[0], des_key[1], des_key[2], des_key[3], des_key[4], des_key[5], des_key[6], des_key[7])); #endif } @@ -348,6 +313,8 @@ ChapMS_NT( char *rchallenge, u_char unicodePassword[MAX_NT_PASSWORD * 2]; static int low_byte_first = -1; + LWIP_UNUSED_ARG(rchallenge_len); + /* Initialize the Unicode version of the secret (== password). */ /* This implicitly supports 8-bit ISO8859/1 characters. */ BZERO(unicodePassword, sizeof(unicodePassword)); @@ -358,15 +325,16 @@ ChapMS_NT( char *rchallenge, MDupdate(&md4Context, unicodePassword, secret_len * 2 * 8); /* Unicode is 2 bytes/char, *8 for bit count */ if (low_byte_first == -1) { - low_byte_first = (htons((unsigned short int)1) != 1); + low_byte_first = (PP_HTONS((unsigned short int)1) != 1); } if (low_byte_first == 0) { - MDreverse((u_long *)&md4Context); /* sfb 961105 */ + /* @todo: arg type - u_long* or u_int* ? */ + MDreverse((unsigned int*)&md4Context); /* sfb 961105 */ } MDupdate(&md4Context, NULL, 0); /* Tell MD4 we're done */ - ChallengeResponse(rchallenge, (char *)md4Context.buffer, response->NTResp); + ChallengeResponse((u_char*)rchallenge, (u_char*)md4Context.buffer, response->NTResp); } #ifdef MSLANMAN @@ -394,6 +362,35 @@ ChapMS_LANMan( char *rchallenge, } #endif +void +ChapMS( chap_state *cstate, char *rchallenge, int rchallenge_len, char *secret, int secret_len) +{ + MS_ChapResponse response; +#ifdef MSLANMAN + extern int ms_lanman; +#endif + +#if 0 + CHAPDEBUG(LOG_INFO, ("ChapMS: secret is '%.*s'\n", secret_len, secret)); +#endif + BZERO(&response, sizeof(response)); + + /* Calculate both always */ + ChapMS_NT(rchallenge, rchallenge_len, secret, secret_len, &response); + +#ifdef MSLANMAN + ChapMS_LANMan(rchallenge, rchallenge_len, secret, secret_len, &response); + + /* prefered method is set by option */ + response.UseNT = !ms_lanman; +#else + response.UseNT = 1; +#endif + + BCOPY(&response, cstate->response, MS_CHAP_RESPONSE_LEN); + cstate->resp_length = MS_CHAP_RESPONSE_LEN; +} + #endif /* MSCHAP_SUPPORT */ #endif /* PPP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/fsm.c b/core/lwip/src/netif/ppp/fsm.c index ee549f23..2e73c5af 100644 --- a/core/lwip/src/netif/ppp/fsm.c +++ b/core/lwip/src/netif/ppp/fsm.c @@ -66,13 +66,7 @@ #include <string.h> - -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ - #if PPP_DEBUG - static const char *ppperr_strerr[] = { "LS_INITIAL", /* LS_INITIAL 0 */ "LS_STARTING", /* LS_STARTING 1 */ @@ -85,17 +79,8 @@ static const char *ppperr_strerr[] = { "LS_ACKSENT", /* LS_ACKSENT 8 */ "LS_OPENED" /* LS_OPENED 9 */ }; - #endif /* PPP_DEBUG */ -/************************/ -/*** LOCAL DATA TYPES ***/ -/************************/ - - -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ static void fsm_timeout (void *); static void fsm_rconfreq (fsm *, u_char, u_char *, int); static void fsm_rconfack (fsm *, int, u_char *, int); @@ -107,22 +92,9 @@ static void fsm_sconfreq (fsm *, int); #define PROTO_NAME(f) ((f)->callbacks->proto_name) - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ - - -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ int peer_mru[NUM_PPP]; -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ - /* * fsm_init - Initialize fsm. * @@ -168,11 +140,11 @@ fsm_lowerup(fsm *f) break; default: - FSMDEBUG((LOG_INFO, "%s: Up event in state %d (%s)!\n", + FSMDEBUG(LOG_INFO, ("%s: Up event in state %d (%s)!\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } - - FSMDEBUG((LOG_INFO, "%s: lowerup state %d (%s) -> %d (%s)\n", + + FSMDEBUG(LOG_INFO, ("%s: lowerup state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); } @@ -222,11 +194,11 @@ fsm_lowerdown(fsm *f) break; default: - FSMDEBUG((LOG_INFO, "%s: Down event in state %d (%s)!\n", + FSMDEBUG(LOG_INFO, ("%s: Down event in state %d (%s)!\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } - FSMDEBUG((LOG_INFO, "%s: lowerdown state %d (%s) -> %d (%s)\n", + FSMDEBUG(LOG_INFO, ("%s: lowerdown state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); } @@ -271,10 +243,23 @@ fsm_open(fsm *f) break; } - FSMDEBUG((LOG_INFO, "%s: open state %d (%s) -> %d (%s)\n", + FSMDEBUG(LOG_INFO, ("%s: open state %d (%s) -> %d (%s)\n", PROTO_NAME(f), oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); } +#if 0 /* backport pppd 2.4.4b1; */ +/* + * terminate_layer - Start process of shutting down the FSM + * + * Cancel any timeout running, notify upper layers we're done, and + * send a terminate-request message as configured. + */ +static void +terminate_layer(fsm *f, int nextstate) +{ + /* @todo */ +} +#endif /* * fsm_close - Start closing connection. @@ -290,7 +275,7 @@ fsm_close(fsm *f, char *reason) LWIP_UNUSED_ARG(oldState); f->term_reason = reason; - f->term_reason_len = (reason == NULL? 0: strlen(reason)); + f->term_reason_len = (reason == NULL ? 0 : (int)strlen(reason)); switch( f->state ) { case LS_STARTING: f->state = LS_INITIAL; @@ -322,38 +307,71 @@ fsm_close(fsm *f, char *reason) break; } - FSMDEBUG((LOG_INFO, "%s: close reason=%s state %d (%s) -> %d (%s)\n", + FSMDEBUG(LOG_INFO, ("%s: close reason=%s state %d (%s) -> %d (%s)\n", PROTO_NAME(f), reason, oldState, ppperr_strerr[oldState], f->state, ppperr_strerr[f->state])); } /* - * fsm_sdata - Send some data. - * - * Used for all packets sent to our peer by this module. + * fsm_timeout - Timeout expired. */ -void -fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen) +static void +fsm_timeout(void *arg) { - u_char *outp; - int outlen; + fsm *f = (fsm *) arg; - /* Adjust length to be smaller than MTU */ - outp = outpacket_buf[f->unit]; - if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { - datalen = peer_mru[f->unit] - HEADERLEN; - } - if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { - BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); + switch (f->state) { + case LS_CLOSING: + case LS_STOPPING: + if( f->retransmits <= 0 ) { + FSMDEBUG(LOG_WARNING, ("%s: timeout sending Terminate-Request state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* + * We've waited for an ack long enough. Peer probably heard us. + */ + f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + } else { + FSMDEBUG(LOG_WARNING, ("%s: timeout resending Terminate-Requests state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* Send Terminate-Request */ + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, f->timeouttime); + --f->retransmits; + } + break; + + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + if (f->retransmits <= 0) { + FSMDEBUG(LOG_WARNING, ("%s: timeout sending Config-Requests state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + f->state = LS_STOPPED; + if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + } else { + FSMDEBUG(LOG_WARNING, ("%s: timeout resending Config-Request state=%d (%s)\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + /* Retransmit the configure-request */ + if (f->callbacks->retransmit) { + (*f->callbacks->retransmit)(f); + } + fsm_sconfreq(f, 1); /* Re-send Configure-Request */ + if( f->state == LS_ACKRCVD ) { + f->state = LS_REQSENT; + } + } + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: UNHANDLED timeout event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } - outlen = datalen + HEADERLEN; - MAKEHEADER(outp, f->protocol); - PUTCHAR(code, outp); - PUTCHAR(id, outp); - PUTSHORT(outlen, outp); - pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); - FSMDEBUG((LOG_INFO, "fsm_sdata(%s): Sent code %d,%d,%d.\n", - PROTO_NAME(f), code, id, outlen)); } @@ -372,7 +390,7 @@ fsm_input(fsm *f, u_char *inpacket, int l) * If packet too short, drop it. */ if (l < HEADERLEN) { - FSMDEBUG((LOG_WARNING, "fsm_input(%x): Rcvd short header.\n", + FSMDEBUG(LOG_WARNING, ("fsm_input(%x): Rcvd short header.\n", f->protocol)); return; } @@ -380,23 +398,23 @@ fsm_input(fsm *f, u_char *inpacket, int l) GETCHAR(id, inp); GETSHORT(len, inp); if (len < HEADERLEN) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd illegal length.\n", + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd illegal length.\n", f->protocol)); return; } if (len > l) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd short packet.\n", + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd short packet.\n", f->protocol)); return; } len -= HEADERLEN; /* subtract header length */ if( f->state == LS_INITIAL || f->state == LS_STARTING ) { - FSMDEBUG((LOG_INFO, "fsm_input(%x): Rcvd packet in state %d (%s).\n", + FSMDEBUG(LOG_INFO, ("fsm_input(%x): Rcvd packet in state %d (%s).\n", f->protocol, f->state, ppperr_strerr[f->state])); return; } - FSMDEBUG((LOG_INFO, "fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); + FSMDEBUG(LOG_INFO, ("fsm_input(%s):%d,%d,%d\n", PROTO_NAME(f), code, id, l)); /* * Action depends on code. */ @@ -427,6 +445,7 @@ fsm_input(fsm *f, u_char *inpacket, int l) break; default: + FSMDEBUG(LOG_INFO, ("fsm_input(%s): default: \n", PROTO_NAME(f))); if( !f->callbacks->extcode || !(*f->callbacks->extcode)(f, code, id, inp, len) ) { fsm_sdata(f, CODEREJ, ++f->id, inpacket, len + HEADERLEN); @@ -437,129 +456,6 @@ fsm_input(fsm *f, u_char *inpacket, int l) /* - * fsm_protreject - Peer doesn't speak this protocol. - * - * Treat this as a catastrophic error (RXJ-). - */ -void -fsm_protreject(fsm *f) -{ - switch( f->state ) { - case LS_CLOSING: - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - /* fall through */ - case LS_CLOSED: - f->state = LS_CLOSED; - if( f->callbacks->finished ) { - (*f->callbacks->finished)(f); - } - break; - - case LS_STOPPING: - case LS_REQSENT: - case LS_ACKRCVD: - case LS_ACKSENT: - UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ - /* fall through */ - case LS_STOPPED: - f->state = LS_STOPPED; - if( f->callbacks->finished ) { - (*f->callbacks->finished)(f); - } - break; - - case LS_OPENED: - if( f->callbacks->down ) { - (*f->callbacks->down)(f); - } - /* Init restart counter, send Terminate-Request */ - f->retransmits = f->maxtermtransmits; - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, - (u_char *) f->term_reason, f->term_reason_len); - TIMEOUT(fsm_timeout, f, f->timeouttime); - --f->retransmits; - - f->state = LS_STOPPING; - break; - - default: - FSMDEBUG((LOG_INFO, "%s: Protocol-reject event in state %d (%s)!\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - } -} - - - - - -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ - -/* - * fsm_timeout - Timeout expired. - */ -static void -fsm_timeout(void *arg) -{ - fsm *f = (fsm *) arg; - - switch (f->state) { - case LS_CLOSING: - case LS_STOPPING: - if( f->retransmits <= 0 ) { - FSMDEBUG((LOG_WARNING, "%s: timeout sending Terminate-Request state=%d (%s)\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - /* - * We've waited for an ack long enough. Peer probably heard us. - */ - f->state = (f->state == LS_CLOSING)? LS_CLOSED: LS_STOPPED; - if( f->callbacks->finished ) { - (*f->callbacks->finished)(f); - } - } else { - FSMDEBUG((LOG_WARNING, "%s: timeout resending Terminate-Requests state=%d (%s)\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - /* Send Terminate-Request */ - fsm_sdata(f, TERMREQ, f->reqid = ++f->id, - (u_char *) f->term_reason, f->term_reason_len); - TIMEOUT(fsm_timeout, f, f->timeouttime); - --f->retransmits; - } - break; - - case LS_REQSENT: - case LS_ACKRCVD: - case LS_ACKSENT: - if (f->retransmits <= 0) { - FSMDEBUG((LOG_WARNING, "%s: timeout sending Config-Requests state=%d (%s)\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - f->state = LS_STOPPED; - if( (f->flags & OPT_PASSIVE) == 0 && f->callbacks->finished ) { - (*f->callbacks->finished)(f); - } - } else { - FSMDEBUG((LOG_WARNING, "%s: timeout resending Config-Request state=%d (%s)\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - /* Retransmit the configure-request */ - if (f->callbacks->retransmit) { - (*f->callbacks->retransmit)(f); - } - fsm_sconfreq(f, 1); /* Re-send Configure-Request */ - if( f->state == LS_ACKRCVD ) { - f->state = LS_REQSENT; - } - } - break; - - default: - FSMDEBUG((LOG_INFO, "%s: UNHANDLED timeout event in state %d (%s)!\n", - PROTO_NAME(f), f->state, ppperr_strerr[f->state])); - } -} - - -/* * fsm_rconfreq - Receive Configure-Request. */ static void @@ -567,7 +463,7 @@ fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) { int code, reject_if_disagree; - FSMDEBUG((LOG_INFO, "fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rconfreq(%s): Rcvd id %d state=%d (%s)\n", PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); switch( f->state ) { case LS_CLOSED: @@ -638,7 +534,7 @@ fsm_rconfreq(fsm *f, u_char id, u_char *inp, int len) static void fsm_rconfack(fsm *f, int id, u_char *inp, int len) { - FSMDEBUG((LOG_INFO, "fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rconfack(%s): Rcvd id %d state=%d (%s)\n", PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); if (id != f->reqid || f->seen_ack) { /* Expected id? */ @@ -646,7 +542,7 @@ fsm_rconfack(fsm *f, int id, u_char *inp, int len) } if( !(f->callbacks->ackci? (*f->callbacks->ackci)(f, inp, len): (len == 0)) ) { /* Ack is bad - ignore it */ - FSMDEBUG((LOG_INFO, "%s: received bad Ack (length %d)\n", + FSMDEBUG(LOG_INFO, ("%s: received bad Ack (length %d)\n", PROTO_NAME(f), len)); return; } @@ -700,7 +596,7 @@ fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) int (*proc) (fsm *, u_char *, int); int ret; - FSMDEBUG((LOG_INFO, "fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rconfnakrej(%s): Rcvd id %d state=%d (%s)\n", PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); if (id != f->reqid || f->seen_ack) { /* Expected id? */ @@ -709,7 +605,7 @@ fsm_rconfnakrej(fsm *f, int code, int id, u_char *inp, int len) proc = (code == CONFNAK)? f->callbacks->nakci: f->callbacks->rejci; if (!proc || !((ret = proc(f, inp, len)))) { /* Nak/reject is bad - ignore it */ - FSMDEBUG((LOG_INFO, "%s: received bad %s (length %d)\n", + FSMDEBUG(LOG_INFO, ("%s: received bad %s (length %d)\n", PROTO_NAME(f), (code==CONFNAK? "Nak": "reject"), len)); return; } @@ -759,7 +655,7 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len) { LWIP_UNUSED_ARG(p); - FSMDEBUG((LOG_INFO, "fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rtermreq(%s): Rcvd id %d state=%d (%s)\n", PROTO_NAME(f), id, f->state, ppperr_strerr[f->state])); switch (f->state) { @@ -770,9 +666,9 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len) case LS_OPENED: if (len > 0) { - FSMDEBUG((LOG_INFO, "%s terminated by peer (%x)\n", PROTO_NAME(f), p)); + FSMDEBUG(LOG_INFO, ("%s terminated by peer (%p)\n", PROTO_NAME(f), p)); } else { - FSMDEBUG((LOG_INFO, "%s terminated by peer\n", PROTO_NAME(f))); + FSMDEBUG(LOG_INFO, ("%s terminated by peer\n", PROTO_NAME(f))); } if (f->callbacks->down) { (*f->callbacks->down)(f); /* Inform upper layers */ @@ -793,7 +689,7 @@ fsm_rtermreq(fsm *f, int id, u_char *p, int len) static void fsm_rtermack(fsm *f) { - FSMDEBUG((LOG_INFO, "fsm_rtermack(%s): state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): state=%d (%s)\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); switch (f->state) { @@ -823,6 +719,9 @@ fsm_rtermack(fsm *f) } fsm_sconfreq(f, 0); break; + default: + FSMDEBUG(LOG_INFO, ("fsm_rtermack(%s): UNHANDLED state=%d (%s)!!!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); } } @@ -835,16 +734,16 @@ fsm_rcoderej(fsm *f, u_char *inp, int len) { u_char code, id; - FSMDEBUG((LOG_INFO, "fsm_rcoderej(%s): state=%d (%s)\n", + FSMDEBUG(LOG_INFO, ("fsm_rcoderej(%s): state=%d (%s)\n", PROTO_NAME(f), f->state, ppperr_strerr[f->state])); if (len < HEADERLEN) { - FSMDEBUG((LOG_INFO, "fsm_rcoderej: Rcvd short Code-Reject packet!\n")); + FSMDEBUG(LOG_INFO, ("fsm_rcoderej: Rcvd short Code-Reject packet!\n")); return; } GETCHAR(code, inp); GETCHAR(id, inp); - FSMDEBUG((LOG_WARNING, "%s: Rcvd Code-Reject for code %d, id %d\n", + FSMDEBUG(LOG_WARNING, ("%s: Rcvd Code-Reject for code %d, id %d\n", PROTO_NAME(f), code, id)); if( f->state == LS_ACKRCVD ) { @@ -854,6 +753,59 @@ fsm_rcoderej(fsm *f, u_char *inp, int len) /* + * fsm_protreject - Peer doesn't speak this protocol. + * + * Treat this as a catastrophic error (RXJ-). + */ +void +fsm_protreject(fsm *f) +{ + switch( f->state ) { + case LS_CLOSING: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + case LS_CLOSED: + f->state = LS_CLOSED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_STOPPING: + case LS_REQSENT: + case LS_ACKRCVD: + case LS_ACKSENT: + UNTIMEOUT(fsm_timeout, f); /* Cancel timeout */ + /* fall through */ + case LS_STOPPED: + f->state = LS_STOPPED; + if( f->callbacks->finished ) { + (*f->callbacks->finished)(f); + } + break; + + case LS_OPENED: + if( f->callbacks->down ) { + (*f->callbacks->down)(f); + } + /* Init restart counter, send Terminate-Request */ + f->retransmits = f->maxtermtransmits; + fsm_sdata(f, TERMREQ, f->reqid = ++f->id, + (u_char *) f->term_reason, f->term_reason_len); + TIMEOUT(fsm_timeout, f, f->timeouttime); + --f->retransmits; + + f->state = LS_STOPPING; + break; + + default: + FSMDEBUG(LOG_INFO, ("%s: Protocol-reject event in state %d (%s)!\n", + PROTO_NAME(f), f->state, ppperr_strerr[f->state])); + } +} + + +/* * fsm_sconfreq - Send a Configure-Request. */ static void @@ -901,8 +853,38 @@ fsm_sconfreq(fsm *f, int retransmit) --f->retransmits; TIMEOUT(fsm_timeout, f, f->timeouttime); - FSMDEBUG((LOG_INFO, "%s: sending Configure-Request, id %d\n", + FSMDEBUG(LOG_INFO, ("%s: sending Configure-Request, id %d\n", PROTO_NAME(f), f->reqid)); } + +/* + * fsm_sdata - Send some data. + * + * Used for all packets sent to our peer by this module. + */ +void +fsm_sdata( fsm *f, u_char code, u_char id, u_char *data, int datalen) +{ + u_char *outp; + int outlen; + + /* Adjust length to be smaller than MTU */ + outp = outpacket_buf[f->unit]; + if (datalen > peer_mru[f->unit] - (int)HEADERLEN) { + datalen = peer_mru[f->unit] - HEADERLEN; + } + if (datalen && data != outp + PPP_HDRLEN + HEADERLEN) { + BCOPY(data, outp + PPP_HDRLEN + HEADERLEN, datalen); + } + outlen = datalen + HEADERLEN; + MAKEHEADER(outp, f->protocol); + PUTCHAR(code, outp); + PUTCHAR(id, outp); + PUTSHORT(outlen, outp); + pppWrite(f->unit, outpacket_buf[f->unit], outlen + PPP_HDRLEN); + FSMDEBUG(LOG_INFO, ("fsm_sdata(%s): Sent code %d,%d,%d.\n", + PROTO_NAME(f), code, id, outlen)); +} + #endif /* PPP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/fsm.h b/core/lwip/src/netif/ppp/fsm.h index 14034ec7..8d41b5f5 100644 --- a/core/lwip/src/netif/ppp/fsm.h +++ b/core/lwip/src/netif/ppp/fsm.h @@ -48,15 +48,12 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: fsm.h,v 1.4 2007/12/19 20:47:23 fbernon Exp $ + * $Id: fsm.h,v 1.5 2009/12/31 17:08:08 goldsimon Exp $ */ #ifndef FSM_H #define FSM_H -/***************************************************************************** -************************* PUBLIC DEFINITIONS ********************************* -*****************************************************************************/ /* * LCP Packet header = Code, id, length. */ @@ -74,32 +71,8 @@ #define TERMACK 6 /* Termination Ack */ #define CODEREJ 7 /* Code Reject */ -/* - * Link states. - */ -#define LS_INITIAL 0 /* Down, hasn't been opened */ -#define LS_STARTING 1 /* Down, been opened */ -#define LS_CLOSED 2 /* Up, hasn't been opened */ -#define LS_STOPPED 3 /* Open, waiting for down event */ -#define LS_CLOSING 4 /* Terminating the connection, not open */ -#define LS_STOPPING 5 /* Terminating, but open */ -#define LS_REQSENT 6 /* We've sent a Config Request */ -#define LS_ACKRCVD 7 /* We've received a Config Ack */ -#define LS_ACKSENT 8 /* We've sent a Config Ack */ -#define LS_OPENED 9 /* Connection available */ /* - * Flags - indicate options controlling FSM operation - */ -#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ -#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ -#define OPT_SILENT 4 /* Wait for peer to speak first */ - - -/***************************************************************************** -************************* PUBLIC DATA TYPES ********************************** -*****************************************************************************/ -/* * Each FSM is described by an fsm structure and fsm callbacks. */ typedef struct fsm { @@ -141,18 +114,27 @@ typedef struct fsm_callbacks { } fsm_callbacks; -/***************************************************************************** -*********************** PUBLIC DATA STRUCTURES ******************************* -*****************************************************************************/ /* - * Variables + * Link states. */ -extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ +#define LS_INITIAL 0 /* Down, hasn't been opened */ +#define LS_STARTING 1 /* Down, been opened */ +#define LS_CLOSED 2 /* Up, hasn't been opened */ +#define LS_STOPPED 3 /* Open, waiting for down event */ +#define LS_CLOSING 4 /* Terminating the connection, not open */ +#define LS_STOPPING 5 /* Terminating, but open */ +#define LS_REQSENT 6 /* We've sent a Config Request */ +#define LS_ACKRCVD 7 /* We've received a Config Ack */ +#define LS_ACKSENT 8 /* We've sent a Config Ack */ +#define LS_OPENED 9 /* Connection available */ +/* + * Flags - indicate options controlling FSM operation + */ +#define OPT_PASSIVE 1 /* Don't die if we don't get a response */ +#define OPT_RESTART 2 /* Treat 2nd OPEN as DOWN, UP */ +#define OPT_SILENT 4 /* Wait for peer to speak first */ -/***************************************************************************** -************************** PUBLIC FUNCTIONS ********************************** -*****************************************************************************/ /* * Prototypes @@ -166,4 +148,10 @@ void fsm_input (fsm*, u_char*, int); void fsm_protreject (fsm*); void fsm_sdata (fsm*, u_char, u_char, u_char*, int); + +/* + * Variables + */ +extern int peer_mru[]; /* currently negotiated peer MRU (per unit) */ + #endif /* FSM_H */ diff --git a/core/lwip/src/netif/ppp/ipcp.c b/core/lwip/src/netif/ppp/ipcp.c index 0ff4ce3f..461a600f 100644 --- a/core/lwip/src/netif/ppp/ipcp.c +++ b/core/lwip/src/netif/ppp/ipcp.c @@ -1,3 +1,5 @@ +/** In contrast to pppd 2.3.1, DNS support has been added, proxy-ARP and + dial-on-demand has been stripped. */ /***************************************************************************** * ipcp.c - Network PPP IP Control Protocol program file. * @@ -61,27 +63,23 @@ #include "vj.h" #include "ipcp.h" +#include "lwip/inet.h" + #include <string.h> -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ /* #define OLD_CI_ADDRS 1 */ /* Support deprecated address negotiation. */ -/* - * Lengths of configuration options. - */ -#define CILEN_VOID 2 -#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ -#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ -#define CILEN_ADDR 6 /* new-style single address option */ -#define CILEN_ADDRS 10 /* old-style dual address option */ +/* global vars */ +ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ +/* local vars */ +static int default_route_set[NUM_PPP]; /* Have set up a default route */ +static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ /* * Callbacks for fsm code. (CI = Configuration Information) */ @@ -94,11 +92,33 @@ static int ipcp_rejci (fsm *, u_char *, int); /* Peer rej'd our CI */ static int ipcp_reqci (fsm *, u_char *, int *, int); /* Rcv CI */ static void ipcp_up (fsm *); /* We're UP */ static void ipcp_down (fsm *); /* We're DOWN */ -#if 0 +#if PPP_ADDITIONAL_CALLBACKS static void ipcp_script (fsm *, char *); /* Run an up/down script */ #endif static void ipcp_finished (fsm *); /* Don't need lower layer */ + +fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ + + +static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ + ipcp_resetci, /* Reset our Configuration Information */ + ipcp_cilen, /* Length of our Configuration Information */ + ipcp_addci, /* Add our Configuration Information */ + ipcp_ackci, /* ACK our Configuration Information */ + ipcp_nakci, /* NAK our Configuration Information */ + ipcp_rejci, /* Reject our Configuration Information */ + ipcp_reqci, /* Request peer's Configuration Information */ + ipcp_up, /* Called when fsm reaches LS_OPENED state */ + ipcp_down, /* Called when fsm leaves LS_OPENED state */ + NULL, /* Called when we want the lower layer up */ + ipcp_finished, /* Called when we want the lower layer down */ + NULL, /* Called when Protocol-Reject received */ + NULL, /* Retransmission is necessary */ + NULL, /* Called to handle protocol-specific codes */ + "IPCP" /* String name of protocol */ +}; + /* * Protocol entry points from main code. */ @@ -110,23 +130,6 @@ static void ipcp_lowerdown (int); static void ipcp_input (int, u_char *, int); static void ipcp_protrej (int); -static void ipcp_clear_addrs (int); - -#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ - (x) == CONFNAK ? "NAK" : "REJ") - - - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ -/* global vars */ -ipcp_options ipcp_wantoptions[NUM_PPP]; /* Options that we want to request */ -ipcp_options ipcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ -ipcp_options ipcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ -ipcp_options ipcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ - -fsm ipcp_fsm[NUM_PPP]; /* IPCP fsm structure */ struct protent ipcp_protent = { PPP_IPCP, @@ -137,53 +140,34 @@ struct protent ipcp_protent = { ipcp_lowerdown, ipcp_open, ipcp_close, -#if 0 +#if PPP_ADDITIONAL_CALLBACKS ipcp_printpkt, NULL, -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ 1, "IPCP", -#if 0 +#if PPP_ADDITIONAL_CALLBACKS ip_check_options, NULL, ip_active_pkt -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ }; +static void ipcp_clear_addrs (int); - -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ -/* local vars */ -static int cis_received[NUM_PPP]; /* # Conf-Reqs received */ -static int default_route_set[NUM_PPP]; /* Have set up a default route */ - -static fsm_callbacks ipcp_callbacks = { /* IPCP callback routines */ - ipcp_resetci, /* Reset our Configuration Information */ - ipcp_cilen, /* Length of our Configuration Information */ - ipcp_addci, /* Add our Configuration Information */ - ipcp_ackci, /* ACK our Configuration Information */ - ipcp_nakci, /* NAK our Configuration Information */ - ipcp_rejci, /* Reject our Configuration Information */ - ipcp_reqci, /* Request peer's Configuration Information */ - ipcp_up, /* Called when fsm reaches LS_OPENED state */ - ipcp_down, /* Called when fsm leaves LS_OPENED state */ - NULL, /* Called when we want the lower layer up */ - ipcp_finished, /* Called when we want the lower layer down */ - NULL, /* Called when Protocol-Reject received */ - NULL, /* Retransmission is necessary */ - NULL, /* Called to handle protocol-specific codes */ - "IPCP" /* String name of protocol */ -}; - +/* + * Lengths of configuration options. + */ +#define CILEN_VOID 2 +#define CILEN_COMPRESS 4 /* min length for compression protocol opt. */ +#define CILEN_VJ 6 /* length for RFC1332 Van-Jacobson opt. */ +#define CILEN_ADDR 6 /* new-style single address option */ +#define CILEN_ADDRS 10 /* old-style dual address option */ -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ +#define CODENAME(x) ((x) == CONFACK ? "ACK" : \ + (x) == CONFNAK ? "NAK" : "REJ") -#define inet_ntoa(addr) ip_ntoa(((struct ip_addr*)&(addr))) /* * ipcp_init - Initialize IPCP. @@ -542,9 +526,9 @@ ipcp_ackci(fsm *f, u_char *p, int len) goto bad; } return (1); - + bad: - IPCPDEBUG((LOG_INFO, "ipcp_ackci: received bad Ack!\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_ackci: received bad Ack!\n")); return (0); } @@ -628,12 +612,12 @@ ipcp_nakci(fsm *f, u_char *p, int len) NAKCIADDR((go->old_addrs? CI_ADDRS: CI_ADDR), neg_addr, go->old_addrs, if (go->accept_local && ciaddr1) { /* Do we know our address? */ try.ouraddr = ciaddr1; - IPCPDEBUG((LOG_INFO, "local IP address %s\n", + IPCPDEBUG(LOG_INFO, ("local IP address %s\n", inet_ntoa(ciaddr1))); } if (go->accept_remote && ciaddr2) { /* Does he know his? */ try.hisaddr = ciaddr2; - IPCPDEBUG((LOG_INFO, "remote IP address %s\n", + IPCPDEBUG(LOG_INFO, ("remote IP address %s\n", inet_ntoa(ciaddr2))); } ); @@ -671,12 +655,12 @@ ipcp_nakci(fsm *f, u_char *p, int len) NAKCIDNS(CI_MS_DNS1, req_dns1, try.dnsaddr[0] = cidnsaddr; - IPCPDEBUG((LOG_INFO, "primary DNS address %s\n", inet_ntoa(cidnsaddr))); + IPCPDEBUG(LOG_INFO, ("primary DNS address %s\n", inet_ntoa(cidnsaddr))); ); NAKCIDNS(CI_MS_DNS2, req_dns2, try.dnsaddr[1] = cidnsaddr; - IPCPDEBUG((LOG_INFO, "secondary DNS address %s\n", inet_ntoa(cidnsaddr))); + IPCPDEBUG(LOG_INFO, ("secondary DNS address %s\n", inet_ntoa(cidnsaddr))); ); /* @@ -754,7 +738,7 @@ ipcp_nakci(fsm *f, u_char *p, int len) return 1; bad: - IPCPDEBUG((LOG_INFO, "ipcp_nakci: received bad Nak!\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_nakci: received bad Nak!\n")); return 0; } @@ -869,7 +853,7 @@ ipcp_rejci(fsm *f, u_char *p, int len) return 1; bad: - IPCPDEBUG((LOG_INFO, "ipcp_rejci: received bad Reject!\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_rejci: received bad Reject!\n")); return 0; } @@ -922,9 +906,9 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: bad CI length!\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: bad CI length!\n")); orc = CONFREJ; /* Reject bad CI */ - cilen = l; /* Reject till end of packet */ + cilen = (u_short)l;/* Reject till end of packet */ l = 0; /* Don't loop again */ goto endswitch; } @@ -936,7 +920,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested switch (citype) { /* Check CI type */ #ifdef OLD_CI_ADDRS /* Need to save space... */ case CI_ADDRS: - IPCPDEBUG((LOG_INFO, "ipcp_reqci: received ADDRS\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received ADDRS\n")); if (!ao->neg_addr || cilen != CILEN_ADDRS) { /* Check CI length */ orc = CONFREJ; /* Reject CI */ @@ -951,7 +935,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested */ GETLONG(tl, p); /* Parse source address (his) */ ciaddr1 = htonl(tl); - IPCPDEBUG((LOG_INFO, "his addr %s\n", inet_ntoa(ciaddr1))); + IPCPDEBUG(LOG_INFO, ("his addr %s\n", inet_ntoa(ciaddr1))); if (ciaddr1 != wo->hisaddr && (ciaddr1 == 0 || !wo->accept_remote)) { orc = CONFNAK; @@ -975,7 +959,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested */ GETLONG(tl, p); /* Parse desination address (ours) */ ciaddr2 = htonl(tl); - IPCPDEBUG((LOG_INFO, "our addr %s\n", inet_ntoa(ciaddr2))); + IPCPDEBUG(LOG_INFO, ("our addr %s\n", inet_ntoa(ciaddr2))); if (ciaddr2 != wo->ouraddr) { if (ciaddr2 == 0 || !wo->accept_local) { orc = CONFNAK; @@ -998,11 +982,11 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested case CI_ADDR: if (!ao->neg_addr) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR not allowed\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR not allowed\n")); orc = CONFREJ; /* Reject CI */ break; } else if (cilen != CILEN_ADDR) { /* Check CI length */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR bad len\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR bad len\n")); orc = CONFREJ; /* Reject CI */ break; } @@ -1023,12 +1007,12 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested tl = ntohl(wo->hisaddr); PUTLONG(tl, p); } - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1))); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Nak ADDR %s\n", inet_ntoa(ciaddr1))); } else if (ciaddr1 == 0 && wo->hisaddr == 0) { /* * Don't ACK an address of 0.0.0.0 - reject it instead. */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1))); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Reject ADDR %s\n", inet_ntoa(ciaddr1))); orc = CONFREJ; wo->req_addr = 0; /* don't NAK with 0.0.0.0 later */ break; @@ -1036,7 +1020,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested ho->neg_addr = 1; ho->hisaddr = ciaddr1; - IPCPDEBUG((LOG_INFO, "ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1))); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: ADDR %s\n", inet_ntoa(ciaddr1))); break; case CI_MS_DNS1: @@ -1047,27 +1031,27 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested /* If we do not have a DNS address then we cannot send it */ if (ao->dnsaddr[d] == 0 || cilen != CILEN_ADDR) { /* Check CI length */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting DNS%d Request\n", d+1)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting DNS%d Request\n", d+1)); orc = CONFREJ; /* Reject CI */ break; } GETLONG(tl, p); if (htonl(tl) != ao->dnsaddr[d]) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking DNS%d Request %d\n", + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking DNS%d Request %s\n", d+1, inet_ntoa(tl))); DECPTR(sizeof(u32_t), p); tl = ntohl(ao->dnsaddr[d]); PUTLONG(tl, p); orc = CONFNAK; } - IPCPDEBUG((LOG_INFO, "ipcp_reqci: received DNS%d Request\n", d+1)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received DNS%d Request\n", d+1)); break; case CI_MS_WINS1: case CI_MS_WINS2: /* Microsoft primary or secondary WINS request */ d = citype == CI_MS_WINS2; - IPCPDEBUG((LOG_INFO, "ipcp_reqci: received WINS%d Request\n", d+1)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: received WINS%d Request\n", d+1)); /* If we do not have a DNS address then we cannot send it */ if (ao->winsaddr[d] == 0 || @@ -1086,11 +1070,11 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested case CI_COMPRESSTYPE: if (!ao->neg_vj) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE not allowed\n")); orc = CONFREJ; break; } else if (cilen != CILEN_VJ && cilen != CILEN_COMPRESS) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE len=%d\n", cilen)); orc = CONFREJ; break; } @@ -1098,7 +1082,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested if (!(cishort == IPCP_VJ_COMP || (cishort == IPCP_VJ_COMP_OLD && cilen == CILEN_COMPRESS))) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting COMPRESSTYPE %d\n", cishort)); orc = CONFREJ; break; } @@ -1108,7 +1092,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested if (cilen == CILEN_VJ) { GETCHAR(maxslotindex, p); if (maxslotindex > ao->maxslotindex) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ max slot %d\n", maxslotindex)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ max slot %d\n", maxslotindex)); orc = CONFNAK; if (!reject_if_disagree) { DECPTR(1, p); @@ -1117,7 +1101,7 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested } GETCHAR(cflag, p); if (cflag && !ao->cflag) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Naking VJ cflag %d\n", cflag)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Naking VJ cflag %d\n", cflag)); orc = CONFNAK; if (!reject_if_disagree) { DECPTR(1, p); @@ -1131,13 +1115,13 @@ ipcp_reqci(fsm *f, u_char *inp/* Requested CIs */,int *len/* Length of requested ho->maxslotindex = MAX_SLOTS - 1; ho->cflag = 1; } - IPCPDEBUG((LOG_INFO, + IPCPDEBUG(LOG_INFO, ( "ipcp_reqci: received COMPRESSTYPE p=%d old=%d maxslot=%d cflag=%d\n", ho->vj_protocol, ho->old_vj, ho->maxslotindex, ho->cflag)); break; default: - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting unknown CI type %d\n", citype)); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting unknown CI type %d\n", citype)); orc = CONFREJ; break; } @@ -1150,7 +1134,7 @@ endswitch: if (orc == CONFNAK) { /* Nak this CI? */ if (reject_if_disagree) { /* Getting fed up with sending NAKs? */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Rejecting too many naks\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Rejecting too many naks\n")); orc = CONFREJ; /* Get tough if so */ } else { if (rc == CONFREJ) { /* Rejecting prior CI? */ @@ -1187,7 +1171,7 @@ endswitch: */ if (rc != CONFREJ && !ho->neg_addr && wo->req_addr && !reject_if_disagree) { - IPCPDEBUG((LOG_INFO, "ipcp_reqci: Requesting peer address\n")); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: Requesting peer address\n")); if (rc == CONFACK) { rc = CONFNAK; ucp = inp; /* reset pointer */ @@ -1200,7 +1184,7 @@ endswitch: } *len = (int)(ucp - inp); /* Compute output length */ - IPCPDEBUG((LOG_INFO, "ipcp_reqci: returning Configure-%s\n", CODENAME(rc))); + IPCPDEBUG(LOG_INFO, ("ipcp_reqci: returning Configure-%s\n", CODENAME(rc))); return (rc); /* Return final code */ } @@ -1241,7 +1225,7 @@ ipcp_up(fsm *f) ipcp_options *wo = &ipcp_wantoptions[f->unit]; np_up(f->unit, PPP_IP); - IPCPDEBUG((LOG_INFO, "ipcp: up\n")); + IPCPDEBUG(LOG_INFO, ("ipcp: up\n")); /* * We must have a non-zero IP address for both ends of the link. @@ -1251,12 +1235,12 @@ ipcp_up(fsm *f) } if (ho->hisaddr == 0) { - IPCPDEBUG((LOG_ERR, "Could not determine remote IP address\n")); + IPCPDEBUG(LOG_ERR, ("Could not determine remote IP address\n")); ipcp_close(f->unit, "Could not determine remote IP address"); return; } if (go->ouraddr == 0) { - IPCPDEBUG((LOG_ERR, "Could not determine local IP address\n")); + IPCPDEBUG(LOG_ERR, ("Could not determine local IP address\n")); ipcp_close(f->unit, "Could not determine local IP address"); return; } @@ -1269,7 +1253,7 @@ ipcp_up(fsm *f) * Check that the peer is allowed to use the IP address it wants. */ if (!auth_ip_addr(f->unit, ho->hisaddr)) { - IPCPDEBUG((LOG_ERR, "Peer is not authorized to use remote address %s\n", + IPCPDEBUG(LOG_ERR, ("Peer is not authorized to use remote address %s\n", inet_ntoa(ho->hisaddr))); ipcp_close(f->unit, "Unauthorized remote IP address"); return; @@ -1284,14 +1268,14 @@ ipcp_up(fsm *f) mask = GetMask(go->ouraddr); if (!sifaddr(f->unit, go->ouraddr, ho->hisaddr, mask, go->dnsaddr[0], go->dnsaddr[1])) { - IPCPDEBUG((LOG_WARNING, "sifaddr failed\n")); + IPCPDEBUG(LOG_WARNING, ("sifaddr failed\n")); ipcp_close(f->unit, "Interface configuration failed"); return; } /* bring the interface up for IP */ if (!sifup(f->unit)) { - IPCPDEBUG((LOG_WARNING, "sifup failed\n")); + IPCPDEBUG(LOG_WARNING, ("sifup failed\n")); ipcp_close(f->unit, "Interface configuration failed"); return; } @@ -1305,13 +1289,13 @@ ipcp_up(fsm *f) } } - IPCPDEBUG((LOG_NOTICE, "local IP address %s\n", inet_ntoa(go->ouraddr))); - IPCPDEBUG((LOG_NOTICE, "remote IP address %s\n", inet_ntoa(ho->hisaddr))); + IPCPDEBUG(LOG_NOTICE, ("local IP address %s\n", inet_ntoa(go->ouraddr))); + IPCPDEBUG(LOG_NOTICE, ("remote IP address %s\n", inet_ntoa(ho->hisaddr))); if (go->dnsaddr[0]) { - IPCPDEBUG((LOG_NOTICE, "primary DNS address %s\n", inet_ntoa(go->dnsaddr[0]))); + IPCPDEBUG(LOG_NOTICE, ("primary DNS address %s\n", inet_ntoa(go->dnsaddr[0]))); } if (go->dnsaddr[1]) { - IPCPDEBUG((LOG_NOTICE, "secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1]))); + IPCPDEBUG(LOG_NOTICE, ("secondary DNS address %s\n", inet_ntoa(go->dnsaddr[1]))); } } @@ -1325,7 +1309,7 @@ ipcp_up(fsm *f) static void ipcp_down(fsm *f) { - IPCPDEBUG((LOG_INFO, "ipcp: down\n")); + IPCPDEBUG(LOG_INFO, ("ipcp: down\n")); np_down(f->unit, PPP_IP); sifvjcomp(f->unit, 0, 0, 0); @@ -1361,7 +1345,7 @@ ipcp_finished(fsm *f) np_finished(f->unit, PPP_IP); } -#if 0 +#if PPP_ADDITIONAL_CALLBACKS static int ipcp_printpkt(u_char *p, int plen, void (*printer) (void *, char *, ...), void *arg) { @@ -1422,6 +1406,6 @@ ip_active_pkt(u_char *pkt, int len) } return 1; } -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ #endif /* PPP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/ipcp.h b/core/lwip/src/netif/ppp/ipcp.h index dfcf4fba..de03f460 100644 --- a/core/lwip/src/netif/ppp/ipcp.h +++ b/core/lwip/src/netif/ppp/ipcp.h @@ -48,15 +48,12 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: ipcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + * $Id: ipcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $ */ #ifndef IPCP_H #define IPCP_H -/************************* -*** PUBLIC DEFINITIONS *** -*************************/ /* * Options. */ @@ -64,10 +61,10 @@ #define CI_COMPRESSTYPE 2 /* Compression Type */ #define CI_ADDR 3 -#define CI_MS_WINS1 128 /* Primary WINS value */ #define CI_MS_DNS1 129 /* Primary DNS value */ -#define CI_MS_WINS2 130 /* Secondary WINS value */ +#define CI_MS_WINS1 128 /* Primary WINS value */ #define CI_MS_DNS2 131 /* Secondary DNS value */ +#define CI_MS_WINS2 130 /* Secondary WINS value */ #define IPCP_VJMODE_OLD 1 /* "old" mode (option # = 0x0037) */ #define IPCP_VJMODE_RFC1172 2 /* "old-rfc"mode (option # = 0x002d) */ @@ -78,11 +75,6 @@ #define IPCP_VJ_COMP_OLD 0x0037 /* "old" (i.e, broken) value for VJ */ /* compression option */ - -/************************ -*** PUBLIC DATA TYPES *** -************************/ - typedef struct ipcp_options { u_int neg_addr : 1; /* Negotiate IP Address? */ u_int old_addrs : 1; /* Use old (IP-Addresses) option? */ @@ -103,11 +95,6 @@ typedef struct ipcp_options { u32_t winsaddr[2]; /* Primary and secondary MS WINS entries */ } ipcp_options; - -/***************************** -*** PUBLIC DATA STRUCTURES *** -*****************************/ - extern fsm ipcp_fsm[]; extern ipcp_options ipcp_wantoptions[]; extern ipcp_options ipcp_gotoptions[]; @@ -116,9 +103,4 @@ extern ipcp_options ipcp_hisoptions[]; extern struct protent ipcp_protent; - -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ - #endif /* IPCP_H */ diff --git a/core/lwip/src/netif/ppp/lcp.c b/core/lwip/src/netif/ppp/lcp.c index 85a0add9..21c83ac4 100644 --- a/core/lwip/src/netif/ppp/lcp.c +++ b/core/lwip/src/netif/ppp/lcp.c @@ -72,25 +72,43 @@ #define PPPOE_MAXMTU PPP_MAXMRU #endif - -/*************************/ -/*** LOCAL DEFINITIONS ***/ -/*************************/ +#if 0 /* UNUSED */ /* - * Length of each type of configuration option (in octets) + * LCP-related command-line options. */ -#define CILEN_VOID 2 -#define CILEN_CHAR 3 -#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ -#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ -#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ -#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ -#define CILEN_CBCP 3 +int lcp_echo_interval = 0; /* Interval between LCP echo-requests */ +int lcp_echo_fails = 0; /* Tolerance to unanswered echo-requests */ +bool lax_recv = 0; /* accept control chars in asyncmap */ +static int setescape (char **); + +static option_t lcp_option_list[] = { + /* LCP options */ + /* list stripped for simplicity */ + {NULL} +}; +#endif /* UNUSED */ + +/* options */ +LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ +static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ +static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ + +/* global vars */ +static fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ +lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ +lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ +lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ +lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ +ext_accm xmit_accm[NUM_PPP]; /* extended transmit ACCM */ + +static u32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ +static u32_t lcp_echo_number = 0; /* ID number of next echo frame */ +static u32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ + +/* @todo: do we really need such a large buffer? The typical 1500 bytes seem too much. */ +static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ /* * Callbacks for fsm code. (CI = Configuration Information) */ @@ -106,12 +124,12 @@ static void lcp_down (fsm*); /* We're DOWN */ static void lcp_starting (fsm*); /* We need lower layer up */ static void lcp_finished (fsm*); /* We need lower layer down */ static int lcp_extcode (fsm*, int, u_char, u_char*, int); - static void lcp_rprotrej (fsm*, u_char*, int); /* * routines to send LCP echos to peer */ + static void lcp_echo_lowerup (int); static void lcp_echo_lowerdown (int); static void LcpEchoTimeout (void*); @@ -120,41 +138,6 @@ static void LcpSendEchoRequest (fsm*); static void LcpLinkFailure (fsm*); static void LcpEchoCheck (fsm*); -/* - * Protocol entry points. - * Some of these are called directly. - */ -static void lcp_input (int, u_char *, int); -static void lcp_protrej (int); - -#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") - - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ -/* global vars */ -LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ -lcp_options lcp_wantoptions[NUM_PPP]; /* Options that we want to request */ -lcp_options lcp_gotoptions[NUM_PPP]; /* Options that peer ack'd */ -lcp_options lcp_allowoptions[NUM_PPP]; /* Options we allow peer to request */ -lcp_options lcp_hisoptions[NUM_PPP]; /* Options that we ack'd */ -ext_accm xmit_accm[NUM_PPP]; /* extended transmit ACCM */ - - - -/*****************************/ -/*** LOCAL DATA STRUCTURES ***/ -/*****************************/ -static fsm lcp_fsm[NUM_PPP]; /* LCP fsm structure (global)*/ -static u_int lcp_echo_interval = LCP_ECHOINTERVAL; /* Interval between LCP echo-requests */ -static u_int lcp_echo_fails = LCP_MAXECHOFAILS; /* Tolerance to unanswered echo-requests */ -static u32_t lcp_echos_pending = 0; /* Number of outstanding echo msgs */ -static u32_t lcp_echo_number = 0; /* ID number of next echo frame */ -static u32_t lcp_echo_timer_running = 0; /* TRUE if a timer is running */ - -static u_char nak_buffer[PPP_MRU]; /* where we construct a nak packet */ - static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ lcp_resetci, /* Reset our Configuration Information */ lcp_cilen, /* Length of our Configuration Information */ @@ -173,6 +156,14 @@ static fsm_callbacks lcp_callbacks = { /* LCP callback routines */ "LCP" /* String name of protocol */ }; +/* + * Protocol entry points. + * Some of these are called directly. + */ + +static void lcp_input (int, u_char *, int); +static void lcp_protrej (int); + struct protent lcp_protent = { PPP_LCP, lcp_init, @@ -182,26 +173,66 @@ struct protent lcp_protent = { lcp_lowerdown, lcp_open, lcp_close, -#if 0 +#if PPP_ADDITIONAL_CALLBACKS lcp_printpkt, NULL, -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ 1, "LCP", -#if 0 +#if PPP_ADDITIONAL_CALLBACKS NULL, NULL, NULL -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ }; int lcp_loopbackfail = DEFLOOPBACKFAIL; +/* + * Length of each type of configuration option (in octets) + */ +#define CILEN_VOID 2 +#define CILEN_CHAR 3 +#define CILEN_SHORT 4 /* CILEN_VOID + sizeof(short) */ +#define CILEN_CHAP 5 /* CILEN_VOID + sizeof(short) + 1 */ +#define CILEN_LONG 6 /* CILEN_VOID + sizeof(long) */ +#define CILEN_LQR 8 /* CILEN_VOID + sizeof(short) + sizeof(long) */ +#define CILEN_CBCP 3 +#define CODENAME(x) ((x) == CONFACK ? "ACK" : (x) == CONFNAK ? "NAK" : "REJ") + +#if 0 /* UNUSED */ +/* + * setescape - add chars to the set we escape on transmission. + */ +static int +setescape(argv) + char **argv; +{ + int n, ret; + char *p, *endp; + + p = *argv; + ret = 1; + while (*p) { + n = strtol(p, &endp, 16); + if (p == endp) { + option_error("escape parameter contains invalid hex number '%s'", p); + return 0; + } + p = endp; + if (n < 0 || n == 0x5E || n > 0xFF) { + option_error("can't escape character 0x%x", n); + ret = 0; + } else + xmit_accm[0][n >> 5] |= 1 << (n & 0x1F); + while (*p == ',' || *p == ' ') + ++p; + } + return ret; +} +#endif /* UNUSED */ -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ /* * lcp_init - Initialize LCP. */ @@ -211,13 +242,13 @@ lcp_init(int unit) fsm *f = &lcp_fsm[unit]; lcp_options *wo = &lcp_wantoptions[unit]; lcp_options *ao = &lcp_allowoptions[unit]; - + f->unit = unit; f->protocol = PPP_LCP; f->callbacks = &lcp_callbacks; - + fsm_init(f); - + wo->passive = 0; wo->silent = 0; wo->restart = 0; /* Set to 1 in kernels or multi-line implementations */ @@ -233,7 +264,7 @@ lcp_init(int unit) wo->neg_accompression = 1; wo->neg_lqr = 0; /* no LQR implementation yet */ wo->neg_cbcp = 0; - + ao->neg_mru = 1; ao->mru = PPP_MAXMRU; ao->neg_asyncmap = 1; @@ -257,7 +288,7 @@ lcp_init(int unit) xmit_accm[unit][1] = (u_char)((ao->asyncmap >> 8) & 0xFF); xmit_accm[unit][2] = (u_char)((ao->asyncmap >> 16) & 0xFF); xmit_accm[unit][3] = (u_char)((ao->asyncmap >> 24) & 0xFF); - LCPDEBUG((LOG_INFO, "lcp_init: xmit_accm=%X %X %X %X\n", + LCPDEBUG(LOG_INFO, ("lcp_init: xmit_accm=%X %X %X %X\n", xmit_accm[unit][0], xmit_accm[unit][1], xmit_accm[unit][2], @@ -310,7 +341,7 @@ lcp_close(int unit, char *reason) f->state = LS_CLOSED; lcp_finished(f); } else { - fsm_close(&lcp_fsm[unit], reason); + fsm_close(f, reason); } } @@ -337,7 +368,7 @@ lcp_lowerup(int unit) | ((u_long)xmit_accm[unit][1] << 8) | ((u_long)xmit_accm[unit][2] << 16) | ((u_long)xmit_accm[unit][3] << 24); - LCPDEBUG((LOG_INFO, "lcp_lowerup: asyncmap=%X %X %X %X\n", + LCPDEBUG(LOG_INFO, ("lcp_lowerup: asyncmap=%X %X %X %X\n", xmit_accm[unit][3], xmit_accm[unit][2], xmit_accm[unit][1], @@ -356,25 +387,7 @@ lcp_lowerdown(int unit) fsm_lowerdown(&lcp_fsm[unit]); } -/* - * lcp_sprotrej - Send a Protocol-Reject for some protocol. - */ -void -lcp_sprotrej(int unit, u_char *p, int len) -{ - /* - * Send back the protocol and the information field of the - * rejected packet. We only get here if LCP is in the LS_OPENED state. - */ - - fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); -} - - -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ /* * lcp_input - Input LCP packet. */ @@ -404,7 +417,7 @@ lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) if (f->state != LS_OPENED) { break; } - LCPDEBUG((LOG_INFO, "lcp: Echo-Request, Rcvd id %d\n", id)); + LCPDEBUG(LOG_INFO, ("lcp: Echo-Request, Rcvd id %d\n", id)); magp = inp; PUTLONG(lcp_gotoptions[f->unit].magicnumber, magp); fsm_sdata(f, ECHOREP, id, inp, len); @@ -413,10 +426,10 @@ lcp_extcode(fsm *f, int code, u_char id, u_char *inp, int len) case ECHOREP: lcp_received_echo_reply(f, id, inp, len); break; - + case DISCREQ: break; - + default: return 0; } @@ -436,21 +449,21 @@ lcp_rprotrej(fsm *f, u_char *inp, int len) struct protent *protp; u_short prot; - if (len < sizeof (u_short)) { - LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); + if (len < (int)sizeof (u_short)) { + LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd short Protocol-Reject packet!\n")); return; } GETSHORT(prot, inp); - LCPDEBUG((LOG_INFO, "lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); + LCPDEBUG(LOG_INFO, ("lcp_rprotrej: Rcvd Protocol-Reject packet for %x!\n", prot)); /* * Protocol-Reject packets received in any state other than the LCP * LS_OPENED state SHOULD be silently discarded. */ if( f->state != LS_OPENED ) { - LCPDEBUG((LOG_INFO, "Protocol-Reject discarded: LCP in state %d\n", f->state)); + LCPDEBUG(LOG_INFO, ("Protocol-Reject discarded: LCP in state %d\n", f->state)); return; } @@ -464,7 +477,7 @@ lcp_rprotrej(fsm *f, u_char *inp, int len) } } - LCPDEBUG((LOG_WARNING, "Protocol-Reject for unsupported protocol 0x%x\n", prot)); + LCPDEBUG(LOG_WARNING, ("Protocol-Reject for unsupported protocol 0x%x\n", prot)); } @@ -478,12 +491,27 @@ lcp_protrej(int unit) /* * Can't reject LCP! */ - LCPDEBUG((LOG_WARNING, "lcp_protrej: Received Protocol-Reject for LCP!\n")); + LCPDEBUG(LOG_WARNING, ("lcp_protrej: Received Protocol-Reject for LCP!\n")); fsm_protreject(&lcp_fsm[unit]); } /* + * lcp_sprotrej - Send a Protocol-Reject for some protocol. + */ +void +lcp_sprotrej(int unit, u_char *p, int len) +{ + /* + * Send back the protocol and the information field of the + * rejected packet. We only get here if LCP is in the LS_OPENED state. + */ + + fsm_sdata(&lcp_fsm[unit], PROTREJ, ++lcp_fsm[unit].id, p, len); +} + + +/* * lcp_resetci - Reset our CI. */ static void @@ -500,7 +528,8 @@ lcp_resetci(fsm *f) /* * lcp_cilen - Return length of our CI. */ -static int lcp_cilen(fsm *f) +static int +lcp_cilen(fsm *f) { lcp_options *go = &lcp_gotoptions[f->unit]; @@ -537,20 +566,20 @@ lcp_addci(fsm *f, u_char *ucp, int *lenp) #define ADDCIVOID(opt, neg) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: opt=%d\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: opt=%d\n", opt)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_VOID, ucp); \ } #define ADDCISHORT(opt, neg, val) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: INT opt=%d %X\n", opt, val)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: INT opt=%d %X\n", opt, val)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_SHORT, ucp); \ PUTSHORT(val, ucp); \ } #define ADDCICHAP(opt, neg, val, digest) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: CHAP opt=%d %X\n", opt, val)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: CHAP opt=%d %X\n", opt, val)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_CHAP, ucp); \ PUTSHORT(val, ucp); \ @@ -558,14 +587,14 @@ lcp_addci(fsm *f, u_char *ucp, int *lenp) } #define ADDCILONG(opt, neg, val) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: L opt=%d %lX\n", opt, val)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: L opt=%d %lX\n", opt, val)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LONG, ucp); \ PUTLONG(val, ucp); \ } #define ADDCILQR(opt, neg, val) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: LQR opt=%d %lX\n", opt, val)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: LQR opt=%d %lX\n", opt, val)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_LQR, ucp); \ PUTSHORT(PPP_LQR, ucp); \ @@ -573,7 +602,7 @@ lcp_addci(fsm *f, u_char *ucp, int *lenp) } #define ADDCICHAR(opt, neg, val) \ if (neg) { \ - LCPDEBUG((LOG_INFO, "lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ + LCPDEBUG(LOG_INFO, ("lcp_addci: CHAR opt=%d %X '%z'\n", opt, val, val)); \ PUTCHAR(opt, ucp); \ PUTCHAR(CILEN_CHAR, ucp); \ PUTCHAR(val, ucp); \ @@ -591,7 +620,7 @@ lcp_addci(fsm *f, u_char *ucp, int *lenp) if (ucp - start_ucp != *lenp) { /* this should never happen, because peer_mtu should be 1500 */ - LCPDEBUG((LOG_ERR, "Bug in lcp_addci: wrong length\n")); + LCPDEBUG(LOG_ERR, ("Bug in lcp_addci: wrong length\n")); } } @@ -709,10 +738,10 @@ lcp_ackci(fsm *f, u_char *p, int len) if (len != 0) { goto bad; } - LCPDEBUG((LOG_INFO, "lcp_acki: Ack\n")); + LCPDEBUG(LOG_INFO, ("lcp_acki: Ack\n")); return (1); bad: - LCPDEBUG((LOG_WARNING, "lcp_acki: received bad Ack!\n")); + LCPDEBUG(LOG_WARNING, ("lcp_acki: received bad Ack!\n")); return (0); } @@ -1020,7 +1049,7 @@ lcp_nakci(fsm *f, u_char *p, int len) if (f->state != LS_OPENED) { if (looped_back) { if (++try.numloops >= lcp_loopbackfail) { - LCPDEBUG((LOG_NOTICE, "Serial line is looped back.\n")); + LCPDEBUG(LOG_NOTICE, ("Serial line is looped back.\n")); lcp_close(f->unit, "Loopback detected"); } } else { @@ -1032,7 +1061,7 @@ lcp_nakci(fsm *f, u_char *p, int len) return 1; bad: - LCPDEBUG((LOG_WARNING, "lcp_nakci: received bad Nak!\n")); + LCPDEBUG(LOG_WARNING, ("lcp_nakci: received bad Nak!\n")); return 0; } @@ -1070,7 +1099,7 @@ lcp_rejci(fsm *f, u_char *p, int len) len -= CILEN_VOID; \ INCPTR(CILEN_VOID, p); \ try.neg = 0; \ - LCPDEBUG((LOG_INFO, "lcp_rejci: void opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: void opt %d rejected\n", opt)); \ } #define REJCISHORT(opt, neg, val) \ if (go->neg && \ @@ -1085,7 +1114,7 @@ lcp_rejci(fsm *f, u_char *p, int len) goto bad; \ } \ try.neg = 0; \ - LCPDEBUG((LOG_INFO,"lcp_rejci: short opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: short opt %d rejected\n", opt)); \ } #define REJCICHAP(opt, neg, val, digest) \ if (go->neg && \ @@ -1102,7 +1131,7 @@ lcp_rejci(fsm *f, u_char *p, int len) } \ try.neg = 0; \ try.neg_upap = 0; \ - LCPDEBUG((LOG_INFO,"lcp_rejci: chap opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: chap opt %d rejected\n", opt)); \ } #define REJCILONG(opt, neg, val) \ if (go->neg && \ @@ -1117,7 +1146,7 @@ lcp_rejci(fsm *f, u_char *p, int len) goto bad; \ } \ try.neg = 0; \ - LCPDEBUG((LOG_INFO,"lcp_rejci: long opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: long opt %d rejected\n", opt)); \ } #define REJCILQR(opt, neg, val) \ if (go->neg && \ @@ -1133,7 +1162,7 @@ lcp_rejci(fsm *f, u_char *p, int len) goto bad; \ } \ try.neg = 0; \ - LCPDEBUG((LOG_INFO,"lcp_rejci: LQR opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: LQR opt %d rejected\n", opt)); \ } #define REJCICBCP(opt, neg, val) \ if (go->neg && \ @@ -1148,7 +1177,7 @@ lcp_rejci(fsm *f, u_char *p, int len) goto bad; \ } \ try.neg = 0; \ - LCPDEBUG((LOG_INFO,"lcp_rejci: Callback opt %d rejected\n", opt)); \ + LCPDEBUG(LOG_INFO, ("lcp_rejci: Callback opt %d rejected\n", opt)); \ } REJCISHORT(CI_MRU, neg_mru, go->mru); @@ -1178,7 +1207,7 @@ lcp_rejci(fsm *f, u_char *p, int len) return 1; bad: - LCPDEBUG((LOG_WARNING, "lcp_rejci: received bad Reject!\n")); + LCPDEBUG(LOG_WARNING, ("lcp_rejci: received bad Reject!\n")); return 0; } @@ -1200,7 +1229,8 @@ lcp_reqci(fsm *f, lcp_options *ho = &lcp_hisoptions[f->unit]; lcp_options *ao = &lcp_allowoptions[f->unit]; u_char *cip, *next; /* Pointer to current and next CIs */ - int cilen, citype, cichar; /* Parsed len, type, char value */ + int cilen, citype; /* Parsed len, type */ + u_char cichar; /* Parsed char value */ u_short cishort; /* Parsed short value */ u32_t cilong; /* Parse long value */ int rc = CONFACK; /* Final packet return code */ @@ -1211,7 +1241,7 @@ lcp_reqci(fsm *f, int l = *lenp; /* Length left */ #if TRACELCP > 0 char traceBuf[80]; - int traceNdx = 0; + size_t traceNdx = 0; #endif /* @@ -1231,7 +1261,7 @@ lcp_reqci(fsm *f, if (l < 2 || /* Not enough data for CI header or */ p[1] < 2 || /* CI length too small or */ p[1] > l) { /* CI length too big? */ - LCPDEBUG((LOG_WARNING, "lcp_reqci: bad CI length!\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: bad CI length!\n")); orc = CONFREJ; /* Reject bad CI */ cilen = l; /* Reject till end of packet */ l = 0; /* Don't loop again */ @@ -1246,11 +1276,11 @@ lcp_reqci(fsm *f, switch (citype) { /* Check CI type */ case CI_MRU: if (!ao->neg_mru) { /* Allow option? */ - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - not allowed\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - not allowed\n")); orc = CONFREJ; /* Reject CI */ break; } else if (cilen != CILEN_SHORT) { /* Check CI length */ - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject MRU - bad length\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject MRU - bad length\n")); orc = CONFREJ; /* Reject CI */ break; } @@ -1262,7 +1292,7 @@ lcp_reqci(fsm *f, * we'll just ignore it. */ if (cishort < PPP_MINMRU) { - LCPDEBUG((LOG_INFO, "lcp_reqci: Nak - MRU too small\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak - MRU too small\n")); orc = CONFNAK; /* Nak CI */ PUTCHAR(CI_MRU, nakp); PUTCHAR(CILEN_SHORT, nakp); @@ -1279,11 +1309,11 @@ lcp_reqci(fsm *f, case CI_ASYNCMAP: if (!ao->neg_asyncmap) { - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP not allowed\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP not allowed\n")); orc = CONFREJ; break; } else if (cilen != CILEN_LONG) { - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject ASYNCMAP bad length\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject ASYNCMAP bad length\n")); orc = CONFREJ; break; } @@ -1294,7 +1324,7 @@ lcp_reqci(fsm *f, * which are set in lcp_allowoptions[unit].asyncmap. */ if ((ao->asyncmap & ~cilong) != 0) { - LCPDEBUG((LOG_INFO, "lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", + LCPDEBUG(LOG_INFO, ("lcp_reqci: Nak ASYNCMAP %lX missing %lX\n", cilong, ao->asyncmap)); orc = CONFNAK; PUTCHAR(CI_ASYNCMAP, nakp); @@ -1312,14 +1342,14 @@ lcp_reqci(fsm *f, case CI_AUTHTYPE: if (cilen < CILEN_SHORT) { - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE missing arg\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE missing arg\n")); orc = CONFREJ; break; } else if (!(ao->neg_upap || ao->neg_chap)) { /* * Reject the option if we're not willing to authenticate. */ - LCPDEBUG((LOG_INFO, "lcp_reqci: Reject AUTHTYPE not allowed\n")); + LCPDEBUG(LOG_INFO, ("lcp_reqci: Reject AUTHTYPE not allowed\n")); orc = CONFREJ; break; } @@ -1338,16 +1368,16 @@ lcp_reqci(fsm *f, if (cishort == PPP_PAP) { if (ho->neg_chap) { /* we've already accepted CHAP */ - LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP already accepted\n")); orc = CONFREJ; break; } else if (cilen != CILEN_SHORT) { - LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE PAP bad len\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE PAP bad len\n")); orc = CONFREJ; break; } if (!ao->neg_upap) { /* we don't want to do PAP */ - LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE PAP not allowed\n")); orc = CONFNAK; /* NAK it and suggest CHAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); @@ -1364,16 +1394,16 @@ lcp_reqci(fsm *f, } if (cishort == PPP_CHAP) { if (ho->neg_upap) { /* we've already accepted PAP */ - LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP accepted PAP\n")); orc = CONFREJ; break; } else if (cilen != CILEN_CHAP) { - LCPDEBUG((LOG_WARNING, "lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Reject AUTHTYPE CHAP bad len\n")); orc = CONFREJ; break; } if (!ao->neg_chap) { /* we don't want to do CHAP */ - LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP not allowed\n")); orc = CONFNAK; /* NAK it and suggest PAP */ PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_SHORT, nakp); @@ -1382,11 +1412,11 @@ lcp_reqci(fsm *f, } GETCHAR(cichar, p); /* get digest type*/ if (cichar != CHAP_DIGEST_MD5 -#ifdef CHAPMS +#if MSCHAP_SUPPORT && cichar != CHAP_MICROSOFT #endif ) { - LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", cichar)); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE CHAP digest=%d\n", (int)cichar)); orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); PUTCHAR(CILEN_CHAP, nakp); @@ -1395,7 +1425,7 @@ lcp_reqci(fsm *f, break; } #if TRACELCP > 0 - snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, cichar); + snprintf(&traceBuf[traceNdx], sizeof(traceBuf), " CHAP %X,%d", cishort, (int)cichar); traceNdx = strlen(traceBuf); #endif ho->chap_mdtype = cichar; /* save md type */ @@ -1411,12 +1441,12 @@ lcp_reqci(fsm *f, orc = CONFNAK; PUTCHAR(CI_AUTHTYPE, nakp); if (ao->neg_chap) { - LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req CHAP\n", cishort)); PUTCHAR(CILEN_CHAP, nakp); PUTSHORT(PPP_CHAP, nakp); PUTCHAR(ao->chap_mdtype, nakp); } else { - LCPDEBUG((LOG_WARNING, "lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); + LCPDEBUG(LOG_WARNING, ("lcp_reqci: Nak AUTHTYPE %d req PAP\n", cishort)); PUTCHAR(CILEN_SHORT, nakp); PUTSHORT(PPP_PAP, nakp); } @@ -1541,7 +1571,7 @@ lcp_reqci(fsm *f, endswitch: #if TRACELCP if (traceNdx >= 80 - 32) { - LCPDEBUG((LOG_INFO, "lcp_reqci: rcvd%s\n", traceBuf)); + LCPDEBUG(LOG_INFO, ("lcp_reqci: rcvd%s\n", traceBuf)); traceNdx = 0; } #endif @@ -1595,10 +1625,10 @@ lcp_reqci(fsm *f, #if TRACELCP > 0 if (traceNdx > 0) { - LCPDEBUG((LOG_INFO, "lcp_reqci: %s\n", traceBuf)); + LCPDEBUG(LOG_INFO, ("lcp_reqci: %s\n", traceBuf)); } #endif - LCPDEBUG((LOG_INFO, "lcp_reqci: returning CONF%s.\n", CODENAME(rc))); + LCPDEBUG(LOG_INFO, ("lcp_reqci: returning CONF%s.\n", CODENAME(rc))); return (rc); /* Return final code */ } @@ -1645,7 +1675,7 @@ lcp_up(fsm *f) lcp_echo_lowerup(f->unit); /* Enable echo messages */ - link_established(f->unit); + link_established(f->unit); /* The link is up; authenticate now */ } @@ -1677,7 +1707,7 @@ lcp_down(fsm *f) static void lcp_starting(fsm *f) { - link_required(f->unit); + link_required(f->unit); /* lwip: currently does nothing */ } @@ -1687,11 +1717,11 @@ lcp_starting(fsm *f) static void lcp_finished(fsm *f) { - link_terminated(f->unit); + link_terminated(f->unit); /* we are finished with the link */ } -#if 0 +#if PPP_ADDITIONAL_CALLBACKS /* * print_string - print a readable representation of a string using * printer. @@ -1898,7 +1928,7 @@ lcp_printpkt( u_char *p, int plen, void (*printer) (void *, char *, ...), void * return (int)(p - pstart); } -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ /* * Time to shut down the link because there is nothing out there. @@ -1907,8 +1937,8 @@ static void LcpLinkFailure (fsm *f) { if (f->state == LS_OPENED) { - LCPDEBUG((LOG_INFO, "No response to %d echo-requests\n", lcp_echos_pending)); - LCPDEBUG((LOG_NOTICE, "Serial link appears to be disconnected.\n")); + LCPDEBUG(LOG_INFO, ("No response to %d echo-requests\n", lcp_echos_pending)); + LCPDEBUG(LOG_NOTICE, ("Serial link appears to be disconnected.\n")); lcp_close(f->unit, "Peer not responding"); } } @@ -1954,15 +1984,15 @@ lcp_received_echo_reply (fsm *f, int id, u_char *inp, int len) /* Check the magic number - don't count replies from ourselves. */ if (len < 4) { - LCPDEBUG((LOG_WARNING, "lcp: received short Echo-Reply, length %d\n", len)); + LCPDEBUG(LOG_WARNING, ("lcp: received short Echo-Reply, length %d\n", len)); return; } GETLONG(magic, inp); if (lcp_gotoptions[f->unit].neg_magicnumber && magic == lcp_gotoptions[f->unit].magicnumber) { - LCPDEBUG((LOG_WARNING, "appear to have received our own echo-reply!\n")); + LCPDEBUG(LOG_WARNING, ("appear to have received our own echo-reply!\n")); return; } - + /* Reset the number of outstanding echo frames */ lcp_echos_pending = 0; } @@ -1980,7 +2010,7 @@ LcpSendEchoRequest (fsm *f) * Detect the failure of the peer at this point. */ if (lcp_echo_fails != 0) { - if (lcp_echos_pending++ >= lcp_echo_fails) { + if (lcp_echos_pending >= lcp_echo_fails) { LcpLinkFailure(f); lcp_echos_pending = 0; } @@ -1994,6 +2024,7 @@ LcpSendEchoRequest (fsm *f) pktp = pkt; PUTLONG(lcp_magic, pktp); fsm_sdata(f, ECHOREQ, (u_char)(lcp_echo_number++ & 0xFF), pkt, (int)(pktp - pkt)); + ++lcp_echos_pending; } } diff --git a/core/lwip/src/netif/ppp/lcp.h b/core/lwip/src/netif/ppp/lcp.h index 1a5e5a4c..b9201eeb 100644 --- a/core/lwip/src/netif/ppp/lcp.h +++ b/core/lwip/src/netif/ppp/lcp.h @@ -48,15 +48,11 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: lcp.h,v 1.3 2007/12/19 20:47:23 fbernon Exp $ + * $Id: lcp.h,v 1.4 2010/01/18 20:49:43 goldsimon Exp $ */ #ifndef LCP_H #define LCP_H - -/************************* -*** PUBLIC DEFINITIONS *** -*************************/ /* * Options. */ @@ -73,7 +69,7 @@ #define CI_EPDISC 19 /* endpoint discriminator */ /* - * LCP-specific packet types. + * LCP-specific packet types (code numbers). */ #define PROTREJ 8 /* Protocol Reject */ #define ECHOREQ 9 /* Echo Request */ @@ -81,11 +77,6 @@ #define DISCREQ 11 /* Discard Request */ #define CBCP_OPT 6 /* Use callback control protocol */ - -/************************ -*** PUBLIC DATA TYPES *** -************************/ - /* * The state of options is described by an lcp_options structure. */ @@ -135,9 +126,6 @@ typedef enum { } LinkPhase; -/***************************** -*** PUBLIC DATA STRUCTURES *** -*****************************/ extern LinkPhase lcp_phase[NUM_PPP]; /* Phase of link session (RFC 1661) */ extern lcp_options lcp_wantoptions[]; @@ -147,10 +135,6 @@ extern lcp_options lcp_hisoptions[]; extern ext_accm xmit_accm[]; -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ - void lcp_init (int); void lcp_open (int); void lcp_close (int, char *); diff --git a/core/lwip/src/netif/ppp/magic.c b/core/lwip/src/netif/ppp/magic.c index d3922bb5..39013308 100644 --- a/core/lwip/src/netif/ppp/magic.c +++ b/core/lwip/src/netif/ppp/magic.c @@ -57,9 +57,7 @@ #include "randm.h" #include "magic.h" -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ + /* * magicInit - Initialize the magic number generator. * diff --git a/core/lwip/src/netif/ppp/magic.h b/core/lwip/src/netif/ppp/magic.h index bc517499..eba70d20 100644 --- a/core/lwip/src/netif/ppp/magic.h +++ b/core/lwip/src/netif/ppp/magic.h @@ -48,16 +48,12 @@ * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. * - * $Id: magic.h,v 1.2 2007/12/02 22:35:55 fbernon Exp $ + * $Id: magic.h,v 1.3 2010/01/18 20:49:43 goldsimon Exp $ */ #ifndef MAGIC_H #define MAGIC_H -/***************************************************************************** -************************** PUBLIC FUNCTIONS ********************************** -*****************************************************************************/ - /* Initialize the magic number generator */ void magicInit(void); diff --git a/core/lwip/src/netif/ppp/md5.c b/core/lwip/src/netif/ppp/md5.c index 7a60d783..3cb69e2b 100644 --- a/core/lwip/src/netif/ppp/md5.c +++ b/core/lwip/src/netif/ppp/md5.c @@ -138,8 +138,8 @@ MD5Update(MD5_CTX *mdContext, unsigned char *inBuf, unsigned int inLen) unsigned int i, ii; #if 0 - ppp_trace(LOG_INFO, "MD5Update: %u:%.*H\n", inLen, MIN(inLen, 20) * 2, inBuf); - ppp_trace(LOG_INFO, "MD5Update: %u:%s\n", inLen, inBuf); + PPPDEBUG(LOG_INFO, ("MD5Update: %u:%.*H\n", inLen, LWIP_MIN(inLen, 20) * 2, inBuf)); + PPPDEBUG(LOG_INFO, ("MD5Update: %u:%s\n", inLen, inBuf)); #endif /* compute number of bytes mod 64 */ diff --git a/core/lwip/src/netif/ppp/pap.c b/core/lwip/src/netif/ppp/pap.c index e8c45dff..ac44e646 100644 --- a/core/lwip/src/netif/ppp/pap.c +++ b/core/lwip/src/netif/ppp/pap.c @@ -63,9 +63,27 @@ #include <string.h> -/***********************************/ -/*** LOCAL FUNCTION DECLARATIONS ***/ -/***********************************/ +#if 0 /* UNUSED */ +static bool hide_password = 1; + +/* + * Command-line options. + */ +static option_t pap_option_list[] = { + { "hide-password", o_bool, &hide_password, + "Don't output passwords to log", 1 }, + { "show-password", o_bool, &hide_password, + "Show password string in debug log messages", 0 }, + { "pap-restart", o_int, &upap[0].us_timeouttime, + "Set retransmit timeout for PAP" }, + { "pap-max-authreq", o_int, &upap[0].us_maxtransmits, + "Set max number of transmissions for auth-reqs" }, + { "pap-timeout", o_int, &upap[0].us_reqtimeout, + "Set time limit for peer PAP authentication" }, + { NULL } +}; +#endif + /* * Protocol entry points. */ @@ -74,19 +92,10 @@ static void upap_lowerup (int); static void upap_lowerdown (int); static void upap_input (int, u_char *, int); static void upap_protrej (int); +#if PPP_ADDITIONAL_CALLBACKS +static int upap_printpkt (u_char *, int, void (*)(void *, char *, ...), void *); +#endif /* PPP_ADDITIONAL_CALLBACKS */ -static void upap_timeout (void *); -static void upap_reqtimeout(void *); -static void upap_rauthreq (upap_state *, u_char *, int, int); -static void upap_rauthack (upap_state *, u_char *, int, int); -static void upap_rauthnak (upap_state *, u_char *, int, int); -static void upap_sauthreq (upap_state *); -static void upap_sresp (upap_state *, u_char, u_char, char *, int); - - -/******************************/ -/*** PUBLIC DATA STRUCTURES ***/ -/******************************/ struct protent pap_protent = { PPP_PAP, upap_init, @@ -96,41 +105,51 @@ struct protent pap_protent = { upap_lowerdown, NULL, NULL, -#if 0 +#if PPP_ADDITIONAL_CALLBACKS upap_printpkt, NULL, -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ 1, "PAP", -#if 0 +#if PPP_ADDITIONAL_CALLBACKS NULL, NULL, NULL -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ }; upap_state upap[NUM_PPP]; /* UPAP state; one for each unit */ +static void upap_timeout (void *); +static void upap_reqtimeout(void *); +static void upap_rauthreq (upap_state *, u_char *, u_char, int); +static void upap_rauthack (upap_state *, u_char *, int, int); +static void upap_rauthnak (upap_state *, u_char *, int, int); +static void upap_sauthreq (upap_state *); +static void upap_sresp (upap_state *, u_char, u_char, char *, int); -/***********************************/ -/*** PUBLIC FUNCTION DEFINITIONS ***/ -/***********************************/ /* - * Set the default login name and password for the pap sessions + * upap_init - Initialize a UPAP unit. */ -void -upap_setloginpasswd(int unit, const char *luser, const char *lpassword) +static void +upap_init(int unit) { upap_state *u = &upap[unit]; - - /* Save the username and password we're given */ - u->us_user = luser; - u->us_userlen = strlen(luser); - u->us_passwd = lpassword; - u->us_passwdlen = strlen(lpassword); -} + UPAPDEBUG(LOG_INFO, ("upap_init: %d\n", unit)); + u->us_unit = unit; + u->us_user = NULL; + u->us_userlen = 0; + u->us_passwd = NULL; + u->us_passwdlen = 0; + u->us_clientstate = UPAPCS_INITIAL; + u->us_serverstate = UPAPSS_INITIAL; + u->us_id = 0; + u->us_timeouttime = UPAP_DEFTIMEOUT; + u->us_maxtransmits = 10; + u->us_reqtimeout = UPAP_DEFREQTIME; +} /* * upap_authwithpeer - Authenticate us with our peer (start client). @@ -142,10 +161,14 @@ upap_authwithpeer(int unit, char *user, char *password) { upap_state *u = &upap[unit]; - UPAPDEBUG((LOG_INFO, "upap_authwithpeer: %d user=%s password=%s s=%d\n", + UPAPDEBUG(LOG_INFO, ("upap_authwithpeer: %d user=%s password=%s s=%d\n", unit, user, password, u->us_clientstate)); - upap_setloginpasswd(unit, user, password); + /* Save the username and password we're given */ + u->us_user = user; + u->us_userlen = (int)strlen(user); + u->us_passwd = password; + u->us_passwdlen = (int)strlen(password); u->us_transmits = 0; @@ -183,33 +206,6 @@ upap_authpeer(int unit) } } - - -/**********************************/ -/*** LOCAL FUNCTION DEFINITIONS ***/ -/**********************************/ -/* - * upap_init - Initialize a UPAP unit. - */ -static void -upap_init(int unit) -{ - upap_state *u = &upap[unit]; - - UPAPDEBUG((LOG_INFO, "upap_init: %d\n", unit)); - u->us_unit = unit; - u->us_user = NULL; - u->us_userlen = 0; - u->us_passwd = NULL; - u->us_passwdlen = 0; - u->us_clientstate = UPAPCS_INITIAL; - u->us_serverstate = UPAPSS_INITIAL; - u->us_id = 0; - u->us_timeouttime = UPAP_DEFTIMEOUT; - u->us_maxtransmits = 10; - u->us_reqtimeout = UPAP_DEFREQTIME; -} - /* * upap_timeout - Retransmission timer for sending auth-reqs expired. */ @@ -218,22 +214,23 @@ upap_timeout(void *arg) { upap_state *u = (upap_state *) arg; - UPAPDEBUG((LOG_INFO, "upap_timeout: %d timeout %d expired s=%d\n", + UPAPDEBUG(LOG_INFO, ("upap_timeout: %d timeout %d expired s=%d\n", u->us_unit, u->us_timeouttime, u->us_clientstate)); if (u->us_clientstate != UPAPCS_AUTHREQ) { + UPAPDEBUG(LOG_INFO, ("upap_timeout: not in AUTHREQ state!\n")); return; } if (u->us_transmits >= u->us_maxtransmits) { /* give up in disgust */ - UPAPDEBUG((LOG_ERR, "No response to PAP authenticate-requests\n")); + UPAPDEBUG(LOG_ERR, ("No response to PAP authenticate-requests\n")); u->us_clientstate = UPAPCS_BADAUTH; auth_withpeer_fail(u->us_unit, PPP_PAP); return; } - upap_sauthreq(u); /* Send Authenticate-Request */ + upap_sauthreq(u); /* Send Authenticate-Request and set upap timeout*/ } @@ -264,12 +261,13 @@ upap_lowerup(int unit) { upap_state *u = &upap[unit]; - UPAPDEBUG((LOG_INFO, "upap_lowerup: %d s=%d\n", unit, u->us_clientstate)); + UPAPDEBUG(LOG_INFO, ("upap_lowerup: init %d clientstate s=%d\n", unit, u->us_clientstate)); if (u->us_clientstate == UPAPCS_INITIAL) { u->us_clientstate = UPAPCS_CLOSED; } else if (u->us_clientstate == UPAPCS_PENDING) { upap_sauthreq(u); /* send an auth-request */ + /* now client state is UPAPCS__AUTHREQ */ } if (u->us_serverstate == UPAPSS_INITIAL) { @@ -293,7 +291,7 @@ upap_lowerdown(int unit) { upap_state *u = &upap[unit]; - UPAPDEBUG((LOG_INFO, "upap_lowerdown: %d s=%d\n", unit, u->us_clientstate)); + UPAPDEBUG(LOG_INFO, ("upap_lowerdown: %d s=%d\n", unit, u->us_clientstate)); if (u->us_clientstate == UPAPCS_AUTHREQ) { /* Timeout pending? */ UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ @@ -318,11 +316,11 @@ upap_protrej(int unit) upap_state *u = &upap[unit]; if (u->us_clientstate == UPAPCS_AUTHREQ) { - UPAPDEBUG((LOG_ERR, "PAP authentication failed due to protocol-reject\n")); + UPAPDEBUG(LOG_ERR, ("PAP authentication failed due to protocol-reject\n")); auth_withpeer_fail(unit, PPP_PAP); } if (u->us_serverstate == UPAPSS_LISTEN) { - UPAPDEBUG((LOG_ERR, "PAP authentication of peer failed (protocol-reject)\n")); + UPAPDEBUG(LOG_ERR, ("PAP authentication of peer failed (protocol-reject)\n")); auth_peer_fail(unit, PPP_PAP); } upap_lowerdown(unit); @@ -345,19 +343,19 @@ upap_input(int unit, u_char *inpacket, int l) * If packet too short, drop it. */ inp = inpacket; - if (l < UPAP_HEADERLEN) { - UPAPDEBUG((LOG_INFO, "pap_input: rcvd short header.\n")); + if (l < (int)UPAP_HEADERLEN) { + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short header.\n")); return; } GETCHAR(code, inp); GETCHAR(id, inp); GETSHORT(len, inp); - if (len < UPAP_HEADERLEN) { - UPAPDEBUG((LOG_INFO, "pap_input: rcvd illegal length.\n")); + if (len < (int)UPAP_HEADERLEN) { + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd illegal length.\n")); return; } if (len > l) { - UPAPDEBUG((LOG_INFO, "pap_input: rcvd short packet.\n")); + UPAPDEBUG(LOG_INFO, ("pap_input: rcvd short packet.\n")); return; } len -= UPAP_HEADERLEN; @@ -379,6 +377,7 @@ upap_input(int unit, u_char *inpacket, int l) break; default: /* XXX Need code reject */ + UPAPDEBUG(LOG_INFO, ("pap_input: UNHANDLED default: code: %d, id: %d, len: %d.\n", code, id, len)); break; } } @@ -388,15 +387,15 @@ upap_input(int unit, u_char *inpacket, int l) * upap_rauth - Receive Authenticate. */ static void -upap_rauthreq(upap_state *u, u_char *inp, int id, int len) +upap_rauthreq(upap_state *u, u_char *inp, u_char id, int len) { u_char ruserlen, rpasswdlen; char *ruser, *rpasswd; - int retcode; + u_char retcode; char *msg; int msglen; - UPAPDEBUG((LOG_INFO, "pap_rauth: Rcvd id %d.\n", id)); + UPAPDEBUG(LOG_INFO, ("pap_rauth: Rcvd id %d.\n", id)); if (u->us_serverstate < UPAPSS_LISTEN) { return; @@ -418,21 +417,21 @@ upap_rauthreq(upap_state *u, u_char *inp, int id, int len) /* * Parse user/passwd. */ - if (len < sizeof (u_char)) { - UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); + if (len < (int)sizeof (u_char)) { + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); return; } GETCHAR(ruserlen, inp); len -= sizeof (u_char) + ruserlen + sizeof (u_char); if (len < 0) { - UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); return; } ruser = (char *) inp; INCPTR(ruserlen, inp); GETCHAR(rpasswdlen, inp); if (len < rpasswdlen) { - UPAPDEBUG((LOG_INFO, "pap_rauth: rcvd short packet.\n")); + UPAPDEBUG(LOG_INFO, ("pap_rauth: rcvd short packet.\n")); return; } rpasswd = (char *) inp; @@ -441,6 +440,7 @@ upap_rauthreq(upap_state *u, u_char *inp, int id, int len) * Check the username and password given. */ retcode = check_passwd(u->us_unit, ruser, ruserlen, rpasswd, rpasswdlen, &msg, &msglen); + /* lwip: currently retcode is always UPAP_AUTHACK */ BZERO(rpasswd, rpasswdlen); upap_sresp(u, retcode, id, msg, msglen); @@ -470,28 +470,30 @@ upap_rauthack(upap_state *u, u_char *inp, int id, int len) LWIP_UNUSED_ARG(id); - UPAPDEBUG((LOG_INFO, "pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate)); + UPAPDEBUG(LOG_INFO, ("pap_rauthack: Rcvd id %d s=%d\n", id, u->us_clientstate)); if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ + UPAPDEBUG(LOG_INFO, ("pap_rauthack: us_clientstate != UPAPCS_AUTHREQ\n")); return; } /* * Parse message. */ - if (len < sizeof (u_char)) { - UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); - return; - } - GETCHAR(msglen, inp); - len -= sizeof (u_char); - if (len < msglen) { - UPAPDEBUG((LOG_INFO, "pap_rauthack: rcvd short packet.\n")); - return; + if (len < (int)sizeof (u_char)) { + UPAPDEBUG(LOG_INFO, ("pap_rauthack: ignoring missing msg-length.\n")); + } else { + GETCHAR(msglen, inp); + if (msglen > 0) { + len -= sizeof (u_char); + if (len < msglen) { + UPAPDEBUG(LOG_INFO, ("pap_rauthack: rcvd short packet.\n")); + return; + } + msg = (char *) inp; + PRINTMSG(msg, msglen); + } } - msg = (char *) inp; - PRINTMSG(msg, msglen); - UNTIMEOUT(upap_timeout, u); /* Cancel timeout */ u->us_clientstate = UPAPCS_OPEN; @@ -500,7 +502,7 @@ upap_rauthack(upap_state *u, u_char *inp, int id, int len) /* - * upap_rauthnak - Receive Authenticate-Nakk. + * upap_rauthnak - Receive Authenticate-Nak. */ static void upap_rauthnak(upap_state *u, u_char *inp, int id, int len) @@ -510,7 +512,7 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len) LWIP_UNUSED_ARG(id); - UPAPDEBUG((LOG_INFO, "pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate)); + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: Rcvd id %d s=%d\n", id, u->us_clientstate)); if (u->us_clientstate != UPAPCS_AUTHREQ) { /* XXX */ return; @@ -520,13 +522,13 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len) * Parse message. */ if (len < sizeof (u_char)) { - UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: ignoring missing msg-length.\n")); } else { GETCHAR(msglen, inp); if(msglen > 0) { len -= sizeof (u_char); if (len < msglen) { - UPAPDEBUG((LOG_INFO, "pap_rauthnak: rcvd short packet.\n")); + UPAPDEBUG(LOG_INFO, ("pap_rauthnak: rcvd short packet.\n")); return; } msg = (char *) inp; @@ -536,7 +538,7 @@ upap_rauthnak(upap_state *u, u_char *inp, int id, int len) u->us_clientstate = UPAPCS_BADAUTH; - UPAPDEBUG((LOG_ERR, "PAP authentication failed\n")); + UPAPDEBUG(LOG_ERR, ("PAP authentication failed\n")); auth_withpeer_fail(u->us_unit, PPP_PAP); } @@ -567,7 +569,7 @@ upap_sauthreq(upap_state *u) pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); - UPAPDEBUG((LOG_INFO, "pap_sauth: Sent id %d\n", u->us_id)); + UPAPDEBUG(LOG_INFO, ("pap_sauth: Sent id %d\n", u->us_id)); TIMEOUT(upap_timeout, u, u->us_timeouttime); ++u->us_transmits; @@ -595,10 +597,14 @@ upap_sresp(upap_state *u, u_char code, u_char id, char *msg, int msglen) BCOPY(msg, outp, msglen); pppWrite(u->us_unit, outpacket_buf[u->us_unit], outlen + PPP_HDRLEN); - UPAPDEBUG((LOG_INFO, "pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate)); + UPAPDEBUG(LOG_INFO, ("pap_sresp: Sent code %d, id %d s=%d\n", code, id, u->us_clientstate)); } -#if 0 +#if PPP_ADDITIONAL_CALLBACKS +static char *upap_codenames[] = { + "AuthReq", "AuthAck", "AuthNak" +}; + /* * upap_printpkt - print the contents of a PAP packet. */ @@ -615,7 +621,7 @@ static int upap_printpkt( LWIP_UNUSED_ARG(arg); return 0; } -#endif /* 0 */ +#endif /* PPP_ADDITIONAL_CALLBACKS */ #endif /* PAP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/pap.h b/core/lwip/src/netif/ppp/pap.h index 0a09fc84..c99a2040 100644 --- a/core/lwip/src/netif/ppp/pap.h +++ b/core/lwip/src/netif/ppp/pap.h @@ -54,9 +54,6 @@ #if PAP_SUPPORT /* don't build if not configured for use in lwipopts.h */ -/************************* -*** PUBLIC DEFINITIONS *** -*************************/ /* * Packet header = Code, id, length. */ @@ -71,6 +68,24 @@ #define UPAP_AUTHNAK 3 /* Authenticate-Nak */ /* + * Each interface is described by upap structure. + */ +typedef struct upap_state { + int us_unit; /* Interface unit number */ + const char *us_user; /* User */ + int us_userlen; /* User length */ + const char *us_passwd; /* Password */ + int us_passwdlen; /* Password length */ + int us_clientstate; /* Client state */ + int us_serverstate; /* Server state */ + u_char us_id; /* Current id */ + int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */ + int us_transmits; /* Number of auth-reqs sent */ + int us_maxtransmits; /* Maximum number of auth-reqs to send */ + int us_reqtimeout; /* Time to wait for auth-req from peer */ +} upap_state; + +/* * Client states. */ #define UPAPCS_INITIAL 0 /* Connection down */ @@ -91,36 +106,8 @@ #define UPAPSS_BADAUTH 5 /* We've sent a Nak */ -/************************ -*** PUBLIC DATA TYPES *** -************************/ - -/* - * Each interface is described by upap structure. - */ -typedef struct upap_state { - int us_unit; /* Interface unit number */ - const char *us_user; /* User */ - int us_userlen; /* User length */ - const char *us_passwd; /* Password */ - int us_passwdlen; /* Password length */ - int us_clientstate; /* Client state */ - int us_serverstate; /* Server state */ - u_char us_id; /* Current id */ - int us_timeouttime; /* Timeout (seconds) for auth-req retrans. */ - int us_transmits; /* Number of auth-reqs sent */ - int us_maxtransmits; /* Maximum number of auth-reqs to send */ - int us_reqtimeout; /* Time to wait for auth-req from peer */ -} upap_state; - - -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ - extern upap_state upap[]; -void upap_setloginpasswd(int unit, const char *luser, const char *lpassword); void upap_authwithpeer (int, char *, char *); void upap_authpeer (int); diff --git a/core/lwip/src/netif/ppp/ppp.c b/core/lwip/src/netif/ppp/ppp.c index 13fa5ed0..e9b433b0 100644 --- a/core/lwip/src/netif/ppp/ppp.c +++ b/core/lwip/src/netif/ppp/ppp.c @@ -107,12 +107,35 @@ #include "netif/ppp_oe.h" #endif /* PPPOE_SUPPORT */ +#include "lwip/tcpip.h" +#include "lwip/api.h" +#include "lwip/snmp.h" + #include <string.h> /*************************/ /*** LOCAL DEFINITIONS ***/ /*************************/ +/** PPP_INPROC_MULTITHREADED==1 call pppInput using tcpip_callback(). + * Set this to 0 if pppInProc is called inside tcpip_thread or with NO_SYS==1. + * Default is 1 for NO_SYS==0 (multithreaded) and 0 for NO_SYS==1 (single-threaded). + */ +#ifndef PPP_INPROC_MULTITHREADED +#define PPP_INPROC_MULTITHREADED (NO_SYS==0) +#endif + +/** PPP_INPROC_OWNTHREAD==1: start a dedicated RX thread per PPP session. + * Default is 0: call pppos_input() for received raw characters, charcater + * reception is up to the port */ +#ifndef PPP_INPROC_OWNTHREAD +#define PPP_INPROC_OWNTHREAD PPP_INPROC_MULTITHREADED +#endif + +#if PPP_INPROC_OWNTHREAD && !PPP_INPROC_MULTITHREADED + #error "PPP_INPROC_OWNTHREAD needs PPP_INPROC_MULTITHREADED==1" +#endif + /* * The basic PPP frame. */ @@ -137,10 +160,37 @@ typedef enum { /************************/ /*** LOCAL DATA TYPES ***/ /************************/ + +/** RX buffer size: this may be configured smaller! */ +#ifndef PPPOS_RX_BUFSIZE +#define PPPOS_RX_BUFSIZE (PPP_MRU + PPP_HDRLEN) +#endif + +typedef struct PPPControlRx_s { + /** unit number / ppp descriptor */ + int pd; + /** the rx file descriptor */ + sio_fd_t fd; + /** receive buffer - encoded data is stored here */ + u_char rxbuf[PPPOS_RX_BUFSIZE]; + + /* The input packet. */ + struct pbuf *inHead, *inTail; + +#if PPPOS_SUPPORT + u16_t inProtocol; /* The input protocol code. */ + u16_t inFCS; /* Input Frame Check Sequence value. */ +#endif /* PPPOS_SUPPORT */ + PPPDevStates inState; /* The input process state. */ + char inEscaped; /* Escape next character. */ + ext_accm inACCM; /* Async-Ctl-Char-Map for input. */ +} PPPControlRx; + /* * PPP interface control block. */ typedef struct PPPControl_s { + PPPControlRx rx; char openFlag; /* True when in use. */ #if PPPOE_SUPPORT struct netif *ethif; @@ -150,19 +200,11 @@ typedef struct PPPControl_s { int errCode; /* Code indicating why interface is down. */ #if PPPOS_SUPPORT sio_fd_t fd; /* File device ID of port. */ - int kill_link; /* Shut the link down. */ - int sig_hup; /* Carrier lost. */ - struct pbuf *inHead, *inTail; /* The input packet. */ - PPPDevStates inState; /* The input process state. */ - char inEscaped; /* Escape next character. */ - u16_t inProtocol; /* The input protocol code. */ - u16_t inFCS; /* Input Frame Check Sequence value. */ #endif /* PPPOS_SUPPORT */ - int mtu; /* Peer's mru */ + u16_t mtu; /* Peer's mru */ int pcomp; /* Does peer accept protocol compression? */ int accomp; /* Does peer accept addr/ctl compression? */ u_long lastXMit; /* Time of last transmission. */ - ext_accm inACCM; /* Async-Ctl-Char-Map for input. */ ext_accm outACCM; /* Async-Ctl-Char-Map for output. */ #if PPPOS_SUPPORT && VJ_SUPPORT int vjEnabled; /* Flag indicating VJ compression enabled. */ @@ -194,9 +236,11 @@ struct npioctl { /*** LOCAL FUNCTION DECLARATIONS ***/ /***********************************/ #if PPPOS_SUPPORT -static void pppMain(void *pd); -static void pppDrop(PPPControl *pc); -static void pppInProc(int pd, u_char *s, int l); +#if PPP_INPROC_OWNTHREAD +static void pppInputThread(void *arg); +#endif /* PPP_INPROC_OWNTHREAD */ +static void pppDrop(PPPControlRx *pcrx); +static void pppInProc(PPPControlRx *pcrx, u_char *s, int l); #endif /* PPPOS_SUPPORT */ @@ -245,6 +289,7 @@ u_char outpacket_buf[NUM_PPP][PPP_MRU+PPP_HDRLEN]; #if PPPOS_SUPPORT /* * FCS lookup table as calculated by genfcstab. + * @todo: smaller, slower implementation for lower memory footprint? */ static const u_short fcstab[256] = { 0x0000, 0x1189, 0x2312, 0x329b, 0x4624, 0x57ad, 0x6536, 0x74bf, @@ -294,80 +339,84 @@ static u_char pppACCMMask[] = { 0x80 }; - -void -pppMainWakeup(int pd) +/** Wake up the task blocked in reading from serial line (if any) */ +static void +pppRecvWakeup(int pd) { - PPPDEBUG((LOG_DEBUG, "pppMainWakeup: unit %d\n", pd)); - sio_read_abort(pppControl[pd].fd); + PPPDEBUG(LOG_DEBUG, ("pppRecvWakeup: unit %d\n", pd)); + if (pppControl[pd].openFlag != 0) { + sio_read_abort(pppControl[pd].fd); + } } #endif /* PPPOS_SUPPORT */ void pppLinkTerminated(int pd) { - PPPDEBUG((LOG_DEBUG, "pppLinkTerminated: unit %d\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d\n", pd)); #if PPPOE_SUPPORT - if(pppControl[pd].ethif) { + if (pppControl[pd].ethif) { pppoe_disconnect(pppControl[pd].pppoe_sc); } else #endif /* PPPOE_SUPPORT */ { #if PPPOS_SUPPORT - pppMainWakeup(pd); + PPPControl* pc; + pppRecvWakeup(pd); + pc = &pppControl[pd]; + + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { + pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); + } + + pc->openFlag = 0;/**/ #endif /* PPPOS_SUPPORT */ } + PPPDEBUG(LOG_DEBUG, ("pppLinkTerminated: finished.\n")); } void pppLinkDown(int pd) { - PPPDEBUG((LOG_DEBUG, "pppLinkDown: unit %d\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppLinkDown: unit %d\n", pd)); #if PPPOE_SUPPORT - if(pppControl[pd].ethif) { + if (pppControl[pd].ethif) { pppoe_disconnect(pppControl[pd].pppoe_sc); } else #endif /* PPPOE_SUPPORT */ { #if PPPOS_SUPPORT - pppMainWakeup(pd); + pppRecvWakeup(pd); #endif /* PPPOS_SUPPORT */ } } -/* these callbacks are necessary because lcp_* functions - must be called in the same context as pppInput(), - namely the tcpip_thread(), essentially because - they manipulate timeouts which are thread-private -*/ - +/** Initiate LCP open request */ static void -pppStartCB(void *arg) +pppStart(int pd) { - int pd = (int)arg; - - PPPDEBUG((LOG_DEBUG, "pppStartCB: unit %d\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppStart: unit %d\n", pd)); lcp_lowerup(pd); lcp_open(pd); /* Start protocol */ + PPPDEBUG(LOG_DEBUG, ("pppStart: finished\n")); } +/** LCP close request */ static void -pppStopCB(void *arg) +pppStop(int pd) { - int pd = (int)arg; - - PPPDEBUG((LOG_DEBUG, "pppStopCB: unit %d\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppStop: unit %d\n", pd)); lcp_close(pd, "User request"); } +/** Called when carrier/link is lost */ static void -pppHupCB(void *arg) +pppHup(int pd) { - int pd = (int)arg; - - PPPDEBUG((LOG_DEBUG, "pppHupCB: unit %d\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppHupCB: unit %d\n", pd)); lcp_lowerdown(pd); link_terminated(pd); } @@ -391,22 +440,14 @@ pppInit(void) magicInit(); - subnetMask = htonl(0xffffff00); + subnetMask = PP_HTONL(0xffffff00UL); for (i = 0; i < NUM_PPP; i++) { - pppControl[i].openFlag = 0; - - /* - * Initialize to the standard option set. - */ + /* Initialize each protocol to the standard option set. */ for (j = 0; (protp = ppp_protocols[j]) != NULL; ++j) { (*protp->init)(i); } } - -#if PPPOE_SUPPORT - pppoe_init(); -#endif /* PPPOE_SUPPORT */ } void @@ -475,50 +516,44 @@ pppSetAuth(enum pppAuthType authType, const char *user, const char *passwd) } #if PPPOS_SUPPORT -/* Open a new PPP connection using the given I/O device. +/** Open a new PPP connection using the given I/O device. * This initializes the PPP control block but does not * attempt to negotiate the LCP session. If this port * connects to a modem, the modem connection must be * established before calling this. * Return a new PPP connection descriptor on success or - * an error code (negative) on failure. */ + * an error code (negative) on failure. + * + * pppOpen() is directly defined to this function. + */ int pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void *arg), void *linkStatusCtx) { PPPControl *pc; int pd; - /* Find a free PPP session descriptor. Critical region? */ + if (linkStatusCB == NULL) { + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + return PPPERR_PARAM; + } + + /* Find a free PPP session descriptor. */ for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); if (pd >= NUM_PPP) { pd = PPPERR_OPEN; } else { - pppControl[pd].openFlag = !0; - } - - /* Launch a deamon thread. */ - if (pd >= 0) { - pppControl[pd].openFlag = 1; - - lcp_init(pd); pc = &pppControl[pd]; + /* @todo: is this correct or do I overwrite something? */ + memset(pc, 0, sizeof(PPPControl)); + pc->rx.pd = pd; + pc->rx.fd = fd; + + pc->openFlag = 1; pc->fd = fd; -#if PPPOE_SUPPORT - pc->ethif= NULL; -#endif /* PPPOE_SUPPORT */ - pc->kill_link = 0; - pc->sig_hup = 0; - pc->if_up = 0; - pc->errCode = 0; - pc->inState = PDIDLE; - pc->inHead = NULL; - pc->inTail = NULL; - pc->inEscaped = 0; - pc->lastXMit = 0; #if VJ_SUPPORT - pc->vjEnabled = 0; vj_compress_init(&pc->vjComp); #endif /* VJ_SUPPORT */ @@ -526,28 +561,20 @@ pppOverSerialOpen(sio_fd_t fd, void (*linkStatusCB)(void *ctx, int errCode, void * Default the in and out accm so that escape and flag characters * are always escaped. */ - memset(pc->inACCM, 0, sizeof(ext_accm)); - pc->inACCM[15] = 0x60; - memset(pc->outACCM, 0, sizeof(ext_accm)); + pc->rx.inACCM[15] = 0x60; /* no need to protect since RX is not running */ pc->outACCM[15] = 0x60; pc->linkStatusCB = linkStatusCB; pc->linkStatusCtx = linkStatusCtx; - sys_thread_new(PPP_THREAD_NAME, pppMain, (void*)pd, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); - if(!linkStatusCB) { - while(pd >= 0 && !pc->if_up) { - sys_msleep(500); - if (lcp_phase[pd] == PHASE_DEAD) { - pppClose(pd); - if (pc->errCode) { - pd = pc->errCode; - } else { - pd = PPPERR_CONNECT; - } - } - } - } + /* + * Start the connection and handle incoming events (packet or timeout). + */ + PPPDEBUG(LOG_INFO, ("pppOverSerialOpen: unit %d: Connecting\n", pd)); + pppStart(pd); +#if PPP_INPROC_OWNTHREAD + sys_thread_new(PPP_THREAD_NAME, pppInputThread, (void*)&pc->rx, PPP_THREAD_STACKSIZE, PPP_THREAD_PRIO); +#endif } return pd; @@ -576,20 +603,24 @@ int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const cha LWIP_UNUSED_ARG(service_name); LWIP_UNUSED_ARG(concentrator_name); + if (linkStatusCB == NULL) { + /* PPP is single-threaded: without a callback, + * there is no way to know when the link is up. */ + return PPPERR_PARAM; + } + /* Find a free PPP session descriptor. Critical region? */ for (pd = 0; pd < NUM_PPP && pppControl[pd].openFlag != 0; pd++); if (pd >= NUM_PPP) { pd = PPPERR_OPEN; } else { - pppControl[pd].openFlag = !0; - } - - /* PPP session descriptor found, start PPPoE */ - if (pd >= 0) { - - pppControl[pd].openFlag = 1; + pc = &pppControl[pd]; + memset(pc, 0, sizeof(PPPControl)); + pc->openFlag = 1; + pc->ethif = ethif; - lcp_init(pd); + pc->linkStatusCB = linkStatusCB; + pc->linkStatusCtx = linkStatusCtx; lcp_wantoptions[pd].mru = PPPOE_MAXMTU; lcp_wantoptions[pd].neg_asyncmap = 0; @@ -601,49 +632,12 @@ int pppOverEthernetOpen(struct netif *ethif, const char *service_name, const cha lcp_allowoptions[pd].neg_pcompression = 0; lcp_allowoptions[pd].neg_accompression = 0; - pc = &pppControl[pd]; - pc->if_up = 0; - pc->errCode = 0; - pc->lastXMit = 0; -#if PPPOS_SUPPORT - pc->kill_link = 0; - pc->sig_hup = 0; - pc->inState = PDIDLE; - pc->inHead = NULL; - pc->inTail = NULL; - pc->inEscaped = 0; -#if VJ_SUPPORT - pc->vjEnabled = 0; -#endif /* VJ_SUPPORT */ -#endif /* PPPOS_SUPPORT */ - pc->ethif= ethif; - - memset(pc->inACCM, 0, sizeof(ext_accm)); - memset(pc->outACCM, 0, sizeof(ext_accm)); - - pc->linkStatusCB = linkStatusCB; - pc->linkStatusCtx = linkStatusCtx; - if(pppoe_create(ethif, pd, pppOverEthernetLinkStatusCB, &pc->pppoe_sc) != ERR_OK) { pc->openFlag = 0; return PPPERR_OPEN; } pppoe_connect(pc->pppoe_sc); - - if(!linkStatusCB) { - while(pd >= 0 && !pc->if_up) { - sys_msleep(500); - if (lcp_phase[pd] == PHASE_DEAD) { - pppClose(pd); - if (pc->errCode) { - pd = pc->errCode; - } else { - pd = PPPERR_CONNECT; - } - } - } - } } return pd; @@ -660,29 +654,27 @@ pppClose(int pd) PPPControl *pc = &pppControl[pd]; int st = 0; + PPPDEBUG(LOG_DEBUG, ("pppClose() called\n")); + /* Disconnect */ #if PPPOE_SUPPORT if(pc->ethif) { - PPPDEBUG((LOG_DEBUG, "pppClose: unit %d kill_link -> pppStopCB\n", pd)); + PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd)); pc->errCode = PPPERR_USER; /* This will leave us at PHASE_DEAD. */ - tcpip_callback(pppStopCB, (void*)pd); + pppStop(pd); } else #endif /* PPPOE_SUPPORT */ { #if PPPOS_SUPPORT - pc->kill_link = !0; - pppMainWakeup(pd); + PPPDEBUG(LOG_DEBUG, ("pppClose: unit %d kill_link -> pppStop\n", pd)); + pc->errCode = PPPERR_USER; + /* This will leave us at PHASE_DEAD. */ + pppStop(pd); + pppRecvWakeup(pd); #endif /* PPPOS_SUPPORT */ } - if(!pc->linkStatusCB) { - while(st >= 0 && lcp_phase[pd] != PHASE_DEAD) { - sys_msleep(500); - break; - } - } - return st; } @@ -690,20 +682,8 @@ pppClose(int pd) void pppSigHUP(int pd) { - PPPControl *pc = &pppControl[pd]; - -#if PPPOE_SUPPORT - if(pc->ethif) { - PPPDEBUG((LOG_DEBUG, "pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd)); - tcpip_callback(pppHupCB, (void*)pd); - } else -#endif /* PPPOE_SUPPORT */ - { -#if PPPOS_SUPPORT - pc->sig_hup = 1; - pppMainWakeup(pd); -#endif /* PPPOS_SUPPORT */ - } + PPPDEBUG(LOG_DEBUG, ("pppSigHUP: unit %d sig_hup -> pppHupCB\n", pd)); + pppHup(pd); } #if PPPOS_SUPPORT @@ -715,14 +695,18 @@ nPut(PPPControl *pc, struct pbuf *nb) for(b = nb; b != NULL; b = b->next) { if((c = sio_write(pc->fd, b->payload, b->len)) != b->len) { - PPPDEBUG((LOG_WARNING, - "PPP nPut: incomplete sio_write(%d,, %u) = %d\n", pc->fd, b->len, c)); + PPPDEBUG(LOG_WARNING, + ("PPP nPut: incomplete sio_write(fd:%"SZT_F", len:%d, c: 0x%"X8_F") c = %d\n", (size_t)pc->fd, b->len, c, c)); LINK_STATS_INC(link.err); pc->lastXMit = 0; /* prepend PPP_FLAG to next packet */ - break; + snmp_inc_ifoutdiscards(&pc->netif); + pbuf_free(nb); + return; } } + snmp_add_ifoutoctets(&pc->netif, nb->tot_len); + snmp_inc_ifoutucastpkts(&pc->netif); pbuf_free(nb); LINK_STATS_INC(link.xmit); } @@ -773,15 +757,18 @@ pppifOutputOverEthernet(int pd, struct pbuf *p) struct pbuf *pb; u_short protocol = PPP_IP; int i=0; + u16_t tot_len; - pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + sizeof(protocol), PBUF_RAM); + /* @todo: try to use pbuf_header() here! */ + pb = pbuf_alloc(PBUF_LINK, PPPOE_HDRLEN + sizeof(protocol), PBUF_RAM); if(!pb) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); return ERR_MEM; } - pbuf_header(pb, -pppoe_hdrlen); + pbuf_header(pb, -(s16_t)PPPOE_HDRLEN); pc->lastXMit = sys_jiffies(); @@ -791,12 +778,16 @@ pppifOutputOverEthernet(int pd, struct pbuf *p) *((u_char*)pb->payload + i) = protocol & 0xFF; pbuf_chain(pb, p); + tot_len = pb->tot_len; if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { LINK_STATS_INC(link.err); + snmp_inc_ifoutdiscards(&pc->netif); return PPPERR_DEVICE; } + snmp_add_ifoutoctets(&pc->netif, tot_len); + snmp_inc_ifoutucastpkts(&pc->netif); LINK_STATS_INC(link.xmit); return ERR_OK; } @@ -804,9 +795,9 @@ pppifOutputOverEthernet(int pd, struct pbuf *p) /* Send a packet on the given connection. */ static err_t -pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) +pppifOutput(struct netif *netif, struct pbuf *pb, ip_addr_t *ipaddr) { - int pd = (int)netif->state; + int pd = (int)(size_t)netif->state; PPPControl *pc = &pppControl[pd]; #if PPPOS_SUPPORT u_short protocol = PPP_IP; @@ -821,18 +812,20 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) /* We let any protocol value go through - it can't hurt us * and the peer will just drop it if it's not accepting it. */ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag || !pb) { - PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad parms prot=%d pb=%p\n", + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad parms prot=%d pb=%p\n", pd, PPP_IP, pb)); LINK_STATS_INC(link.opterr); LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); return ERR_ARG; } /* Check that the link is up. */ if (lcp_phase[pd] == PHASE_DEAD) { - PPPDEBUG((LOG_ERR, "pppifOutput[%d]: link not up\n", pd)); + PPPDEBUG(LOG_ERR, ("pppifOutput[%d]: link not up\n", pd)); LINK_STATS_INC(link.rterr); LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); return ERR_RTE; } @@ -846,9 +839,10 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) /* Grab an output buffer. */ headMB = pbuf_alloc(PBUF_RAW, 0, PBUF_POOL); if (headMB == NULL) { - PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: first alloc fail\n", pd)); + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: first alloc fail\n", pd)); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); return ERR_MEM; } @@ -870,9 +864,10 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) protocol = PPP_VJC_UNCOMP; break; default: - PPPDEBUG((LOG_WARNING, "pppifOutput[%d]: bad IP packet\n", pd)); + PPPDEBUG(LOG_WARNING, ("pppifOutput[%d]: bad IP packet\n", pd)); LINK_STATS_INC(link.proterr); LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); pbuf_free(headMB); return ERR_VAL; } @@ -929,17 +924,18 @@ pppifOutput(struct netif *netif, struct pbuf *pb, struct ip_addr *ipaddr) /* If we failed to complete the packet, throw it away. */ if (!tailMB) { - PPPDEBUG((LOG_WARNING, - "pppifOutput[%d]: Alloc err - dropping proto=%d\n", + PPPDEBUG(LOG_WARNING, + ("pppifOutput[%d]: Alloc err - dropping proto=%d\n", pd, protocol)); pbuf_free(headMB); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.drop); + snmp_inc_ifoutdiscards(netif); return ERR_MEM; } /* Send it. */ - PPPDEBUG((LOG_INFO, "pppifOutput[%d]: proto=0x%04X\n", pd, protocol)); + PPPDEBUG(LOG_INFO, ("pppifOutput[%d]: proto=0x%"X16_F"\n", pd, protocol)); nPut(pc, headMB); #endif /* PPPOS_SUPPORT */ @@ -981,7 +977,7 @@ pppIOCtl(int pd, int cmd, void *arg) } break; #if PPPOS_SUPPORT - case PPPCTLG_FD: + case PPPCTLG_FD: /* Get the fd associated with the ppp */ if (arg) { *(sio_fd_t *)arg = pc->fd; } else { @@ -1001,11 +997,11 @@ pppIOCtl(int pd, int cmd, void *arg) /* * Return the Maximum Transmission Unit for the given PPP connection. */ -u_int +u_short pppMTU(int pd) { PPPControl *pc = &pppControl[pd]; - u_int st; + u_short st; /* Validate parameters. */ if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { @@ -1028,14 +1024,16 @@ pppWriteOverEthernet(int pd, const u_char *s, int n) s += 2; n -= 2; - pb = pbuf_alloc(PBUF_LINK, pppoe_hdrlen + n, PBUF_RAM); + LWIP_ASSERT("PPPOE_HDRLEN + n <= 0xffff", PPPOE_HDRLEN + n <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(PPPOE_HDRLEN + n), PBUF_RAM); if(!pb) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); return PPPERR_ALLOC; } - pbuf_header(pb, -pppoe_hdrlen); + pbuf_header(pb, -(s16_t)PPPOE_HDRLEN); pc->lastXMit = sys_jiffies(); @@ -1043,9 +1041,12 @@ pppWriteOverEthernet(int pd, const u_char *s, int n) if(pppoe_xmit(pc->pppoe_sc, pb) != ERR_OK) { LINK_STATS_INC(link.err); + snmp_inc_ifoutdiscards(&pc->netif); return PPPERR_DEVICE; } + snmp_add_ifoutoctets(&pc->netif, (u16_t)n); + snmp_inc_ifoutucastpkts(&pc->netif); LINK_STATS_INC(link.xmit); return PPPERR_NONE; } @@ -1077,6 +1078,7 @@ pppWrite(int pd, const u_char *s, int n) if (headMB == NULL) { LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); return PPPERR_ALLOC; } @@ -1111,16 +1113,17 @@ pppWrite(int pd, const u_char *s, int n) /* If we failed to complete the packet, throw it away. * Otherwise send it. */ if (!tailMB) { - PPPDEBUG((LOG_WARNING, - "pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len)); + PPPDEBUG(LOG_WARNING, + ("pppWrite[%d]: Alloc err - dropping pbuf len=%d\n", pd, headMB->len)); /*"pppWrite[%d]: Alloc err - dropping %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ pbuf_free(headMB); LINK_STATS_INC(link.memerr); LINK_STATS_INC(link.proterr); + snmp_inc_ifoutdiscards(&pc->netif); return PPPERR_ALLOC; } - PPPDEBUG((LOG_INFO, "pppWrite[%d]: len=%d\n", pd, headMB->len)); + PPPDEBUG(LOG_INFO, ("pppWrite[%d]: len=%d\n", pd, headMB->len)); /* "pppWrite[%d]: %d:%.*H", pd, headMB->len, LWIP_MIN(headMB->len * 2, 40), headMB->payload)); */ nPut(pc, headMB); #endif /* PPPOS_SUPPORT */ @@ -1133,7 +1136,7 @@ pppWrite(int pd, const u_char *s, int n) * the ppp interface. */ void -ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp) +ppp_send_config( int unit, u16_t mtu, u32_t asyncmap, int pcomp, int accomp) { PPPControl *pc = &pppControl[unit]; int i; @@ -1146,7 +1149,7 @@ ppp_send_config( int unit, int mtu, u32_t asyncmap, int pcomp, int accomp) for (i = 0; i < 32/8; i++) { pc->outACCM[i] = (u_char)((asyncmap >> (8 * i)) & 0xFF); } - PPPDEBUG((LOG_INFO, "ppp_send_config[%d]: outACCM=%X %X %X %X\n", + PPPDEBUG(LOG_INFO, ("ppp_send_config[%d]: outACCM=%X %X %X %X\n", unit, pc->outACCM[0], pc->outACCM[1], pc->outACCM[2], pc->outACCM[3])); } @@ -1159,7 +1162,7 @@ void ppp_set_xaccm(int unit, ext_accm *accm) { SMEMCPY(pppControl[unit].outACCM, accm, sizeof(ext_accm)); - PPPDEBUG((LOG_INFO, "ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n", + PPPDEBUG(LOG_INFO, ("ppp_set_xaccm[%d]: outACCM=%X %X %X %X\n", unit, pppControl[unit].outACCM[0], pppControl[unit].outACCM[1], @@ -1177,18 +1180,22 @@ ppp_recv_config( int unit, int mru, u32_t asyncmap, int pcomp, int accomp) { PPPControl *pc = &pppControl[unit]; int i; + SYS_ARCH_DECL_PROTECT(lev); LWIP_UNUSED_ARG(accomp); LWIP_UNUSED_ARG(pcomp); LWIP_UNUSED_ARG(mru); /* Load the ACCM bits for the 32 control codes. */ + SYS_ARCH_PROTECT(lev); for (i = 0; i < 32 / 8; i++) { - pc->inACCM[i] = (u_char)(asyncmap >> (i * 8)); + /* @todo: does this work? ext_accm has been modified from pppd! */ + pc->rx.inACCM[i] = (u_char)(asyncmap >> (i * 8)); } - PPPDEBUG((LOG_INFO, "ppp_recv_config[%d]: inACCM=%X %X %X %X\n", + SYS_ARCH_UNPROTECT(lev); + PPPDEBUG(LOG_INFO, ("ppp_recv_config[%d]: inACCM=%X %X %X %X\n", unit, - pc->inACCM[0], pc->inACCM[1], pc->inACCM[2], pc->inACCM[3])); + pc->rx.inACCM[0], pc->rx.inACCM[1], pc->rx.inACCM[2], pc->rx.inACCM[3])); } #if 0 @@ -1254,12 +1261,12 @@ GetMask(u32_t addr) u32_t mask, nmask; htonl(addr); - if (IN_CLASSA(addr)) { /* determine network mask for address class */ - nmask = IN_CLASSA_NET; - } else if (IN_CLASSB(addr)) { - nmask = IN_CLASSB_NET; + if (IP_CLASSA(addr)) { /* determine network mask for address class */ + nmask = IP_CLASSA_NET; + } else if (IP_CLASSB(addr)) { + nmask = IP_CLASSB_NET; } else { - nmask = IN_CLASSC_NET; + nmask = IP_CLASSC_NET; } /* class D nets are disallowed by bad_ip_adrs */ @@ -1277,7 +1284,7 @@ GetMask(u32_t addr) * sifvjcomp - config tcp header compression */ int -sifvjcomp(int pd, int vjcomp, int cidcomp, int maxcid) +sifvjcomp(int pd, int vjcomp, u8_t cidcomp, u8_t maxcid) { #if PPPOS_SUPPORT && VJ_SUPPORT PPPControl *pc = &pppControl[pd]; @@ -1285,7 +1292,7 @@ sifvjcomp(int pd, int vjcomp, int cidcomp, int maxcid) pc->vjEnabled = vjcomp; pc->vjComp.compressSlot = cidcomp; pc->vjComp.maxSlotIndex = maxcid; - PPPDEBUG((LOG_INFO, "sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", + PPPDEBUG(LOG_INFO, ("sifvjcomp: VJ compress enable=%d slot=%d max slot=%d\n", vjcomp, cidcomp, maxcid)); #else /* PPPOS_SUPPORT && VJ_SUPPORT */ LWIP_UNUSED_ARG(pd); @@ -1306,7 +1313,12 @@ pppifNetifInit(struct netif *netif) netif->name[0] = 'p'; netif->name[1] = 'p'; netif->output = pppifOutput; - netif->mtu = pppMTU((int)netif->state); + netif->mtu = pppMTU((int)(size_t)netif->state); + netif->flags = NETIF_FLAG_POINTTOPOINT | NETIF_FLAG_LINK_UP; +#if LWIP_NETIF_HOSTNAME + /* @todo: Initialize interface hostname */ + /* netif_set_hostname(netif, "lwip"); */ +#endif /* LWIP_NETIF_HOSTNAME */ return ERR_OK; } @@ -1322,21 +1334,22 @@ sifup(int pd) if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); } else { netif_remove(&pc->netif); - if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, &pc->addrs.his_ipaddr, (void *)pd, pppifNetifInit, ip_input)) { + if (netif_add(&pc->netif, &pc->addrs.our_ipaddr, &pc->addrs.netmask, + &pc->addrs.his_ipaddr, (void *)(size_t)pd, pppifNetifInit, ip_input)) { netif_set_up(&pc->netif); pc->if_up = 1; pc->errCode = PPPERR_NONE; - PPPDEBUG((LOG_DEBUG, "sifup: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); - if(pc->linkStatusCB) { + PPPDEBUG(LOG_DEBUG, ("sifup: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { pc->linkStatusCB(pc->linkStatusCtx, pc->errCode, &pc->addrs); } } else { st = 0; - PPPDEBUG((LOG_ERR, "sifup[%d]: netif_add failed\n", pd)); + PPPDEBUG(LOG_ERR, ("sifup[%d]: netif_add failed\n", pd)); } } @@ -1366,14 +1379,14 @@ sifdown(int pd) if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifdown[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifdown[%d]: bad parms\n", pd)); } else { pc->if_up = 0; /* make sure the netif status callback is called */ netif_set_down(&pc->netif); netif_remove(&pc->netif); - PPPDEBUG((LOG_DEBUG, "sifdown: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); - if(pc->linkStatusCB) { + PPPDEBUG(LOG_DEBUG, ("sifdown: unit %d: linkStatusCB=%p errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); + if (pc->linkStatusCB) { pc->linkStatusCB(pc->linkStatusCtx, PPPERR_CONNECT, NULL); } } @@ -1397,7 +1410,7 @@ sifaddr( int pd, u32_t o, u32_t h, u32_t m, u32_t ns1, u32_t ns2) if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); } else { SMEMCPY(&pc->addrs.our_ipaddr, &o, sizeof(o)); SMEMCPY(&pc->addrs.his_ipaddr, &h, sizeof(h)); @@ -1425,7 +1438,7 @@ cifaddr( int pd, u32_t o, u32_t h) LWIP_UNUSED_ARG(h); if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); } else { IP4_ADDR(&pc->addrs.our_ipaddr, 0,0,0,0); IP4_ADDR(&pc->addrs.his_ipaddr, 0,0,0,0); @@ -1450,7 +1463,7 @@ sifdefaultroute(int pd, u32_t l, u32_t g) if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); } else { netif_set_default(&pc->netif); } @@ -1474,7 +1487,7 @@ cifdefaultroute(int pd, u32_t l, u32_t g) if (pd < 0 || pd >= NUM_PPP || !pc->openFlag) { st = 0; - PPPDEBUG((LOG_WARNING, "sifup[%d]: bad parms\n", pd)); + PPPDEBUG(LOG_WARNING, ("sifup[%d]: bad parms\n", pd)); } else { netif_set_default(NULL); } @@ -1486,76 +1499,36 @@ cifdefaultroute(int pd, u32_t l, u32_t g) /*** LOCAL FUNCTION DEFINITIONS ***/ /**********************************/ -#if PPPOS_SUPPORT +#if PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD /* The main PPP process function. This implements the state machine according * to section 4 of RFC 1661: The Point-To-Point Protocol. */ static void -pppMain(void *arg) +pppInputThread(void *arg) { - int pd = (int)arg; - struct pbuf *p; - PPPControl* pc; - int c; + int count; + PPPControlRx *pcrx = arg; - pc = &pppControl[pd]; - - p = pbuf_alloc(PBUF_RAW, PPP_MRU+PPP_HDRLEN, PBUF_RAM); - if (!p) { - LWIP_ASSERT("p != NULL", p); - pc->errCode = PPPERR_ALLOC; - goto out; - } - - /* - * Start the connection and handle incoming events (packet or timeout). - */ - PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); - tcpip_callback(pppStartCB, arg); - while (lcp_phase[pd] != PHASE_DEAD) { - if (pc->kill_link) { - PPPDEBUG((LOG_DEBUG, "pppMain: unit %d kill_link -> pppStopCB\n", pd)); - pc->errCode = PPPERR_USER; - /* This will leave us at PHASE_DEAD. */ - tcpip_callback(pppStopCB, arg); - pc->kill_link = 0; - } else if (pc->sig_hup) { - PPPDEBUG((LOG_DEBUG, "pppMain: unit %d sig_hup -> pppHupCB\n", pd)); - pc->sig_hup = 0; - tcpip_callback(pppHupCB, arg); + while (lcp_phase[pcrx->pd] != PHASE_DEAD) { + count = sio_read(pcrx->fd, pcrx->rxbuf, PPPOS_RX_BUFSIZE); + if(count > 0) { + pppInProc(pcrx, pcrx->rxbuf, count); } else { - c = sio_read(pc->fd, p->payload, p->len); - if(c > 0) { - pppInProc(pd, p->payload, c); - } else { - /* nothing received, give other tasks a chance to run */ - sys_msleep(1); - } + /* nothing received, give other tasks a chance to run */ + sys_msleep(1); } } - PPPDEBUG((LOG_INFO, "pppMain: unit %d: PHASE_DEAD\n", pd)); - pppDrop(pc); /* bug fix #17726 */ - pbuf_free(p); - -out: - PPPDEBUG((LOG_DEBUG, "pppMain: unit %d: linkStatusCB=%lx errCode=%d\n", pd, pc->linkStatusCB, pc->errCode)); - if(pc->linkStatusCB) { - pc->linkStatusCB(pc->linkStatusCtx, pc->errCode ? pc->errCode : PPPERR_PROTOCOL, NULL); - } - - pc->openFlag = 0; } -#endif /* PPPOS_SUPPORT */ +#endif /* PPPOS_SUPPORT && PPP_INPROC_OWNTHREAD */ #if PPPOE_SUPPORT void -pppOverEthernetInitFailed(void* arg) +pppOverEthernetInitFailed(int pd) { PPPControl* pc; - int pd = (int)arg; - pppHupCB(arg); - pppStopCB(arg); + pppHup(pd); + pppStop(pd); pc = &pppControl[pd]; pppoe_destroy(&pc->netif); @@ -1570,12 +1543,10 @@ static void pppOverEthernetLinkStatusCB(int pd, int up) { if(up) { - PPPDEBUG((LOG_INFO, "pppMain: unit %d: Connecting\n", pd)); - tcpip_callback(pppStartCB, (void*)pd); + PPPDEBUG(LOG_INFO, ("pppOverEthernetLinkStatusCB: unit %d: Connecting\n", pd)); + pppStart(pd); } else { - PPPControl* pc; - pc = &pppControl[pd]; - tcpip_callback(pppOverEthernetInitFailed, (void*)pd); + pppOverEthernetInitFailed(pd); } } #endif /* PPPOE_SUPPORT */ @@ -1592,8 +1563,8 @@ pppSingleBuf(struct pbuf *p) q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM); if(!q) { - PPPDEBUG((LOG_ERR, - "pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len)); + PPPDEBUG(LOG_ERR, + ("pppSingleBuf: unable to alloc new buf (%d)\n", p->tot_len)); return p; /* live dangerously */ } @@ -1632,6 +1603,8 @@ pppInput(void *arg) } LINK_STATS_INC(link.recv); + snmp_inc_ifinucastpkts(&pppControl[pd].netif); + snmp_add_ifinoctets(&pppControl[pd].netif, nb->tot_len); /* * Toss all non-LCP packets unless LCP is OPEN. @@ -1641,7 +1614,7 @@ pppInput(void *arg) if((lcp_phase[pd] <= PHASE_AUTHENTICATE) && (protocol != PPP_LCP)) { if(!((protocol == PPP_LQR) || (protocol == PPP_PAP) || (protocol == PPP_CHAP)) || (lcp_phase[pd] != PHASE_AUTHENTICATE)) { - PPPDEBUG((LOG_INFO, "pppInput: discarding proto 0x%04X in phase %d\n", protocol, lcp_phase[pd])); + PPPDEBUG(LOG_INFO, ("pppInput: discarding proto 0x%"X16_F" in phase %d\n", protocol, lcp_phase[pd])); goto drop; } } @@ -1649,7 +1622,7 @@ pppInput(void *arg) switch(protocol) { case PPP_VJC_COMP: /* VJ compressed TCP */ #if PPPOS_SUPPORT && VJ_SUPPORT - PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_comp in pbuf len=%d\n", pd, nb->len)); /* * Clip off the VJ header and prepend the rebuilt TCP/IP header and * pass the result to IP. @@ -1659,16 +1632,16 @@ pppInput(void *arg) return; } /* Something's wrong so drop it. */ - PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ compressed\n", pd)); + PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ compressed\n", pd)); #else /* PPPOS_SUPPORT && VJ_SUPPORT */ /* No handler for this protocol so drop the packet. */ - PPPDEBUG((LOG_INFO, "pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: drop VJ Comp in %d:%s\n", pd, nb->len, nb->payload)); #endif /* PPPOS_SUPPORT && VJ_SUPPORT */ break; case PPP_VJC_UNCOMP: /* VJ uncompressed TCP */ #if PPPOS_SUPPORT && VJ_SUPPORT - PPPDEBUG((LOG_INFO, "pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: vj_un in pbuf len=%d\n", pd, nb->len)); /* * Process the TCP/IP header for VJ header compression and then pass * the packet to IP. @@ -1678,17 +1651,17 @@ pppInput(void *arg) return; } /* Something's wrong so drop it. */ - PPPDEBUG((LOG_WARNING, "pppInput[%d]: Dropping VJ uncompressed\n", pd)); + PPPDEBUG(LOG_WARNING, ("pppInput[%d]: Dropping VJ uncompressed\n", pd)); #else /* PPPOS_SUPPORT && VJ_SUPPORT */ /* No handler for this protocol so drop the packet. */ - PPPDEBUG((LOG_INFO, - "pppInput[%d]: drop VJ UnComp in %d:.*H\n", + PPPDEBUG(LOG_INFO, + ("pppInput[%d]: drop VJ UnComp in %d:.*H\n", pd, nb->len, LWIP_MIN(nb->len * 2, 40), nb->payload)); #endif /* PPPOS_SUPPORT && VJ_SUPPORT */ break; case PPP_IP: /* Internet Protocol */ - PPPDEBUG((LOG_INFO, "pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: ip in pbuf len=%d\n", pd, nb->len)); if (pppControl[pd].netif.input) { pppControl[pd].netif.input(nb, &pppControl[pd].netif); return; @@ -1704,23 +1677,24 @@ pppInput(void *arg) */ for (i = 0; (protp = ppp_protocols[i]) != NULL; ++i) { if (protp->protocol == protocol && protp->enabled_flag) { - PPPDEBUG((LOG_INFO, "pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: %s len=%d\n", pd, protp->name, nb->len)); nb = pppSingleBuf(nb); (*protp->input)(pd, nb->payload, nb->len); + PPPDEBUG(LOG_DETAIL, ("pppInput[%d]: packet processed\n", pd)); goto out; } } /* No handler for this protocol so reject the packet. */ - PPPDEBUG((LOG_INFO, "pppInput[%d]: rejecting unsupported proto 0x%04X len=%d\n", pd, protocol, nb->len)); + PPPDEBUG(LOG_INFO, ("pppInput[%d]: rejecting unsupported proto 0x%"X16_F" len=%d\n", pd, protocol, nb->len)); if (pbuf_header(nb, sizeof(protocol))) { LWIP_ASSERT("pbuf_header failed\n", 0); goto drop; } #if BYTE_ORDER == LITTLE_ENDIAN protocol = htons(protocol); - SMEMCPY(nb->payload, &protocol, sizeof(protocol)); #endif /* BYTE_ORDER == LITTLE_ENDIAN */ + SMEMCPY(nb->payload, &protocol, sizeof(protocol)); lcp_sprotrej(pd, nb->payload, nb->len); } break; @@ -1728,6 +1702,7 @@ pppInput(void *arg) drop: LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pd].netif); out: pbuf_free(nb); @@ -1739,118 +1714,145 @@ out: * Drop the input packet. */ static void -pppDrop(PPPControl *pc) +pppDrop(PPPControlRx *pcrx) { - if (pc->inHead != NULL) { + if (pcrx->inHead != NULL) { #if 0 - PPPDEBUG((LOG_INFO, "pppDrop: %d:%.*H\n", pc->inHead->len, min(60, pc->inHead->len * 2), pc->inHead->payload)); + PPPDEBUG(LOG_INFO, ("pppDrop: %d:%.*H\n", pcrx->inHead->len, min(60, pcrx->inHead->len * 2), pcrx->inHead->payload)); #endif - PPPDEBUG((LOG_INFO, "pppDrop: pbuf len=%d\n", pc->inHead->len)); - if (pc->inTail && (pc->inTail != pc->inHead)) { - pbuf_free(pc->inTail); + PPPDEBUG(LOG_INFO, ("pppDrop: pbuf len=%d, addr %p\n", pcrx->inHead->len, (void*)pcrx->inHead)); + if (pcrx->inTail && (pcrx->inTail != pcrx->inHead)) { + pbuf_free(pcrx->inTail); } - pbuf_free(pc->inHead); - pc->inHead = NULL; - pc->inTail = NULL; + pbuf_free(pcrx->inHead); + pcrx->inHead = NULL; + pcrx->inTail = NULL; } #if VJ_SUPPORT - vj_uncompress_err(&pc->vjComp); + vj_uncompress_err(&pppControl[pcrx->pd].vjComp); #endif /* VJ_SUPPORT */ LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif); +} + +/** Pass received raw characters to PPPoS to be decoded. This function is + * thread-safe and can be called from a dedicated RX-thread or from a main-loop. + * + * @param pd PPP descriptor index, returned by pppOpen() + * @param data received data + * @param len length of received data + */ +void +pppos_input(int pd, u_char* data, int len) +{ + pppInProc(&pppControl[pd].rx, data, len); } /** * Process a received octet string. */ static void -pppInProc(int pd, u_char *s, int l) +pppInProc(PPPControlRx *pcrx, u_char *s, int l) { - PPPControl *pc = &pppControl[pd]; struct pbuf *nextNBuf; u_char curChar; + u_char escaped; + SYS_ARCH_DECL_PROTECT(lev); - PPPDEBUG((LOG_DEBUG, "pppInProc[%d]: got %d bytes\n", pd, l)); + PPPDEBUG(LOG_DEBUG, ("pppInProc[%d]: got %d bytes\n", pcrx->pd, l)); while (l-- > 0) { curChar = *s++; - + + SYS_ARCH_PROTECT(lev); + escaped = ESCAPE_P(pcrx->inACCM, curChar); + SYS_ARCH_UNPROTECT(lev); /* Handle special characters. */ - if (ESCAPE_P(pc->inACCM, curChar)) { + if (escaped) { /* Check for escape sequences. */ /* XXX Note that this does not handle an escaped 0x5d character which * would appear as an escape character. Since this is an ASCII ']' * and there is no reason that I know of to escape it, I won't complicate * the code to handle this case. GLL */ if (curChar == PPP_ESCAPE) { - pc->inEscaped = 1; + pcrx->inEscaped = 1; /* Check for the flag character. */ } else if (curChar == PPP_FLAG) { - /* If this is just an extra flag character, ignore it. */ - if (pc->inState <= PDADDRESS) { - /* ignore it */; - /* If we haven't received the packet header, drop what has come in. */ - } else if (pc->inState < PDDATA) { - PPPDEBUG((LOG_WARNING, - "pppInProc[%d]: Dropping incomplete packet %d\n", - pd, pc->inState)); - LINK_STATS_INC(link.lenerr); - pppDrop(pc); - /* If the fcs is invalid, drop the packet. */ - } else if (pc->inFCS != PPP_GOODFCS) { - PPPDEBUG((LOG_INFO, - "pppInProc[%d]: Dropping bad fcs 0x%04X proto=0x%04X\n", - pd, pc->inFCS, pc->inProtocol)); - LINK_STATS_INC(link.chkerr); - pppDrop(pc); - /* Otherwise it's a good packet so pass it on. */ - } else { - /* Trim off the checksum. */ - if(pc->inTail->len >= 2) { - pc->inTail->len -= 2; - - pc->inTail->tot_len = pc->inTail->len; - if (pc->inTail != pc->inHead) { - pbuf_cat(pc->inHead, pc->inTail); - } - } else { - pc->inTail->tot_len = pc->inTail->len; - if (pc->inTail != pc->inHead) { - pbuf_cat(pc->inHead, pc->inTail); - } - - pbuf_realloc(pc->inHead, pc->inHead->tot_len - 2); - } - - /* Dispatch the packet thereby consuming it. */ - if(tcpip_callback(pppInput, pc->inHead) != ERR_OK) { - PPPDEBUG((LOG_ERR, "pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pd)); - pbuf_free(pc->inHead); - LINK_STATS_INC(link.drop); - } - pc->inHead = NULL; - pc->inTail = NULL; - } - - /* Prepare for a new packet. */ - pc->inFCS = PPP_INITFCS; - pc->inState = PDADDRESS; - pc->inEscaped = 0; + /* If this is just an extra flag character, ignore it. */ + if (pcrx->inState <= PDADDRESS) { + /* ignore it */; + /* If we haven't received the packet header, drop what has come in. */ + } else if (pcrx->inState < PDDATA) { + PPPDEBUG(LOG_WARNING, + ("pppInProc[%d]: Dropping incomplete packet %d\n", + pcrx->pd, pcrx->inState)); + LINK_STATS_INC(link.lenerr); + pppDrop(pcrx); + /* If the fcs is invalid, drop the packet. */ + } else if (pcrx->inFCS != PPP_GOODFCS) { + PPPDEBUG(LOG_INFO, + ("pppInProc[%d]: Dropping bad fcs 0x%"X16_F" proto=0x%"X16_F"\n", + pcrx->pd, pcrx->inFCS, pcrx->inProtocol)); + /* Note: If you get lots of these, check for UART frame errors or try different baud rate */ + LINK_STATS_INC(link.chkerr); + pppDrop(pcrx); + /* Otherwise it's a good packet so pass it on. */ + } else { + struct pbuf *inp; + /* Trim off the checksum. */ + if(pcrx->inTail->len >= 2) { + pcrx->inTail->len -= 2; + + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + } + } else { + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + } + + pbuf_realloc(pcrx->inHead, pcrx->inHead->tot_len - 2); + } + + /* Dispatch the packet thereby consuming it. */ + inp = pcrx->inHead; + /* Packet consumed, release our references. */ + pcrx->inHead = NULL; + pcrx->inTail = NULL; +#if PPP_INPROC_MULTITHREADED + if(tcpip_callback_with_block(pppInput, inp, 0) != ERR_OK) { + PPPDEBUG(LOG_ERR, ("pppInProc[%d]: tcpip_callback() failed, dropping packet\n", pcrx->pd)); + pbuf_free(inp); + LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pcrx->pd].netif); + } +#else /* PPP_INPROC_MULTITHREADED */ + pppInput(inp); +#endif /* PPP_INPROC_MULTITHREADED */ + } + + /* Prepare for a new packet. */ + pcrx->inFCS = PPP_INITFCS; + pcrx->inState = PDADDRESS; + pcrx->inEscaped = 0; /* Other characters are usually control characters that may have * been inserted by the physical layer so here we just drop them. */ } else { - PPPDEBUG((LOG_WARNING, - "pppInProc[%d]: Dropping ACCM char <%d>\n", pd, curChar)); + PPPDEBUG(LOG_WARNING, + ("pppInProc[%d]: Dropping ACCM char <%d>\n", pcrx->pd, curChar)); } /* Process other characters. */ } else { /* Unencode escaped characters. */ - if (pc->inEscaped) { - pc->inEscaped = 0; + if (pcrx->inEscaped) { + pcrx->inEscaped = 0; curChar ^= PPP_TRANS; } /* Process character relative to current state. */ - switch(pc->inState) { + switch(pcrx->inState) { case PDIDLE: /* Idle state - waiting. */ /* Drop the character if it's not 0xff * we would have processed a flag character above. */ @@ -1861,12 +1863,12 @@ pppInProc(int pd, u_char *s, int l) /* Fall through */ case PDSTART: /* Process start flag. */ /* Prepare for a new packet. */ - pc->inFCS = PPP_INITFCS; + pcrx->inFCS = PPP_INITFCS; /* Fall through */ case PDADDRESS: /* Process address field. */ if (curChar == PPP_ALLSTATIONS) { - pc->inState = PDCONTROL; + pcrx->inState = PDCONTROL; break; } /* Else assume compressed address and control fields so @@ -1874,38 +1876,40 @@ pppInProc(int pd, u_char *s, int l) case PDCONTROL: /* Process control field. */ /* If we don't get a valid control code, restart. */ if (curChar == PPP_UI) { - pc->inState = PDPROTOCOL1; + pcrx->inState = PDPROTOCOL1; break; } #if 0 else { - PPPDEBUG((LOG_WARNING, - "pppInProc[%d]: Invalid control <%d>\n", pd, curChar)); - pc->inState = PDSTART; + PPPDEBUG(LOG_WARNING, + ("pppInProc[%d]: Invalid control <%d>\n", pcrx->pd, curChar)); + pcrx->inState = PDSTART; } #endif case PDPROTOCOL1: /* Process protocol field 1. */ /* If the lower bit is set, this is the end of the protocol * field. */ if (curChar & 1) { - pc->inProtocol = curChar; - pc->inState = PDDATA; + pcrx->inProtocol = curChar; + pcrx->inState = PDDATA; } else { - pc->inProtocol = (u_int)curChar << 8; - pc->inState = PDPROTOCOL2; + pcrx->inProtocol = (u_int)curChar << 8; + pcrx->inState = PDPROTOCOL2; } break; case PDPROTOCOL2: /* Process protocol field 2. */ - pc->inProtocol |= curChar; - pc->inState = PDDATA; + pcrx->inProtocol |= curChar; + pcrx->inState = PDDATA; break; case PDDATA: /* Process data byte. */ /* Make space to receive processed data. */ - if (pc->inTail == NULL || pc->inTail->len == PBUF_POOL_BUFSIZE) { - if(pc->inTail) { - pc->inTail->tot_len = pc->inTail->len; - if (pc->inTail != pc->inHead) { - pbuf_cat(pc->inHead, pc->inTail); + if (pcrx->inTail == NULL || pcrx->inTail->len == PBUF_POOL_BUFSIZE) { + if (pcrx->inTail != NULL) { + pcrx->inTail->tot_len = pcrx->inTail->len; + if (pcrx->inTail != pcrx->inHead) { + pbuf_cat(pcrx->inHead, pcrx->inTail); + /* give up the inTail reference now */ + pcrx->inTail = NULL; } } /* If we haven't started a packet, we need a packet header. */ @@ -1914,33 +1918,33 @@ pppInProc(int pd, u_char *s, int l) /* No free buffers. Drop the input packet and let the * higher layers deal with it. Continue processing * the received pbuf chain in case a new packet starts. */ - PPPDEBUG((LOG_ERR, "pppInProc[%d]: NO FREE MBUFS!\n", pd)); + PPPDEBUG(LOG_ERR, ("pppInProc[%d]: NO FREE MBUFS!\n", pcrx->pd)); LINK_STATS_INC(link.memerr); - pppDrop(pc); - pc->inState = PDSTART; /* Wait for flag sequence. */ + pppDrop(pcrx); + pcrx->inState = PDSTART; /* Wait for flag sequence. */ break; } - if (pc->inHead == NULL) { + if (pcrx->inHead == NULL) { struct pppInputHeader *pih = nextNBuf->payload; - pih->unit = pd; - pih->proto = pc->inProtocol; + pih->unit = pcrx->pd; + pih->proto = pcrx->inProtocol; nextNBuf->len += sizeof(*pih); - pc->inHead = nextNBuf; + pcrx->inHead = nextNBuf; } - pc->inTail = nextNBuf; + pcrx->inTail = nextNBuf; } /* Load character into buffer. */ - ((u_char*)pc->inTail->payload)[pc->inTail->len++] = curChar; + ((u_char*)pcrx->inTail->payload)[pcrx->inTail->len++] = curChar; break; } /* update the frame check sequence number. */ - pc->inFCS = PPP_FCS(pc->inFCS, curChar); + pcrx->inFCS = PPP_FCS(pcrx->inFCS, curChar); } - } + } /* while (l-- > 0), all bytes processed */ avRandomize(); } @@ -1954,7 +1958,7 @@ pppInProcOverEthernet(int pd, struct pbuf *pb) u16_t inProtocol; if(pb->len < sizeof(inProtocol)) { - PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: too small for protocol field\n")); + PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: too small for protocol field\n")); goto drop; } @@ -1962,7 +1966,7 @@ pppInProcOverEthernet(int pd, struct pbuf *pb) /* make room for pppInputHeader - should not fail */ if (pbuf_header(pb, sizeof(*pih) - sizeof(inProtocol)) != 0) { - PPPDEBUG((LOG_ERR, "pppInProcOverEthernet: could not allocate room for header\n")); + PPPDEBUG(LOG_ERR, ("pppInProcOverEthernet: could not allocate room for header\n")); goto drop; } @@ -1972,18 +1976,45 @@ pppInProcOverEthernet(int pd, struct pbuf *pb) pih->proto = inProtocol; /* Dispatch the packet thereby consuming it. */ - if(tcpip_callback(pppInput, pb) != ERR_OK) { - PPPDEBUG((LOG_ERR, "pppInProcOverEthernet[%d]: tcpip_callback() failed, dropping packet\n", pd)); - goto drop; - } - + pppInput(pb); return; drop: LINK_STATS_INC(link.drop); + snmp_inc_ifindiscards(&pppControl[pd].netif); pbuf_free(pb); return; } #endif /* PPPOE_SUPPORT */ +#if LWIP_NETIF_STATUS_CALLBACK +/** Set the status callback of a PPP's netif + * + * @param pd The PPP descriptor returned by pppOpen() + * @param status_callback pointer to the status callback function + * + * @see netif_set_status_callback + */ +void +ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback) +{ + netif_set_status_callback(&pppControl[pd].netif, status_callback); +} +#endif /* LWIP_NETIF_STATUS_CALLBACK */ + +#if LWIP_NETIF_LINK_CALLBACK +/** Set the link callback of a PPP's netif + * + * @param pd The PPP descriptor returned by pppOpen() + * @param link_callback pointer to the link callback function + * + * @see netif_set_link_callback + */ +void +ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback) +{ + netif_set_link_callback(&pppControl[pd].netif, link_callback); +} +#endif /* LWIP_NETIF_LINK_CALLBACK */ + #endif /* PPP_SUPPORT */ diff --git a/core/lwip/src/netif/ppp/ppp.h b/core/lwip/src/netif/ppp/ppp.h index ebc733be..a72ac957 100644 --- a/core/lwip/src/netif/ppp/ppp.h +++ b/core/lwip/src/netif/ppp/ppp.h @@ -40,12 +40,23 @@ #include "lwip/def.h" #include "lwip/sio.h" -#include "lwip/api.h" -#include "lwip/sockets.h" #include "lwip/stats.h" #include "lwip/mem.h" -#include "lwip/tcpip.h" #include "lwip/netif.h" +#include "lwip/sys.h" +#include "lwip/timers.h" + +/** Some defines for code we skip compared to the original pppd. + * These are just here to minimise the use of the ugly "#if 0". */ +#define PPP_ADDITIONAL_CALLBACKS 0 + +/** Some error checks to test for unsupported code */ +#if CBCP_SUPPORT +#error "CBCP is not supported in lwIP PPP" +#endif +#if CCP_SUPPORT +#error "CCP is not supported in lwIP PPP" +#endif /* * pppd.h - PPP daemon global declarations. @@ -93,7 +104,7 @@ * OR MODIFICATIONS. */ -#define TIMEOUT(f, a, t) sys_untimeout((f), (a)), sys_timeout((t)*1000, (f), (a)) +#define TIMEOUT(f, a, t) do { sys_untimeout((f), (a)); sys_timeout((t)*1000, (f), (a)); } while(0) #define UNTIMEOUT(f, a) sys_untimeout((f), (a)) @@ -212,7 +223,7 @@ enum NPmode { #define BZERO(s, n) memset(s, 0, n) #if PPP_DEBUG -#define PRINTMSG(m, l) { m[l] = '\0'; ppp_trace(LOG_INFO, "Remote message: %s\n", m); } +#define PRINTMSG(m, l) { m[l] = '\0'; LWIP_DEBUGF(LOG_INFO, ("Remote message: %s\n", m)); } #else /* PPP_DEBUG */ #define PRINTMSG(m, l) #endif /* PPP_DEBUG */ @@ -276,24 +287,24 @@ struct protent { void (*open) (int unit); /* Close the protocol */ void (*close) (int unit, char *reason); -#if 0 +#if PPP_ADDITIONAL_CALLBACKS /* Print a packet in readable form */ int (*printpkt) (u_char *pkt, int len, void (*printer) (void *, char *, ...), void *arg); /* Process a received data packet */ void (*datainput) (int unit, u_char *pkt, int len); -#endif - int enabled_flag; /* 0 iff protocol is disabled */ +#endif /* PPP_ADDITIONAL_CALLBACKS */ + int enabled_flag; /* 0 if protocol is disabled */ char *name; /* Text name of protocol */ -#if 0 +#if PPP_ADDITIONAL_CALLBACKS /* Check requested options, assign defaults */ void (*check_options) (u_long); /* Configure interface for demand-dial */ int (*demand_conf) (int unit); /* Say whether to bring up link for this pkt */ int (*active_pkt) (u_char *pkt, int len); -#endif +#endif /* PPP_ADDITIONAL_CALLBACKS */ }; /* @@ -325,7 +336,7 @@ struct ppp_settings { }; struct ppp_addrs { - struct ip_addr our_ipaddr, his_ipaddr, netmask, dns1, dns2; + ip_addr_t our_ipaddr, his_ipaddr, netmask, dns1, dns2; }; /***************************** @@ -413,7 +424,7 @@ int pppIOCtl(int pd, int cmd, void *arg); /* * Return the Maximum Transmission Unit for the given PPP connection. */ -u_int pppMTU(int pd); +u_short pppMTU(int pd); /* * Write n characters to a ppp link. @@ -429,10 +440,10 @@ void pppLinkTerminated(int pd); void pppLinkDown(int pd); -void pppMainWakeup(int pd); +void pppos_input(int pd, u_char* data, int len); /* Configure i/f transmit parameters */ -void ppp_send_config (int, int, u32_t, int, int); +void ppp_send_config (int, u16_t, u32_t, int, int); /* Set extended transmit ACCM */ void ppp_set_xaccm (int, ext_accm *); /* Configure i/f receive parameters */ @@ -441,7 +452,7 @@ void ppp_recv_config (int, int, u32_t, int, int); int get_idle_time (int, struct ppp_idle *); /* Configure VJ TCP header compression */ -int sifvjcomp (int, int, int, int); +int sifvjcomp (int, int, u8_t, u8_t); /* Configure i/f down (for IP) */ int sifup (int); /* Set mode for handling packets for proto */ @@ -460,6 +471,13 @@ int cifdefaultroute (int, u32_t, u32_t); /* Get appropriate netmask for address */ u32_t GetMask (u32_t); +#if LWIP_NETIF_STATUS_CALLBACK +void ppp_set_netif_statuscallback(int pd, netif_status_callback_fn status_callback); +#endif /* LWIP_NETIF_STATUS_CALLBACK */ +#if LWIP_NETIF_LINK_CALLBACK +void ppp_set_netif_linkcallback(int pd, netif_status_callback_fn link_callback); +#endif /* LWIP_NETIF_LINK_CALLBACK */ + #endif /* PPP_SUPPORT */ #endif /* PPP_H */ diff --git a/core/lwip/src/netif/ppp/ppp_oe.c b/core/lwip/src/netif/ppp/ppp_oe.c index 5a8a45cf..040a0bc9 100644 --- a/core/lwip/src/netif/ppp/ppp_oe.c +++ b/core/lwip/src/netif/ppp/ppp_oe.c @@ -72,104 +72,22 @@ #if PPPOE_SUPPORT /* don't build if not configured for use in lwipopts.h */ +#include "netif/ppp_oe.h" + #include "ppp.h" #include "pppdebug.h" -#include "lwip/sys.h" - -#include "netif/ppp_oe.h" -#include "netif/etharp.h" +#include "lwip/timers.h" +#include "lwip/memp.h" #include <string.h> #include <stdio.h> -/** @todo Replace this part with a simple list like other lwIP lists */ -#ifndef _SYS_QUEUE_H_ -#define _SYS_QUEUE_H_ - -/* - * A list is headed by a single forward pointer (or an array of forward - * pointers for a hash table header). The elements are doubly linked - * so that an arbitrary element can be removed without a need to - * traverse the list. New elements can be added to the list before - * or after an existing element or at the head of the list. A list - * may only be traversed in the forward direction. - * - * For details on the use of these macros, see the queue(3) manual page. - */ - -/* - * List declarations. - */ -#define LIST_HEAD(name, type) \ -struct name { \ - struct type *lh_first; /* first element */ \ -} - -#define LIST_HEAD_INITIALIZER(head) \ - { NULL } - -#define LIST_ENTRY(type) \ -struct { \ - struct type *le_next; /* next element */ \ - struct type **le_prev; /* address of previous next element */ \ -} - -/* - * List functions. - */ - -#define LIST_EMPTY(head) ((head)->lh_first == NULL) - -#define LIST_FIRST(head) ((head)->lh_first) - -#define LIST_FOREACH(var, head, field) \ - for ((var) = LIST_FIRST((head)); \ - (var); \ - (var) = LIST_NEXT((var), field)) - -#define LIST_INIT(head) do { \ - LIST_FIRST((head)) = NULL; \ -} while (0) - -#define LIST_INSERT_AFTER(listelm, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_NEXT((listelm), field)) != NULL) \ - LIST_NEXT((listelm), field)->field.le_prev = \ - &LIST_NEXT((elm), field); \ - LIST_NEXT((listelm), field) = (elm); \ - (elm)->field.le_prev = &LIST_NEXT((listelm), field); \ -} while (0) - -#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ - (elm)->field.le_prev = (listelm)->field.le_prev; \ - LIST_NEXT((elm), field) = (listelm); \ - *(listelm)->field.le_prev = (elm); \ - (listelm)->field.le_prev = &LIST_NEXT((elm), field); \ -} while (0) - -#define LIST_INSERT_HEAD(head, elm, field) do { \ - if ((LIST_NEXT((elm), field) = LIST_FIRST((head))) != NULL) \ - LIST_FIRST((head))->field.le_prev = &LIST_NEXT((elm), field); \ - LIST_FIRST((head)) = (elm); \ - (elm)->field.le_prev = &LIST_FIRST((head)); \ -} while (0) - -#define LIST_NEXT(elm, field) ((elm)->field.le_next) - -#define LIST_REMOVE(elm, field) do { \ - if (LIST_NEXT((elm), field) != NULL) \ - LIST_NEXT((elm), field)->field.le_prev = \ - (elm)->field.le_prev; \ - *(elm)->field.le_prev = LIST_NEXT((elm), field); \ -} while (0) - -#endif /* !_SYS_QUEUE_H_ */ - /* Add a 16 bit unsigned value to a buffer pointed to by PTR */ #define PPPOE_ADD_16(PTR, VAL) \ - *(PTR)++ = (VAL) / 256; \ - *(PTR)++ = (VAL) % 256 + *(PTR)++ = (u8_t)((VAL) / 256); \ + *(PTR)++ = (u8_t)((VAL) % 256) /* Add a complete PPPoE header to the buffer pointed to by PTR */ #define PPPOE_ADD_HEADER(PTR, CODE, SESS, LEN) \ @@ -184,31 +102,16 @@ struct { \ #define PPPOE_DISC_MAXPADR 2 /* retry PADR twice */ #ifdef PPPOE_SERVER +#error "PPPOE_SERVER is not yet supported under lwIP!" /* from if_spppsubr.c */ #define IFF_PASSIVE IFF_LINK0 /* wait passively for connection */ #endif -struct pppoe_softc { - LIST_ENTRY(pppoe_softc) sc_list; - struct netif *sc_ethif; /* ethernet interface we are using */ - int sc_pd; /* ppp unit number */ - void (*sc_linkStatusCB)(int pd, int up); - - int sc_state; /* discovery phase or session connected */ - struct eth_addr sc_dest; /* hardware address of concentrator */ - u16_t sc_session; /* PPPoE session id */ - - char *sc_service_name; /* if != NULL: requested name of service */ - char *sc_concentrator_name; /* if != NULL: requested concentrator id */ - u8_t *sc_ac_cookie; /* content of AC cookie we must echo back */ - size_t sc_ac_cookie_len; /* length of cookie data */ -#ifdef PPPOE_SERVER - u8_t *sc_hunique; /* content of host unique we must echo back */ - size_t sc_hunique_len; /* length of host unique */ +#ifndef PPPOE_ERRORSTRING_LEN +#define PPPOE_ERRORSTRING_LEN 64 #endif - int sc_padi_retried; /* number of PADI retries already done */ - int sc_padr_retried; /* number of PADR retries already done */ -}; +static char pppoe_error_tmp[PPPOE_ERRORSTRING_LEN]; + /* input routines */ static void pppoe_dispatch_disc_pkt(struct netif *, struct pbuf *); @@ -234,24 +137,16 @@ static err_t pppoe_send_padt(struct netif *, u_int, const u8_t *); static struct pppoe_softc * pppoe_find_softc_by_session(u_int, struct netif *); static struct pppoe_softc * pppoe_find_softc_by_hunique(u8_t *, size_t, struct netif *); -static LIST_HEAD(pppoe_softc_head, pppoe_softc) pppoe_softc_list; - -int pppoe_hdrlen; - -void -pppoe_init(void) -{ - pppoe_hdrlen = sizeof(struct eth_hdr) + PPPOE_HEADERLEN; - LIST_INIT(&pppoe_softc_list); -} +/** linked list of created pppoe interfaces */ +static struct pppoe_softc *pppoe_softc_list; err_t pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), struct pppoe_softc **scptr) { struct pppoe_softc *sc; - sc = mem_malloc(sizeof(struct pppoe_softc)); - if(!sc) { + sc = (struct pppoe_softc *)memp_malloc(MEMP_PPPOE_IF); + if (sc == NULL) { *scptr = NULL; return ERR_MEM; } @@ -264,7 +159,9 @@ pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), sc->sc_linkStatusCB = linkStatusCB; sc->sc_ethif = ethif; - LIST_INSERT_HEAD(&pppoe_softc_list, sc, sc_list); + /* put the new interface at the head of the list */ + sc->next = pppoe_softc_list; + pppoe_softc_list = sc; *scptr = sc; @@ -274,9 +171,9 @@ pppoe_create(struct netif *ethif, int pd, void (*linkStatusCB)(int pd, int up), err_t pppoe_destroy(struct netif *ifp) { - struct pppoe_softc * sc; + struct pppoe_softc *sc, *prev = NULL; - LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + for (sc = pppoe_softc_list; sc != NULL; prev = sc, sc = sc->next) { if (sc->sc_ethif == ifp) { break; } @@ -286,19 +183,24 @@ pppoe_destroy(struct netif *ifp) return ERR_IF; } - tcpip_untimeout(pppoe_timeout, sc); - LIST_REMOVE(sc, sc_list); + sys_untimeout(pppoe_timeout, sc); + if (prev == NULL) { + /* remove sc from the head of the list */ + pppoe_softc_list = sc->next; + } else { + /* remove sc from the list */ + prev->next = sc->next; + } +#ifdef PPPOE_TODO if (sc->sc_concentrator_name) { mem_free(sc->sc_concentrator_name); } if (sc->sc_service_name) { mem_free(sc->sc_service_name); } - if (sc->sc_ac_cookie) { - mem_free(sc->sc_ac_cookie); - } - mem_free(sc); +#endif /* PPPOE_TODO */ + memp_free(MEMP_PPPOE_IF, sc); return ERR_OK; } @@ -318,7 +220,7 @@ pppoe_find_softc_by_session(u_int session, struct netif *rcvif) return NULL; } - LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { if (sc->sc_state == PPPOE_STATE_SESSION && sc->sc_session == session) { if (sc->sc_ethif == rcvif) { @@ -338,7 +240,7 @@ pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) { struct pppoe_softc *sc, *t; - if (LIST_EMPTY(&pppoe_softc_list)) { + if (pppoe_softc_list == NULL) { return NULL; } @@ -347,14 +249,14 @@ pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) } MEMCPY(&t, token, len); - LIST_FOREACH(sc, &pppoe_softc_list, sc_list) { + for (sc = pppoe_softc_list; sc != NULL; sc = sc->next) { if (sc == t) { break; } } if (sc == NULL) { - PPPDEBUG((LOG_DEBUG, "pppoe: alien host unique tag, no session found\n")); + PPPDEBUG(LOG_DEBUG, ("pppoe: alien host unique tag, no session found\n")); return NULL; } @@ -373,10 +275,8 @@ pppoe_find_softc_by_hunique(u8_t *token, size_t len, struct netif *rcvif) } static void -pppoe_linkstatus_up(void *arg) +pppoe_linkstatus_up(struct pppoe_softc *sc) { - struct pppoe_softc *sc = (struct pppoe_softc*)arg; - sc->sc_linkStatusCB(sc->sc_pd, 1); } @@ -389,9 +289,8 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) struct pppoe_softc *sc; const char *err_msg; char devname[6]; - char *error; u8_t *ac_cookie; - size_t ac_cookie_len; + u16_t ac_cookie_len; #ifdef PPPOE_SERVER u8_t *hunique; size_t hunique_len; @@ -439,7 +338,7 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) goto done; } if(pb->tot_len == pb->len) { - pb->tot_len = pb->len = off + plen; /* ignore trailing garbage */ + pb->tot_len = pb->len = (u16_t)off + plen; /* ignore trailing garbage */ } tag = 0; len = 0; @@ -492,17 +391,11 @@ pppoe_dispatch_disc_pkt(struct netif *netif, struct pbuf *pb) break; } if (err_msg) { - error = NULL; if (errortag && len) { - error = mem_malloc(len+1); - if (error) { - strncpy(error, (char*)pb->payload + off + sizeof(pt), len); - error[len-1] = '\0'; - } - } - if (error) { - printf("%s: %s: %s\n", devname, err_msg, error); - mem_free(error); + u16_t error_len = LWIP_MIN(len, sizeof(pppoe_error_tmp)-1); + strncpy(pppoe_error_tmp, (char*)pb->payload + off + sizeof(pt), error_len); + pppoe_error_tmp[error_len-1] = '\0'; + printf("%s: %s: %s\n", devname, err_msg, pppoe_error_tmp); } else { printf("%s: %s\n", devname, err_msg); } @@ -554,9 +447,9 @@ breakbreak:; sc->sc_state = PPPOE_STATE_PADO_SENT; pppoe_send_pado(sc); break; - #endif /* PPPOE_SERVER */ +#endif /* PPPOE_SERVER */ case PPPOE_CODE_PADR: - #ifdef PPPOE_SERVER +#ifdef PPPOE_SERVER /* * get sc from ac_cookie if IFF_PASSIVE */ @@ -590,16 +483,16 @@ breakbreak:; } pppoe_send_pads(sc); sc->sc_state = PPPOE_STATE_SESSION; - tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ + pppoe_linkstatus_up(sc); /* notify upper layers */ break; - #else +#else /* ignore, we are no access concentrator */ goto done; - #endif /* PPPOE_SERVER */ +#endif /* PPPOE_SERVER */ case PPPOE_CODE_PADO: if (sc == NULL) { /* be quiet if there is not a single pppoe instance */ - if (!LIST_EMPTY(&pppoe_softc_list)) { + if (pppoe_softc_list != NULL) { printf("pppoe: received PADO but could not find request for it\n"); } goto done; @@ -609,34 +502,27 @@ breakbreak:; goto done; } if (ac_cookie) { - if (sc->sc_ac_cookie) { - mem_free(sc->sc_ac_cookie); - } - sc->sc_ac_cookie = mem_malloc(ac_cookie_len); - if (sc->sc_ac_cookie == NULL) { - goto done; - } sc->sc_ac_cookie_len = ac_cookie_len; MEMCPY(sc->sc_ac_cookie, ac_cookie, ac_cookie_len); } MEMCPY(&sc->sc_dest, ethhdr->src.addr, sizeof(sc->sc_dest.addr)); - tcpip_untimeout(pppoe_timeout, sc); + sys_untimeout(pppoe_timeout, sc); sc->sc_padr_retried = 0; sc->sc_state = PPPOE_STATE_PADR_SENT; if ((err = pppoe_send_padr(sc)) != 0) { - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } - tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); break; case PPPOE_CODE_PADS: if (sc == NULL) { goto done; } sc->sc_session = session; - tcpip_untimeout(pppoe_timeout, sc); - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x connected\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, session)); sc->sc_state = PPPOE_STATE_SESSION; - tcpip_timeout (100, pppoe_linkstatus_up, sc); /* notify upper layers */ + pppoe_linkstatus_up(sc); /* notify upper layers */ break; case PPPOE_CODE_PADT: if (sc == NULL) { @@ -646,11 +532,11 @@ breakbreak:; break; default: if(sc) { - printf("%c%c%"U16_F": unknown code (0x%04x) session = 0x%04x\n", + printf("%c%c%"U16_F": unknown code (0x%"X16_F") session = 0x%"X16_F"\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, - ph->code, session); + (u16_t)ph->code, session); } else { - printf("pppoe: unknown code (0x%04x) session = 0x%04x\n", ph->code, session); + printf("pppoe: unknown code (0x%"X16_F") session = 0x%"X16_F"\n", (u16_t)ph->code, session); } break; } @@ -664,7 +550,7 @@ void pppoe_disc_input(struct netif *netif, struct pbuf *p) { /* avoid error messages if there is not a single pppoe instance */ - if (!LIST_EMPTY(&pppoe_softc_list)) { + if (pppoe_softc_list != NULL) { pppoe_dispatch_disc_pkt(netif, p); } else { pbuf_free(p); @@ -686,7 +572,7 @@ pppoe_data_input(struct netif *netif, struct pbuf *pb) #endif if (pbuf_header(pb, -(int)sizeof(struct eth_hdr)) != 0) { /* bail out */ - PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header failed\n")); + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header failed\n")); LINK_STATS_INC(link.lenerr); goto drop; } @@ -726,12 +612,12 @@ pppoe_data_input(struct netif *netif, struct pbuf *pb) if (pbuf_header(pb, -(int)(PPPOE_HEADERLEN)) != 0) { /* bail out */ - PPPDEBUG((LOG_ERR, "pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); + PPPDEBUG(LOG_ERR, ("pppoe_data_input: pbuf_header PPPOE_HEADERLEN failed\n")); LINK_STATS_INC(link.lenerr); goto drop; } - PPPDEBUG((LOG_DEBUG, "pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", + PPPDEBUG(LOG_DEBUG, ("pppoe_data_input: %c%c%"U16_F": pkthdr.len=%d, pppoe.len=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, pb->len, plen)); @@ -765,7 +651,7 @@ pppoe_output(struct pppoe_softc *sc, struct pbuf *pb) MEMCPY(ethhdr->dest.addr, sc->sc_dest.addr, sizeof(ethhdr->dest.addr)); MEMCPY(ethhdr->src.addr, ((struct eth_addr *)sc->sc_ethif->hwaddr)->addr, sizeof(ethhdr->src.addr)); - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F" (%x) state=%d, session=0x%x output -> %02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F":%02"X16_F", len=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, etype, sc->sc_state, sc->sc_session, sc->sc_dest.addr[0], sc->sc_dest.addr[1], sc->sc_dest.addr[2], sc->sc_dest.addr[3], sc->sc_dest.addr[4], sc->sc_dest.addr[5], @@ -783,46 +669,59 @@ pppoe_send_padi(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; - int len, l1 = 0, l2 = 0; /* XXX: gcc */ + int len; +#ifdef PPPOE_TODO + int l1 = 0, l2 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ if (sc->sc_state >PPPOE_STATE_PADI_SENT) { - PPPDEBUG((LOG_ERR, "ERROR: pppoe_send_padi in state %d", sc->sc_state)); + PPPDEBUG(LOG_ERR, ("ERROR: pppoe_send_padi in state %d", sc->sc_state)); } /* calculate length of frame (excluding ethernet header + pppoe header) */ len = 2 + 2 + 2 + 2 + sizeof sc; /* service name tag is required, host unique is send too */ +#ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { - l1 = strlen(sc->sc_service_name); + l1 = (int)strlen(sc->sc_service_name); len += l1; } if (sc->sc_concentrator_name != NULL) { - l2 = strlen(sc->sc_concentrator_name); + l2 = (int)strlen(sc->sc_concentrator_name); len += 2 + 2 + l2; } +#endif /* PPPOE_TODO */ + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); /* allocate a buffer */ - pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload + sizeof (struct eth_hdr); /* fill in pkt */ - PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, len); + PPPOE_ADD_HEADER(p, PPPOE_CODE_PADI, 0, (u16_t)len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { PPPOE_ADD_16(p, l1); MEMCPY(p, sc->sc_service_name, l1); p += l1; - } else { + } else +#endif /* PPPOE_TODO */ + { PPPOE_ADD_16(p, 0); } +#ifdef PPPOE_TODO if (sc->sc_concentrator_name != NULL) { PPPOE_ADD_16(p, PPPOE_TAG_ACNAME); PPPOE_ADD_16(p, l2); MEMCPY(p, sc->sc_concentrator_name, l2); p += l2; } +#endif /* PPPOE_TODO */ PPPOE_ADD_16(p, PPPOE_TAG_HUNIQUE); PPPOE_ADD_16(p, sizeof(sc)); MEMCPY(p, &sc, sizeof sc); @@ -837,7 +736,7 @@ pppoe_timeout(void *arg) int retry_wait, err; struct pppoe_softc *sc = (struct pppoe_softc*)arg; - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": timeout\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); switch (sc->sc_state) { case PPPOE_STATE_PADI_SENT: @@ -869,9 +768,9 @@ pppoe_timeout(void *arg) } if ((err = pppoe_send_padi(sc)) != 0) { sc->sc_padi_retried--; - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to transmit PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } - tcpip_timeout(retry_wait, pppoe_timeout, sc); + sys_timeout(retry_wait, pppoe_timeout, sc); break; case PPPOE_STATE_PADR_SENT: @@ -881,16 +780,16 @@ pppoe_timeout(void *arg) sc->sc_state = PPPOE_STATE_PADI_SENT; sc->sc_padr_retried = 0; if ((err = pppoe_send_padi(sc)) != 0) { - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } - tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padi_retried), pppoe_timeout, sc); return; } if ((err = pppoe_send_padr(sc)) != 0) { sc->sc_padr_retried--; - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": failed to send PADR, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); } - tcpip_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); + sys_timeout(PPPOE_DISC_TIMEOUT * (1 + sc->sc_padr_retried), pppoe_timeout, sc); break; case PPPOE_STATE_CLOSING: pppoe_do_disconnect(sc); @@ -920,8 +819,8 @@ pppoe_connect(struct pppoe_softc *sc) sc->sc_state = PPPOE_STATE_PADI_SENT; sc->sc_padr_retried = 0; err = pppoe_send_padi(sc); - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": failed to send PADI, error=%d\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, err)); - tcpip_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); + 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)); + sys_timeout(PPPOE_DISC_TIMEOUT, pppoe_timeout, sc); return err; } @@ -938,7 +837,7 @@ pppoe_disconnect(struct pppoe_softc *sc) * function and defer disconnecting to the timeout handler. */ sc->sc_state = PPPOE_STATE_CLOSING; - tcpip_timeout(20, pppoe_timeout, sc); + sys_timeout(20, pppoe_timeout, sc); } static int @@ -949,17 +848,13 @@ pppoe_do_disconnect(struct pppoe_softc *sc) if (sc->sc_state < PPPOE_STATE_SESSION) { err = EBUSY; } else { - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": disconnecting\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); err = pppoe_send_padt(sc->sc_ethif, sc->sc_session, (const u8_t *)&sc->sc_dest); } /* cleanup softc */ sc->sc_state = PPPOE_STATE_INITIAL; MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - if (sc->sc_ac_cookie) { - mem_free(sc->sc_ac_cookie); - sc->sc_ac_cookie = NULL; - } sc->sc_ac_cookie_len = 0; #ifdef PPPOE_SERVER if (sc->sc_hunique) { @@ -995,32 +890,43 @@ pppoe_send_padr(struct pppoe_softc *sc) { struct pbuf *pb; u8_t *p; - size_t len, l1 = 0; /* XXX: gcc */ + size_t len; +#ifdef PPPOE_TODO + size_t l1 = 0; /* XXX: gcc */ +#endif /* PPPOE_TODO */ if (sc->sc_state != PPPOE_STATE_PADR_SENT) { return ERR_CONN; } len = 2 + 2 + 2 + 2 + sizeof(sc); /* service name, host unique */ +#ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { /* service name tag maybe empty */ l1 = strlen(sc->sc_service_name); len += l1; } +#endif /* PPPOE_TODO */ if (sc->sc_ac_cookie_len > 0) { len += 2 + 2 + sc->sc_ac_cookie_len; /* AC cookie */ } - pb = pbuf_alloc(PBUF_LINK, sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len, PBUF_RAM); + LWIP_ASSERT("sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff", + sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len <= 0xffff); + pb = pbuf_alloc(PBUF_LINK, (u16_t)(sizeof(struct eth_hdr) + PPPOE_HEADERLEN + len), PBUF_RAM); if (!pb) { return ERR_MEM; } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload + sizeof (struct eth_hdr); PPPOE_ADD_HEADER(p, PPPOE_CODE_PADR, 0, len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); +#ifdef PPPOE_TODO if (sc->sc_service_name != NULL) { PPPOE_ADD_16(p, l1); MEMCPY(p, sc->sc_service_name, l1); p += l1; - } else { + } else +#endif /* PPPOE_TODO */ + { PPPOE_ADD_16(p, 0); } if (sc->sc_ac_cookie_len > 0) { @@ -1049,9 +955,10 @@ pppoe_send_padt(struct netif *outgoing_if, u_int session, const u8_t *dest) if (!pb) { return ERR_MEM; } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); ethhdr = (struct eth_hdr *)pb->payload; - ethhdr->type = htons(ETHTYPE_PPPOEDISC); + ethhdr->type = PP_HTONS(ETHTYPE_PPPOEDISC); MEMCPY(ethhdr->dest.addr, dest, sizeof(ethhdr->dest.addr)); MEMCPY(ethhdr->src.addr, ((struct eth_addr *)outgoing_if->hwaddr)->addr, sizeof(ethhdr->src.addr)); @@ -1087,6 +994,7 @@ pppoe_send_pado(struct pppoe_softc *sc) if (!pb) { return ERR_MEM; } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload + sizeof (struct eth_hdr); PPPOE_ADD_HEADER(p, PPPOE_CODE_PADO, 0, len); PPPOE_ADD_16(p, PPPOE_TAG_ACCOOKIE); @@ -1123,6 +1031,7 @@ pppoe_send_pads(struct pppoe_softc *sc) if (!pb) { return ERR_MEM; } + LWIP_ASSERT("pb->tot_len == pb->len", pb->tot_len == pb->len); p = (u8_t*)pb->payload + sizeof (struct eth_hdr); PPPOE_ADD_HEADER(p, PPPOE_CODE_PADS, sc->sc_session, len); PPPOE_ADD_16(p, PPPOE_TAG_SNAME); @@ -1158,7 +1067,7 @@ pppoe_xmit(struct pppoe_softc *sc, struct pbuf *pb) /* make room for Ethernet header - should not fail */ if (pbuf_header(pb, sizeof(struct eth_hdr) + PPPOE_HEADERLEN) != 0) { /* bail out */ - PPPDEBUG((LOG_ERR, "pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); + PPPDEBUG(LOG_ERR, ("pppoe: %c%c%"U16_F": pppoe_xmit: could not allocate room for header\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num)); LINK_STATS_INC(link.lenerr); pbuf_free(pb); return ERR_BUF; @@ -1204,8 +1113,8 @@ pppoe_clear_softc(struct pppoe_softc *sc, const char *message) LWIP_UNUSED_ARG(message); /* stop timer */ - tcpip_untimeout(pppoe_timeout, sc); - PPPDEBUG((LOG_DEBUG, "pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); + sys_untimeout(pppoe_timeout, sc); + PPPDEBUG(LOG_DEBUG, ("pppoe: %c%c%"U16_F": session 0x%x terminated, %s\n", sc->sc_ethif->name[0], sc->sc_ethif->name[1], sc->sc_ethif->num, sc->sc_session, message)); /* fix our state */ sc->sc_state = PPPOE_STATE_INITIAL; @@ -1215,10 +1124,6 @@ pppoe_clear_softc(struct pppoe_softc *sc, const char *message) /* clean up softc */ MEMCPY(&sc->sc_dest, ethbroadcast.addr, sizeof(sc->sc_dest)); - if (sc->sc_ac_cookie) { - mem_free(sc->sc_ac_cookie); - sc->sc_ac_cookie = NULL; - } sc->sc_ac_cookie_len = 0; sc->sc_session = 0; } diff --git a/core/lwip/src/netif/ppp/pppdebug.h b/core/lwip/src/netif/ppp/pppdebug.h index 6253863c..81349971 100644 --- a/core/lwip/src/netif/ppp/pppdebug.h +++ b/core/lwip/src/netif/ppp/pppdebug.h @@ -36,50 +36,37 @@ #ifndef PPPDEBUG_H #define PPPDEBUG_H -/************************ -*** PUBLIC DATA TYPES *** -************************/ /* Trace levels. */ -typedef enum { -LOG_CRITICAL = 0, -LOG_ERR = 1, -LOG_NOTICE = 2, -LOG_WARNING = 3, -LOG_INFO = 5, -LOG_DETAIL = 6, -LOG_DEBUG = 7 -} LogCodes; +#define LOG_CRITICAL (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_ERR (PPP_DEBUG | LWIP_DBG_LEVEL_SEVERE) +#define LOG_NOTICE (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_WARNING (PPP_DEBUG | LWIP_DBG_LEVEL_WARNING) +#define LOG_INFO (PPP_DEBUG) +#define LOG_DETAIL (PPP_DEBUG) +#define LOG_DEBUG (PPP_DEBUG) -/*********************** -*** PUBLIC FUNCTIONS *** -***********************/ -/* - * ppp_trace - a form of printf to send tracing information to stderr - */ -void ppp_trace(int level, const char *format,...); - #define TRACELCP PPP_DEBUG #if PPP_DEBUG -#define AUTHDEBUG(a) ppp_trace a -#define IPCPDEBUG(a) ppp_trace a -#define UPAPDEBUG(a) ppp_trace a -#define LCPDEBUG(a) ppp_trace a -#define FSMDEBUG(a) ppp_trace a -#define CHAPDEBUG(a) ppp_trace a -#define PPPDEBUG(a) ppp_trace a +#define AUTHDEBUG(a, b) LWIP_DEBUGF(a, b) +#define IPCPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define UPAPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define LCPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define FSMDEBUG(a, b) LWIP_DEBUGF(a, b) +#define CHAPDEBUG(a, b) LWIP_DEBUGF(a, b) +#define PPPDEBUG(a, b) LWIP_DEBUGF(a, b) #else /* PPP_DEBUG */ -#define AUTHDEBUG(a) -#define IPCPDEBUG(a) -#define UPAPDEBUG(a) -#define LCPDEBUG(a) -#define FSMDEBUG(a) -#define CHAPDEBUG(a) -#define PPPDEBUG(a) +#define AUTHDEBUG(a, b) +#define IPCPDEBUG(a, b) +#define UPAPDEBUG(a, b) +#define LCPDEBUG(a, b) +#define FSMDEBUG(a, b) +#define CHAPDEBUG(a, b) +#define PPPDEBUG(a, b) #endif /* PPP_DEBUG */ diff --git a/core/lwip/src/netif/ppp/randm.c b/core/lwip/src/netif/ppp/randm.c index 83c41741..2f35caf6 100644 --- a/core/lwip/src/netif/ppp/randm.c +++ b/core/lwip/src/netif/ppp/randm.c @@ -85,7 +85,7 @@ avChurnRand(char *randData, u32_t randLen) { MD5_CTX md5; - /* ppp_trace(LOG_INFO, "churnRand: %u@%P\n", randLen, randData); */ + /* LWIP_DEBUGF(LOG_INFO, ("churnRand: %u@%P\n", randLen, randData)); */ MD5Init(&md5); MD5Update(&md5, (u_char *)randPool, sizeof(randPool)); if (randData) { @@ -100,7 +100,7 @@ avChurnRand(char *randData, u32_t randLen) MD5Update(&md5, (u_char *)&sysData, sizeof(sysData)); } MD5Final((u_char *)randPool, &md5); -/* ppp_trace(LOG_INFO, "churnRand: -> 0\n"); */ +/* LWIP_DEBUGF(LOG_INFO, ("churnRand: -> 0\n")); */ } /* diff --git a/core/lwip/src/netif/ppp/vj.c b/core/lwip/src/netif/ppp/vj.c index 694b7027..b7f2d54c 100644 --- a/core/lwip/src/netif/ppp/vj.c +++ b/core/lwip/src/netif/ppp/vj.c @@ -47,18 +47,10 @@ #define INCR(counter) #endif -#if defined(NO_CHAR_BITFIELDS) -#define getip_hl(base) ((base).ip_hl_v&0xf) -#define getth_off(base) (((base).th_x2_off&0xf0)>>4) -#else -#define getip_hl(base) ((base).ip_hl) -#define getth_off(base) ((base).th_off) -#endif - void vj_compress_init(struct vjcompress *comp) { - register u_int i; + register u_char i; register struct cstate *tstate = comp->tstate; #if MAX_SLOTS == 0 @@ -86,21 +78,21 @@ vj_compress_init(struct vjcompress *comp) #define ENCODE(n) { \ if ((u_short)(n) >= 256) { \ *cp++ = 0; \ - cp[1] = (n); \ - cp[0] = (n) >> 8; \ + cp[1] = (u_char)(n); \ + cp[0] = (u_char)((n) >> 8); \ cp += 2; \ } else { \ - *cp++ = (n); \ + *cp++ = (u_char)(n); \ } \ } #define ENCODEZ(n) { \ if ((u_short)(n) >= 256 || (u_short)(n) == 0) { \ *cp++ = 0; \ - cp[1] = (n); \ - cp[0] = (n) >> 8; \ + cp[1] = (u_char)(n); \ + cp[0] = (u_char)((n) >> 8); \ cp += 2; \ } else { \ - *cp++ = (n); \ + *cp++ = (u_char)(n); \ } \ } @@ -145,11 +137,11 @@ vj_compress_init(struct vjcompress *comp) u_int vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) { - register struct ip *ip = (struct ip *)pb->payload; + register struct ip_hdr *ip = (struct ip_hdr *)pb->payload; register struct cstate *cs = comp->last_cs->cs_next; - register u_short hlen = getip_hl(*ip); - register struct tcphdr *oth; - register struct tcphdr *th; + register u_short hlen = IPH_HL(ip); + register struct tcp_hdr *oth; + register struct tcp_hdr *th; register u_short deltaS, deltaA; register u_long deltaL; register u_int changes = 0; @@ -159,7 +151,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) /* * Check that the packet is IP proto TCP. */ - if (ip->ip_p != IPPROTO_TCP) { + if (IPH_PROTO(ip) != IP_PROTO_TCP) { return (TYPE_IP); } @@ -168,11 +160,11 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) * `compressible' (i.e., ACK isn't set or some other control bit is * set). */ - if ((ip->ip_off & htons(0x3fff)) || pb->tot_len < 40) { + if ((IPH_OFFSET(ip) & PP_HTONS(0x3fff)) || pb->tot_len < 40) { return (TYPE_IP); } - th = (struct tcphdr *)&((long *)ip)[hlen]; - if ((th->th_flags & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { + th = (struct tcp_hdr *)&((long *)ip)[hlen]; + if ((TCPH_FLAGS(th) & (TCP_SYN|TCP_FIN|TCP_RST|TCP_ACK)) != TCP_ACK) { return (TYPE_IP); } /* @@ -183,9 +175,9 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) * again & we don't have to do any reordering if it's used. */ INCR(vjs_packets); - if (ip->ip_src.s_addr != cs->cs_ip.ip_src.s_addr - || ip->ip_dst.s_addr != cs->cs_ip.ip_dst.s_addr - || *(long *)th != ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { + if (!ip_addr_cmp(&ip->src, &cs->cs_ip.src) + || !ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) + || *(long *)th != ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { /* * Wasn't the first -- search for it. * @@ -204,9 +196,9 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) do { lcs = cs; cs = cs->cs_next; INCR(vjs_searches); - if (ip->ip_src.s_addr == cs->cs_ip.ip_src.s_addr - && ip->ip_dst.s_addr == cs->cs_ip.ip_dst.s_addr - && *(long *)th == ((long *)&cs->cs_ip)[getip_hl(cs->cs_ip)]) { + if (ip_addr_cmp(&ip->src, &cs->cs_ip.src) + && ip_addr_cmp(&ip->dest, &cs->cs_ip.dest) + && *(long *)th == ((long *)&cs->cs_ip)[IPH_HL(&cs->cs_ip)]) { goto found; } } while (cs != lastcs); @@ -221,7 +213,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) */ INCR(vjs_misses); comp->last_cs = lcs; - hlen += getth_off(*th); + hlen += TCPH_OFFSET(th); hlen <<= 2; /* Check that the IP/TCP headers are contained in the first buffer. */ if (hlen > pb->len) { @@ -242,13 +234,13 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) } } - oth = (struct tcphdr *)&((long *)&cs->cs_ip)[hlen]; + oth = (struct tcp_hdr *)&((long *)&cs->cs_ip)[hlen]; deltaS = hlen; - hlen += getth_off(*th); + hlen += TCPH_OFFSET(th); hlen <<= 2; /* Check that the IP/TCP headers are contained in the first buffer. */ if (hlen > pb->len) { - PPPDEBUG((LOG_INFO, "vj_compress_tcp: header len %d spans buffers\n", hlen)); + PPPDEBUG(LOG_INFO, ("vj_compress_tcp: header len %d spans buffers\n", hlen)); return (TYPE_IP); } @@ -266,9 +258,9 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) if (((u_short *)ip)[0] != ((u_short *)&cs->cs_ip)[0] || ((u_short *)ip)[3] != ((u_short *)&cs->cs_ip)[3] || ((u_short *)ip)[4] != ((u_short *)&cs->cs_ip)[4] - || getth_off(*th) != getth_off(*oth) + || TCPH_OFFSET(th) != TCPH_OFFSET(oth) || (deltaS > 5 && BCMP(ip + 1, &cs->cs_ip + 1, (deltaS - 5) << 2)) - || (getth_off(*th) > 5 && BCMP(th + 1, oth + 1, (getth_off(*th) - 5) << 2))) { + || (TCPH_OFFSET(th) > 5 && BCMP(th + 1, oth + 1, (TCPH_OFFSET(th) - 5) << 2))) { goto uncompressed; } @@ -278,11 +270,11 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) * ack, seq (the order minimizes the number of temporaries * needed in this section of code). */ - if (th->th_flags & TCP_URG) { - deltaS = ntohs(th->th_urp); + if (TCPH_FLAGS(th) & TCP_URG) { + deltaS = ntohs(th->urgp); ENCODEZ(deltaS); changes |= NEW_U; - } else if (th->th_urp != oth->th_urp) { + } else if (th->urgp != oth->urgp) { /* argh! URG not set but urp changed -- a sensible * implementation should never do this but RFC793 * doesn't prohibit the change so we have to deal @@ -290,12 +282,12 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) goto uncompressed; } - if ((deltaS = (u_short)(ntohs(th->th_win) - ntohs(oth->th_win))) != 0) { + if ((deltaS = (u_short)(ntohs(th->wnd) - ntohs(oth->wnd))) != 0) { ENCODE(deltaS); changes |= NEW_W; } - if ((deltaL = ntohl(th->th_ack) - ntohl(oth->th_ack)) != 0) { + if ((deltaL = ntohl(th->ackno) - ntohl(oth->ackno)) != 0) { if (deltaL > 0xffff) { goto uncompressed; } @@ -304,7 +296,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) changes |= NEW_A; } - if ((deltaL = ntohl(th->th_seq) - ntohl(oth->th_seq)) != 0) { + if ((deltaL = ntohl(th->seqno) - ntohl(oth->seqno)) != 0) { if (deltaL > 0xffff) { goto uncompressed; } @@ -323,8 +315,8 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) * retransmitted ack or window probe. Send it uncompressed * in case the other side missed the compressed version. */ - if (ip->ip_len != cs->cs_ip.ip_len && - ntohs(cs->cs_ip.ip_len) == hlen) { + if (IPH_LEN(ip) != IPH_LEN(&cs->cs_ip) && + ntohs(IPH_LEN(&cs->cs_ip)) == hlen) { break; } @@ -339,7 +331,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) goto uncompressed; case NEW_S|NEW_A: - if (deltaS == deltaA && deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + if (deltaS == deltaA && deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for echoed terminal traffic */ changes = SPECIAL_I; cp = new_seq; @@ -347,7 +339,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) break; case NEW_S: - if (deltaS == ntohs(cs->cs_ip.ip_len) - hlen) { + if (deltaS == ntohs(IPH_LEN(&cs->cs_ip)) - hlen) { /* special case for data xfer */ changes = SPECIAL_D; cp = new_seq; @@ -355,19 +347,19 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) break; } - deltaS = (u_short)(ntohs(ip->ip_id) - ntohs(cs->cs_ip.ip_id)); + deltaS = (u_short)(ntohs(IPH_ID(ip)) - ntohs(IPH_ID(&cs->cs_ip))); if (deltaS != 1) { ENCODEZ(deltaS); changes |= NEW_I; } - if (th->th_flags & TCP_PSH) { + if (TCPH_FLAGS(th) & TCP_PSH) { changes |= TCP_PUSH_BIT; } /* * Grab the cksum before we overwrite it below. Then update our * state with this packet's header. */ - deltaA = ntohs(th->th_sum); + deltaA = ntohs(th->chksum); BCOPY(ip, &cs->cs_ip, hlen); /* @@ -388,7 +380,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; - *cp++ = changes | NEW_C; + *cp++ = (u_char)(changes | NEW_C); *cp++ = cs->cs_id; } else { hlen -= deltaS + 3; @@ -397,10 +389,10 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) LWIP_ASSERT("pbuf_header failed\n", 0); } cp = (u_char *)pb->payload; - *cp++ = changes; + *cp++ = (u_char)changes; } - *cp++ = deltaA >> 8; - *cp++ = deltaA; + *cp++ = (u_char)(deltaA >> 8); + *cp++ = (u_char)deltaA; BCOPY(new_seq, cp, deltaS); INCR(vjs_compressed); return (TYPE_COMPRESSED_TCP); @@ -412,7 +404,7 @@ vj_compress_tcp(struct vjcompress *comp, struct pbuf *pb) */ uncompressed: BCOPY(ip, &cs->cs_ip, hlen); - ip->ip_p = cs->cs_id; + IPH_PROTO_SET(ip, cs->cs_id); comp->last_xmit = cs->cs_id; return (TYPE_UNCOMPRESSED_TCP); } @@ -436,26 +428,26 @@ vj_uncompress_uncomp(struct pbuf *nb, struct vjcompress *comp) { register u_int hlen; register struct cstate *cs; - register struct ip *ip; + register struct ip_hdr *ip; - ip = (struct ip *)nb->payload; - hlen = getip_hl(*ip) << 2; - if (ip->ip_p >= MAX_SLOTS - || hlen + sizeof(struct tcphdr) > nb->len - || (hlen += getth_off(*((struct tcphdr *)&((char *)ip)[hlen])) << 2) + ip = (struct ip_hdr *)nb->payload; + hlen = IPH_HL(ip) << 2; + if (IPH_PROTO(ip) >= MAX_SLOTS + || hlen + sizeof(struct tcp_hdr) > nb->len + || (hlen += TCPH_OFFSET(((struct tcp_hdr *)&((char *)ip)[hlen])) << 2) > nb->len || hlen > MAX_HDR) { - PPPDEBUG((LOG_INFO, "vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", - ip->ip_p, hlen, nb->len)); + PPPDEBUG(LOG_INFO, ("vj_uncompress_uncomp: bad cid=%d, hlen=%d buflen=%d\n", + IPH_PROTO(ip), hlen, nb->len)); comp->flags |= VJF_TOSS; INCR(vjs_errorin); return -1; } - cs = &comp->rstate[comp->last_recv = ip->ip_p]; + cs = &comp->rstate[comp->last_recv = IPH_PROTO(ip)]; comp->flags &=~ VJF_TOSS; - ip->ip_p = IPPROTO_TCP; + IPH_PROTO_SET(ip, IP_PROTO_TCP); BCOPY(ip, &cs->cs_ip, hlen); - cs->cs_hlen = hlen; + cs->cs_hlen = (u_short)hlen; INCR(vjs_uncompressedin); return 0; } @@ -472,7 +464,7 @@ int vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) { u_char *cp; - struct tcphdr *th; + struct tcp_hdr *th; struct cstate *cs; u_short *bp; struct pbuf *n0 = *nb; @@ -488,7 +480,7 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) * If we have a good state index, clear the 'discard' flag. */ if (*cp >= MAX_SLOTS) { - PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: bad cid=%d\n", *cp)); + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: bad cid=%d\n", *cp)); goto bad; } @@ -501,63 +493,63 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) * explicit state index, we have to toss the packet. */ if (comp->flags & VJF_TOSS) { - PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: tossing\n")); + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: tossing\n")); INCR(vjs_tossed); return (-1); } } cs = &comp->rstate[comp->last_recv]; - hlen = getip_hl(cs->cs_ip) << 2; - th = (struct tcphdr *)&((u_char *)&cs->cs_ip)[hlen]; - th->th_sum = htons((*cp << 8) | cp[1]); + hlen = IPH_HL(&cs->cs_ip) << 2; + th = (struct tcp_hdr *)&((u_char *)&cs->cs_ip)[hlen]; + th->chksum = htons((*cp << 8) | cp[1]); cp += 2; if (changes & TCP_PUSH_BIT) { - th->th_flags |= TCP_PSH; + TCPH_SET_FLAG(th, TCP_PSH); } else { - th->th_flags &=~ TCP_PSH; + TCPH_UNSET_FLAG(th, TCP_PSH); } switch (changes & SPECIALS_MASK) { case SPECIAL_I: { - register u32_t i = ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; + register u32_t i = ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->th_ack) + i; - th->th_ack = htonl(tmp); - tmp = ntohl(th->th_seq) + i; - th->th_seq = htonl(tmp); + tmp = ntohl(th->ackno) + i; + th->ackno = htonl(tmp); + tmp = ntohl(th->seqno) + i; + th->seqno = htonl(tmp); } break; case SPECIAL_D: /* some compilers can't nest inline assembler.. */ - tmp = ntohl(th->th_seq) + ntohs(cs->cs_ip.ip_len) - cs->cs_hlen; - th->th_seq = htonl(tmp); + tmp = ntohl(th->seqno) + ntohs(IPH_LEN(&cs->cs_ip)) - cs->cs_hlen; + th->seqno = htonl(tmp); break; default: if (changes & NEW_U) { - th->th_flags |= TCP_URG; - DECODEU(th->th_urp); + TCPH_SET_FLAG(th, TCP_URG); + DECODEU(th->urgp); } else { - th->th_flags &=~ TCP_URG; + TCPH_UNSET_FLAG(th, TCP_URG); } if (changes & NEW_W) { - DECODES(th->th_win); + DECODES(th->wnd); } if (changes & NEW_A) { - DECODEL(th->th_ack); + DECODEL(th->ackno); } if (changes & NEW_S) { - DECODEL(th->th_seq); + DECODEL(th->seqno); } break; } if (changes & NEW_I) { - DECODES(cs->cs_ip.ip_id); + DECODES(cs->cs_ip._id); } else { - cs->cs_ip.ip_id = ntohs(cs->cs_ip.ip_id) + 1; - cs->cs_ip.ip_id = htons(cs->cs_ip.ip_id); + IPH_ID_SET(&cs->cs_ip, ntohs(IPH_ID(&cs->cs_ip)) + 1); + IPH_ID_SET(&cs->cs_ip, htons(IPH_ID(&cs->cs_ip))); } /* @@ -571,27 +563,27 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) * We must have dropped some characters (crc should detect * this but the old slip framing won't) */ - PPPDEBUG((LOG_INFO, "vj_uncompress_tcp: head buffer %d too short %d\n", + PPPDEBUG(LOG_INFO, ("vj_uncompress_tcp: head buffer %d too short %d\n", n0->len, vjlen)); goto bad; } #if BYTE_ORDER == LITTLE_ENDIAN tmp = n0->tot_len - vjlen + cs->cs_hlen; - cs->cs_ip.ip_len = htons(tmp); + IPH_LEN_SET(&cs->cs_ip, htons((u_short)tmp)); #else - cs->cs_ip.ip_len = htons(n0->tot_len - vjlen + cs->cs_hlen); + IPH_LEN_SET(&cs->cs_ip, htons(n0->tot_len - vjlen + cs->cs_hlen)); #endif /* recompute the ip header checksum */ bp = (u_short *) &cs->cs_ip; - cs->cs_ip.ip_sum = 0; + IPH_CHKSUM_SET(&cs->cs_ip, 0); for (tmp = 0; hlen > 0; hlen -= 2) { tmp += *bp++; } tmp = (tmp & 0xffff) + (tmp >> 16); tmp = (tmp & 0xffff) + (tmp >> 16); - cs->cs_ip.ip_sum = (u_short)(~tmp); + IPH_CHKSUM_SET(&cs->cs_ip, (u_short)(~tmp)); /* Remove the compressed header and prepend the uncompressed header. */ if(pbuf_header(n0, -((s16_t)(vjlen)))) { @@ -606,7 +598,7 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) np = pbuf_alloc(PBUF_RAW, n0->len + cs->cs_hlen, PBUF_POOL); if(!np) { - PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: realign failed\n")); + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: realign failed\n")); goto bad; } @@ -636,7 +628,7 @@ vj_uncompress_tcp(struct pbuf **nb, struct vjcompress *comp) LWIP_ASSERT("vj_uncompress_tcp: cs->cs_hlen <= PBUF_POOL_BUFSIZE", cs->cs_hlen <= PBUF_POOL_BUFSIZE); np = pbuf_alloc(PBUF_RAW, cs->cs_hlen, PBUF_POOL); if(!np) { - PPPDEBUG((LOG_WARNING, "vj_uncompress_tcp: prepend failed\n")); + PPPDEBUG(LOG_WARNING, ("vj_uncompress_tcp: prepend failed\n")); goto bad; } pbuf_cat(np, n0); diff --git a/core/lwip/src/netif/ppp/vj.h b/core/lwip/src/netif/ppp/vj.h index b9617da4..fad12136 100644 --- a/core/lwip/src/netif/ppp/vj.h +++ b/core/lwip/src/netif/ppp/vj.h @@ -1,7 +1,7 @@ /* * Definitions for tcp compression routines. * - * $Id: vj.h,v 1.5 2007/12/19 20:47:23 fbernon Exp $ + * $Id: vj.h,v 1.7 2010/02/22 17:52:09 goldsimon Exp $ * * Copyright (c) 1989 Regents of the University of California. * All rights reserved. @@ -25,7 +25,8 @@ #ifndef VJ_H #define VJ_H -#include "vjbsdhdr.h" +#include "lwip/ip.h" +#include "lwip/tcp_impl.h" #define MAX_SLOTS 16 /* must be > 2 and < 256 */ #define MAX_HDR 128 @@ -108,7 +109,7 @@ struct cstate { u_char cs_filler; union { char csu_hdr[MAX_HDR]; - struct ip csu_ip; /* ip/tcp hdr from most recent packet */ + struct ip_hdr csu_ip; /* ip/tcp hdr from most recent packet */ } vjcs_u; }; #define cs_ip vjcs_u.csu_ip diff --git a/core/lwip/src/netif/ppp/vjbsdhdr.h b/core/lwip/src/netif/ppp/vjbsdhdr.h deleted file mode 100644 index f4626761..00000000 --- a/core/lwip/src/netif/ppp/vjbsdhdr.h +++ /dev/null @@ -1,75 +0,0 @@ -#ifndef VJBSDHDR_H -#define VJBSDHDR_H - -#include "lwip/tcp.h" - -/* - * Structure of an internet header, naked of options. - * - * We declare ip_len and ip_off to be short, rather than u_short - * pragmatically since otherwise unsigned comparisons can result - * against negative integers quite easily, and fail in subtle ways. - */ -PACK_STRUCT_BEGIN -struct ip -{ -#if defined(NO_CHAR_BITFIELDS) - u_char ip_hl_v; /* bug in GCC for mips means the bitfield stuff will sometimes break - so we use a char for both and get round it with macro's instead... */ -#else -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned ip_hl:4, /* header length */ - ip_v :4; /* version */ -#elif BYTE_ORDER == BIG_ENDIAN - unsigned ip_v :4, /* version */ - ip_hl:4; /* header length */ -#else - COMPLAIN - NO BYTE ORDER SELECTED! -#endif -#endif - u_char ip_tos; /* type of service */ - u_short ip_len; /* total length */ - u_short ip_id; /* identification */ - u_short ip_off; /* fragment offset field */ -#define IP_DF 0x4000 /* dont fragment flag */ -#define IP_MF 0x2000 /* more fragments flag */ -#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */ - u_char ip_ttl; /* time to live */ - u_char ip_p; /* protocol */ - u_short ip_sum; /* checksum */ - struct in_addr ip_src,ip_dst; /* source and dest address */ -}; -PACK_STRUCT_END - -typedef u32_t tcp_seq; - -/* - * TCP header. - * Per RFC 793, September, 1981. - */ -PACK_STRUCT_BEGIN -struct tcphdr -{ - u_short th_sport; /* source port */ - u_short th_dport; /* destination port */ - tcp_seq th_seq; /* sequence number */ - tcp_seq th_ack; /* acknowledgement number */ -#if defined(NO_CHAR_BITFIELDS) - u_char th_x2_off; -#else -#if BYTE_ORDER == LITTLE_ENDIAN - unsigned th_x2 :4, /* (unused) */ - th_off:4; /* data offset */ -#endif -#if BYTE_ORDER == BIG_ENDIAN - unsigned th_off:4, /* data offset */ - th_x2 :4; /* (unused) */ -#endif -#endif - u_char th_flags; - u_short th_win; /* window */ - u_short th_sum; /* checksum */ - u_short th_urp; /* urgent pointer */ -}; -PACK_STRUCT_END - -#endif /* VJBSDHDR_H */ diff --git a/core/lwip/src/netif/slipif.c b/core/lwip/src/netif/slipif.c index 089d2d3e..c19333dd 100644 --- a/core/lwip/src/netif/slipif.c +++ b/core/lwip/src/netif/slipif.c @@ -88,7 +88,7 @@ struct slipif_priv { * @return always returns ERR_OK since the serial layer does not provide return values */ err_t -slipif_output(struct netif *netif, struct pbuf *p, struct ip_addr *ipaddr) +slipif_output(struct netif *netif, struct pbuf *p, ip_addr_t *ipaddr) { struct slipif_priv *priv; struct pbuf *q; |