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 | |
parent | c135aeebe08d857548a3a56b6fc3a0125ec8972c (diff) | |
parent | 930e929b202ed292077fb14981e5c6bd4c55651e (diff) | |
download | syslinux-d493d0416f038f80d73b897e317e6d2c251c1775.tar.gz syslinux-d493d0416f038f80d73b897e317e6d2c251c1775.tar.xz syslinux-d493d0416f038f80d73b897e317e6d2c251c1775.zip |
Merge remote-tracking branch 'genec/lwip-1.4.0-test-2' into lwip
Diffstat (limited to 'core')
114 files changed, 12485 insertions, 7889 deletions
diff --git a/core/fs/pxe/tcp.c b/core/fs/pxe/tcp.c index daff4d70..ec7679e7 100644 --- a/core/fs/pxe/tcp.c +++ b/core/fs/pxe/tcp.c @@ -51,8 +51,8 @@ void tcp_fill_buffer(struct inode *inode) } /* If needed get a new netbuf */ if (!socket->buf) { - socket->buf = netconn_recv(socket->conn); - if (!socket->buf) { + err = netconn_recv(socket->conn, &(socket->buf)); + if (!socket->buf || err) { socket->tftp_goteof = 1; if (inode->size == -1) inode->size = socket->tftp_filepos; diff --git a/core/fs/pxe/tftp.c b/core/fs/pxe/tftp.c index 429e8ffe..f6ea2974 100644 --- a/core/fs/pxe/tftp.c +++ b/core/fs/pxe/tftp.c @@ -138,6 +138,7 @@ static void tftp_get_packet(struct inode *inode) struct netbuf *nbuf; u16_t nbuf_len; struct pxe_pvt_inode *socket = PVT(inode); + err_t err; /* * Start by ACKing the previous packet; this should cause @@ -151,8 +152,8 @@ static void tftp_get_packet(struct inode *inode) ack_packet(inode, socket->tftp_lastpkt); while (timeout) { - nbuf = netconn_recv(socket->conn); - if (!nbuf) { + err = netconn_recv(socket->conn, &nbuf); + if (!nbuf || err) { jiffies_t now = jiffies(); if (now-oldtime >= timeout) { @@ -318,8 +319,8 @@ sendreq: wait_pkt: netconn_disconnect(socket->conn); for (;;) { - nbuf = netconn_recv(socket->conn); - if (!nbuf) { + err = netconn_recv(socket->conn, &nbuf); + if (!nbuf || err) { jiffies_t now = jiffies(); if (now - oldtime >= timeout) goto sendreq; 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 |