Compare commits

...

746 Commits

Author SHA1 Message Date
goldsimon
7385449f33 Fixed wrong endianess of port in bind() and connect() broken with the last commit 2011-07-06 07:18:06 +00:00
goldsimon
1f4b814d0b Include opt.h so that LWIP_ERROR works correctly 2011-07-06 07:13:45 +00:00
goldsimon
a93d9c4310 Fixed bug #33561 bugs in recvfrom() and sendto() 2011-07-05 19:42:23 +00:00
goldsimon
1813d11b9d Fixed invalid SOCK_ADDR_TYPE_MATCH check in lwip_sendto() 2011-07-04 19:39:16 +00:00
goldsimon
09ac68c196 Fixed documentation after changing sys arch prototypes for 1.4.0 2011-07-04 19:33:33 +00:00
goldsimon
c2fd905e32 No need to pass 'acc' as u16_t since the _base functions are internal (we save one AND op when passing as u32_t) 2011-07-04 19:10:49 +00:00
goldsimon
cc84f28d1b Fixed bug #33672 (checksum calculate error!!!) by folding 'acc' to u16_t before calling checksum_pseudo_*_base functions 2011-06-29 19:54:33 +00:00
goldsimon
2bd498524d Fixed bug #33653 (ip_data.current_ip_header_tot_len calculation errors!) introduced while mergin IPv4 and IPv6 2011-06-29 19:46:21 +00:00
goldsimon
4b934945f3 Slightly reorderd fields of struct tcp_pcb to plug holes introduced by member alignment (to reduce RAM usage) 2011-06-26 17:53:45 +00:00
goldsimon
b666ab0673 Init checks: LWIP_RAND is needed for IPv6, too 2011-06-26 17:51:55 +00:00
goldsimon
6a4c30fe5d fixed bug #31723 (tcp_kill_prio() kills pcbs with the same prio) by updating its documentation only. 2011-06-26 17:37:09 +00:00
goldsimon
4002aef594 fixed bug #33545: With MEM_USE_POOLS==1, mem_malloc can return an unaligned pointer. 2011-06-26 17:31:10 +00:00
goldsimon
ba28d36e67 Fixed bug #33544 (warning in mem.c in lwip 1.4.0 with NO_SYS=1) 2011-06-26 17:13:57 +00:00
goldsimon
4444db2990 Added some more asserts to check that pcb->state != LISTEN 2011-06-26 17:07:13 +00:00
goldsimon
d0026793bf Cleaned up usage of sys.h a bit 2011-06-26 16:51:04 +00:00
goldsimon
93b5cd5ddd Provide a default for SNMP_GET_SYSUPTIME() based on sys_now() 2011-06-26 16:50:28 +00:00
goldsimon
12c2d7e4cf - changed "struct ip_addr" to "ip_addr_t";
- tcp_accepted(): added a note to call this on the listening pcb, not the connection pcb;
- tcp_write(): change last parameter from "copy" to "apiflags", documented the apiflags
2011-06-25 18:39:37 +00:00
idelamer
4eb5acd9e2 Don't forward IPv6 packets that are larger than outgoing MTU, send ICMPv6 message back for Path MTU discovery. 2011-06-22 12:14:58 +00:00
idelamer
0f56d838ec Process IPv6 packets arriving from non-Ethernet links. 2011-06-17 11:06:06 +00:00
idelamer
12a948dacb Allow routing IPv6 packets to neighbours with manually-configured non-link-local addresses. 2011-06-17 11:05:38 +00:00
idelamer
137953605e Allow IPv6 addresses with arbitrary prefix. 2011-06-17 11:04:47 +00:00
idelamer
629fad6f5f Minor edits for for IPv6 compilation 2011-06-17 11:03:15 +00:00
goldsimon
2911c84a69 Fixed compilation error after converting sockaddr_aligned from struct to union 2011-06-12 11:57:34 +00:00
goldsimon
89a1420609 Fix compilation error when checking for hidden variable names ('s8_t i' was hidden in some case statements in nd6_input()). 2011-06-08 16:31:55 +00:00
goldsimon
e584557afe - sockaddr_aligned: use a union instead of a manually aligned struct;
- fixed compilation for different configurations
2011-06-07 19:36:05 +00:00
goldsimon
2ed5413e24 use const char for name pointers in display functions 2011-06-07 19:32:20 +00:00
goldsimon
91532b2d5c Removed unused static function 2011-06-07 19:19:24 +00:00
goldsimon
732cac1c0e Moved static variable from inside the function to global scope 2011-06-07 19:10:55 +00:00
goldsimon
5b04860b8b Moved common call to pbuf_header outside the switch() 2011-06-07 19:10:10 +00:00
goldsimon
5a674f419d Restructured the code a bit to help my dump compiler not creating a jump table in ROM 2011-06-07 19:07:00 +00:00
goldsimon
d30246dc05 Fixed bug #33492 (fixed stats for IPv6 protocols) 2011-06-07 19:05:22 +00:00
goldsimon
af5a913019 Fixed compilation with LWIP_IPV6==0 2011-06-06 16:04:06 +00:00
goldsimon
604e69c7ae - fixed bug #33485 (forgot '!' before SOCK_ADDR_MATCH*);
- fixed 'cast increases alignment' by casting via 'void*';
- introduced 'struct sockaddr_aligned' where the 'base' type is instantiated to make sure the alignment is correct;
2011-06-06 16:00:06 +00:00
goldsimon
d765c9de37 Fixed ipX_netif_get_local_ipX for LWIP_IPV6==0 2011-05-28 09:32:42 +00:00
goldsimon
98b6e2bcce Fixed ip_2_ipX() and ip6_2_ipX() macros #if !LWIP_ALLOW_STATIC_FN_IN_HEADER 2011-05-28 09:32:07 +00:00
goldsimon
d80be7961c use PCB_IS_IPV6(pcb) instead of pcb->isipv6 everywhere; fixed compilation with LWIP_IPV6==1 but LWIP_IGMP==0 2011-05-28 09:30:43 +00:00
goldsimon
2aec3a9789 use PCB_IS_IPV6(pcb) instead of pcb->isipv6 everywhere 2011-05-28 09:28:18 +00:00
goldsimon
ccd7dbe0e4 Added ipX versions for routing 2011-05-26 15:46:44 +00:00
goldsimon
92fcfd7a6f Fixed two compilation errors with different opt.h settings 2011-05-26 14:47:28 +00:00
goldsimon
1b2b054139 Fixed bug #33337 (which is #32906 reappearing after adding IPv6 support) 2011-05-25 17:40:42 +00:00
goldsimon
853d1eac96 Fixed pointless conversion when checking TCP port range (bug #33398) 2011-05-25 17:22:56 +00:00
goldsimon
2ef29d6839 Use conversion defines instead of casting IP addresses 2011-05-25 17:22:13 +00:00
goldsimon
6865806b55 Combined IPv4 and IPv6 code where possible, added defines to access IPv4/IPv6 in non-IP code so that the code is more readable. 2011-05-25 17:16:35 +00:00
goldsimon
9546e65617 Removed autoip_init() since it does nothing; minor coding style changes 2011-05-21 16:01:19 +00:00
goldsimon
5852993243 Removed files of old IPv6 implementation 2011-05-17 19:56:08 +00:00
goldsimon
90a03a77ad Added new files for IPv6 2011-05-17 19:54:40 +00:00
goldsimon
4bfbe7ebeb ... and finally, we got a first working version of a dual-stack lwIP runnin IPv4 and IPv6 in parallel - big thanks to Ivan Delamer! (this is work in progress, so please beware, test a lot and report problems!) 2011-05-17 19:35:14 +00:00
goldsimon
f3c1686a40 replaced tab with spaces 2011-05-16 18:45:51 +00:00
goldsimon
33a587d97e Added a test for fast-rexmit 2011-05-14 15:26:43 +00:00
goldsimon
a444ec5111 patch #7449 allow tcpip callback from interrupt with static memory message 2011-05-14 12:23:10 +00:00
kieranm
5ead1bf5c8 Update version numbers for 1.4.1 development 2011-05-06 09:07:38 +00:00
kieranm
3a267586f4 Update CHANGELOG and version numbers for 1.4.0 release 2011-05-06 08:48:37 +00:00
goldsimon
52271e0366 Used upper case 'L' instead of lower case 'l' for long constant for better readability 2011-04-29 11:37:29 +00:00
goldsimon
e4739da961 Fixed overflow in tcp_new_port() after changing port range to IANA "Dynamic and/or Private Ports" range 2011-04-29 11:23:04 +00:00
goldsimon
80b344e9fc Fixed printf-format error (bug #33079) 2011-04-21 05:15:45 +00:00
goldsimon
036cb26fa3 sys_arch_timeouts() is not needed any more. 2011-04-20 11:31:07 +00:00
goldsimon
33d6dcec5b Fixed bug #33048 (Bad range for IP source port numbers) by using ports in the IANA private/dynamic range (49152 through 65535). 2011-04-13 17:52:00 +00:00
goldsimon
791505ab6e Fixed tcp unit tests after introducing ip_addr_p_t and letting tcp_input check for broadcasts by using current_iphdr_dest. 2011-03-30 18:50:00 +00:00
goldsimon
88e1719d8e Fixed etharp unit test after changing struct etharp_hdr 2011-03-30 18:47:20 +00:00
goldsimon
0885555521 Fixed broken VLAN support. 2011-03-29 18:56:26 +00:00
goldsimon
36c1750b8f ethernet_input: check for minimum packet length to prevent assertions from firing. 2011-03-29 07:55:16 +00:00
goldsimon
11b1c9f19f 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 17:12:26 +00:00
goldsimon
b5dd87b184 Fixed bug #32280 (ppp: a pbuf is freed twice) 2011-03-27 13:58:26 +00:00
goldsimon
b54c7bedfd Fixed bug #32906: lwip_connect+lwip_send did not work for udp and raw pcbs with LWIP_TCPIP_CORE_LOCKING==1. 2011-03-27 13:36:32 +00:00
goldsimon
783404d8d4 Move tcp_pcb_lists to const section. 2011-03-27 13:04:16 +00:00
goldsimon
3bad9f013e Fixed bug #32820 (Outgoing TCP connections created before route is present never times out) by starting retransmission timer before checking route. 2011-03-27 13:00:54 +00:00
goldsimon
4495516497 Removed 'dataptr' from 'struct tcp_seg' and calculate it in tcp_zero_window_probe (the only place where it was used). 2011-03-27 12:56:16 +00:00
goldsimon
3f849848a4 Fixed bug #32648 (PPP code crashes when terminating a link) by only calling sio_read_abort() if the file descriptor is valid. 2011-03-22 20:59:49 +00:00
goldsimon
7203680146 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-14 21:21:26 +00:00
goldsimon
d793ed3b9b 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 11:21:06 +00:00
goldsimon
c6de17d1e5 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 11:17:18 +00:00
goldsimon
5b084f4b95 tcp_bind: return ERR_VAL instead of ERR_ISCONN when trying to bind with state!=CLOSED; fixed a typo 2011-03-13 11:15:32 +00:00
goldsimon
4e3b2b9f6b Fixed bug #32561 tcp_poll argument definition out-of-order in documentation 2011-02-21 19:26:57 +00:00
goldsimon
856ccb5bb7 Added missing U/UL modifiers to fix 16-bit-arch portability. 2011-02-18 13:31:28 +00:00
goldsimon
dbf5659cd9 Indentation changed 2011-02-18 13:30:35 +00:00
goldsimon
fee0c6afe9 Fixed constant not being 32 bit. 2011-02-17 17:03:12 +00:00
kieranm
fb7d3a159a Update version for 1.4.0 rc2 2011-02-03 12:46:56 +00:00
goldsimon
dc6b4e65e0 Adde missing extern "C" 2011-01-25 11:35:48 +00:00
goldsimon
17d4ef4053 Added missing "extern "C" {" 2011-01-25 06:18:50 +00:00
goldsimon
03be8f88fe Fixed bug #31741: lwip_select seems to have threading problems 2011-01-24 19:28:28 +00:00
goldsimon
effcb90fdf Mreged back changes that were lost during the savannah hack 3 weeks ago (using the sources from http://git.infradead.org/users/dwmw2/lwip.git) 2010-12-20 18:03:51 +00:00
goldsimon
1bd06bee82 Added note about changed ARP_QUEUEING==0 2010-12-02 20:09:58 +00:00
goldsimon
92cdc1e33f Fixed ERR_IS_FATAL so that ERR_WOULDBLOCK is not fatal. 2010-12-02 07:07:18 +00:00
goldsimon
377628216e Fixed bug #31590: getsockopt(... SO_ERROR ...) gives EINPROGRESS after a successful nonblocking connection. 2010-11-22 20:55:57 +00:00
goldsimon
f7627929d5 Fixed bug #31722: IP packets sent with an AutoIP source addr must be sent link-local 2010-11-22 19:55:05 +00:00
goldsimon
b49cf5e7a2 patch #7328: Autoip: ETHADDR16_COPY can be used 2010-11-22 17:35:57 +00:00
goldsimon
231a6cecb4 patch #7329: tcp_timer_needed prototype was ifdef'ed out for LWIP_TIMERS==0 2010-11-22 17:32:12 +00:00
goldsimon
32f02325f9 Added a function to deallocate the struct dhcp from a netif (fixes bug #31525). 2010-11-21 13:41:11 +00:00
goldsimon
f418782c2c tcp_slowtmr(): change the scope of 'pcb2' to reflect its block-only usage. 2010-11-21 10:41:27 +00:00
goldsimon
e52730d1fb Fixed bug #31170: lwip_setsockopt() does not set socket number 2010-11-20 18:01:01 +00:00
goldsimon
d2679e58a6 Fixed bug #31304: Changed SHUT_RD, SHUT_WR and SHUT_RDWR to resemble other stacks. 2010-11-20 17:48:10 +00:00
goldsimon
e3817cd549 Fixed bug #31535: TCP_SND_QUEUELEN must be at least 2 or else no-copy TCP writes will never succeed. 2010-11-20 17:34:10 +00:00
goldsimon
4ace50a7d7 Fix alignment checking of tcphdr: check for MEM_ALIGNMENT, not for 4 2010-11-20 17:30:48 +00:00
goldsimon
fa092c47c8 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-11-20 16:40:35 +00:00
goldsimon
704d90f693 Fixed bug #31385: sizeof(struct sockaddr) is 30 but should be 16 2010-10-20 17:58:52 +00:00
goldsimon
93dc36e091 Once again fixed #30038: DHCP/AutoIP cooperation failed when replugging the network cable after an AutoIP address was assigned. 2010-10-06 11:40:30 +00:00
goldsimon
4cc36b2284 Fixed bug #30728: tcp_new_port() did not check listen pcbs 2010-08-10 20:15:31 +00:00
goldsimon
aaa8d2795e Don't chain empty pbufs when sending them (fixes bug #30625) 2010-08-03 08:38:59 +00:00
goldsimon
229137cad1 Applied patch #7264 (PPP protocols are rejected incorrectly on big endian architectures) 2010-08-01 11:15:48 +00:00
goldsimon
d73262a0e5 Fixed compilation with TCP or UDP disabled. 2010-07-29 19:25:50 +00:00
goldsimon
cd22a8d851 Fixed bug #30565 (tcp_connect() check bound list): that check did no harm but never did anything 2010-07-28 16:48:51 +00:00
goldsimon
7f7df4ae19 Fixed bug #30447: tcp.c:tcp_bind() - suspicious nested #if 2010-07-28 16:44:59 +00:00
goldsimon
3c5723e49d Fixed invalid fix for bug #30402 (CHECKSUM_GEN_IP_INLINE does not add IP options) 2010-07-21 12:11:22 +00:00
kieranm
960fb14bf5 Update release number for 1.4.0 release candidate 1 2010-07-16 12:50:29 +00:00
kieranm
21e17f649a Fixed SNMP ASN constant defines to not use ! operator 2010-07-16 12:14:01 +00:00
goldsimon
9782c40d21 fixed the change not about tcp_close chang (bug #30444) 2010-07-14 15:53:44 +00:00
goldsimon
04beab4f7d IP_MULTICAST_LOOP shall be disabled by default 2010-07-12 14:10:28 +00:00
goldsimon
194a85387b patch #7239: make tcp_state_str pointers constant 2010-07-12 09:49:00 +00:00
goldsimon
a99219ad1f added missing casts 2010-07-12 09:34:17 +00:00
goldsimon
691410ba18 task #10495: Added support for IP_MULTICAST_LOOP at socket- and raw-API level. 2010-07-12 09:34:11 +00:00
goldsimon
714a43b18c Fixed bug #30402: CHECKSUM_GEN_IP_INLINE does not add IP options 2010-07-10 12:02:28 +00:00
goldsimon
9f457d3331 Updated to current CHANGELOG 2010-07-06 20:18:12 +00:00
goldsimon
60a456f757 Added ip_addr_netmask_valid() to check if a netmask is valid (starting with ones, then only zeros) 2010-07-05 14:20:58 +00:00
goldsimon
2b355d6b34 Added some helper functions to find strings in chained pbufs 2010-07-05 14:18:03 +00:00
goldsimon
48be546357 fixed bug #30300 (shutdown parameter was not initialized in netconn_delete) 2010-06-30 08:33:14 +00:00
goldsimon
0f74a57267 Re-enabled timer logging if LWIP_DEBUG_TIMERNAMES!=0 (without function pointers, only function names), changed parameter names from 'h' to 'handler' 2010-06-29 19:55:21 +00:00
kieranm
272270c7f4 Remove unportable printing of C function pointers 2010-06-28 13:32:13 +00:00
kieranm
e2f014f457 cleanup: fix minor build failures on unix 2010-06-28 13:24:14 +00:00
goldsimon
1fba33628d Fixed compilation error due to unexpected include order 2010-06-25 18:59:29 +00:00
goldsimon
7d604a23f0 From patch #7221: added flag NO_SYS_NO_TIMERS to drop timer support for NO_SYS==1 for easier upgrading 2010-06-24 20:27:49 +00:00
goldsimon
6929a786aa Fixed bug #10088: Correctly implemented shutdown at socket level. 2010-06-24 19:33:14 +00:00
goldsimon
f61b80ca6a 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-21 18:50:16 +00:00
goldsimon
1aba9f031d nicer code for the last fix 2010-06-17 11:53:16 +00:00
goldsimon
2ffcc52f03 Fixed bug #30159: WomnIP_ACCEPT_LINK_LAYER_ADDRESSING 2010-06-16 19:53:07 +00:00
goldsimon
72518a0d6e fixed typos that MSVS did not complain about 2010-06-16 12:53:46 +00:00
goldsimon
1242575f0f 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-06-16 12:25:00 +00:00
goldsimon
6ccc2ef804 Removed leading underscore from struct name, added a comment 2010-06-15 20:33:40 +00:00
goldsimon
b3dc6f2b5b ... and forgot one tiny character... 2010-06-15 20:21:30 +00:00
goldsimon
2427917db8 Fixed bug #29970: DHCP endian issue parsing option responses 2010-06-15 20:19:14 +00:00
goldsimon
5ab40f016d Fixed bug #30039: AutoIP does not reuse previous addresses 2010-06-14 20:27:14 +00:00
goldsimon
435115d4fb Use ip_addr_set_zero instead of memset(0) 2010-06-14 20:17:08 +00:00
goldsimon
24d823dae6 bug #30129: struct _ip_addr should be struct ip_addr 2010-06-14 19:52:45 +00:00
goldsimon
2c60a48d02 ip_addr_set_any does not work on pointers... 2010-06-14 19:52:17 +00:00
goldsimon
4b0be4a477 Fixed invalid fix for bug #30038 2010-06-14 19:18:11 +00:00
goldsimon
505dd10d3c Fixed bug #29979 (lwip_sendto did not check parameter "to" != NULL) 2010-06-12 18:46:19 +00:00
goldsimon
ddd2b69f27 bug #29976: forgot some places using the changed IP address (copy vs. pointer) 2010-06-12 18:37:41 +00:00
goldsimon
66b57f89df Fixed bug #30038: dhcp_network_changed doesn't reset AUTOIP coop state 2010-06-12 17:14:00 +00:00
goldsimon
69bd5a29d9 Fixed a possible NULL-pointer deref before checking it 2010-06-12 17:05:54 +00:00
goldsimon
f7479781c1 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-22 21:11:02 +00:00
goldsimon
9bfeb4e5af Minor: added some spaces for indentation 2010-05-22 21:01:38 +00:00
goldsimon
d3e5ade2da Correctly NULL-terminate h_addr_list 2010-05-17 12:36:45 +00:00
goldsimon
3833dd86aa Added LWIP_DEBUGF warning if dns_send returns an error 2010-05-17 12:29:31 +00:00
goldsimon
25f33c8444 struct etharp_hdr: split _hwlen_protolen into two u8_t's to prevent using htons on little-endian platforms 2010-05-16 16:26:12 +00:00
goldsimon
dae247809b Add preprocessor-macros for compile-time htonl calculation (and use them throughout the stack where applicable) 2010-05-16 15:57:42 +00:00
goldsimon
81df8bdabd Added PP_HTONx/PP_NTOHx macros that can be calculated by the preprocessor (used for constants only) 2010-05-16 15:55:45 +00:00
goldsimon
03e4eb4de8 changed the semantics of LWIP_PREFIX_BYTEORDER_FUNCS to prevent "symbol already defined" i.e. when linking to winsock 2010-05-16 15:09:55 +00:00
goldsimon
290bd400c3 No need to call pppoe_init any more (since the linked list is implicitly initialized to zero by the loader) 2010-05-16 14:35:03 +00:00
goldsimon
5d0785e47a 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 14:34:16 +00:00
goldsimon
16434568b0 Use a simple linked list (next pointer) instead of sys/queue.h (from BSD) 2010-05-16 14:24:40 +00:00
goldsimon
c0e7d54e37 Removed 2 mem_mallocs: error string can be a global variable, include memory for sc_ac_cookie in struct pppoe_softc; commented out unused code (sc_service_name/sc_concentrator_name) 2010-05-16 14:11:53 +00:00
goldsimon
ccb53d9e7d DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own MEMP pool instead of the heap 2010-05-16 14:06:46 +00:00
goldsimon
03bd61c799 DNS_LOCAL_HOSTLIST_IS_DYNAMIC uses its own MEMP pool instead of the heap 2010-05-16 13:36:51 +00:00
goldsimon
6ffd29507c Free recv_data when TF_RXCLOSED is set 2010-05-16 13:12:15 +00:00
goldsimon
a880709776 Let FIN come through although TF_RXCLOSED is set, send RST when data is received although TF_RXCLOSED is set, added TCP_EVENT_CLOSED for clearer code 2010-05-15 18:12:37 +00:00
goldsimon
874d1641df Fix compilation for LWIP_EVENT_API==1 (unused args) 2010-05-15 18:10:55 +00:00
goldsimon
d8d964d09e udp_input/SO_REUSE_RXTOALL: only call pbuf_header if there is a 2nd pcb to pass the data to 2010-05-15 17:11:41 +00:00
goldsimon
46b3cb580d Removed unused SOF_* flags, ip_pcb.so_options can now be an u8_t instead of an u16_t (saves 3 bytes per pcb on a 32-bit platform) 2010-05-15 17:10:08 +00:00
goldsimon
02f5e19420 udp_input: use SO_REUSE && SO_REUSE_RXTOALL to copy incoming (broad-/multicast) data to additional pcbs 2010-05-15 16:46:53 +00:00
goldsimon
a945bf07af SO_REUSE: tcp_input: correctly handle multiple pcbs listening on the same port (but different address): first search for a specific address an only pass to ANY if no specific address has been found listening 2010-05-15 16:45:43 +00:00
goldsimon
7e5b0a9eb6 SO_REUSE: tcp_listen/tcp_connect: make sure that the 5-tuple is unique 2010-05-15 16:44:09 +00:00
goldsimon
a56795c149 Added new option SO_REUSE_RXTOALL to pass received UDP broadcast/multicast packets to more than one pcb 2010-05-15 14:52:39 +00:00
goldsimon
baeb41f5f4 SO_REUSEADDR / SO_REUSE is implemented and safe to use 2010-05-12 22:34:06 +00:00
goldsimon
d0348e0c60 task #6995: Implement SO_REUSEADDR (correctly) 2010-05-12 22:29:58 +00:00
goldsimon
ef0a7ecbcd Remove uused SOF_* flags, define inherited flags in ip.h, not in tcp_in.c 2010-05-12 22:26:06 +00:00
goldsimon
778c65d27c CHECKSUM_GEN_IP_INLINE: Use defines to access the u32_t part of an IP address 2010-05-12 08:11:45 +00:00
goldsimon
f3face9f0c Fix printf-formatter for sio_fd_t/size_t 2010-05-12 07:48:30 +00:00
goldsimon
2edd5230c9 auth_withpeer_fail(): call lcp_close(), like pppd 2.4.5 does 2010-05-11 18:11:46 +00:00
goldsimon
1551bb702d Fixed bug #29855: PPP: Backport a bugfix in LcpSendEchoRequest from pppd 2010-05-11 16:53:41 +00:00
goldsimon
d656e9f28e Added option LWIP_ARP_FILTER_NETIF to use multiple IPs on one hardware interface (by using multiple netifs, each with its own IP) 2010-05-10 14:10:46 +00:00
goldsimon
597764e35b Minor: source code layout 2010-05-10 14:02:52 +00:00
goldsimon
f9f77876a1 .. and deleted NAT again as Christian obviously didn't have the copyright on the code he sent us... THANKS!!! 2010-05-05 19:49:40 +00:00
goldsimon
67d8c7999a Free NAT entries on remove (fixes a memory leak) 2010-05-05 19:39:29 +00:00
goldsimon
a7fdb67e8f task #7506: added NAT support 2010-05-05 19:34:23 +00:00
goldsimon
4d1ff2418e Fixed bug #29271 (Application can't re-use pbufs) by updating the doc to not allow reusing pbufs after passing them to a send function 2010-05-04 19:36:49 +00:00
goldsimon
71f5fdef42 Fixed bug #29769 (sys_check_timeouts: sys_now() may overflow) 2010-05-04 19:27:42 +00:00
goldsimon
abc36471d9 Fixed bug #29763 (CHECKSUM_GEN_IP_INLINE), added macro LWIP_MAKE_U16() that's improved for endianess 2010-05-04 18:59:52 +00:00
goldsimon
4b7288e8f4 use checksum-on-copy for sending UDP data for LWIP_NETIF_TX_SINGLE_PBUF==1 2010-05-02 17:25:33 +00:00
goldsimon
108ed3c81a struct netbuf: reorder members to save some space 2010-05-02 09:10:58 +00:00
goldsimon
f98e5717e5 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-30 20:39:45 +00:00
goldsimon
3685bc4828 fixed a type 2010-04-30 20:37:22 +00:00
goldsimon
72c580236e Create overridable macros for copying 2-byte-aligned IP addresses and MAC addresses 2010-04-29 04:57:31 +00:00
goldsimon
01d2a87f5d Inline generating IP checksum to save a function call 2010-04-28 19:36:51 +00:00
goldsimon
51061fb61e Fixed bug #29617 (sometime cause stall on delete listening connection) 2010-04-21 19:59:40 +00:00
goldsimon
49e8e28cf6 Check that tcp_abort/tcp_abandon isn't called for listen-pcbs 2010-04-21 19:55:14 +00:00
goldsimon
d2c632fb18 patch #7145: Various typos in SNMP files 2010-04-14 19:13:35 +00:00
goldsimon
3562be2188 tabs -> spaces 2010-04-14 07:03:31 +00:00
goldsimon
2e18a9be63 Added an overridable define to get informed when the tcpip_thread processes messages or timeouts to implement a watchdog. 2010-04-14 07:02:26 +00:00
goldsimon
3347762df3 MEMP_OVERFLOW_CHECK: dump the element's pool's index and name when an overflow/underflow is detected 2010-04-12 11:08:11 +00:00
goldsimon
f1bc73c3ed Fixed compilation errors 2010-04-02 16:48:53 +00:00
goldsimon
a96fa7d221 Fixed compilation of debug log code (that is currently commented out) 2010-04-02 16:17:51 +00:00
goldsimon
cc3e01a9f5 Fixed compilation (removed extra tokens after #endif) 2010-03-28 18:47:37 +00:00
goldsimon
6caa389c48 Check IP_FRAG && IP_FRAG_USES_STATIC_BUF && LWIP_NETIF_TX_SINGLE_PBUF 2010-03-28 10:50:05 +00:00
goldsimon
e86446b785 patch #7143: Add a few missing const qualifiers 2010-03-28 10:28:32 +00:00
goldsimon
a00448c35a create a new (contiguous) PBUF_RAM for every outgoing fragment if LWIP_NETIF_TX_SINGLE_PBUF==1 2010-03-28 10:22:48 +00:00
goldsimon
82b9152b8d Removed checking ARP_TABLE_SIZE, this is done by the etharp module itself 2010-03-27 17:12:48 +00:00
goldsimon
d778fbb24f Speedup TX by moving code from find_entry to etharp_output/etharp_query to prevent unnecessary function calls (inspired by patch #7135). 2010-03-27 16:51:27 +00:00
goldsimon
3803a0021d patch #7130: remove meaningless const qualifiers 2010-03-27 16:25:35 +00:00
goldsimon
3c96819a2c Make LWIP_NETIF_TX_SINGLE_PBUF work for TCP, too 2010-03-26 16:54:15 +00:00
goldsimon
846a2fb933 Fixed compiling with different options disabled (TCP/UDP), triggered by bug #29345; don't allocate acceptmbox if LWIP_TCP is disabled 2010-03-26 16:09:02 +00:00
goldsimon
7e9eb55350 Added printf format modifier for mem_size_t depending on heap size 2010-03-26 15:38:01 +00:00
goldsimon
46b7bd6ec3 Make functions static where applicable, add default cases to switches where applicable, prevent old-style function prototypes (without arguments) 2010-03-26 14:07:05 +00:00
goldsimon
8bbe3d2fe0 Correctly cast pointers when assigning from void* 2010-03-26 14:05:56 +00:00
goldsimon
25f59761b3 fixed bug #29346 (removed comma after last enum member) 2010-03-26 14:05:22 +00:00
goldsimon
4b038f13de sys_thread_new: name is a const pointer 2010-03-26 14:04:03 +00:00
goldsimon
da3d84d1dc Fix compilation if ETHARP_SUPPORT_STATIC_ENTRIES==0 2010-03-26 13:40:31 +00:00
goldsimon
5ef976aed5 Fixed bug #29332: lwip_select() processes readset incorrectly 2010-03-25 12:19:39 +00:00
goldsimon
cf0b831971 Fixed bug #29080: Correctly handle remote side overrunning our rcv_wnd in ooseq case. 2010-03-25 06:39:01 +00:00
goldsimon
d861daeb4e Removed function prototype that had no corresponding implementation (pbuf_ref_chain) 2010-03-22 15:46:09 +00:00
goldsimon
0a2eb3fdc8 minor: fixed coding style 2010-03-22 15:45:34 +00:00
goldsimon
6fb248c9e0 task #10088: Fixed a bug in RST-on-close-when-not-all-data-acked implementation (plus removed some unnecessary casts) 2010-03-22 12:32:05 +00:00
goldsimon
40946a79d3 Removed duplicate TCP_REG/TCP_RMV macros, fixed debug macro implementation 2010-03-22 12:27:38 +00:00
goldsimon
124ca0fed2 tcp_listen() did not copy the pcb's prio 2010-03-22 10:06:49 +00:00
goldsimon
5d153ca1b3 Fixed compilation for MEM_USE_POOLS under MSVC (where ++ doesn't work for enums) 2010-03-22 08:38:28 +00:00
goldsimon
a5b0ea97d6 Updated netconn_write doc/comment about api_flags 2010-03-21 12:19:56 +00:00
goldsimon
0a49f2e068 Corrected spelling of ERR_WOULDBLOCK (D was missing) 2010-03-20 12:56:47 +00:00
goldsimon
57594ad7b6 tcp_write: moved initial checks to an own static function for clarity 2010-03-20 12:08:07 +00:00
goldsimon
75bb43698c Disable MEMP_TCPIP_MSG_INPKT pool for LWIP_TCPIP_CORE_LOCKING_INPUT==1 2010-03-20 11:57:34 +00:00
goldsimon
f70014b8ea Added an option to disable tcpip_(un)timeout code since the linker cannot do this automatically to save space. 2010-03-20 11:55:41 +00:00
goldsimon
5fd410db4b Added support for static ARP table entries (added option ETHARP_SUPPORT_STATIC_ENTRIES) (+ added test); refactored the etharp code a bit 2010-03-20 11:45:25 +00:00
goldsimon
385d044f7d Corrected spelling of milliseconds (my dictionary tells me to use two l's :) 2010-03-20 11:34:50 +00:00
goldsimon
d0f1c552e2 Fixed bug #29256: SNMP Trap address was not correctly set 2010-03-19 20:49:13 +00:00
goldsimon
a54bb7205d Added missing casts, use strlen + MEMCPY instead of strcpy (as that might overrun the buffer) 2010-03-16 15:14:14 +00:00
goldsimon
7466474365 Fixed compiler warnings when casting where we know the source is aligned (by casting to void-pointer first) 2010-03-15 10:44:19 +00:00
goldsimon
c4bc9ce59a Fixed alignment warnings when we know alignment is correct (by using LWIP_MEM_ALIGN) 2010-03-15 09:57:03 +00:00
goldsimon
e25c9f7951 Fixed compiler warning when LWIP_SNMP==0 2010-03-15 09:47:43 +00:00
goldsimon
94cbed5096 Corrected comment 2010-03-14 12:35:30 +00:00
goldsimon
f83ace2034 task #6849: Calculate checksum when creating TCP segments, not when (re-)transmitting them. 2010-03-14 11:26:05 +00:00
goldsimon
84ed9de21a Prepared for checksum-on-copy (task #6849):
- Added option LWIP_CHECKSUM_ON_COPY;
- Added function + define lwip_chksum_copy to create checksum when copying data
2010-03-14 11:23:37 +00:00
goldsimon
4e764017c1 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-14 10:16:43 +00:00
goldsimon
67f5e17588 Bug #29210: check alignment of struct sockaddr vs. struct sockaddr_in 2010-03-14 09:54:47 +00:00
goldsimon
d13ac66cc4 Fixed sending one byte of data in tcp_zero_window_probe (which I accidentally broke with v1.103) 2010-03-14 09:43:10 +00:00
goldsimon
9f0b7261e5 Fix calculation of tcp_mss(): when timestamps are on, this is pcb->mss - 12 or else NOCOPY-apps might generate unperformant PBUF_REF chains 2010-03-13 15:04:08 +00:00
goldsimon
ad4a869b94 Some fixes to the TCP_OVERSIZE code:
- fix compiling with TCP_OVERSIZE==0;
- fix segment-size calculation when options are used;
2010-03-13 14:29:13 +00:00
goldsimon
79d3b41e13 Reverted the change in struct sockaddr since it wasn't compatible to the standard (bug #29210) 2010-03-13 14:09:52 +00:00
goldsimon
839befe68a Corrected comment 2010-03-12 16:06:08 +00:00
goldsimon
097e8c8eb4 Fixed some issues in the TCP_OVERSIZE code:
- reset tcp_pcb.unsent_oversize when last_unsent is changed;
- added TCP_OVERSIZE_DBGCHECK: check tcp_pcb.unsent_oversize vs. (debug-only) tcp_seg.oversize_left to ensure the pcb counter is correct;
- fixed a memory leak in tcp_write;
2010-03-12 15:40:01 +00:00
goldsimon
90c7d3aaff Temporary upgrade helper: define format string for u8_t as hex if not defined in cc.h 2010-03-10 16:18:12 +00:00
goldsimon
2621e3fa19 Use a union to let struct sockaddr have the same alignment requirements as struct sockaddr_in 2010-03-10 10:53:14 +00:00
goldsimon
36d7f50d77 Renamed tcp_output_set_header to tcp_output_alloc_header and included more code common to all callers 2010-03-09 16:29:19 +00:00
goldsimon
ffbb582dde ip_output: assert for p->ref == 1 to catch TCP retransmissions where the netif hasn't freed the pbuf yet 2010-03-09 16:24:38 +00:00
goldsimon
3bfc07eb92 Added comment, use braces for single-line if-blocks 2010-03-09 15:49:57 +00:00
goldsimon
d91caf1cd3 ip_input: better check for old link-local-address (explicitly check for autoip->llipaddr instead of letting all link-local-addresses through) 2010-03-08 18:24:23 +00:00
goldsimon
2a2be49d2c 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-08 18:17:52 +00:00
goldsimon
d47a04456b bug #29105: Review printf formatters 2010-03-08 17:07:35 +00:00
goldsimon
b9499d07c2 bug #29105: Review printf formatters: added X8_F to cc.h and use it in etharp.c 2010-03-08 17:04:27 +00:00
goldsimon
5d20e690fd Added/corrected casts 2010-03-08 12:17:29 +00:00
goldsimon
1c23bfdc7f Only add hostname if it's not empty (strlen > 0) 2010-03-08 12:15:58 +00:00
goldsimon
d5531a239b 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-07 18:40:54 +00:00
goldsimon
9e37d70163 Create mem_mutext at the end of mem_init. This enables sys_mutex_new to use the heap if required. 2010-03-07 16:50:08 +00:00
goldsimon
99ff7efe80 Use braces for if-blocks 2010-03-06 12:26:20 +00:00
goldsimon
43a08bef14 tcp_accepted(): check pcb state to verify it isn't called on a connection-pcb 2010-03-06 12:06:27 +00:00
goldsimon
92beddd72f 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 11:55:00 +00:00
goldsimon
f5b783d107 Fixed LWIP_NETIF_TX_SINGLE_PBUF for LWIP_TCPIP_CORE_LOCKING 2010-03-06 11:52:55 +00:00
goldsimon
a5a870c683 LWIP_NETIF_TX_SINGLE_PBUF needs TCP_OVERSIZE >= TCP_MSS for TCP 2010-03-06 11:51:31 +00:00
goldsimon
19ab25c861 LWIP_TCPIP_CORE_LOCKING_INPUT needs LWIP_TCPIP_CORE_LOCKING to work correctly 2010-03-06 11:32:40 +00:00
goldsimon
38fcfcdfac 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-06 11:29:01 +00:00
goldsimon
957f4d8096 renamed struct lwip_socket to struct lwip_sock to avoid duplicate names (function lwip_socket) 2010-03-06 10:21:03 +00:00
goldsimon
5d4438e652 Don't try to forward link-local addresses 2010-03-06 10:15:39 +00:00
goldsimon
4649c14856 Correctly identify link-local addresses when sending ARP packets 2010-03-06 09:56:52 +00:00
goldsimon
fcf6434b4b Fixed bug #29087: etharp: don't send packets for LinkLocal-addresses to gw 2010-03-06 09:33:17 +00:00
goldsimon
464950d51e Fixed bug #29072: Correctly set ciaddr based on message-type and state. Renamed dhcp_create/delect_request to dhcp_create/delete_msg. 2010-03-05 13:37:37 +00:00
goldsimon
0b5d60db5e Correctly set TCP_WRITE_FLAG_MORE when netconn_write is split into multiple calls to tcp_write. 2010-03-05 11:34:43 +00:00
goldsimon
b6542b977e 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-03-05 11:14:31 +00:00
goldsimon
2bf1184c39 Added comment after #endif 2010-03-03 16:05:20 +00:00
goldsimon
103b5a760f tcp_connect: send timestamp-option only if (pcb->flags & TF_TIMESTAMP) != NULL (same as for passive open) 2010-03-01 19:05:52 +00:00
goldsimon
2b1c389955 Fixed accessing invalid memory when closing a listening pcb (introduced with tcp_shutdown) 2010-03-01 18:43:37 +00:00
goldsimon
8d9fa63460 PPP: use LWIP_DEBUGF() instead of ppp_trace() 2010-02-22 20:16:39 +00:00
goldsimon
52b87b751f Added a note about socket recv/accept timeout errno value 2010-02-22 19:12:21 +00:00
goldsimon
e934f8aac6 Added/improved comments and debug output; renamed 'pc' to 'pcrx' where appropriate to reflect the variable type 2010-02-22 17:58:05 +00:00
goldsimon
311d16df7d Fixed compilation error after splitting tcp.h/tcp_impl.h 2010-02-22 17:52:09 +00:00
goldsimon
ea78d69c6d Added debug output and missing casts 2010-02-22 17:49:49 +00:00
goldsimon
402597c2cb Fixed bug #28970 (invalid preprocessor macro introduced with LWIP_TCPIP_CORE_LOCKING_INPUT) 2010-02-22 12:57:00 +00:00
goldsimon
68678e21df Fixed compilation for DNS_LOCAL_HOSTLIST==1 and DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 (bug #28968) 2010-02-22 08:36:23 +00:00
goldsimon
19a9b52c06 Corrected comment 2010-02-21 19:28:46 +00:00
goldsimon
db38ee6630 Added define LWIP_TCPIP_CORE_LOCKING_INPUT that lets tcpip_input omit the thread-change to tcpip_thread and instead lock the core 2010-02-21 12:38:08 +00:00
goldsimon
1d8538bca4 Added const char* name to mem- and memp-stats for easier debugging. 2010-02-21 12:32:29 +00:00
goldsimon
b73dcfb8cf task #10140: Remove DNS_USES_STATIC_BUF (keep the implementation of DNS_USES_STATIC_BUF==1) 2010-02-21 12:15:01 +00:00
goldsimon
bcd4b76d31 Moved stack-internal parts of tcp.h to tcp_impl.h, tcp.h now only contains the actual application programmer's API 2010-02-21 11:35:21 +00:00
goldsimon
7c57ee0c17 Use tcp_debug_state_str() instead of tcp_debug_print_state() 2010-02-21 10:56:00 +00:00
goldsimon
d9157a71bb 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-20 18:05:56 +00:00
goldsimon
eae9798276 Fixed pcb leak when accept-callback is NULL and asserts are disabled 2010-02-20 17:27:08 +00:00
goldsimon
e131d3e32a tcp_alloc: set given prio to the new pcb, not TCP_PRIO_NORMAL; minor: changed comments and source code layout 2010-02-20 10:03:03 +00:00
goldsimon
36043a92e7 Restructured TCP_PCB_COMMON for a smaller size (u16_t at the end) 2010-02-20 10:01:43 +00:00
goldsimon
9b48657444 Added UPGRADING doc file that should help to upgrade apps/ports from older versions of lwIP 2010-02-20 09:36:40 +00:00
goldsimon
52970c2459 Renamed mem_realloc() to mem_trim() to prevent confusion with realloc() 2010-02-19 16:23:46 +00:00
goldsimon
8336796c1a Add matching comment to #endif 2010-02-16 21:05:06 +00:00
goldsimon
16a63c6554 Bug #28917: don't increase error counters for icmp echo response 2010-02-16 20:38:35 +00:00
goldsimon
c637441f52 tcp_seg(s)_free: remove return value, noone uses it 2010-02-16 17:20:10 +00:00
goldsimon
5b221ecd4f Added missing cast; added more debug output 2010-02-16 11:28:40 +00:00
goldsimon
7af77aefa7 Added missing casts 2010-02-16 11:28:15 +00:00
goldsimon
7c2054091d Link status does not depend on LWIP_NETIF_LINK_CALLBACK (fixes bug #28899) 2010-02-15 19:53:46 +00:00
goldsimon
e04e0cb98e 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 20:20:28 +00:00
goldsimon
e983865ad5 Disable ETHARP_TRUST_IP_MAC by default since it slows down packet reception and is not really necessary 2010-02-14 18:10:34 +00:00
goldsimon
4c9fe60693 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 18:08:16 +00:00
goldsimon
c5dfa4099d 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-14 16:44:47 +00:00
goldsimon
524b7bc36b Documented the use of netif flags 2010-02-14 16:00:46 +00:00
goldsimon
8908055b63 Revert my last changes and remove structure packing from struct dns_query and struct dns_answer since they are only used with SMEMCPY 2010-02-14 14:02:05 +00:00
goldsimon
10abe8aba2 Use pointers instead of using SMEMCPY 2010-02-14 12:51:53 +00:00
goldsimon
7b24a6360c Minor speedups: use ip_addr_copy, use SMEMCPY, use htonX on constants instead of variables 2010-02-14 12:43:24 +00:00
goldsimon
96e9689dbd Use new macro ip_addr_copy where applicable 2010-02-14 12:42:49 +00:00
goldsimon
7e0204bb7b Improved some defines working on ip addresses, added faster macro to copy addresses that cannot be NULL 2010-02-14 12:41:46 +00:00
goldsimon
dfb80c6b86 fixed compilation for LWIp_SNMP && PPP_INPROC_MULTITHREADED 2010-02-14 12:26:01 +00:00
goldsimon
838c35acf6 struct ip_hdr: split u16_t _ttl_proto to u8_t _ttl and u8_t _proto to prevent unnecessary loading and htons 2010-02-14 11:42:08 +00:00
goldsimon
c858aa5686 Fixed compiler warnings for checksum algorithms 2 and 3 2010-02-14 11:40:13 +00:00
goldsimon
b1736b13d7 Use checksum algorithm 2 as default as it should be faster than 1 on most (if not all) platforms 2010-02-14 11:31:10 +00:00
goldsimon
cbb86fe590 Added stats for mutexes 2010-02-13 17:26:40 +00:00
goldsimon
a61f5f3a78 Fixed old comments 2010-02-13 17:26:08 +00:00
goldsimon
0792effc2a task #7865 (implement non-blocking send operation) 2010-02-13 17:08:40 +00:00
goldsimon
49c6ce3703 Add a new err_t, ERR_WOULDBLOCK in preparation for non-blocking send 2010-02-13 16:03:12 +00:00
goldsimon
0f05a6aede Fixed compilation for LWIP_DNS==1 after changing sys layer 2010-02-13 15:43:19 +00:00
goldsimon
7ccf8cb731 Fixed compilation with LWIP_DNS==1 after changing sys layer 2010-02-13 15:01:55 +00:00
goldsimon
7c28c66d32 Don't use C++ reserved keyword 'class' 2010-02-13 14:51:46 +00:00
goldsimon
c49a3ab2d6 Fixed compilation for LWIP_SO_RCVBUF==0 2010-02-13 10:06:42 +00:00
goldsimon
8fbaf0304a Added a minimal version of posix fctl() to have a standardised way to set O_NONBLOCK for nonblocking sockets. 2010-02-12 17:59:20 +00:00
goldsimon
f89c08872c Fixed indentation 2010-02-12 17:57:02 +00:00
goldsimon
29eb56a2f6 netif_set_link_up/down: only do something if the link state actually changes 2010-02-12 16:50:23 +00:00
goldsimon
2e795d2706 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 16:42:02 +00:00
goldsimon
8768e4488a patch #6865: use so_options SOF_REUSEADDR instead of flags TF_REUSEADDR (which has ben removed again) 2010-02-12 16:32:31 +00:00
goldsimon
bd3f86e505 Code layout: splitted long line 2010-02-12 16:31:18 +00:00
goldsimon
82e4716784 Fixed comment to our flag names 2010-02-12 16:30:58 +00:00
goldsimon
d3635c5eef patch #6865 (SO_REUSEADDR for TCP): if tcp_pcb.flags has TF_REUSEADDR set, allow binding to endpoint in TIME_WAIT 2010-02-12 15:33:02 +00:00
goldsimon
c73b1b4fa2 Fixed bug #28865 (Cannot close socket/netconn in non-blocking connect) 2010-02-12 15:21:37 +00:00
goldsimon
39df7d048c Added comment about mem_realloc() vs. realloc() 2010-02-12 14:56:34 +00:00
goldsimon
3529349470 Fixed compilation for NO_SYS==1 2010-02-12 13:56:51 +00:00
goldsimon
0030d1ade5 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-12 13:49:21 +00:00
goldsimon
2d1631792a struct netconn.socket is only used with LWIP_SOCKET; added comments 2010-02-12 09:58:44 +00:00
goldsimon
b6babe38ea Use braces for if blocks 2010-02-12 09:51:30 +00:00
goldsimon
df7e435b86 Fixed bug #28866 (mem_realloc function defined in mem.h) 2010-02-12 09:30:31 +00:00
goldsimon
9e59f661bc Fixed a compiler warning (comparison between signed and unsigned) 2010-02-10 08:11:18 +00:00
goldsimon
87c2d911c9 Removed invalid assert (always true) 2010-02-10 07:58:21 +00:00
goldsimon
44af02aa1e Fixed wrong printf formatter 2010-02-10 07:58:01 +00:00
goldsimon
45e51d1929 Removed sys_sem_wait_timeout, added comments to the port-supplied sys(-arch)-functions 2010-02-09 21:05:39 +00:00
goldsimon
59a623e648 Use sys_arch_sem_wait instead of sys_sem_wait_timeout (same function, different name) 2010-02-09 21:04:50 +00:00
goldsimon
306f2203fa Fixed bug #22110 (recv() makes receive window update for data that wasn't received by application); added function-like macros to correctly access/change conn->recv_timeout and conn->recv_bufsize 2010-02-09 20:23:39 +00:00
goldsimon
7699b59e27 Another fix for bug #28853 (recv returns 0 on recv-timeout or any other error), fixed err_to_errno_table: ERR_TIMEOUT is EWOULDBLOCK, not ETIMEDOUT 2010-02-09 20:17:06 +00:00
goldsimon
1550c4215d Fixed bug #28853 (lwip_recvfrom() returns 0 on receive time-out or any netconn_recv() error) 2010-02-09 18:46:54 +00:00
goldsimon
a84590273d Merge 3 u8_t for netconn-internal status into one u8_t 'flags' to prevent waisting memory when adding more flags 2010-02-09 18:41:07 +00:00
goldsimon
6fe258c6bc task #10154 (PPP: Update snmp in/out counters for tx/rx packets) 2010-02-09 18:21:21 +00:00
goldsimon
27c1c7a0f7 Added function sys_restart_timeouts() from patch #7085 (Restart system timeout handling) 2010-02-09 17:49:20 +00:00
goldsimon
a668a4e4d1 Fixed compilation for NO_SYS==1 2010-02-09 17:41:34 +00:00
goldsimon
b1250f003d For loopback packets, adjust the stats- and snmp-counters for the loopback netif. 2010-02-09 17:00:57 +00:00
goldsimon
3f8e6c423c Fixed unit tests after changing struct ip_addr to ip_addr_t 2010-02-09 16:40:52 +00:00
goldsimon
077caac76d 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-09 16:01:24 +00:00
goldsimon
91d70a3364 Fixed copying multiple IP addresses from options (e.g. multiple DNS servers) - the amount copied was correct, but the value copied was always the first. 2010-02-09 11:40:46 +00:00
goldsimon
6af20340dd Minor: Fixed indentation after changing struct ip_addr to ip_addr_t 2010-02-09 11:38:59 +00:00
goldsimon
68ab197b68 Fixed a missing cast warning 2010-02-09 11:38:00 +00:00
goldsimon
79e6b4c819 Added reentrant versions of inet_ntoa/ipaddr_ntoa inet_ntoa_r/ipaddr_ntoa_r 2010-02-08 20:14:21 +00:00
goldsimon
ececc3ca45 Internalize another function; use the supplied max_response_time instead of dividing it by 2 2010-02-08 19:50:49 +00:00
goldsimon
630f575017 Moved most defines from igmp.h to igmp.c for clarity since they are not used anywhere else; removed some function prototypes from igmp.h, too 2010-02-08 19:41:53 +00:00
goldsimon
49274c1507 added netif_s/get_igmp_mac_filter() macros 2010-02-08 19:32:40 +00:00
goldsimon
27d4cf6aef Improved IGMP stats (patch from bug #28798) 2010-02-08 19:19:26 +00:00
goldsimon
b156d392cb Fixed bug #28798 (Error in "Max Response Time" processing) and another bug when LWIP_RAND() returns zero. 2010-02-08 18:12:53 +00:00
goldsimon
b0b4290c29 Reduced the time SYS_ARCH_PROTECT is protecting the socket array 2010-02-08 17:25:57 +00:00
goldsimon
90bed0c5ac Added yet another IP-address-modifying define, ip_addr_set_any() 2010-02-08 17:24:08 +00:00
goldsimon
b3caddab30 Minor: source code layout 2010-02-08 17:12:45 +00:00
goldsimon
1017279e68 Minor: removed one space 2010-02-08 17:12:14 +00:00
goldsimon
f74cebcbcd Minot: Fixed comments and code style 2010-02-08 16:53:47 +00:00
goldsimon
848debf999 Fixed bug #28818 (New connection probably not marked writable on accept()) introduced a week ago while implementing non-blocking connect 2010-02-08 12:33:28 +00:00
goldsimon
47756a8faa Fixed macro ip_addr_set_loopback(): htonl was missing (fixes bug #28828: ip_addr.h some macro error) 2010-02-08 12:25:01 +00:00
goldsimon
6c027c153b Fixed compiler warnings 2010-02-08 12:24:29 +00:00
goldsimon
28dc5f491c Correctly initialize netif flags in pppifNetifInit 2010-02-05 11:20:49 +00:00
goldsimon
758e99f362 Added function-like macros to get/set the hostname on a netif 2010-02-05 11:17:55 +00:00
goldsimon
010dc6258e Fixed another compiler warning (missing cast) 2010-02-05 10:35:47 +00:00
goldsimon
a5c5949009 Added missing casts to suppress compiler warnings (this mainly satisfies MSVC - the double casts are a bit ugly but don't hurt...) 2010-02-05 10:09:38 +00:00
goldsimon
d51d6b2d89 Use macros to compare IP addresses 2010-02-05 10:08:49 +00:00
goldsimon
c58dfa2156 Added missing casts to suppress compiler warnings 2010-02-05 10:08:41 +00:00
goldsimon
5d360a6711 Replaced struct ip_addr by typedef ip_addr_t to make changing the actual implementation behind the typedef easier. 2010-02-04 18:47:44 +00:00
goldsimon
24fcf9a86e Accidentally changed the member name of struct ip_addr for testing... 2010-02-04 17:25:22 +00:00
goldsimon
a23b446ddf 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-02-04 17:21:32 +00:00
goldsimon
258fe88232 Added an own debug-print option for timers.c (used TCPIP_DEBUG and SYS_DEBUG as the code was copied from there) 2010-02-04 16:53:10 +00:00
goldsimon
9ff7d29696 Fixed compiler warnings when MEM_SIZE < 64000 2010-02-02 20:14:05 +00:00
goldsimon
30d69d68e3 Fix handling of zero-padding and parse file before sname field (if overloaded, according to the RFC) 2010-02-02 18:26:40 +00:00
goldsimon
4495d9ef5b Fixed an error in dhcp_free_request() from dhcp_inform() 2010-02-02 16:30:11 +00:00
goldsimon
a66039b86c Let netdb use a memp pool for allocating memory when getaddrinfo() is called. 2010-02-01 21:04:29 +00:00
goldsimon
81c5d9e983 Prevent mem_free (leave struct dhcp allocated on dhcp_stop) to prevent calling mem_malloc when restarting dhcp later 2010-02-01 20:20:38 +00:00
goldsimon
c6f7a34abe Prevent mem_malloc in dhcp_inform, fix check for subnet mask (remember if it was given by server or not) set back request_timeout in dhcp_set_state() 2010-02-01 19:55:16 +00:00
goldsimon
72d6f1a418 Don't parse broadcast option, we don't use it anyway (made up from ipaddr and netmask), layout change of struct dhcp 2010-01-31 18:59:37 +00:00
goldsimon
8cb3ea1398 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-31 17:27:15 +00:00
goldsimon
8712deb0b2 Don't call the link-callback from netif_set_up/down() since
this invalidly retriggers DHCP.
2010-01-31 13:30:47 +00:00
goldsimon
2e8de4f601 Updated comment about recv_bufsize 2010-01-30 15:20:01 +00:00
goldsimon
c22d3b4c98 Use SYS_LIGHTWEIGHT_PROT instead of a semaphore to protect the sockets array since the protection time is short 2010-01-30 15:01:29 +00:00
goldsimon
f8c22c7428 Moved freeing a socket to its own function (free_socket, like alloc_socket 2010-01-30 14:19:18 +00:00
goldsimon
855dcadf7a Added except set support in select (patch #6860) 2010-01-29 23:05:33 +00:00
goldsimon
9c41e1eea3 Replaced tabs with spaces 2010-01-29 23:04:06 +00:00
goldsimon
c70c3eac62 Added function-like macro for struct netconn::non_blocking 2010-01-29 22:21:45 +00:00
goldsimon
e58f4c567a Add non-blocking support for connect (partly from patch #6860) plus many cleanups in socket & netconn API 2010-01-29 22:09:31 +00:00
goldsimon
1dd8300e69 Added comments 2010-01-29 14:41:54 +00:00
goldsimon
5fa0347e64 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-29 08:20:32 +00:00
goldsimon
32c16fad42 igmp related: renamed netif pointers from 'interface' to 'netif' to not use keywords (or at least my editor highlights it as one...) 2010-01-28 18:42:40 +00:00
goldsimon
ea3b8f52d5 renamed netif pointer in struct igmp from 'interface' to 'netif' to not use keywords (or at least my editor highlights it as one...); minor layout change 2010-01-28 18:27:26 +00:00
kieranm
95445fc328 Ensure ssthresh >= 2*MSS 2010-01-28 13:14:42 +00:00
goldsimon
21e3cde95c Added missing casts (bug #28659) 2010-01-28 12:05:14 +00:00
goldsimon
d587940801 Keep 'const' of varius snmp structs the same throughout 'derived structs' 2010-01-28 12:04:06 +00:00
goldsimon
f5d4f3d83c For wrong configurations, let the test fail instead of the compiler 2010-01-27 20:37:02 +00:00
goldsimon
04a8b0f85d Added TCP_SNDQUEUELOWAT corresponding to TCP_SNDLOWAT and added tcp_sndqueuelen() - this fixes bug #28605 2010-01-27 18:24:57 +00:00
goldsimon
853e33bdb4 snmp_recv: don't peek the UDP header, p->tot_len does the same; no need for the extra checks at the beginning; don't use so many if/else but if/return instead to make the code more readable 2010-01-27 17:36:37 +00:00
goldsimon
0644c4c08e 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-27 17:22:06 +00:00
goldsimon
606fed8896 Use memp pools for snmp instead of the heap; added 4 new pools. 2010-01-26 20:28:24 +00:00
goldsimon
a5463f0400 Moved missing include 2010-01-26 16:09:03 +00:00
goldsimon
96338314f1 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-25 17:44:07 +00:00
goldsimon
5d3cab0042 Added one more missing cast 2010-01-25 09:19:52 +00:00
goldsimon
e678e1bdcb bug #28659: Missing casts 2010-01-25 08:24:30 +00:00
goldsimon
1811a344f5 Renamed the private mib node from 'private' to 'mib_private' to *not* use reserved C/C++ keywords 2010-01-24 17:25:22 +00:00
goldsimon
ef31aa12e2 Renamed the private mib node from 'private' to 'mib_private' to *not* use reserved C/C++ keywords, added comments, added init-define for private MIB 2010-01-24 17:16:37 +00:00
goldsimon
9dd6c28523 bug #26523: Compiler Warnings 2010-01-24 14:35:28 +00:00
goldsimon
61e5301d49 bug #26523: Compiler Warnings 2010-01-24 13:19:34 +00:00
goldsimon
408829bcf6 Fixed compilation for LWIP_TCPIP_CORE_LOCKING 2010-01-23 18:13:55 +00:00
goldsimon
dbcce3a4be bug #26523: Compiler Warnings 2010-01-23 17:48:36 +00:00
goldsimon
426dd9bfad Fixed bug #28716: select() returns 0 after waiting for less than 1 ms 2010-01-23 15:01:15 +00:00
goldsimon
82318c0ef1 Fixed bug #28651 (tcp_connect: no callbacks called if tcp_enqueue fails) both in raw- and netconn-API 2010-01-21 18:43:37 +00:00
goldsimon
60696a8485 Removed unused function declaration for netbuf_len (is a macro now) 2010-01-21 17:18:15 +00:00
goldsimon
7044385d8e Fixed netconn_err() macro 2010-01-20 07:37:24 +00:00
goldsimon
a7139ef06b Added missing include 2010-01-20 07:36:45 +00:00
goldsimon
52389fc09a Fixed bug #27316 (netconn: Possible deadlock in err_tcp) by using sys_mbox_trypost in err_tcp 2010-01-19 18:34:01 +00:00
goldsimon
972ca9e6c1 reorganised PPP sourcecode to 2.3.11 including some bugfix backports from 2.4.x. 2010-01-18 20:49:43 +00:00
goldsimon
e0c5c4de88 Fixed bug #28679: mem_realloc calculates mem_stats wrong and added test case for it 2010-01-18 17:45:41 +00:00
goldsimon
149f21dc58 Only check for LWIP_RAND() if IGMP is used, for now 2010-01-18 08:19:48 +00:00
goldsimon
9632632b85 Minor: source code layout 2010-01-18 08:11:57 +00:00
goldsimon
cc1e9370af Minor: fixed argument casts for mbox_fetch parameters (to fix compiler warnings) 2010-01-18 08:11:39 +00:00
goldsimon
34139606ca task #10102: "netconn: clean up conn->err threading issues" by adding error return value to struct api_msg_msg 2010-01-17 18:28:56 +00:00
goldsimon
3e1cca65bd task #10102: "netconn: clean up conn->err threading issues" by adding error return value to struct api_msg_msg 2010-01-17 18:28:56 +00:00
goldsimon
0e3c256667 Added comment 2010-01-17 17:37:10 +00:00
goldsimon
618355f5a7 Minor: source code layout 2010-01-17 16:23:26 +00:00
goldsimon
ca11baf1cd Changed netconn_recv() and netconn_accept() to return err_t (bugs #27709 and #28087) 2010-01-17 16:21:07 +00:00
goldsimon
7ede02ca8b Fixed bug #27856: PPP: Set netif link- and status-callback by adding ppp_set_netif_statuscallback()/ppp_set_netif_linkcallback() 2010-01-14 20:04:52 +00:00
goldsimon
2d4e76874c Using typedefs for function prototypes and -pointers throughout the stack for clarity 2010-01-14 20:02:15 +00:00
goldsimon
b463562241 Use protocol definition from tcp.h, not from sockets.h 2010-01-14 19:59:28 +00:00
goldsimon
04f17c4709 Improved includes in snmp 2010-01-14 19:59:03 +00:00
goldsimon
97f797e859 do_connect(): set conn->err to an error if conn->pcb is NULL 2010-01-14 19:49:27 +00:00
goldsimon
9521f54741 Another fix for bug #28562: Segfault @ err_tcp 2010-01-14 15:43:11 +00:00
goldsimon
0e38a52edc Again: Fixed bug #26672 (close connection when receive window = 0) by correctly draining recvmbox/acceptmbox 2010-01-13 15:59:47 +00:00
goldsimon
6df94d3c76 Coding style 2010-01-13 15:17:01 +00:00
goldsimon
59005b544f Minor fix: bug #28555: Retransmission timer only stopped if TCP_QUEUE_OOSEQ==1 2010-01-13 14:24:15 +00:00
goldsimon
8596bb7e7e 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-13 13:09:55 +00:00
goldsimon
1c47d15577 Minor speedup ip_output_if when writing TTL/proto to ip header 2010-01-13 12:52:15 +00:00
goldsimon
67c587f9f7 Fixed NO_SYS==0: starting pppInputThread failed; fixed some comments 2010-01-13 11:19:03 +00:00
goldsimon
052be0a328 Added comments 2010-01-13 11:16:47 +00:00
goldsimon
68ddcc6ca7 Fixed bug #13315 (PPP PAP authentication can result in erroneous callbacks) by copying the code from recent pppd 2010-01-11 16:38:56 +00:00
goldsimon
9a2d97ec41 Fixed bug #28551 (Compiler warning introduced with closed bug #28506) 2010-01-11 09:51:33 +00:00
goldsimon
47e770dffa Fixed comment on struct mem.prev 2010-01-11 09:49:31 +00:00
goldsimon
8292cebfd9 Fixed bug #28506 (raw_bind should filter received packets) 2010-01-10 13:45:24 +00:00
goldsimon
c483c13dc4 Fixed bug #28248 (netif_remove doesn't call netif callback) by calling netif_set_down() from netif_remove() 2010-01-10 13:34:21 +00:00
goldsimon
86f2942c2a Minor coding style changes, added assertion 2010-01-10 13:32:36 +00:00
goldsimon
e4d19dc4a0 GCC didn't like memp_memory_XXX -> now using memp_memory_XXX_base (as in Bill's original patch) 2010-01-10 13:09:55 +00:00
goldsimon
763760503b patch #6822 (Add option to place memory pools in separate arrays) - new config option MEMP_SEPARATE_POOLS 2010-01-10 12:44:09 +00:00
goldsimon
13c9d2dade Added/changed comments 2010-01-10 11:48:28 +00:00
goldsimon
97f6c5b239 D'Oh! 2010-01-10 11:42:31 +00:00
goldsimon
f4a9d173a1 bug #28127: remove call to tcp_output() from tcp_ack(_now)() 2010-01-10 11:41:25 +00:00
goldsimon
d85a18752f patch #6463 (IGMP - Adding Random Delay): added define LWIP_RAND() for lwip-wide randomization (to be defined in cc.h) 2010-01-10 10:47:27 +00:00
goldsimon
aa7dd9a8ad Forgot one line & comments 2010-01-10 10:32:56 +00:00
goldsimon
27c9670718 Fixed bug #28529: macro LWIP_DEBUG_TIMERNAMES in timers.h 2010-01-09 19:14:23 +00:00
goldsimon
32833bcd56 Inlined netif_is_up() and netif_is_link_up() as defines for speed reasons; fixed type and macro definition. 2010-01-09 13:25:15 +00:00
goldsimon
53bc34f3e2 Fixed bug #28195 (PPP: remove duplicate TCP/IP protocol header definitions - use the lwIP ones) - deleted unused header file 2010-01-09 12:45:23 +00:00
goldsimon
81640c4a83 Fixed compilation of VJ_SUPPORT after separating tx and rx 2010-01-08 15:52:17 +00:00
goldsimon
533e6b5f8d Fixed bug #26672 (close connection when receive window = 0) by correctly draining recvmbox/acceptmbox 2010-01-08 15:10:03 +00:00
goldsimon
28f0bbd575 Fixed bug #28519 (lwip_recvfrom bug with len > 65535) 2010-01-08 14:51:14 +00:00
goldsimon
39717b2d9d Copy hostname for DNS_LOCAL_HOSTLIST_IS_DYNAMIC==1 since string passed to dns_local_addhost() might be volatile 2010-01-08 14:42:09 +00:00
goldsimon
79c88cdcfd Added function names to timer debug output 2010-01-08 14:08:47 +00:00
goldsimon
8a34c16aee Improved assertion message when MEMP_SYS_TIMEOUT pool is empty 2010-01-08 13:40:50 +00:00
goldsimon
cce192a671 Call tcp_timer_needed() with NO_SYS==1, too 2010-01-07 09:47:30 +00:00
goldsimon
cfe4a12a46 Fixed bug #28496: missing include guards in netdb.h 2010-01-06 16:30:23 +00:00
goldsimon
3269da52cc Initial version of PPP for NO_SYS==1, some TODOs are remaining, but it works... 2009-12-31 17:56:51 +00:00
goldsimon
9c51487d1a Renamed PPP tasks from "pppMain" to "pppInputThread" 2009-12-31 17:21:11 +00:00
goldsimon
3ba5ddefa7 Removed unnecessary tcpip-callbacks: this whole module runs inside the tcpip-thread. This also makes PPPoE usable with NO_SYS==1 2009-12-31 17:18:09 +00:00
goldsimon
1d45aa8d45 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-31 17:08:08 +00:00
goldsimon
a7bcdf4398 Remove warning for TCP_LISTEN_BACKLOG==0 2009-12-31 16:51:17 +00:00
goldsimon
9a0dac5885 Removed unused test function 2009-12-31 16:50:11 +00:00
goldsimon
c9e0652526 Remove C++-style comments 2009-12-31 16:49:36 +00:00
goldsimon
a566f9d8f2 Separated timer implementation from semaphore/mbox implementation, moved timer implementation to timers.c/.h (TASK#7235) 2009-12-31 16:16:44 +00:00
goldsimon
1740b0d421 Some functions were located outside extern "C" {} 2009-12-31 15:57:22 +00:00
goldsimon
802a048302 Commented 2 variables 2009-12-31 15:12:00 +00:00
goldsimon
fa08823ac4 Added an additional option LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) 2009-12-27 11:42:16 +00:00
goldsimon
a1c0b9da7b Added an additional option LWIP_ETHERNET to support ethernet without ARP (necessary for pure PPPoE) - no changes in the ppp code yet 2009-12-27 11:40:48 +00:00
goldsimon
bf261f4f13 Another fix for bug #28241 (ooseq processing) and adapted corresponding unit test 2009-12-27 11:31:19 +00:00
kieranm
dc8639bc06 Update version numbering for 1.4.0 CVS development 2009-12-24 15:49:12 +00:00
kieranm
125efd8396 Update CHANGELOG for 1.3.2 2009-12-24 15:33:19 +00:00
kieranm
4a9557fa84 Update version information for 1.3.2 2009-12-24 15:32:19 +00:00
kieranm
6b6c82aaee BUG28241: improve oos sequence processing with patches from Oleg Tyshev. 2009-12-24 15:31:44 +00:00
goldsimon
feca27d69e Slightly modified the out-of-sequence-FIN test: receive packets with FIN & data and with FIN alone 2009-12-11 13:07:47 +00:00
goldsimon
fbef894674 tcp_set_state: fail on unimplemented state 2009-12-11 13:07:06 +00:00
goldsimon
2e4bb8b3b7 Added explicit check for number of segments and seqno/len of each segment on pcb->ooseq 2009-12-10 17:34:11 +00:00
goldsimon
e9940acb54 Updated comments on which sio-functions are used 2009-12-07 18:58:13 +00:00
goldsimon
957331fff4 Added a note why MSCHAP currently doesn't work with lwIP PPP 2009-12-07 07:50:24 +00:00
goldsimon
faba395cae Added description about the PPP stack 2009-12-07 07:28:27 +00:00
goldsimon
1d5809679b Various small improvements from patch #6965 (removed _inet_ntoa, set PPP netif down before removing, change log message and comment) 2009-12-06 11:59:56 +00:00
goldsimon
b5014b0966 tcp_process: add state info to log message that is used for multiple states ("TCP connection closed") 2009-12-06 11:57:31 +00:00
goldsimon
b1ad36eece Fixed bug #27079 (Yet another leak in PPP): outpacket_buf can be statically allocated (like in ucip) 2009-12-06 11:12:18 +00:00
goldsimon
1b42286bda pppInit: Remove zeroing the stats - no protocol does that 2009-12-06 10:56:28 +00:00
goldsimon
5da0620c6b Fixed checking input packet length (20 bytes is a valid packet and is used e.g. with MS RAS server) 2009-12-06 10:14:46 +00:00
goldsimon
96e8f16c05 Sligthly reordered struct netif's members to better meet alignment requirements 2009-12-06 08:58:41 +00:00
goldsimon
b5d28e0a9c patch #6969: PPP: missing PAP authentication UNTIMEOUT 2009-12-04 15:41:26 +00:00
goldsimon
73251bc9c1 PPP: Make MAXNAMELEN/MAXSECRETLEN overridable in lwipopts.h 2009-12-04 09:00:55 +00:00
goldsimon
3fa63b35b3 The guy's name is Van Jacobson (not Jabobsen or Jacobsen :-) 2009-12-04 08:57:22 +00:00
goldsimon
65f006e52e Moved the function definitions so that other modules can use the ICMP protocol header definitions when LWIP_ICMP==0 2009-12-04 08:11:57 +00:00
goldsimon
7d46e06824 Fixed bug #28106: dup ack for fast retransmit could have non-zero length 2009-12-03 19:42:35 +00:00
goldsimon
32acb82bc0 Fixed some typos 2009-12-03 18:07:00 +00:00
goldsimon
3a1c5944e7 Fixed bug #27904: TCP sends too many ACKs: delay resetting tcp_input_pcb until after calling the pcb's callbacks 2009-12-02 17:01:29 +00:00
goldsimon
04c5246e02 Fix compilation for PPPOE without PPPOS and VJ_SUPPORT without PPPOS_SUPPORT 2009-12-01 20:46:14 +00:00
goldsimon
46dc1c9bfb Minor (null-pointer check for not-on-list-netif) 2009-12-01 19:59:36 +00:00
goldsimon
b900253c09 tcp_receive(): removed unnecessary return value, added comment 2009-11-29 13:43:38 +00:00
goldsimon
59a5fb7ce8 Fixed bug #28054: Two segments with FIN flag on the out-of-sequence queue, also fixed PBUF_POOL leak in the out-of-sequence code 2009-11-29 13:23:21 +00:00
goldsimon
c5d2e536cf Worked on tcp_oos unit tests, nearly all TCP_QUEUE_OOS code is covered now 2009-11-29 13:20:13 +00:00
goldsimon
aeef0a21f3 Fixed bug #28064: pbuf_alloc(PBUF_POOL) is not thread-safe by queueing a call into tcpip_thread to free ooseq-bufs if the pool is empty 2009-11-29 11:57:35 +00:00
goldsimon
902ad897b8 Initial check-in of some unit tests 2009-11-27 08:03:53 +00:00
goldsimon
478ccee5fc tcp_rexmit(): no need to call tcp_output, since always called from tcp_input and thus tcp_output always returns without sending (prevent confusion by thinking data was sent while in tcp_rexmit!) 2009-11-26 16:44:16 +00:00
goldsimon
43fd5c28b5 Fixed bug #28098: Nagle can prevent fast retransmit from sending segment by basing the nagle-decision on TF_INFR also 2009-11-26 16:42:13 +00:00
goldsimon
4391463832 Got the tcp_nagle_*() defines wrong (inverted) :-( 2009-11-26 15:51:29 +00:00
goldsimon
c8d2d2a8ea Fixed bug #28099 (API required to disable Nagle algorithm at PCB level): added tcp_nagele_*() function-like macros 2009-11-26 15:19:30 +00:00
goldsimon
6795aabecf Fixed filename in last comment 2009-11-22 17:57:19 +00:00
goldsimon
a939c09a6b Fixed bug #27905: FIN isn't combined with data on unsent 2009-11-22 17:55:03 +00:00
goldsimon
35d1c33e0a tcp_alloc: prevent increasing stats.err for MEMP_TCP_PCB when reusing time-wait pcb as suggested by Bill 4 months ago 2009-11-22 17:52:48 +00:00
goldsimon
10edf64873 Fixed bug #27851 (TCP_EVENT_RECV(pcb, NULL,...) results in unreachable code warning) by calling tcp_recv_null if pcb->recv is null. 2009-11-22 16:17:55 +00:00
goldsimon
6d22c38e59 tcp_recv_null: call tcp_recved() if p != NULL to keep the window correct 2009-11-22 16:16:55 +00:00
goldsimon
8a81cb4ba0 Fixed bug #27955: netconn_close may nether return when LWIP_TCPIP_CORE_LOCKING enabled 2009-11-22 16:08:52 +00:00
goldsimon
6bb7f987f2 Fixed bug #28049 (Keep Alive timeout frees pcb then uses it, sometimes causing crash error) by calling tcp_rst() instead of tcp_abort() in tcp_slowtmr() when retransmit timer expires. 2009-11-22 15:44:12 +00:00
goldsimon
1c018caefe move tcp_debug_print_state to prevent accessing pcb when it might already be deallocated due to recv_flags == TF_RESET or TF_CLOSED 2009-11-22 15:42:30 +00:00
goldsimon
0c136893e5 Fixed logging of timeout-function-pointer (pointer to local stack was logged instead of actual function pointer), minor coding style fix 2009-11-22 15:25:13 +00:00
goldsimon
f4c0655190 Fixed usage of logging levels (bug #27948: Incorrect logging levels used in various places) 2009-11-22 15:14:46 +00:00
goldsimon
49bdf32765 Fixed usage of logging levels (bug #27948: Incorrect logging levels used in various places) 2009-11-22 13:31:31 +00:00
goldsimon
88d02a624a Clarified debug levels by renaming level OFF to ALL (the old define still exists for now to prevent breaking old code) 2009-11-22 13:14:57 +00:00
goldsimon
98a58f9e67 tcp_input: move tcp_debug_print_state to prevent accessing pcb when it might already be deallocated due to calling tcp_abort in tcp_process. 2009-11-20 16:56:25 +00:00
goldsimon
b30c6f8b9e Fixed comment: tcp_pcb_remove does *not* deallocate the pcb 2009-11-20 16:43:57 +00:00
goldsimon
94a7fee8c8 Fixed bug #28062: Data received directly after accepting does not wake up select 2009-11-20 16:16:20 +00:00
goldsimon
6f38b63a47 Fixed bug #27994: incorrect define for freeaddrinfo(addrinfo) 2009-11-11 16:52:05 +00:00
goldsimon
70b05c8096 Increased default value for TCP_MSS to 536, updated default value for TCP_WND to 4*TCP_MSS to keep delayed ACK working. 2009-10-30 10:02:06 +00:00
goldsimon
28ac4347d4 Fixed wrong filename 2009-10-29 17:10:19 +00:00
kieranm
dee1d82c11 re-work the fast retransmission code to follow algorithm from TCP/IP
Illustrated
2009-10-29 15:48:57 +00:00
kieranm
6d73f82f41 Update version for 1.3.2 rc 1 2009-10-28 15:17:16 +00:00
kieranm
71ddff4964 Fix BUG#27445: grow cwnd with every duplicate ACK 2009-10-28 15:13:51 +00:00
goldsimon
af3b796488 Corrected parameter spelling in doc 2009-10-27 20:30:44 +00:00
goldsimon
e2de2c6bb2 Added netifapi_netif_set_addr() 2009-10-27 20:29:16 +00:00
goldsimon
2ff0ce2d0a Minor: Improved memory layout/alignment of struct dhcp for 32-bit platforms 2009-10-26 09:59:54 +00:00
goldsimon
b09b8a0ccc Tiny code size improvement using goto instead of duplicating code 2009-10-26 09:55:46 +00:00
goldsimon
db259c3557 Improved heap usage of lwip_getaddrinfo by only allocating one block of memory per call. 2009-10-26 09:30:50 +00:00
goldsimon
bcc87ef851 bug-fix in the TCP_EVENT_RECV macro (has to call tcp_recved if pcb->recv is NULL to keep rcv_wnd correct) 2009-10-25 18:47:44 +00:00
goldsimon
650f16b6d9 Minor: fixed typo 2009-10-25 16:47:41 +00:00
goldsimon
ae2dd38e0d Another fix for bug #26251: RST process in TIME_WAIT TCP state 2009-10-25 11:45:11 +00:00
kieranm
0319c1cf90 Update link to wiki in README file 2009-10-23 15:23:23 +00:00
goldsimon
81f9442ac7 Fixed bug #27783: Silly window avoidance for small window sizes 2009-10-23 13:17:18 +00:00
goldsimon
18ab274af3 Fixed bug #26251: RST process in TIME_WAIT TCP state 2009-10-22 13:37:44 +00:00
goldsimon
65d1f52423 Changed fix for bug #27215 (TCP sent() callback gives leagin and trailing 1 byte len (SYN/FIN)) by decreasing pcb->acked appropriately 2009-10-21 15:42:14 +00:00
goldsimon
f1b82e0e9a bug #27315: zero window probe and FIN: only send pure FIN if the enqueued FIN segment doesn't contain any other data 2009-10-21 15:15:34 +00:00
goldsimon
67411c4299 Minor code simplification (don't store received pbuf, change conditional code to assert where applicable), check pbuf length before testing for valid reply 2009-10-19 20:06:01 +00:00
goldsimon
a37e62b7d0 Removed most calls to udp_connect since they aren't necessary when using udp_sendto_if() - always stay connected to IP_ADDR_ANY. 2009-10-19 16:43:50 +00:00
goldsimon
e2c1f7d5b5 dhcp_unfold_reply: NULL memory might have been freed after mem_malloc returned NULL 2009-10-18 09:26:27 +00:00
goldsimon
ec97fbd101 dhcp_inform(): netif->dhcp pointed to unallocated memory when udp_new() failed 2009-10-18 09:13:47 +00:00
goldsimon
b7d7559cc9 Fixed bug #27215: TCP sent() callback gives leadin and trailing 1 byte len (SYN/FIN) 2009-10-18 08:30:44 +00:00
goldsimon
b4404ff0c8 Corrected typo 2009-10-18 08:23:05 +00:00
goldsimon
502e89f4ad Fixed bug #27315: zero window probe and FIN 2009-10-16 21:07:48 +00:00
goldsimon
d8d8cf7e98 Fixed bug #27390: Source IP check in ip_input() causes it to drop valid DHCP packets -> allow 0.0.0.0 as source address when LWIP_DHCP is enabled 2009-10-16 12:39:24 +00:00
goldsimon
d9a5094068 Fixed bug #27329: dupacks by unidirectional data transmit 2009-10-15 20:09:13 +00:00
goldsimon
a9740c6a44 Fixed bug #27709: conn->err race condition on netconn_recv() timeout by directly returning when sys_arch_mbox_fetch times out. 2009-10-15 14:33:18 +00:00
goldsimon
2dc027401f Fixed bug #27704: autoip starts with wrong address: LWIP_AUTOIP_CREATE_SEED_ADDR() returned address in host byte order instead of network byte order 2009-10-15 14:05:35 +00:00
goldsimon
ac638c85f3 Fixed bug #27504: tcp_enqueue wrongly concatenates segments which are not consecutive when retransmitting unacked segments 2009-10-11 13:06:44 +00:00
goldsimon
c0e22c255c Fixed default values of some stats to only be enabled if used Fixes bug #27338: sys_stats is defined when NO_SYS = 1 2009-10-09 20:18:15 +00:00
goldsimon
1309e5e86f Accidentally endabled to compile the code -> back to #if 0 2009-10-09 20:16:26 +00:00
goldsimon
c34c024dd5 Updated comment in low_level_input() about pbuf len vs. tot_len if using preallocated pbufs (as requested in bug #27576: pbuf_realloc will assert or crash on a non-chained pbuf list) 2009-10-09 19:56:54 +00:00
goldsimon
6ef69ece95 patch #6930: [PATCH trivial] TCP_RMV remove unnecessary check - removed two checks for NULL which are not necessary. 2009-10-07 18:04:24 +00:00
goldsimon
a9cbdc141b patch #6888: Patch for UDP Netbufs to support dest-addr and dest-port 2009-10-07 17:58:30 +00:00
goldsimon
9e5cf1cf8e Reverted change for bug #27252 (Address pointer invalid after freeing pbuf in UDP receive callback) as it made more problems than before :-( 2009-10-07 17:50:46 +00:00
goldsimon
ddc783bee7 Make ip_current_netif() and ip_current_header() a define referring to extern variables to be save the function call. 2009-10-07 17:47:05 +00:00
goldsimon
68f92050e9 Make tcp_debug_state_str() always available, not only in DEBUG mode 2009-10-07 17:44:59 +00:00
goldsimon
bd2bc2ee14 Fixed bug bug #27345: "ip_frag() does not use the LWIP_NETIF_LOOPBACK function" by checking for loopback before calling ip_frag 2009-08-30 20:52:43 +00:00
goldsimon
8a7c1c4926 do_connect: LWIP_ERROR on invalid/disabled protocol 2009-08-30 20:24:08 +00:00
goldsimon
cff3e0cad2 bug #26397: Added SLIP polling support (uses sio_tryread) 2009-08-26 21:06:18 +00:00
stoklund
b55cfbc342 Add patch #6725 to CHANGELOG 2009-08-26 07:18:50 +00:00
goldsimon
3115087d26 Commented the functions, added sio_tryread() for non-blocking read (to be used in slipif-polling mode) 2009-08-25 17:54:28 +00:00
goldsimon
057c51ff6d Use LWIP_UNUSED_ARG() instead of if(){}, fix unused arg warning if LWIP_ARP==0 2009-08-25 17:50:59 +00:00
goldsimon
f2f20cf133 fixed invalid dependency to etharp_query if DHCP_DOES_ARP_CHECK==0 2009-08-25 17:49:47 +00:00
goldsimon
2c618705f0 task #9033: Support IEEE 802.1q tagged frame (VLAN), New configuration options ETHARP_SUPPORT_VLAN and ETHARP_VLAN_CHECK. 2009-08-25 15:24:49 +00:00
goldsimon
bc10ad2356 patch #6900: added define ip_ntoa(struct ip_addr*) 2009-08-25 14:53:25 +00:00
stoklund
857fac1168 Add C++ guards to autoip.h header. 2009-08-24 13:17:42 +00:00
stoklund
103ba9b0fc The DHCP client should enter the REBOOTING state when connecting to a
new network. If DHCP has bound to an address, it must be verified
after netif_set_link_up.
2009-08-24 13:12:37 +00:00
stoklund
d83fc6893b Don't use an AutoIP-configured address on a new network until the address has been configured.
When connecting to a new network with an AutoIP address, take the
interface down until the old address has passed the
AUTOIP_STATE_PROBING state.
2009-08-24 13:11:35 +00:00
goldsimon
e7d5739ce7 Fixed bug #27078: Possible memory leak in pppInit() 2009-08-23 17:40:29 +00:00
goldsimon
8bf57c0e14 Fixed bug #26657: DNS, if host name is "localhost", result is error. 2009-08-23 13:51:12 +00:00
goldsimon
dea7255fc5 Fixed bug #26649: TCP fails when TCP_MSS > TCP_SND_BUF, Fixed wrong parenthesis, added check in init.c 2009-08-23 13:03:20 +00:00
goldsimon
ce3082976c Fixed bug #27266: wait-state debug message in pppMain occurs every ms 2009-08-23 12:37:36 +00:00
goldsimon
362a295e06 Fixed bug #27252: Address pointer invalid after freeing pbuf in UDP receive callback 2009-08-23 11:32:38 +00:00
goldsimon
0e91e2adf2 bug #27267: Added include to string.h where needed 2009-08-23 11:24:51 +00:00
goldsimon
4d49d952b6 patch #6843: tcp.h macro optimization patch (for little endian) 2009-08-23 11:13:19 +00:00
goldsimon
ae7a7a0abf Added function tcp_debug_state_str() to convert a tcp state to a human-readable string. 2009-08-23 10:57:37 +00:00
kieranm
4f265dce60 Update version number for CVS development 2009-08-18 12:53:35 +00:00
kieranm
bd96db8c9f Update version number of 1.3.1 final release 2009-08-18 12:47:13 +00:00
kieranm
0b75917121 BUG27209: handle trimming of segments when out of window or out of
order properly
2009-08-12 08:34:48 +00:00
kieranm
fa2dbc2b1b BUG27199: use snd_wl2 instead of snd_wl1 2009-08-12 08:32:14 +00:00
goldsimon
3a6165f0b9 Added missing include to <string.h> 2009-08-11 14:38:55 +00:00
goldsimon
62c27f7fce Fixed bug #27155: "'NULL' undeclared in inet_checksum.c" 2009-08-03 19:28:35 +00:00
goldsimon
7feb116bae Fixed bug #27105: "realloc() cannot replace mem_realloc()" by making mem_realloc static doing nothing when MEM_LIBC_MALLOC==1 2009-07-28 17:18:46 +00:00
goldsimon
730a938912 Added debug print when rejecting incoming connections due to exceeded listen backlog 2009-07-28 17:04:04 +00:00
goldsimon
3553efb75e Added newline to TCP header flags debug print 2009-07-28 17:02:48 +00:00
kieranm
6111230fe9 Fix compile warning on Linux 2009-07-27 15:39:40 +00:00
kieranm
6bce84e070 Update for 1.3.1rc2 2009-07-27 15:21:36 +00:00
kieranm
a6e316a92d Add missing #include directives 2009-07-27 15:20:33 +00:00
goldsimon
22bcf5892a Fixed bug #27034: "Invalid ASSERT in pbuf_alloc()" to prevent breaking PPP (for now). 2009-07-27 15:17:13 +00:00
goldsimon
cc4b968f0a Fixed bug #27114: Missing #include in api_msg.c on LWIP 1.3.1RC1; added include <string.h> 2009-07-27 15:13:24 +00:00
stoklund
893ddcf61b Implement exponential backoff in dhcp.c 2009-07-23 08:59:13 +00:00
stoklund
cf81dbcca4 Reuse XIDs for DHCP retransmissions 2009-07-23 08:57:45 +00:00
goldsimon
5830200029 Added missing include to netif.h 2009-07-20 15:48:55 +00:00
kieranm
972592cf8a Update version numbers for release candidate 2009-07-09 11:43:28 +00:00
fbernon
ce5699f41b minor changes: typos and coding style 2009-07-09 10:21:16 +00:00
kieranm
1eee0be951 BUG23240 use signed counters for recv_avail and don't increment
counters until message successfully sent to mbox
2009-07-09 09:35:07 +00:00
kieranm
fb555a0633 Update changelog for recent commits 2009-06-25 12:58:52 +00:00
kieranm
2b87f899ab BUG26722: initialise netconn write variables in netconn_alloc 2009-06-25 10:17:18 +00:00
kieranm
776e1926a3 BUG26879: set ret value in TCP_EVENT_ macros when function is not set 2009-06-25 10:03:53 +00:00
kieranm
c232edb83a BUG26301 and BUG26267: correct simultaneous close behaviour, and make
snd_nxt have the same meaning as in the RFCs.
2009-06-25 09:57:36 +00:00
goldsimon
aefeba3fc0 Added note about printf formatter defines 2009-05-20 18:59:05 +00:00
goldsimon
6d4064799a Corrected structure packing 2009-05-20 18:33:45 +00:00
goldsimon
e0e9a63e63 Corrected function implementation of ip_current_* (void was missing) 2009-05-19 18:11:01 +00:00
goldsimon
bcdffce6ce Corrected function definition of ip_current_* (void was missing) 2009-05-19 05:40:30 +00:00
goldsimon
ff97c8a1a9 Moved function definition below defines and typedefs, added missing include to netif.h 2009-05-18 17:56:01 +00:00
goldsimon
30acd1662d fixed bug #26507: "Gratuitous ARP depends on arp_table / uses etharp_query" by adding etharp_gratuitous() 2009-05-12 20:13:45 +00:00
goldsimon
078e2f60d6 bug #26487: Added ip_output_if_opt that can add IP options to the IP header (used by igmp_ip_output_if) 2009-05-12 18:00:47 +00:00
goldsimon
c7ce2792c8 Fixed compilation if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) 2009-05-11 16:11:18 +00:00
goldsimon
22d6558f13 task #7013: Added option LWIP_NETIF_TX_SINGLE_PBUF to try to create transmit packets from only one pbuf to help MACs that don't support scatter-gather DMA. 2009-05-10 17:07:25 +00:00
goldsimon
105d72a3c2 Shrinked ICMP code, added option to NOT check icoming ECHO pbuf for size (just use it): LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 2009-05-09 08:36:36 +00:00
goldsimon
c752e5731c Worked on dns: local host-list can be put into FLASH (by defining storage target/linker section), external function can be defined for lookup, combined dns_local_removehostname/removehostaddr to dns_local_removehost 2009-05-07 15:27:02 +00:00
goldsimon
72e9cf53e7 Added netbuf.h to files that may be called from any thread 2009-05-07 14:20:37 +00:00
goldsimon
e66d315c9b Added more threading info 2009-05-07 14:15:51 +00:00
goldsimon
95f6dc7011 On little endian architectures, use LWIP_PLATFORM_HTONS (if defined) for SWAP_BYTES_IN_WORD to speed up checksumming. 2009-05-06 17:35:50 +00:00
goldsimon
ac9e758f41 Patch #6823: tcp_in.c - small optimization 2009-05-06 17:30:18 +00:00
goldsimon
518b18dad0 Added #if LWIP_SNMP around snmp-internal header files 2009-05-06 15:35:13 +00:00
goldsimon
bdd5586cee Added a word or two on threading, which should be sufficient to close task #6683 2009-05-05 19:33:41 +00:00
goldsimon
14dba4ae2b Added ip_current_netif() & ip_current_header() to receive extended info about the currently received packet. 2009-05-05 17:50:39 +00:00
goldsimon
99d82c4980 Fixed bug #26405: Prematurely released semaphore causes lwip_select() to crash 2009-05-05 17:20:45 +00:00
goldsimon
fb46e0f192 snmp was not initialized in lwip_init() 2009-05-04 19:22:26 +00:00
fbernon
b055128ec4 CHANGELOG: minor, typo 2009-05-04 08:50:24 +00:00
fbernon
e29f94a980 dhcp.c, netbios.c: Changes if IF_SOF_BROADCAST is enabled. 2009-05-04 08:40:44 +00:00
goldsimon
24342eaab0 Fixed bug #26349: Nagle algorithm doesn't send although segment is full (and unsent->next == NULL) 2009-05-03 14:17:33 +00:00
goldsimon
152d22d4f9 fixed tcpip_untimeout (does not need the time, broken after 1.3.0 in CVS only) - fixes compilation of ppp_oe.c 2009-05-02 16:12:35 +00:00
goldsimon
41eecb67d2 fixed bug #25636: SNMPSET value is ignored for integer fields 2009-05-02 15:45:53 +00:00
goldsimon
9317105c37 Addition to patch #6721, bug #25575: call autoip_stop in dhcp_stop if in coop-mode 2009-05-02 15:40:39 +00:00
goldsimon
23d7f5425d Fixed bug #21680: PPP upap_rauthnak() drops legal NAK packets 2009-05-01 12:10:34 +00:00
goldsimon
217f279fdb Fixed bug #24228: Memory corruption with PPP and DHCP 2009-05-01 11:42:36 +00:00
fbernon
d4ecb23015 raw.c, udp.c, init.c, opt.h, ip.h, sockets.h: bug #26309: Implement the SO(F)_BROADCAST filter for all API layers. Avoid the unindented reception of broadcast packets even when this option wasn't set. Port maintainers which want to enable this filter have to set IP_SOF_BROADCAST=1 in opt.h. If you want this option also filter broadcast on recv operations, you also have to set IP_SOF_BROADCAST_RECV=1 in opt.h. 2009-04-29 12:42:43 +00:00
fbernon
42c59e1079 netif.c: minor, fix a warning 2009-04-29 12:39:16 +00:00
goldsimon
3b5993e6ee Integrated patch #6721: new option to adjust the time when DHCP gives over to AUTOIP and some improvements in DHCP/AUTOIP cooperation 2009-04-28 19:29:46 +00:00
goldsimon
4b8255a588 Bug #25608: Made SYS_LIGHTWEIGHT_PROT and sys_now() work with NO_SYS=1 2009-04-27 20:09:52 +00:00
goldsimon
36e3d24331 Fixed a bug in tcp_enqueue introduced with v1.79 of this file while fixing bug #25094 (zero-length pbuf) 2009-04-27 19:00:23 +00:00
goldsimon
261dfdf010 fixed bug #24212: "Deadlocked tcp_retransmit due to exceeded pcb->cwnd": Fixed by sorting the unsent and unacked queues (segments are inserted at the right place in tcp_output and tcp_rexmit) 2009-04-26 12:27:11 +00:00
goldsimon
cbfacb7ed9 bug #26213 "Problem with memory allocation when debugging": memp_sizes contained the wrong sizes (including sanity regions); memp pools for MEM_USE_POOLS were too small; Added option MEM_USE_POOLS_TRY_BIGGER_POOL to try the next bigger malloc pool if one is empty (only usable with MEM_USE_POOLS). 2009-04-25 17:42:27 +00:00
fbernon
4eda29abf9 inet.c: patch #6765: Fix a small problem with the last changes (incorrect behavior, with ip address string not ended by a '\0', a space or a end of line) 2009-04-24 12:14:54 +00:00
goldsimon
c3f7107e2b Fixed some issues with DNS_LOCAL_HOSTLIST 2009-04-23 16:54:30 +00:00
fbernon
67a3976a24 init.c: typo 2009-04-23 15:28:52 +00:00
fbernon
4fba1b1430 netdb.c: remplace some %#p by %p to be more portable. 2009-04-23 14:41:52 +00:00
goldsimon
029b786c77 Fixed bug #26069: Corrected documentation: if tcp_connect fails, pcb->err is called, not pcb->connected (with an error code). 2009-04-21 19:15:16 +00:00
goldsimon
51e02176da task #7507, patch #6786: DNS supports static hosts table. New configuration options DNS_LOCAL_HOSTLIST and DNS_LOCAL_HOSTLIST_IS_DYNAMIC. 2009-04-21 18:35:18 +00:00
goldsimon
ed65d9cd75 Fixed bug #26236: "TCP options (timestamp) don't work with no-copy-tcpwrite": deallocate option data, only concat segments with same flags 2009-04-19 12:42:48 +00:00
goldsimon
542b8fffb1 Fixed bug #25094: "Zero-length pbuf" (options are now allocated in the header pbuf, not the data pbuf); added function comments; "inline" is not supported by ANSI C (tcp_build_timetamp_option) 2009-04-19 12:31:16 +00:00
goldsimon
12c50ed87b tcp_listen_input: format code for #if LWIP_TCP_TIMESTAMPS that calls tcp_enqueue like the other calls. 2009-04-19 12:17:59 +00:00
goldsimon
9d5bf57dd9 fixed bug #25695: Segmentation fault in do_writemore() 2009-04-18 17:48:41 +00:00
goldsimon
04df18bcd3 Changed ??? to LINK_SPEED_OF_YOUR_NETIF_IN_BPS 2009-04-17 10:14:09 +00:00
goldsimon
422ba5bcec tried to fix bug #23559: lwip_recvfrom problem with tcp 2009-04-15 21:13:55 +00:00
goldsimon
27b28a9306 Converted netconn_type() from a function to a macro 2009-04-15 21:04:19 +00:00
goldsimon
620b3e6739 task #9192: mem_free of dhcp->options_in and dhcp->msg_in 2009-04-15 19:53:59 +00:00
goldsimon
580f334274 patch #6808: Add a utility function ip_hinted_output() (for smaller code mainly) 2009-04-15 19:32:01 +00:00
goldsimon
4f52183a39 patch #6765: Supporting new line characters in inet_aton() 2009-04-15 19:06:39 +00:00
goldsimon
a55f354687 patch #6763: Global DHCP XID can be redefined to something more unique 2009-04-15 18:48:10 +00:00
goldsimon
9630c9136b patch #6764: DHCP rebind and renew did not send hostnam option; Converted constant OPTION_MAX_MSG_SIZE to netif->mtu, check if netif->mtu is big enough in dhcp_start 2009-04-15 18:35:04 +00:00
goldsimon
dbd6d7ec8d bug #26027: netbuf_chain resulted in pbuf memory leak 2009-04-15 14:57:32 +00:00
goldsimon
b3a5d6df0d bug #25763: Corrected 4 occurrences of SMEMCPY to MEMCPY; corrected indentation 2009-04-15 14:48:56 +00:00
goldsimon
3587e8481d bug #26121: set_errno can be overridden 2009-04-15 14:33:05 +00:00
kieranm
4f8f6ba205 Patch#6774 TCP_QUEUE_OOSEQ breaks compilation when LWIP_TCP==0 2009-04-09 15:16:26 +00:00
kieranm
f81ed216db Patch#6802 Add do-while-clauses to those function like macros in tcp.h 2009-04-09 15:09:22 +00:00
kieranm
f1a9f7ea70 BUG20515: rework way TCP window updates are calculated and sent 2009-03-31 14:23:40 +00:00
kieranm
4b14621208 TASK9218: add support for TCP timestamp options 2009-03-31 14:13:32 +00:00
kieranm
baf30f5eae BUG20779: cope with SYN packets received during established states,
and retransmission of initial SYN.
2009-03-31 10:55:31 +00:00
kieranm
e7a2ab5de9 BUG26010: set push bit correctly when tcp segments are merged 2009-03-31 10:53:11 +00:00
kieranm
fd41c5de2d Correct change to probe window setting 2009-03-27 11:04:04 +00:00
kieranm
efac109803 BUG25622: handle return code of tcp_enqueue in tcp_listen_input() 2009-03-26 14:31:02 +00:00
kieranm
84505d4cc8 BUG25629: set TCP_ACK flags on keepalive and zero window probes 2009-03-26 14:25:46 +00:00
kieranm
7d8fac62ec Fix compiler warning about %#p 2009-03-25 11:02:24 +00:00
goldsimon
b6e18d9c6f cc.h: Added printf formatter for size_t: SZT_F 2009-02-19 19:29:28 +00:00
goldsimon
c05e968278 Fixed many LWIP_DEBUGF format strings; added new format string SZT_F for size_t 2009-02-18 21:13:06 +00:00
goldsimon
103fe60362 mem_free: fix a warning by converting pointer to mem_ptr_t instead of unsigned long 2009-02-18 20:42:16 +00:00
goldsimon
638020ec70 sys_now() must return u32_t, not unsigned long 2009-02-18 20:37:42 +00:00
goldsimon
56038b6457 Fixed many warnings: use %p to pass pointers to printf 2009-02-18 20:37:09 +00:00
goldsimon
96b788bea7 patch #6528: the buffer used for IP_FRAG_USES_STATIC_BUF could be too small depending on MEM_ALIGNMENT 2009-02-18 16:54:02 +00:00
goldsimon
7b6c11360f Added check: PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or else the offset of a pbuf may take the full first pbuf in a chain (resulting in the first pbuf having len==0) 2009-02-18 16:50:40 +00:00
goldsimon
ea1eb45e3f etharp_raw: allocating PBUF_RAW for outgoing ARP packets instead of PBUF_LINK is enough. 2009-02-18 16:48:30 +00:00
goldsimon
e001a021d5 patch #6539: (configurable) response to broadcast- and multicast pings 2009-02-16 20:24:29 +00:00
goldsimon
14cb4eb735 fixed arguments of socket functions to match the standard; converted size argument of netconn_write to 'size_t' for that; fixed some warnings 2009-02-16 19:33:51 +00:00
goldsimon
d976c8e85f fixed bug #24440: TCP connection close problem on 64-bit host by moving accept callback function pointer to TCP_PCB_COMMON 2009-02-16 16:50:58 +00:00
goldsimon
d2d33cb984 Fixed compilation error in LWIP_VERSION 2009-02-16 16:43:06 +00:00
goldsimon
eeae59ecb7 LWIP_VERSION: corrected shifting for 16-bit platforms, added LWIP_RC_DEVELOPMENT 2009-02-15 20:44:40 +00:00
goldsimon
466f4e699c Added LWIP_VERSION to get the current version of the stack (implements task #9032: Provide means to get Version of Stack and submodules) 2009-02-12 21:00:11 +00:00
goldsimon
bf09400c4c fixed bug #25345 (DHCPDECLINE is sent with "Maximum message size" option) 2009-02-12 16:16:25 +00:00
goldsimon
c4509e700d added MEMP_MEM_MALLOC to use mem_malloc/mem_free instead of the pool allocator (can save code size with MEM_LIBC_MALLOC if libc-malloc is otherwise used) 2009-02-11 20:43:41 +00:00
goldsimon
6472e3b35e fixed bug #24480 (releasing old udp_pdb and pbuf in dhcp_start) 2009-02-11 20:27:00 +00:00
goldsimon
f9bd5019fa including inet.h because htonl is used 2009-02-11 20:21:20 +00:00
goldsimon
8c7705bbf9 added configurable default valud for netconn->recv_bufsize: RECV_BUFSIZE_DEFAULT (fixes bug #23726: pbuf pool exhaustion on slow recv()) 2009-02-11 19:07:22 +00:00
goldsimon
243e3d0d91 Fixed bug #25544: DHCP_COARSE_TIMER_MSECS could overflow on 16-bit targets 2009-02-11 17:48:34 +00:00
goldsimon
19884f40b8 Moved INADDR_* defines to inet.h; removing dependency from inet.h to ip_addr.h 2009-02-10 20:44:51 +00:00
goldsimon
10c3ce08af fixed bug #25467: Listen backlog is not reset on timeout in SYN_RCVD: Accepts_pending is decrease on a corresponding listen pcb when a connection in state SYN_RCVD is close. 2009-02-10 20:29:38 +00:00
jifl
878532a30d * ipv4/inet_chksum.c, ipv4/lwip/inet_chksum.h: inet_chksum_pseudo_partial()
is only used by UDPLITE at present, so conditionalise it.
2009-01-28 23:58:15 +00:00
jifl
102d69004a * pbuf.c: reclaim pbufs from TCP out-of-sequence segments if we run
out of pool pbufs.
2009-01-28 05:43:35 +00:00
goldsimon
b0c61ffbb1 Reverted last changes since it's wrong when sizeof(int)==2... 2008-12-20 12:24:41 +00:00
goldsimon
9f96f09652 Another fix for bug #6683 (and a typo in changelog) 2008-12-19 18:16:50 +00:00
goldsimon
aa568727d1 patch #6699: fixed some warnings on platform where sizeof(int) == 2 2008-12-19 18:08:29 +00:00
fbernon
411cb39eb4 sockets.c: fixed bug #25051: lwip_recvfrom problem with udp: fromaddr and port uses deleted netbuf. 2008-12-10 21:36:44 +00:00
goldsimon
6777ae2ada Another modification for patch #6683 (Customizable AUTOIP seed address) 2008-12-10 17:08:42 +00:00
goldsimon
2cf3e6e9bc Corrected the range calculation of LWIP_AUTOIP_CREATE_SEED_ADDR, corrected comments 2008-12-04 18:34:48 +00:00
goldsimon
491b73d5f2 Checked in (slightly modified) patch #6683: Customizable AUTOIP "seed" address. This should reduce AUTOIP conflicts if LWIP_AUTOIP_CREATE_SEED_ADDR is overridden. 2008-12-03 15:13:21 +00:00
jifl
1f3fe200df Correct commented description of do_recv().
Reported by Charles Landau on lwip-users.
2008-11-12 19:14:21 +00:00
goldsimon
299e2a7077 fixed bug ##24596: Vulnerability on faulty TCP options length in tcp_parseopt 2008-10-18 15:24:06 +00:00
goldsimon
13a139eef7 fixed bug #24517: IP reassembly crashes on unaligned IP headers by packing the struct ip_reass_helper. 2008-10-15 18:20:23 +00:00
jifl
06df1647e1 * etharp.c (etharp_arp_input): Fix type aliasing problem copying ip address. 2008-10-03 14:47:33 +00:00
jifl
1d2804d6a2 * sockets.c (lwip_accept): Return EWOULDBLOCK if would block on non-blocking
socket.
2008-10-02 13:59:18 +00:00
jifl
ba98bcdc60 * dns.c: Hard-code structure sizes, to avoid issues on some compilers where
padding is included.
2008-10-02 13:53:16 +00:00
jifl
0d7dccba5e * sockets.c (lwip_accept): check addr isn't NULL. If it's valid, do an
assertion check that addrlen isn't NULL.
2008-09-30 14:51:27 +00:00
jifl
c231e95cce * tcp.c: Fix bug #24227, wrong error message in tcp_bind. 2008-09-30 13:50:39 +00:00
jifl
6f6c8c5434 * pbuf.c (pbuf_copy_partial): Improve function description comment. Thanks to Luca Ceresoli 2008-09-30 13:40:41 +00:00
goldsimon
edf72a7dfb fixed one small warning (compared u16_t to <= 0) 2008-08-26 19:57:20 +00:00
goldsimon
ba636e19a2 fixed bug #24132: Cross-dependency between ip_addr.h and inet.h -> moved declaration of struct in_addr from ip_addr.h to inet.h 2008-08-26 19:47:05 +00:00
goldsimon
6374766a55 Added 2 asserts in pbuf_realloc to prevent dereferencing a null pointer in invalid pbuf queues 2008-08-26 19:34:18 +00:00
goldsimon
c779a9f29f Fixed some warnings, changed some debug defines to include better names 2008-07-16 20:36:12 +00:00
goldsimon
ae2d5266c5 removed invalid call to tcp_connect() in do_close_internal() 2008-07-15 11:18:58 +00:00
goldsimon
99db244124 fixed bug #23847: do_close_internal references freed memory 2008-07-14 20:12:36 +00:00
fbernon
8367feafa9 stats.h: Fix some build bugs introduced with patch #6483 (missing some parameters in macros, mainly if MEM_STATS=0 and MEMP_STATS=0). 2008-07-08 09:15:56 +00:00
jifl
f6a28808e3 Fix typo of including type in stats_display_memp empty macro 2008-07-07 12:45:47 +00:00
goldsimon
13d8ae859d fixed bug #21433: Calling mem_free/pbuf_free from interrupt context isn't safe: LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT allows mem_free to run between mem_malloc iterations. Added illegal counter for mem stats. 2008-06-30 18:16:51 +00:00
goldsimon
95b15fe463 Fix typo, add comment 2008-06-27 20:34:51 +00:00
goldsimon
779938ea68 patch #6483: stats module improvement: Added defines to display each module's statistic individually, added stats defines for MEM, MEMP and SYS modules, removed (unused) rexmit counter. 2008-06-27 18:37:53 +00:00
jifl
139944a3ac * tcp_in.c: Fix for bug #23693 as suggested by Art R. Ensure cseg is unused
if tcp_seg_copy fails.
2008-06-24 15:46:38 +00:00
goldsimon
b94e3a874d Added debug trace for incoming eth packets in ethernet_input like suggested in patch #6519 2008-06-19 16:40:59 +00:00
goldsimon
3d8e5003af Fixed includes in netif.c, removed loop_cnt_max member in struct netif (instead the define LWIP_LOOPBACK_MAX_PBUFS is used directly) 2008-06-19 16:27:18 +00:00
goldsimon
94cd14e90d patch #6459: Made err_t overridable to use a more efficient type (define LWIP_ERR_T in cc.h) 2008-06-17 20:27:31 +00:00
goldsimon
c93cfb2c74 Changed two MEMCPY calls to SMEMCPY 2008-06-17 20:16:23 +00:00
goldsimon
521d439a07 Added a configuration option for slipif for symmetry to loopif (patch #6480) 2008-06-17 20:14:05 +00:00
goldsimon
460b18e82c Fixed loopif_poll define (now maps directly to netif_poll) 2008-06-17 20:12:22 +00:00
goldsimon
ef3666ef26 Checked in some ideas of patch #6460 (loop optimizations) and created defines for swapping bytes and folding u32 to u16. 2008-06-17 20:06:25 +00:00
goldsimon
e0aaa87b1f Increasing etharp error stats on unsupported ethtype in ethernet_input() 2008-06-17 19:46:30 +00:00
goldsimon
eba83ab740 Changed loopback code (less difference between NO_SYS = 0 / 1), added setting LWIP_LOOPBACK_MAX_PBUFS to limit loopback-queued pbufs 2008-06-17 19:39:22 +00:00
goldsimon
a8141c53a8 Got the date & place of the newest feature wrong ;-) 2008-06-12 20:21:40 +00:00
goldsimon
88ff8c83e9 Checked in slightly modified version of patch # 6370: Moved loopif code to netif.c so that loopback traffic is supported on all netifs (all local IPs). 2008-06-12 20:10:08 +00:00
kieranm
24e0b25215 Remove redundant "if" statement, and use real rcv_wnd
rather than rcv_ann_wnd when deciding if packets are in-window.
Contributed by <arasmussen@consultant.datasys.swri.edu>
2008-05-30 12:21:29 +00:00
kieranm
7bc881ccc5 Fix BUG#23254. Change macro definition of mem_* to allow
passing as function pointers when MEM_LIBC_MALLOC is defined.
2008-05-30 11:37:15 +00:00
jifl
a3bc6cd666 * err.h, err.c, sockets.c: Fix bug #23119: Reorder timeout error code to
stop it being treated as a fatal error.
2008-05-09 12:14:23 +00:00
jifl
40d4a8fc2f Trivial change: correct sense of comment about LWIP_ERROR macro 2008-04-29 16:51:35 +00:00
fbernon
7be9e292dc sockets.h: minor changes, add comments for ToS options 2008-04-26 10:46:23 +00:00
goldsimon
9ccd31a12e fixed bug #22804: dhcp_stop doesn't clear NETIF_FLAG_DHCP (flag now cleared) 2008-04-15 17:24:54 +00:00
goldsimon
a9aefcc1be Fixed comments for pbuf_copy() and find_entry() as proposed by Luca Ceresoli on lwip-users 2008-04-01 19:05:40 +00:00
goldsimon
05587f5da9 Changed the pbuf_free/mem_free callback functions a little: created extra functions for that 2008-03-28 07:56:47 +00:00
goldsimon
43dd38df0a fixed bug #21433 (Calling mem_free/pbuf_free from interrupt context isn't safe): set LWIP_USE_HEAP_FROM_INTERRUPT to 1 in lwipopts.h or use tcpip_callback_nonblocking(pbuf_free_int, p)/ tcpip_callback_nonblocking(mem_free, m) to free pbufs or heap memory from interrupt context 2008-03-27 19:29:35 +00:00
goldsimon
64fa8d78bc Added global #ifndef __SIO_H__ and some comments 2008-03-27 18:06:02 +00:00
goldsimon
aee9c4c8e6 fixed bug #22249: division by zero could occur if a remote host sent a zero mss as TCP option. 2008-03-26 11:57:12 +00:00
154 changed files with 26172 additions and 10575 deletions

1226
CHANGELOG

File diff suppressed because it is too large Load Diff

2
README
View File

@@ -72,7 +72,7 @@ current CVS sources and is available from this web page:
http://www.nongnu.org/lwip/
There is now a constantly growin wiki about lwIP at
http://lwip.scribblewiki.com/
http://lwip.wikia.com/wiki/LwIP_Wiki
Also, there are mailing lists you can subscribe at
http://savannah.nongnu.org/mail/?group=lwip

144
UPGRADING Normal file
View File

@@ -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

View File

@@ -1,5 +1,6 @@
savannah.txt - How to obtain the current development source code.
contrib.txt - How to contribute to lwIP as a developer.
rawapi.txt - The documentation for the core API of lwIP.
Also provides an overview about the other APIs and multithreading.
snmp_agent.txt - The documentation for the lwIP SNMP agent.
sys_arch.txt - The documentation for a system abstraction layer of lwIP.

View File

@@ -2,10 +2,11 @@ Raw TCP/IP interface for lwIP
Authors: Adam Dunkels, Leon Woestenberg, Christiaan Simons
lwIP provides two Application Program's Interfaces (APIs) for programs
lwIP provides three Application Program's Interfaces (APIs) for programs
to use for communication with the TCP/IP code:
* low-level "core" / "callback" or "raw" API.
* higher-level "sequential" API.
* BSD-style socket API.
The sequential API provides a way for ordinary, sequential, programs
to use the lwIP stack. It is quite similar to the BSD socket API. The
@@ -14,6 +15,45 @@ paradigm. Since the TCP/IP stack is event based by nature, the TCP/IP
code and the application program must reside in different execution
contexts (threads).
The socket API is a compatibility API for existing applications,
currently it is built on top of the sequential API. It is meant to
provide all functions needed to run socket API applications running
on other platforms (e.g. unix / windows etc.). However, due to limitations
in the specification of this API, there might be incompatibilities
that require small modifications of existing programs.
** Threading
lwIP started targeting single-threaded environments. When adding multi-
threading support, instead of making the core thread-safe, another
approach was chosen: there is one main thread running the lwIP core
(also known as the "tcpip_thread"). The raw API may only be used from
this thread! Application threads using the sequential- or socket API
communicate with this main thread through message passing.
As such, the list of functions that may be called from
other threads or an ISR is very limited! Only functions
from these API header files are thread-safe:
- api.h
- netbuf.h
- netdb.h
- netifapi.h
- sockets.h
- sys.h
Additionaly, memory (de-)allocation functions may be
called from multiple threads (not ISR!) with NO_SYS=0
since they are protected by SYS_LIGHTWEIGHT_PROT and/or
semaphores.
Only since 1.3.0, if SYS_LIGHTWEIGHT_PROT is set to 1
and LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT is set to 1,
pbuf_free() may also be called from another thread or
an ISR (since only then, mem_free - for PBUF_RAM - may
be called from an ISR: otherwise, the HEAP is only
protected by semaphores).
** The remainder of this document discusses the "raw" API. **
The raw TCP/IP interface allows the application program to integrate
@@ -67,7 +107,7 @@ incoming connections or be explicitly connected to another host.
Creates a new connection identifier (PCB). If memory is not
available for creating the new pcb, NULL is returned.
- err_t tcp_bind(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
- err_t tcp_bind(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local IP address and port number. The IP address
@@ -107,6 +147,8 @@ incoming connections or be explicitly connected to another host.
usually be called from the accept callback. This allows lwIP to perform
housekeeping tasks, such as allowing further incoming connections to be
queued in the listen backlog.
ATTENTION: the PCB passed in must be the listening pcb, not the pcb passed
into the accept callback!
- void tcp_accept(struct tcp_pcb *pcb,
err_t (* accept)(void *arg, struct tcp_pcb *newpcb,
@@ -114,8 +156,8 @@ incoming connections or be explicitly connected to another host.
Specified the callback function that should be called when a new
connection arrives on a listening connection.
- err_t tcp_connect(struct tcp_pcb *pcb, struct ip_addr *ipaddr,
- err_t tcp_connect(struct tcp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port, err_t (* connected)(void *arg,
struct tcp_pcb *tpcb,
err_t err));
@@ -128,14 +170,15 @@ incoming connections or be explicitly connected to another host.
function specified as the fourth argument (the "connected" argument)
when the connection is established. If the connection could not be
properly established, either because the other host refused the
connection or because the other host didn't answer, the "connected"
function will be called with an the "err" argument set accordingly.
connection or because the other host didn't answer, the "err"
callback function of this pcb (registered with tcp_err, see below)
will be called.
The tcp_connect() function can return ERR_MEM if no memory is
available for enqueueing the SYN segment. If the SYN indeed was
enqueued successfully, the tcp_connect() function returns ERR_OK.
--- Sending TCP data
TCP data is sent by enqueueing the data with a call to
@@ -143,15 +186,19 @@ tcp_write(). When the data is successfully transmitted to the remote
host, the application will be notified with a call to a specified
callback function.
- err_t tcp_write(struct tcp_pcb *pcb, void *dataptr, u16_t len,
u8_t copy)
- err_t tcp_write(struct tcp_pcb *pcb, const void *dataptr, u16_t len,
u8_t apiflags)
Enqueues the data pointed to by the argument dataptr. The length of
the data is passed as the len parameter. The copy argument is either
0 or 1 and indicates whether the new memory should be allocated for
the data to be copied into. If the argument is 0, no new memory
should be allocated and the data should only be referenced by
pointer.
the data is passed as the len parameter. The apiflags can be one or more of:
- TCP_WRITE_FLAG_COPY: indicates whether the new memory should be allocated
for the data to be copied into. If this flag is not given, no new memory
should be allocated and the data should only be referenced by pointer. This
also means that the memory behind dataptr must not change until the data is
ACKed by the remote host
- TCP_WRITE_FLAG_MORE: indicates that more data follows. If this is given,
the PSH flag is set in the last segment created by this call to tcp_write.
If this flag is given, the PSH flag is not set.
The tcp_write() function will fail and return ERR_MEM if the length
of the data exceeds the current send buffer size or if the length of
@@ -197,7 +244,7 @@ window.
Must be called when the application has received the data. The len
argument indicates the length of the received data.
--- Application polling
@@ -210,8 +257,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
@@ -237,6 +285,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
@@ -275,14 +328,14 @@ level of complexity of UDP, the interface is significantly simpler.
Removes and deallocates the pcb.
- err_t udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr,
- err_t udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Binds the pcb to a local address. The IP-address argument "ipaddr"
can be IP_ADDR_ANY to indicate that it should listen to any local IP
address. The function currently always return ERR_OK.
- err_t udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr,
- err_t udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr,
u16_t port)
Sets the remote end of the pcb. This function does not generate any
@@ -300,7 +353,7 @@ level of complexity of UDP, the interface is significantly simpler.
- void udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb,
struct pbuf *p,
struct ip_addr *addr,
ip_addr_t *addr,
u16_t port),
void *recv_arg)
@@ -361,8 +414,8 @@ Call these functions in the order of appearance:
Note: you must call tcp_fasttmr() and tcp_slowtmr() at the
predefined regular intervals after this initialization.
- netif_add(struct netif *netif, struct ip_addr *ipaddr,
struct ip_addr *netmask, struct ip_addr *gw,
- netif_add(struct netif *netif, 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))
@@ -435,3 +488,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!

View File

@@ -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

View File

@@ -34,26 +34,36 @@ in the sys_arch.h file. Mailboxes are equivalently represented by the
type "sys_mbox_t". lwIP does not place any restrictions on how
sys_sem_t or sys_mbox_t are represented internally.
Since lwIP 1.4.0, semaphore and mailbox functions are prototyped in a way that
allows both using pointers or actual OS structures to be used. This way, memory
required for such types can be either allocated in place (globally or on the
stack) or on the heap (allocated internally in the "*_new()" functions).
The following functions must be implemented by the sys_arch:
- void sys_init(void)
Is called to initialize the sys_arch layer.
- sys_sem_t sys_sem_new(u8_t count)
- err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Creates and returns a new semaphore. The "count" argument specifies
the initial state of the semaphore.
Creates a new semaphore. The semaphore is allocated to the memory that 'sem'
points to (which can be both a pointer or the actual OS structure).
The "count" argument specifies the initial state of the semaphore (which is
either 0 or 1).
If the semaphore has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_sem_free(sys_sem_t sem)
- void sys_sem_free(sys_sem_t *sem)
Deallocates a semaphore.
- void sys_sem_signal(sys_sem_t sem)
- void sys_sem_signal(sys_sem_t *sem)
Signals a semaphore.
- u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout)
- u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Blocks the thread while waiting for the semaphore to be
signaled. If the "timeout" argument is non-zero, the thread should
@@ -70,30 +80,47 @@ The following functions must be implemented by the sys_arch:
Notice that lwIP implements a function with a similar name,
sys_sem_wait(), that uses the sys_arch_sem_wait() function.
- sys_mbox_t sys_mbox_new(int size)
- int sys_sem_valid(sys_sem_t *sem)
Returns 1 if the semaphore is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_sem_set_invalid(sys_sem_t *sem)
Invalidate a semaphore so that sys_sem_valid() returns 0.
ATTENTION: This does NOT mean that the semaphore shall be deallocated:
sys_sem_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
- err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Creates an empty mailbox for maximum "size" elements. Elements stored
in mailboxes are pointers. You have to define macros "_MBOX_SIZE"
in your lwipopts.h, or ignore this parameter in your implementation
and use a default size.
If the mailbox has been created, ERR_OK should be returned. Returning any
other error will provide a hint what went wrong, but except for assertions,
no real error handling is implemented.
- void sys_mbox_free(sys_mbox_t mbox)
- void sys_mbox_free(sys_mbox_t *mbox)
Deallocates a mailbox. If there are messages still present in the
mailbox when the mailbox is deallocated, it is an indication of a
programming error in lwIP and the developer should be notified.
- void sys_mbox_post(sys_mbox_t mbox, void *msg)
- void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Posts the "msg" to the mailbox. This function have to block until
the "msg" is really posted.
- err_t sys_mbox_trypost(sys_mbox_t mbox, void *msg)
- err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Try to post the "msg" to the mailbox. Returns ERR_MEM if this one
is full, else, ERR_OK if the "msg" is posted.
- u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, u32_t timeout)
- u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Blocks the thread until a message arrives in the mailbox, but does
not block the thread longer than "timeout" milliseconds (similar to
@@ -110,7 +137,7 @@ The following functions must be implemented by the sys_arch:
Note that a function with a similar name, sys_mbox_fetch(), is
implemented by lwIP.
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t mbox, void **msg)
- u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
This is similar to sys_arch_mbox_fetch, however if a message is not
present in the mailbox, it immediately returns with the code
@@ -122,19 +149,21 @@ The following functions must be implemented by the sys_arch:
#define sys_arch_mbox_tryfetch(mbox,msg) \
sys_arch_mbox_fetch(mbox,msg,1)
although this would introduce unnecessary delays.
- struct sys_timeouts *sys_arch_timeouts(void)
Returns a pointer to the per-thread sys_timeouts structure. In lwIP,
each thread has a list of timeouts which is repressented as a linked
list of sys_timeout structures. The sys_timeouts structure holds a
pointer to a linked list of timeouts. This function is called by
the lwIP timeout scheduler and must not return a NULL value.
- int sys_mbox_valid(sys_mbox_t *mbox)
Returns 1 if the mailbox is valid, 0 if it is not valid.
When using pointers, a simple way is to check the pointer for != NULL.
When directly using OS structures, implementing this may be more complex.
This may also be a define, in which case the function is not prototyped.
- void sys_mbox_set_invalid(sys_mbox_t *mbox)
Invalidate a mailbox so that sys_mbox_valid() returns 0.
ATTENTION: This does NOT mean that the mailbox shall be deallocated:
sys_mbox_free() is always called before calling this function!
This may also be a define, in which case the function is not prototyped.
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:
@@ -168,6 +197,16 @@ to be implemented as well:
more information. This function is only required if your port is supporting
an operating system.
For some configurations, you also need:
- u32_t sys_now(void)
This optional function returns the current time in milliseconds (don't care
for wraparound, this is only used for time diffs).
Not implementing this function means you cannot use some modules (e.g. TCP
timestamps, internal timeouts for NO_SYS==1).
Note:
Be carefull with using mem_malloc() in sys_arch. When malloc() refers to
@@ -195,6 +234,8 @@ cc.h - Architecture environment, some compiler specific, some
Platform specific diagnostic output -
LWIP_PLATFORM_DIAG(x) - non-fatal, print a message.
LWIP_PLATFORM_ASSERT(x) - fatal, print message and abandon execution.
Portability defines for printf formatters:
U16_F, S16_F, X16_F, U32_F, S32_F, X32_F, SZT_F
"lightweight" synchronization mechanisms -
SYS_ARCH_DECL_PROTECT(x) - declare a protection state variable.

View File

@@ -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,23 +113,11 @@ netconn_delete(struct netconn *conn)
msg.msg.conn = conn;
tcpip_apimsg(&msg);
conn->pcb.tcp = NULL;
netconn_free(conn);
return ERR_OK;
}
/* don't care for return value of do_delconn since it only calls void functions */
/**
* Get the type of a netconn (as enum netconn_type).
*
* @param conn the netconn of which to get the type
* @return the netconn_type of conn
*/
enum netconn_type
netconn_type(struct netconn *conn)
{
LWIP_ERROR("netconn_type: invalid conn", (conn != NULL), return NETCONN_INVALID;);
return conn->type;
return ERR_OK;
}
/**
@@ -144,9 +132,10 @@ netconn_type(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;);
@@ -154,12 +143,13 @@ netconn_getaddr(struct netconn *conn, struct ip_addr *addr, u16_t *port, u8_t lo
msg.function = do_getaddr;
msg.msg.conn = conn;
msg.msg.msg.ad.ipaddr = addr;
msg.msg.msg.ad.ipaddr = ip_2_ipX(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;
}
/**
@@ -173,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;);
@@ -183,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;
}
/**
@@ -196,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;);
@@ -207,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;
}
/**
@@ -221,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;
}
/**
@@ -241,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);
@@ -253,155 +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;
LWIP_ERROR("netconn_accept: invalid conn", (conn != NULL), return NULL;);
LWIP_ERROR("netconn_accept: invalid acceptmbox", (conn->acceptmbox != SYS_MBOX_NULL), return NULL;);
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, conn->recv_timeout) == SYS_ARCH_TIMEOUT) {
newconn = NULL;
} else
#else
sys_arch_mbox_fetch(conn->acceptmbox, (void *)&newconn, 0);
#endif /* LWIP_SO_RCVTIMEO*/
{
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, 0);
err_t err;
#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);
}
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;);
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;
}
return newconn;
#if LWIP_SO_RCVTIMEO
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);
#endif /* LWIP_SO_RCVTIMEO*/
/* 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
/* 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 */
*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: actual implementation that doesn't care whether pbuf or netbuf
* is received
*
* @param conn the netconn from which to receive data
* @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)
*/
static err_t
netconn_recv_data(struct netconn *conn, void **new_buf)
{
void *buf = NULL;
u16_t len;
err_t err;
#if LWIP_TCP
struct api_msg msg;
#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;);
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 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 LWIP_TCP
if (NETCONNTYPE_GROUP(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);
}
/* If we are closed, we indicate that we no longer wish to use the socket */
if (buf == 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_RCVBUF
SYS_ARCH_DEC(conn->recv_avail, len);
#endif /* LWIP_SO_RCVBUF */
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv_data: received %p, len=%"U16_F"\n", buf, len));
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
}
/**
* 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) &&
NETCONNTYPE_GROUP(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
* @return a new netbuf containing received data or NULL on memory error or timeout
* @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)
*/
struct netbuf *
netconn_recv(struct netconn *conn)
err_t
netconn_recv(struct netconn *conn, struct netbuf **new_buf)
{
struct api_msg msg;
struct netbuf *buf = NULL;
struct pbuf *p;
u16_t len;
LWIP_ERROR("netconn_recv: invalid conn", (conn != NULL), return NULL;);
if (conn->recvmbox == SYS_MBOX_NULL) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal (ERR_CONN)?? */
/* TCP listen conns don't have a recvmbox! */
conn->err = ERR_CONN;
return NULL;
}
if (ERR_IS_FATAL(conn->err)) {
return NULL;
}
if (conn->type == NETCONN_TCP) {
#if LWIP_TCP
if (conn->state == NETCONN_LISTEN) {
/* @todo: should calling netconn_recv on a TCP listen conn be fatal?? */
conn->err = ERR_CONN;
return NULL;
}
struct netbuf *buf = NULL;
err_t err;
#endif /* LWIP_TCP */
buf = memp_malloc(MEMP_NETBUF);
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 (NETCONNTYPE_GROUP(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) {
conn->err = ERR_MEM;
return NULL;
NETCONN_SET_SAFE_ERR(conn, ERR_MEM);
return ERR_MEM;
}
#if LWIP_SO_RCVTIMEO
if (sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, conn->recv_timeout)==SYS_ARCH_TIMEOUT) {
conn->err = ERR_TIMEOUT;
p = NULL;
}
#else
sys_arch_mbox_fetch(conn->recvmbox, (void *)&p, 0);
#endif /* LWIP_SO_RCVTIMEO*/
if (p != NULL) {
len = p->tot_len;
SYS_ARCH_DEC(conn->recv_avail, len);
} else {
len = 0;
}
/* Register event with callback */
API_EVENT(conn, NETCONN_EVT_RCVMINUS, len);
/* If we are closed, we indicate that we no longer wish to use the socket */
if (p == NULL) {
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;
/* Let the stack know that we have taken the data. */
msg.function = do_recv;
msg.msg.conn = conn;
if (buf != NULL) {
msg.msg.msg.r.len = buf->p->tot_len;
} else {
msg.msg.msg.r.len = 1;
}
TCPIP_APIMSG(&msg);
ipX_addr_set_any(LWIP_IPV6, &buf->addr);
*new_buf = buf;
/* don't set conn->last_err: it's only ERR_OK, anyway */
return ERR_OK;
} else
#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);
}
return netconn_recv_data(conn, (void **)new_buf);
#endif /* (LWIP_UDP || LWIP_RAW) */
}
}
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_recv: received %p (err %d)\n", (void *)buf, conn->err));
return buf;
/**
* 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) && (NETCONNTYPE_GROUP(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;
msg.msg.msg.r.len = length;
/* don't care for the return value of do_recv */
TCPIP_APIMSG(&msg);
}
#else /* LWIP_TCP */
LWIP_UNUSED_ARG(conn);
LWIP_UNUSED_ARG(length);
#endif /* LWIP_TCP */
}
/**
@@ -415,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;
ipX_addr_set_ipaddr(PCB_ISIPV6(conn->pcb.ip), &buf->addr, addr);
buf->port = port;
return netconn_send(conn, buf);
}
@@ -436,15 +558,18 @@ 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;);
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %d bytes\n", buf->p->tot_len));
LWIP_DEBUGF(API_LIB_DEBUG, ("netconn_send: sending %"U16_F" bytes\n", buf->p->tot_len));
msg.function = do_send;
msg.msg.conn = conn;
msg.msg.msg.b = buf;
TCPIP_APIMSG(&msg);
return conn->err;
err = TCPIP_APIMSG(&msg);
NETCONN_SET_SAFE_ERR(conn, err);
return err;
}
/**
@@ -454,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, int size, u8_t apiflags)
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;);
LWIP_ERROR("netconn_write: invalid conn->type", (NETCONNTYPE_GROUP(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;
@@ -474,8 +606,37 @@ netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags
/* 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 ot shutdown a TCP netconn (doesn't delete it).
*
* @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
*/
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;
/* 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;
}
/**
@@ -487,60 +648,69 @@ netconn_write(struct netconn *conn, const void *dataptr, int size, u8_t apiflags
err_t
netconn_close(struct netconn *conn)
{
struct api_msg msg;
LWIP_ERROR("netconn_close: invalid conn", (conn != NULL), return ERR_ARG;);
msg.function = do_close;
msg.msg.conn = conn;
tcpip_apimsg(&msg);
return conn->err;
/* shutting down both ends is the same as closing */
return netconn_close_shutdown(conn, NETCONN_SHUT_RDWR);
}
#if LWIP_IGMP
/**
* 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 || (LWIP_IPV6 && LWIP_IPV6_MLD)
/**
* Join multicast groups for UDP netconns.
*
* @param conn the UDP netconn for which to change multicast addresses
* @param multiaddr IP address of the multicast group to join or leave
* @param interface the IP address of the network interface on which to send
* @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.multiaddr = ip_2_ipX(multiaddr);
msg.msg.msg.jl.netif_addr = ip_2_ipX(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 */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
/**
* Execute a DNS query, only one IP address is returned
*
* @param name a string representation of the DNS host name to query
* @param addr a preallocated struct ip_addr where to store the resolved IP address
* @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;
@@ -549,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;
}

File diff suppressed because it is too large Load Diff

View File

@@ -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 */
"Routing problem.", /* ERR_RTE -3 */
"Connection aborted.", /* ERR_ABRT -4 */
"Connection reset.", /* ERR_RST -5 */
"Connection closed.", /* ERR_CLSD -6 */
"Not connected.", /* ERR_CONN -7 */
"Illegal value.", /* ERR_VAL -8 */
"Illegal argument.", /* ERR_ARG -9 */
"Address in use.", /* ERR_USE -10 */
"Low-level netif error.", /* ERR_IF -11 */
"Already connected.", /* ERR_ISCONN -12 */
"Timeout.", /* ERR_TIMEOUT -13 */
"Operation in progress." /* ERR_INPROGRESS -14 */
"Timeout.", /* ERR_TIMEOUT -3 */
"Routing problem.", /* ERR_RTE -4 */
"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 */
};
/**

View File

@@ -57,11 +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;
ipX_addr_set_any(LWIP_IPV6, &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
ipX_addr_set_any(LWIP_IPV6, &buf->toaddr);
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
return buf;
} else {
return NULL;
@@ -158,14 +168,14 @@ netbuf_ref(struct netbuf *buf, const void *dataptr, u16_t size)
* Chain one netbuf to another (@see pbuf_chain)
*
* @param head the first netbuf
* @param tail netbuf to chain after head
* @param tail netbuf to chain after head, freed by this function, may not be reference after returning
*/
void
netbuf_chain(struct netbuf *head, struct netbuf *tail)
{
LWIP_ERROR("netbuf_ref: invalid head", (head != NULL), return;);
LWIP_ERROR("netbuf_chain: invalid tail", (tail != NULL), return;);
pbuf_chain(head->p, tail->p);
pbuf_cat(head->p, tail->p);
head->ptr = head->p;
memp_free(MEMP_NETBUF, tail);
}

View File

@@ -39,13 +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;
};
@@ -80,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);
@@ -98,32 +103,33 @@ 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
/* dump hostent */
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == 0x%08lX\n",(u32_t)(s_hostent.h_aliases)));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_name == %s\n", s_hostent.h_name));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases == %p\n", s_hostent.h_aliases));
if (s_hostent.h_aliases != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_aliases[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == 0x%08lX\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %p\n", idx, s_hostent.h_aliases[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_aliases[%i]-> == %s\n", idx, s_hostent.h_aliases[idx]));
}
}
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %lu\n", (u32_t)(s_hostent.h_addrtype)));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %lu\n", (u32_t)(s_hostent.h_length)));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == 0x%08lX\n", s_hostent.h_addr_list));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addrtype == %d\n", s_hostent.h_addrtype));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_length == %d\n", s_hostent.h_length));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list == %p\n", s_hostent.h_addr_list));
if (s_hostent.h_addr_list != NULL) {
u8_t idx;
for ( idx=0; s_hostent.h_addr_list[idx]; idx++) {
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i] == 0x%08lX\n", idx, s_hostent.h_addr_list[idx]));
LWIP_DEBUGF(DNS_DEBUG, ("hostent.h_addr_list[%i]-> == %s\n", idx, inet_ntoa(*((struct in_addr*)(s_hostent.h_addr_list[idx])))));
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((ip_addr_t*)s_hostent.h_addr_list[idx])));
}
}
#endif /* DNS_DEBUG */
@@ -208,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 */
@@ -231,14 +237,8 @@ lwip_freeaddrinfo(struct addrinfo *ai)
struct addrinfo *next;
while (ai != NULL) {
if (ai->ai_addr != NULL) {
mem_free(ai->ai_addr);
}
if (ai->ai_canonname != NULL) {
mem_free(ai->ai_canonname);
}
next = ai->ai_next;
mem_free(ai);
memp_free(MEMP_NETDB, ai);
ai = next;
}
}
@@ -267,10 +267,12 @@ 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;
size_t total_size;
size_t namelen = 0;
if (res == NULL) {
return EAI_FAIL;
@@ -297,24 +299,29 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
}
} else {
/* service location specified, use loopback address */
addr.addr = INADDR_LOOPBACK;
ip_addr_set_loopback(&addr);
}
ai = mem_malloc(sizeof(struct addrinfo));
total_size = sizeof(struct addrinfo) + sizeof(struct sockaddr_in);
if (nodename != NULL) {
namelen = strlen(nodename);
LWIP_ASSERT("namelen is too long", (namelen + 1) <= (mem_size_t)-1);
total_size += namelen + 1;
}
/* 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, sizeof(struct addrinfo));
sa = mem_malloc(sizeof(struct sockaddr_in));
if (sa == NULL) {
goto memerr;
}
memset(sa, 0, sizeof(struct sockaddr_in));
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;
@@ -325,11 +332,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
}
if (nodename != NULL) {
/* copy nodename to canonname if specified */
size_t namelen = strlen(nodename);
ai->ai_canonname = mem_malloc(namelen + 1);
if (ai->ai_canonname == NULL) {
goto memerr;
}
ai->ai_canonname = ((char*)ai + sizeof(struct addrinfo) + sizeof(struct sockaddr_in));
MEMCPY(ai->ai_canonname, nodename, namelen);
ai->ai_canonname[namelen] = 0;
}
@@ -341,10 +344,7 @@ lwip_getaddrinfo(const char *nodename, const char *servname,
return 0;
memerr:
if (ai != NULL) {
mem_free(ai);
}
if (sa != NULL) {
mem_free(sa);
memp_free(MEMP_NETDB, ai);
}
return EAI_MEMORY;
}

View File

@@ -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,
@@ -58,16 +58,29 @@ do_netifapi_netif_add( struct netifapi_msg_msg *msg)
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call netif_set_addr() inside the tcpip_thread context.
*/
void
do_netifapi_netif_set_addr(struct netifapi_msg_msg *msg)
{
netif_set_addr( msg->netif,
msg->msg.add.ipaddr,
msg->msg.add.netmask,
msg->msg.add.gw);
msg->err = ERR_OK;
TCPIP_NETIFAPI_ACK(msg);
}
/**
* Call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) inside the
* tcpip_thread context.
*/
void
do_netifapi_netif_common( struct netifapi_msg_msg *msg)
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);
@@ -83,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;
@@ -103,6 +116,28 @@ netifapi_netif_add(struct netif *netif,
return msg.msg.err;
}
/**
* Call netif_set_addr() in a thread-safe way by running that function inside the
* tcpip_thread context.
*
* @note for params @see netif_set_addr()
*/
err_t
netifapi_netif_set_addr(struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw)
{
struct netifapi_msg msg;
msg.function = do_netifapi_netif_set_addr;
msg.msg.netif = netif;
msg.msg.msg.add.ipaddr = ipaddr;
msg.msg.msg.add.netmask = netmask;
msg.msg.msg.add.gw = gw;
TCPIP_NETIFAPI(&msg);
return msg.msg.err;
}
/**
* call the "errtfunc" (or the "voidfunc" if "errtfunc" is NULL) in a thread-safe
* way by running that function inside the tcpip_thread context.
@@ -110,9 +145,8 @@ netifapi_netif_add(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;

File diff suppressed because it is too large Load Diff

View File

@@ -42,182 +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();
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
@@ -235,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:
@@ -270,17 +95,25 @@ 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 */
#if LWIP_IPV6
if ((*((unsigned char *)(msg->msg.inp.p->payload)) & 0xf0) == 0x60) {
ip6_input(msg->msg.inp.p, msg->msg.inp.netif);
} else
#endif /* LWIP_IPV6 */
{
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:
@@ -289,23 +122,33 @@ tcpip_thread(void *arg)
break;
#endif /* LWIP_NETIF_API */
#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);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
case TCPIP_MSG_UNTIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: UNTIMEOUT %p\n", (void *)msg));
sys_untimeout(msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
break;
#endif /* LWIP_TCPIP_TIMEOUT */
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;
case TCPIP_MSG_TIMEOUT:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: TIMEOUT %p\n", (void *)msg));
if(msg->msg.tmo.msecs != 0xffffffff)
sys_timeout (msg->msg.tmo.msecs, msg->msg.tmo.h, msg->msg.tmo.arg);
else
sys_untimeout (msg->msg.tmo.h, msg->msg.tmo.arg);
memp_free(MEMP_TCPIP_MSG_API, msg);
case TCPIP_MSG_CALLBACK_STATIC:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: CALLBACK_STATIC %p\n", (void *)msg));
msg->msg.cb.function(msg->msg.cb.ctx);
break;
default:
LWIP_DEBUGF(TCPIP_DEBUG, ("tcpip_thread: invalid message: %d\n", msg->type));
LWIP_ASSERT("tcpip_thread: invalid message", 0);
break;
}
}
@@ -315,30 +158,47 @@ 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 (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return ERR_VAL;
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_INPKT);
if (msg == NULL) {
return ERR_MEM;
}
msg->type = TCPIP_MSG_INPKT;
msg->msg.inp.p = p;
msg->msg.inp.netif = inp;
if (sys_mbox_trypost(&mbox, msg) != ERR_OK) {
memp_free(MEMP_TCPIP_MSG_INPKT, msg);
return ERR_MEM;
}
return ERR_OK;
#endif /* LWIP_TCPIP_CORE_LOCKING_INPUT */
}
/**
@@ -353,23 +213,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;
}
@@ -379,13 +239,22 @@ 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 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
*/
err_t
tcpip_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
if (mbox != SYS_MBOX_NULL) {
msg = memp_malloc(MEMP_TCPIP_MSG_API);
if (sys_mbox_valid(&mbox)) {
msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return ERR_MEM;
}
@@ -394,12 +263,41 @@ 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;
}
/**
* call sys_untimeout in tcpip_thread
*
* @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
*/
err_t
tcpip_untimeout(sys_timeout_handler h, void *arg)
{
struct tcpip_msg *msg;
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_UNTIMEOUT;
msg->msg.tmo.h = h;
msg->msg.tmo.arg = arg;
sys_mbox_post(&mbox, msg);
return ERR_OK;
}
return ERR_VAL;
}
#endif /* LWIP_TCPIP_TIMEOUT */
#if LWIP_NETCONN
/**
* Call the lower part of a netconn_* function
@@ -413,13 +311,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;
}
@@ -436,10 +338,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 */
@@ -459,18 +366,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;
@@ -495,6 +402,52 @@ tcpip_netifapi_lock(struct netifapi_msg* netifapimsg)
#endif /* !LWIP_TCPIP_CORE_LOCKING */
#endif /* LWIP_NETIF_API */
/**
* Allocate a structure for a static callback message and initialize it.
* This is intended to be used to send "static" messages from interrupt context.
*
* @param function the function to call
* @param ctx parameter passed to function
* @return a struct pointer to pass to tcpip_trycallback().
*/
struct tcpip_callback_msg* tcpip_callbackmsg_new(tcpip_callback_fn function, void *ctx)
{
struct tcpip_msg *msg = (struct tcpip_msg *)memp_malloc(MEMP_TCPIP_MSG_API);
if (msg == NULL) {
return NULL;
}
msg->type = TCPIP_MSG_CALLBACK;
msg->msg.cb.function = function;
msg->msg.cb.ctx = ctx;
return (struct tcpip_callback_msg*)msg;
}
/**
* Free a callback message allocated by tcpip_callbackmsg_new().
*
* @param msg the message to free
*/
void tcpip_callbackmsg_delete(struct tcpip_callback_msg* msg)
{
memp_free(MEMP_TCPIP_MSG_API, msg);
}
/**
* Try to post a callback-message to the tcpip_thread mbox
* This is intended to be used to send "static" messages from interrupt context.
*
* @param msg pointer to the message to post
* @return sys_mbox_trypost() return code
*/
err_t
tcpip_trycallback(struct tcpip_callback_msg* msg)
{
if (!sys_mbox_valid(&mbox)) {
return ERR_VAL;
}
return sys_mbox_trypost(&mbox, msg);
}
/**
* Initialize this module:
* - initialize all sub modules
@@ -504,18 +457,60 @@ 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);
}
/**
* Simple callback function used with tcpip_callback to free a pbuf
* (pbuf_free has a wrong signature for tcpip_callback)
*
* @param p The pbuf (chain) to be dereferenced.
*/
static void
pbuf_free_int(void *p)
{
struct pbuf *q = (struct pbuf *)p;
pbuf_free(q);
}
/**
* A simple wrapper function that allows you to free a pbuf from interrupt context.
*
* @param p The pbuf (chain) to be dereferenced.
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
pbuf_free_callback(struct pbuf *p)
{
return tcpip_callback_with_block(pbuf_free_int, p, 0);
}
/**
* A simple wrapper function that allows you to free heap memory from
* interrupt context.
*
* @param m the heap memory to free
* @return ERR_OK if callback could be enqueued, an err_t if not
*/
err_t
mem_free_callback(void *m)
{
return tcpip_callback_with_block(mem_free, m, 0);
}
#endif /* !NO_SYS */

108
src/core/def.c Normal file
View File

@@ -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) */

File diff suppressed because it is too large Load Diff

View File

@@ -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 */
@@ -127,52 +128,41 @@
PACK_STRUCT_BEGIN
/** DNS message header */
struct dns_hdr {
u16_t id;
u8_t flags1;
u8_t flags2;
u16_t numquestions;
u16_t numanswers;
u16_t numauthrr;
u16_t numextrarr;
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u8_t flags1);
PACK_STRUCT_FIELD(u8_t flags2);
PACK_STRUCT_FIELD(u16_t numquestions);
PACK_STRUCT_FIELD(u16_t numanswers);
PACK_STRUCT_FIELD(u16_t numauthrr);
PACK_STRUCT_FIELD(u16_t numextrarr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_DNS_HDR 12
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
/** DNS query message structure */
/** 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. */
u16_t type;
u16_t class;
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
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. */
u16_t type;
u16_t class;
u16_t cls;
u32_t ttl;
u16_t len;
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
};
#define SIZEOF_DNS_ANSWER 10
/** DNS table entry */
struct dns_table_entry {
@@ -184,15 +174,41 @@ 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
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Local host-list. For hostnames in this list, no
* external name resolution is performed */
static struct local_hostlist_entry *local_hostlist_dynamic;
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_PRE
#define DNS_LOCAL_HOSTLIST_STORAGE_PRE static
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_PRE */
/** Defining this allows the local_hostlist_static to be placed in a different
* linker section (e.g. FLASH) */
#ifndef DNS_LOCAL_HOSTLIST_STORAGE_POST
#define DNS_LOCAL_HOSTLIST_STORAGE_POST
#endif /* DNS_LOCAL_HOSTLIST_STORAGE_POST */
DNS_LOCAL_HOSTLIST_STORAGE_PRE struct local_hostlist_entry local_hostlist_static[]
DNS_LOCAL_HOSTLIST_STORAGE_POST = DNS_LOCAL_HOSTLIST_INIT;
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
static void dns_init_local();
#endif /* DNS_LOCAL_HOSTLIST */
/* forward declarations */
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u16_t port);
static void dns_recv(void *s, struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *addr, u16_t port);
static void dns_check_entries(void);
/*-----------------------------------------------------------------------------
@@ -203,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
@@ -216,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"));
@@ -241,6 +258,9 @@ dns_init()
dns_setserver(0, &dnsserver);
}
}
#if DNS_LOCAL_HOSTLIST
dns_init_local();
#endif
}
/**
@@ -250,10 +270,10 @@ 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)
{
if ((numdns < DNS_MAX_SERVERS) && (dns_pcb != NULL) &&
(dnsserver != NULL) && (dnsserver->addr !=0 )) {
(dnsserver != NULL) && !ip_addr_isany(dnsserver)) {
dns_servers[numdns] = (*dnsserver);
}
}
@@ -265,7 +285,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) {
@@ -288,6 +308,131 @@ dns_tmr(void)
}
}
#if DNS_LOCAL_HOSTLIST
static void
dns_init_local()
{
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT)
int i;
struct local_hostlist_entry *entry;
/* Dynamic: copy entries from DNS_LOCAL_HOSTLIST_INIT to list */
struct local_hostlist_entry local_hostlist_init[] = DNS_LOCAL_HOSTLIST_INIT;
size_t namelen;
for (i = 0; i < sizeof(local_hostlist_init) / sizeof(struct local_hostlist_entry); i++) {
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) {
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;
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC && defined(DNS_LOCAL_HOSTLIST_INIT) */
}
/**
* Scans the local host-list for a hostname.
*
* @param hostname Hostname to look for in the local host-list
* @return The first IP address for the hostname in the local host-list or
* IPADDR_NONE if not found.
*/
static u32_t
dns_lookup_local(const char *hostname)
{
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
struct local_hostlist_entry *entry = local_hostlist_dynamic;
while(entry != NULL) {
if(strcmp(entry->name, hostname) == 0) {
return ip4_addr_get_u32(&entry->addr);
}
entry = entry->next;
}
#else /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
int i;
for (i = 0; i < sizeof(local_hostlist_static) / sizeof(struct local_hostlist_entry); i++) {
if(strcmp(local_hostlist_static[i].name, hostname) == 0) {
return ip4_addr_get_u32(&local_hostlist_static[i].addr);
}
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
return IPADDR_NONE;
}
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
/** Remove all entries from the local host-list for a specific hostname
* and/or IP addess
*
* @param hostname hostname for which entries shall be removed from the local
* host-list
* @param addr address for which entries shall be removed from the local host-list
* @return the number of removed entries
*/
int
dns_local_removehost(const char *hostname, const 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) || ip_addr_cmp(&entry->addr, addr))) {
struct local_hostlist_entry *free_entry;
if (last_entry != NULL) {
last_entry->next = entry->next;
} else {
local_hostlist_dynamic = entry->next;
}
free_entry = entry;
entry = entry->next;
memp_free(MEMP_LOCALHOSTLIST, free_entry);
removed++;
} else {
last_entry = entry;
entry = entry->next;
}
}
return removed;
}
/**
* Add a hostname/IP address pair to the local host-list.
* Duplicates are not checked.
*
* @param hostname hostname of the new entry
* @param addr IP address of the new entry
* @return ERR_OK if succeeded or ERR_MEM on memory error
*/
err_t
dns_local_addhost(const char *hostname, const ip_addr_t *addr)
{
struct local_hostlist_entry *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 = (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;
}
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC*/
#endif /* DNS_LOCAL_HOSTLIST */
/**
* Look up a hostname in the array of known hostnames.
*
@@ -297,14 +442,27 @@ dns_tmr(void)
* 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: != 0) or 0 if the hostname was not found
* in the cached dns_table.
* @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
dns_lookup(const char *name)
{
u8_t i;
#if DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN)
u32_t addr;
#endif /* DNS_LOCAL_HOSTLIST || defined(DNS_LOOKUP_LOCAL_EXTERN) */
#if DNS_LOCAL_HOSTLIST
if ((addr = dns_lookup_local(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOCAL_HOSTLIST */
#ifdef DNS_LOOKUP_LOCAL_EXTERN
if((addr = DNS_LOOKUP_LOCAL_EXTERN(name)) != IPADDR_NONE) {
return addr;
}
#endif /* DNS_LOOKUP_LOCAL_EXTERN */
/* Walk through name list, return entry if found. If not, return NULL. */
for (i = 0; i < DNS_TABLE_SIZE; ++i) {
@@ -313,11 +471,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 0;
return IPADDR_NONE;
}
#if DNS_DOES_NAME_CHECK
@@ -412,20 +570,20 @@ 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(struct dns_hdr) + DNS_MAX_NAME_LENGTH +
sizeof(struct dns_query), PBUF_RAM);
p = pbuf_alloc(PBUF_TRANSPORT, SIZEOF_DNS_HDR + DNS_MAX_NAME_LENGTH +
SIZEOF_DNS_QUERY, PBUF_RAM);
if (p != NULL) {
LWIP_ASSERT("pbuf must be in one piece", p->next == NULL);
/* fill dns header */
hdr = (struct dns_hdr*)p->payload;
memset(hdr, 0, sizeof(struct dns_hdr));
memset(hdr, 0, SIZEOF_DNS_HDR);
hdr->id = htons(id);
hdr->flags1 = DNS_FLAG1_RD;
hdr->numquestions = htons(1);
query = (char*)hdr + sizeof(struct dns_hdr);
hdr->numquestions = PP_HTONS(1);
query = (char*)hdr + SIZEOF_DNS_HDR;
pHostname = name;
--pHostname;
@@ -444,12 +602,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(struct 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(struct 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);
@@ -477,6 +635,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);
@@ -491,14 +650,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;
@@ -520,7 +683,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;
}
@@ -563,20 +730,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);
@@ -587,25 +748,16 @@ 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(struct dns_hdr) + sizeof(struct dns_query) + sizeof(struct dns_answer))) {
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;
goto memerr;
}
#if (DNS_USES_STATIC_BUF == 2)
dns_payload = mem_malloc(p->tot_len);
if (dns_payload == NULL) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: mem_malloc error\n"));
/* free pbuf and return */
goto memerr1;
}
#endif /* (DNS_USES_STATIC_BUF == 2) */
/* copy dns payload inside static buffer for processing */
if (pbuf_copy_partial(p, dns_payload, p->tot_len, 0) == p->tot_len) {
/* The ID in the DNS header should be our entry into the name table. */
@@ -632,7 +784,7 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
#if DNS_DOES_NAME_CHECK
/* Check if the name in the "question" part match with the name in the entry. */
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + sizeof(struct dns_hdr)) != 0) {
if (dns_compare_name((unsigned char *)(pEntry->name), (unsigned char *)dns_payload + SIZEOF_DNS_HDR) != 0) {
LWIP_DEBUGF(DNS_DEBUG, ("dns_recv: \"%s\": response not match to query\n", pEntry->name));
/* call callback to indicate error, clean up memory and return */
goto responseerr;
@@ -640,22 +792,23 @@ dns_recv(void *arg, struct udp_pcb *pcb, struct pbuf *p, struct ip_addr *addr, u
#endif /* DNS_DOES_NAME_CHECK */
/* Skip the name in the "question" part */
pHostname = (char *) dns_parse_name((unsigned char *)dns_payload + sizeof(struct dns_hdr)) + sizeof(struct dns_query);
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(struct 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(struct 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"));
@@ -664,9 +817,9 @@ 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(struct dns_answer) + htons(ans.len);
pHostname = pHostname + SIZEOF_DNS_ANSWER + htons(ans.len);
}
--nanswers;
}
@@ -678,7 +831,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 */
@@ -689,13 +842,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;
@@ -715,6 +862,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;
@@ -754,7 +902,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);
@@ -772,9 +922,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!)
@@ -782,28 +933,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 = 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)) != 0)) {
/* 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;
}

View File

@@ -39,8 +39,9 @@
#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
@@ -57,8 +58,9 @@
#ifndef LWIP_CHKSUM
# define LWIP_CHKSUM lwip_standard_chksum
# ifndef LWIP_CHKSUM_ALGORITHM
# define LWIP_CHKSUM_ALGORITHM 1
# define LWIP_CHKSUM_ALGORITHM 2
# endif
u16_t lwip_standard_chksum(void *dataptr, int len);
#endif
/* If none set: */
#ifndef LWIP_CHKSUM_ALGORITHM
@@ -76,7 +78,7 @@
* @note accumulator size limits summable length to 64k
* @note host endianess is irrelevant (p3 RFC1071)
*/
static u16_t
u16_t
lwip_standard_chksum(void *dataptr, u16_t len)
{
u32_t acc;
@@ -86,8 +88,7 @@ lwip_standard_chksum(void *dataptr, u16_t len)
acc = 0;
/* dataptr may be at odd or even addresses */
octetptr = (u8_t*)dataptr;
while (len > 1)
{
while (len > 1) {
/* declare first octet as most significant
thus assume network order, ignoring host order */
src = (*octetptr) << 8;
@@ -98,15 +99,14 @@ lwip_standard_chksum(void *dataptr, u16_t len)
acc += src;
len -= 2;
}
if (len > 0)
{
if (len > 0) {
/* accumulate remaining octet */
src = (*octetptr) << 8;
acc += src;
}
/* add deferred carry bits */
acc = (acc >> 16) + (acc & 0x0000ffffUL);
if ((acc & 0xffff0000) != 0) {
if ((acc & 0xffff0000UL) != 0) {
acc = (acc >> 16) + (acc & 0x0000ffffUL);
}
/* This maybe a little confusing: reorder sum using htons()
@@ -132,13 +132,13 @@ lwip_standard_chksum(void *dataptr, u16_t len)
* @return host order (!) lwip checksum (non-inverted Internet sum)
*/
static u16_t
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) {
@@ -147,28 +147,31 @@ 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;
}
/* Consume left-over byte, if any */
if (len > 0)
((u8_t *)&t)[0] = *(u8_t *)ps;;
if (len > 0) {
((u8_t *)&t)[0] = *(u8_t *)ps;
}
/* Add end bytes */
sum += t;
/* Fold 32-bit sum to 16 bits */
while ((sum >> 16) != 0)
sum = (sum & 0xffff) + (sum >> 16);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
/* Swap if alignment was odd */
if (odd)
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return sum;
return (u16_t)sum;
}
#endif
@@ -185,15 +188,15 @@ lwip_standard_chksum(void *dataptr, int len)
* by Curt McDowell, Broadcom Corp. December 8th, 2005
*/
static u16_t
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++;
@@ -202,7 +205,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;
}
@@ -211,18 +214,20 @@ lwip_standard_chksum(void *dataptr, int len)
while (len > 7) {
tmp = sum + *pl++; /* ping */
if (tmp < sum)
if (tmp < sum) {
tmp++; /* add back carry */
}
sum = tmp + *pl++; /* pong */
if (sum < tmp)
if (sum < tmp) {
sum++; /* add back carry */
}
len -= 8;
}
/* make room in upper bits */
sum = (sum >> 16) + (sum & 0xffff);
sum = FOLD_U32T(sum);
ps = (u16_t *)pl;
@@ -233,73 +238,59 @@ lwip_standard_chksum(void *dataptr, int len)
}
/* dangling tail byte remaining? */
if (len > 0) /* include odd byte */
if (len > 0) { /* include odd byte */
((u8_t *)&t)[0] = *(u8_t *)ps;
}
sum += t; /* add end bytes */
while ((sum >> 16) != 0) /* combine halves */
sum = (sum >> 16) + (sum & 0xffff);
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
sum = FOLD_U32T(sum);
sum = FOLD_U32T(sum);
if (odd)
sum = ((sum & 0xff) << 8) | ((sum & 0xff00) >> 8);
if (odd) {
sum = SWAP_BYTES_IN_WORD(sum);
}
return sum;
return (u16_t)sum;
}
#endif
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len)
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
static u16_t
inet_cksum_pseudo_base(struct pbuf *p, u8_t proto, u16_t proto_len, u32_t acc)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
u8_t swapped = 0;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; q != NULL; q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
(void *)q, (void *)q->next));
acc += LWIP_CHKSUM(q->payload, q->len);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
while ((acc >> 16) != 0) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
/* just executing this next line is probably faster that the if statement needed
to check whether we really need to execute it, and does no harm */
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (src->addr & 0xffffUL);
acc += ((src->addr >> 16) & 0xffffUL);
acc += (dest->addr & 0xffffUL);
acc += ((dest->addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
while ((acc >> 16) != 0) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
@@ -317,17 +308,69 @@ inet_chksum_pseudo(struct pbuf *p,
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo_partial(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len)
inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip_addr_t *src, ip_addr_t *dest)
{
u32_t acc;
u32_t addr;
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);
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
}
#if LWIP_IPV6
/**
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
* IPv6 addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ipv6 address (used for checksum of pseudo header)
* @param dst destination ipv6 address (used for checksum of pseudo header)
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip6_addr_t *src, ip6_addr_t *dest)
{
u32_t acc = 0;
u32_t addr;
u8_t addr_part;
for (addr_part = 0; addr_part < 4; addr_part++) {
addr = src->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = dest->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
}
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_base(p, proto, proto_len, acc);
}
#endif /* LWIP_IPV6 */
/** Parts of the pseudo checksum which are common to IPv4 and IPv6 */
static u16_t
inet_cksum_pseudo_partial_base(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, u32_t acc)
{
struct pbuf *q;
u8_t swapped;
u8_t swapped = 0;
u16_t chklen;
acc = 0;
swapped = 0;
/* iterate through all pbuf in chain */
for(q = p; (q != NULL) && (chksum_len > 0); q = q->next) {
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): checksumming pbuf %p (has next %p) \n",
@@ -340,33 +383,100 @@ inet_chksum_pseudo_partial(struct pbuf *p,
chksum_len -= chklen;
LWIP_ASSERT("delete me", chksum_len < 0x7fff);
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): unwrapped lwip_chksum()=%"X32_F" \n", acc));*/
while ((acc >> 16) != 0) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
/* fold the upper bit down */
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
/*LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): wrapped lwip_chksum()=%"X32_F" \n", acc));*/
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00UL) >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
acc += (src->addr & 0xffffUL);
acc += ((src->addr >> 16) & 0xffffUL);
acc += (dest->addr & 0xffffUL);
acc += ((dest->addr >> 16) & 0xffffUL);
acc += (u32_t)htons((u16_t)proto);
acc += (u32_t)htons(proto_len);
while ((acc >> 16) != 0) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
/* Fold 32-bit sum to 16 bits
calling this twice is propably faster than if statements... */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
LWIP_DEBUGF(INET_DEBUG, ("inet_chksum_pseudo(): pbuf chain lwip_chksum()=%"X32_F"\n", acc));
return (u16_t)~(acc & 0xffffUL);
}
/* inet_chksum_pseudo_partial:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
* IP addresses are expected to be in network byte order.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ip address (used for checksum of pseudo header)
* @param dst destination ip address (used for checksum of pseudo header)
* @param proto ip protocol (used for checksum of pseudo header)
* @param proto_len length of the ip data part (used for checksum of pseudo header)
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest)
{
u32_t acc;
u32_t addr;
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);
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
}
#if LWIP_IPV6
/**
* Calculates the checksum with IPv6 pseudo header used by TCP and UDP for a pbuf chain.
* IPv6 addresses are expected to be in network byte order. Will only compute for a
* portion of the payload.
*
* @param p chain of pbufs over that a checksum should be calculated (ip data part)
* @param src source ipv6 address (used for checksum of pseudo header)
* @param dst destination ipv6 address (used for checksum of pseudo header)
* @param proto ipv6 protocol/next header (used for checksum of pseudo header)
* @param proto_len length of the ipv6 payload (used for checksum of pseudo header)
* @param chksum_len number of payload bytes used to compute chksum
* @return checksum (as u16_t) to be saved directly in the protocol header
*/
u16_t
ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest)
{
u32_t acc = 0;
u32_t addr;
u8_t addr_part;
for (addr_part = 0; addr_part < 4; addr_part++) {
addr = src->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
addr = dest->addr[addr_part];
acc += (addr & 0xffffUL);
acc += ((addr >> 16) & 0xffffUL);
}
/* fold down to 16 bits */
acc = FOLD_U32T(acc);
acc = FOLD_U32T(acc);
return inet_cksum_pseudo_partial_base(p, proto, proto_len, chksum_len, acc);
}
#endif /* LWIP_IPV6 */
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarily for IP
@@ -380,13 +490,7 @@ inet_chksum_pseudo_partial(struct pbuf *p,
u16_t
inet_chksum(void *dataptr, u16_t len)
{
u32_t acc;
acc = LWIP_CHKSUM(dataptr, len);
while ((acc >> 16) != 0) {
acc = (acc & 0xffff) + (acc >> 16);
}
return (u16_t)~(acc & 0xffff);
return ~LWIP_CHKSUM(dataptr, len);
}
/**
@@ -407,17 +511,35 @@ inet_chksum_pbuf(struct pbuf *p)
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += LWIP_CHKSUM(q->payload, q->len);
while ((acc >> 16) != 0) {
acc = (acc & 0xffffUL) + (acc >> 16);
}
acc = FOLD_U32T(acc);
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = (acc & 0x00ffUL << 8) | (acc & 0xff00UL >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
}
if (swapped) {
acc = ((acc & 0x00ffUL) << 8) | ((acc & 0xff00UL) >> 8);
acc = SWAP_BYTES_IN_WORD(acc);
}
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) */

View File

@@ -49,11 +49,16 @@
#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"
#include "lwip/ip6.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
/* Compile-time sanity checks for configuration errors.
* These can be done independently of LWIP_DEBUG, without penalty.
@@ -61,6 +66,9 @@
#ifndef BYTE_ORDER
#error "BYTE_ORDER is not defined, you have to define it in your cc.h"
#endif
#if (!IP_SOF_BROADCAST && IP_SOF_BROADCAST_RECV)
#error "If you want to use broadcast filter per pcb on recv operations, you have to define IP_SOF_BROADCAST=1 in your lwipopts.h"
#endif
#if (!LWIP_ARP && ARP_QUEUEING)
#error "If you want to use ARP Queueing, you have to define LWIP_ARP=1 in your lwipopts.h"
#endif
@@ -76,12 +84,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
@@ -100,6 +108,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
@@ -109,9 +120,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
@@ -143,7 +151,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))
@@ -155,6 +163,33 @@
#if (MEM_USE_POOLS && !MEMP_USE_CUSTOM_POOLS)
#error "MEM_USE_POOLS requires custom pools (MEMP_USE_CUSTOM_POOLS) to be enabled in your lwipopts.h"
#endif
#if (PBUF_POOL_BUFSIZE <= MEM_ALIGNMENT)
#error "PBUF_POOL_BUFSIZE must be greater than MEM_ALIGNMENT or the offset may take the full first pbuf"
#endif
#if (TCP_QUEUE_OOSEQ && !LWIP_TCP)
#error "TCP_QUEUE_OOSEQ requires LWIP_TCP"
#endif
#if (DNS_LOCAL_HOSTLIST && !DNS_LOCAL_HOSTLIST_IS_DYNAMIC && !(defined(DNS_LOCAL_HOSTLIST_INIT)))
#error "you have to define define DNS_LOCAL_HOSTLIST_INIT {{'host1', 0x123}, {'host2', 0x234}} to initialize DNS_LOCAL_HOSTLIST"
#endif
#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 || LWIP_IPV6) && !defined(LWIP_RAND)
#error "When using IGMP or IPv6, 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.
@@ -177,11 +212,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
@@ -195,15 +225,32 @@ lwip_sanity_check(void)
#if LWIP_TCP
if (MEMP_NUM_TCP_SEG < TCP_SND_QUEUELEN)
LWIP_PLATFORM_DIAG(("lwip_sanity_check: WARNING: MEMP_NUM_TCP_SEG should be at least as big as TCP_SND_QUEUELEN\n"));
if (TCP_SND_BUF < 2 * TCP_MSS)
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()
@@ -220,7 +267,9 @@ lwip_init(void)
/* Modules initialization */
stats_init();
#if !NO_SYS
sys_init();
#endif /* !NO_SYS */
mem_init();
memp_init();
pbuf_init();
@@ -241,6 +290,9 @@ lwip_init(void)
#if LWIP_TCP
tcp_init();
#endif /* LWIP_TCP */
#if LWIP_SNMP
snmp_init();
#endif /* LWIP_SNMP */
#if LWIP_AUTOIP
autoip_init();
#endif /* LWIP_AUTOIP */
@@ -250,4 +302,15 @@ lwip_init(void)
#if LWIP_DNS
dns_init();
#endif /* LWIP_DNS */
#if LWIP_IPV6
ip6_init();
nd6_init();
#if LWIP_IPV6_MLD
mld6_init();
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if LWIP_TIMERS
sys_timeouts_init();
#endif /* LWIP_TIMERS */
}

View File

@@ -76,7 +76,15 @@
#include <stdlib.h>
#include <string.h>
/* Pseudo random macro based on netif informations.
/* 169.254.0.0 */
#define AUTOIP_NET 0xA9FE0000
/* 169.254.1.0 */
#define AUTOIP_RANGE_START (AUTOIP_NET | 0x0100)
/* 169.254.254.255 */
#define AUTOIP_RANGE_END (AUTOIP_NET | 0xFEFF)
/** Pseudo random macro based on netif informations.
* You could use "rand()" from the C Library if you define LWIP_AUTOIP_RAND in lwipopts.h */
#ifndef LWIP_AUTOIP_RAND
#define LWIP_AUTOIP_RAND(netif) ( (((u32_t)((netif->hwaddr[5]) & 0xff) << 24) | \
@@ -86,11 +94,24 @@
(netif->autoip?netif->autoip->tried_llipaddr:0))
#endif /* LWIP_AUTOIP_RAND */
/**
* Macro that generates the initial IP address to be tried by AUTOIP.
* If you want to override this, define it to something else in lwipopts.h.
*/
#ifndef LWIP_AUTOIP_CREATE_SEED_ADDR
#define LWIP_AUTOIP_CREATE_SEED_ADDR(netif) \
htonl(AUTOIP_RANGE_START + ((u32_t)(((u8_t)(netif->hwaddr[4])) | \
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)))
#endif /* LWIP_AUTOIP_CREATE_SEED_ADDR */
/* static functions */
static void autoip_handle_arp_conflict(struct netif *netif);
/* creates random LL IP-Address for a network interface */
static void autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr);
/* creates a pseudo random LL IP-Address for a network interface */
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);
/* sends an ARP announce */
static err_t autoip_arp_announce(struct netif *netif);
@@ -98,13 +119,38 @@ static err_t autoip_arp_announce(struct netif *netif);
/* configure interface for use with current LL IP-Address */
static err_t autoip_bind(struct netif *netif);
/**
* Initialize this module
/* start sending probes for llipaddr */
static void autoip_start_probing(struct netif *netif);
/** 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_init(void)
autoip_set_struct(struct netif *netif, struct autoip *autoip)
{
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_init()\n"));
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);
}
/**
@@ -116,27 +162,27 @@ autoip_handle_arp_conflict(struct netif *netif)
/* Somehow detect if we are defending or retreating */
unsigned char defend = 1; /* tbd */
if(defend) {
if(netif->autoip->lastconflict > 0) {
if (defend) {
if (netif->autoip->lastconflict > 0) {
/* retreat, there was a conflicting ARP in the last
* DEFEND_INTERVAL seconds
*/
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("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 | 1,
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("autoip_handle_arp_conflict(): we are defend, send ARP Announce\n"));
autoip_arp_announce(netif);
netif->autoip->lastconflict = DEFEND_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
} else {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
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);
}
}
@@ -144,30 +190,47 @@ autoip_handle_arp_conflict(struct netif *netif)
* Create an IP-Address out of range 169.254.1.0 to 169.254.254.255
*
* @param netif network interface on which create the IP-Address
* @param RandomIPAddr ip address to initialize
* @param ipaddr ip address to initialize
*/
static void
autoip_create_rand_addr(struct netif *netif, struct ip_addr *RandomIPAddr)
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
* We have 254 * 256 possibilities
*/
RandomIPAddr->addr = (0xA9FE0100 + ((u32_t)(((u8_t)(netif->hwaddr[4])) |
((u32_t)((u8_t)(netif->hwaddr[5]))) << 8)) + netif->autoip->tried_llipaddr);
* We have 254 * 256 possibilities */
if (RandomIPAddr->addr>0xA9FEFEFF) {
RandomIPAddr->addr = (0xA9FE0100 + (RandomIPAddr->addr-0xA9FEFEFF));
u32_t addr = ntohl(LWIP_AUTOIP_CREATE_SEED_ADDR(netif));
addr += netif->autoip->tried_llipaddr;
addr = AUTOIP_NET | (addr & 0xffff);
/* Now, 169.254.0.0 <= addr <= 169.254.255.255 */
if (addr < AUTOIP_RANGE_START) {
addr += AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
}
if (RandomIPAddr->addr<0xA9FE0100) {
RandomIPAddr->addr = (0xA9FEFEFF - (0xA9FE0100-RandomIPAddr->addr));
if (addr > AUTOIP_RANGE_END) {
addr -= AUTOIP_RANGE_END - AUTOIP_RANGE_START + 1;
}
RandomIPAddr->addr = htonl(RandomIPAddr->addr);
LWIP_ASSERT("AUTOIP address not in range", (addr >= AUTOIP_RANGE_START) &&
(addr <= AUTOIP_RANGE_END));
ip4_addr_set_u32(ipaddr, htonl(addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
("autoip_create_rand_addr(): tried_llipaddr=%"U16_F", 0x%08"X32_F"\n",
(u16_t)(netif->autoip->tried_llipaddr), (u32_t)(RandomIPAddr->addr)));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("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)));
}
/**
* Sends an ARP probe from a network interface
*
* @param netif network interface used to send the probe
*/
static err_t
autoip_arp_probe(struct netif *netif)
{
return etharp_raw(netif, (struct eth_addr *)netif->hwaddr, &ethbroadcast,
(struct eth_addr *)netif->hwaddr, IP_ADDR_ANY, &ethzero,
&netif->autoip->llipaddr, ARP_REQUEST);
}
/**
@@ -192,11 +255,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 | 3,
("autoip_bind(netif=%p) %c%c%"U16_F" 0x%08"X32_F"\n",
(void*)netif, netif->name[0], netif->name[1], (u16_t)netif->num, autoip->llipaddr.addr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("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);
@@ -222,31 +287,31 @@ autoip_start(struct netif *netif)
struct autoip *autoip = netif->autoip;
err_t result = ERR_OK;
if(netif_is_up(netif)) {
if (netif_is_up(netif)) {
netif_set_down(netif);
}
/* Set IP-Address, Netmask and Gateway to 0 to make sure that
* ARP Packets are formed correctly
*/
netif->ip_addr.addr = 0;
netif->netmask.addr = 0;
netif->gw.addr = 0;
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],
netif->name[1], (u16_t)netif->num));
if(autoip == NULL) {
if (autoip == NULL) {
/* no AutoIP client attached yet? */
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_start(): starting new AUTOIP client\n"));
autoip = mem_malloc(sizeof(struct autoip));
if(autoip == NULL) {
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"));
@@ -254,14 +319,27 @@ 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_rand_addr(netif, &(autoip->llipaddr));
autoip->tried_llipaddr++;
autoip_create_addr(netif, &(autoip->llipaddr));
autoip_start_probing(netif);
return result;
}
static void
autoip_start_probing(struct netif *netif)
{
struct autoip *autoip = netif->autoip;
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.
@@ -274,12 +352,24 @@ autoip_start(struct netif *netif)
* accquiring and probing address
* compliant to RFC 3927 Section 2.2.1
*/
if(autoip->tried_llipaddr > MAX_CONFLICTS) {
if (autoip->tried_llipaddr > MAX_CONFLICTS) {
autoip->ttw = RATE_LIMIT_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
}
return result;
/**
* Handle a possible change in the network configuration.
*
* If there is an AutoIP address configured, take the interface down
* and begin probing with the same address.
*/
void
autoip_network_changed(struct netif *netif)
{
if (netif->autoip && netif->autoip->state != AUTOIP_STATE_OFF) {
netif_set_down(netif);
autoip_start_probing(netif);
}
}
/**
@@ -306,7 +396,7 @@ autoip_tmr()
while (netif != NULL) {
/* only act on AutoIP configured interfaces */
if (netif->autoip != NULL) {
if(netif->autoip->lastconflict > 0) {
if (netif->autoip->lastconflict > 0) {
netif->autoip->lastconflict--;
}
@@ -316,16 +406,20 @@ autoip_tmr()
switch(netif->autoip->state) {
case AUTOIP_STATE_PROBING:
if(netif->autoip->ttw > 0) {
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if(netif->autoip->sent_num == PROBE_NUM) {
if (netif->autoip->sent_num >= PROBE_NUM) {
netif->autoip->state = AUTOIP_STATE_ANNOUNCING;
netif->autoip->sent_num = 0;
netif->autoip->ttw = ANNOUNCE_WAIT * AUTOIP_TICKS_PER_SECOND;
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 {
etharp_request(netif, &(netif->autoip->llipaddr));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
autoip_arp_probe(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() PROBING Sent Probe\n"));
netif->autoip->sent_num++;
/* calculate time to wait to next probe */
@@ -337,26 +431,33 @@ autoip_tmr()
break;
case AUTOIP_STATE_ANNOUNCING:
if(netif->autoip->ttw > 0) {
if (netif->autoip->ttw > 0) {
netif->autoip->ttw--;
} else {
if(netif->autoip->sent_num == 0) {
if (netif->autoip->sent_num == 0) {
/* We are here the first time, so we waited ANNOUNCE_WAIT seconds
* Now we can bind to an IP address and use it
* Now we can bind to an IP address and use it.
*
* autoip_bind calls netif_set_up. This triggers a gratuitous ARP
* which counts as an announcement.
*/
autoip_bind(netif);
}
if(netif->autoip->sent_num == ANNOUNCE_NUM) {
netif->autoip->state = AUTOIP_STATE_BOUND;
netif->autoip->sent_num = 0;
netif->autoip->ttw = 0;
} else {
autoip_arp_announce(netif);
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3,
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE,
("autoip_tmr() ANNOUNCING Sent Announce\n"));
netif->autoip->sent_num++;
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
}
netif->autoip->ttw = ANNOUNCE_INTERVAL * AUTOIP_TICKS_PER_SECOND;
netif->autoip->sent_num++;
if (netif->autoip->sent_num >= ANNOUNCE_NUM) {
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;
@@ -376,27 +477,22 @@ autoip_tmr()
void
autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
{
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | 3, ("autoip_arp_reply()\n"));
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE, ("autoip_arp_reply()\n"));
if ((netif->autoip != NULL) && (netif->autoip->state != AUTOIP_STATE_OFF)) {
/* when ip.src == llipaddr && hw.src != netif->hwaddr
*
* when probing ip.dst == llipaddr && hw.src != netif->hwaddr
* we have a conflict and must solve it
*/
struct ip_addr sipaddr, dipaddr;
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).
*/
MEMCPY(&sipaddr, &hdr->sipaddr, sizeof(sipaddr));
MEMCPY(&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) &&
@@ -410,9 +506,9 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
if ((ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr)) ||
(ip_addr_cmp(&dipaddr, &netif->autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr))) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
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:
@@ -421,7 +517,7 @@ autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr)
*/
if (ip_addr_cmp(&sipaddr, &netif->autoip->llipaddr) &&
!eth_addr_cmp(&netifaddr, &hdr->shwaddr)) {
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 1,
LWIP_DEBUGF(AUTOIP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | LWIP_DBG_LEVEL_WARNING,
("autoip_arp_reply(): Conflicting ARP-Packet detected\n"));
autoip_handle_arp_conflict(netif);
}

View File

@@ -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"
@@ -53,16 +52,25 @@
#include <string.h>
/** Small optimization: set to 0 if incoming PBUF_POOL pbuf always can be
* used to modify and send a response packet (and to 1 if this is not the case,
* e.g. when link header is stripped of when receiving) */
#ifndef LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
#define LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN 1
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
/* The amount of data from the original packet to return in a dest-unreachable */
#define ICMP_DEST_UNREACH_DATASIZE 8
static void icmp_send_response(struct pbuf *p, u8_t type, u8_t code);
/**
* Processes ICMP input packets, called from ip_input().
*
* Currently only processes icmp echo requests and sends
* out the echo response.
*
* @param p the icmp echo request packet, p->payload pointing to the ip header
* @param p the icmp echo request packet, p->payload pointing to the icmp header
* @param inp the netif on which this packet was received
*/
void
@@ -74,16 +82,14 @@ 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 *)ip_current_header();
hlen = IPH_HL(iphdr) * 4;
if (pbuf_header(p, -hlen) || (p->tot_len < sizeof(u16_t)*2)) {
if (p->len < sizeof(u16_t)*2) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: short ICMP (%"U16_F" bytes) received\n", p->tot_len));
goto lenerr;
}
@@ -93,14 +99,35 @@ 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:
/* broadcast or multicast destination address? */
if (ip_addr_isbroadcast(&iphdr->dest, inp) || ip_addr_ismulticast(&iphdr->dest)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
ICMP_STATS_INC(icmp.err);
pbuf_free(p);
return;
#if !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING
{
int accepted = 1;
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip_addr_ismulticast(ip_current_dest_addr())) {
accepted = 0;
}
#endif /* LWIP_MULTICAST_PING */
#if !LWIP_BROADCAST_PING
/* broadcast destination address? */
if (ip_addr_isbroadcast(ip_current_dest_addr(), inp)) {
accepted = 0;
}
#endif /* LWIP_BROADCAST_PING */
/* broadcast or multicast destination address not acceptd? */
if (!accepted) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: Not echoing to multicast or broadcast pings\n"));
ICMP_STATS_INC(icmp.err);
pbuf_free(p);
return;
}
}
#endif /* !LWIP_MULTICAST_PING || !LWIP_BROADCAST_PING */
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
@@ -113,6 +140,7 @@ icmp_input(struct pbuf *p, struct netif *inp)
snmp_inc_icmpinerrors();
return;
}
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
if (pbuf_header(p, (PBUF_IP_HLEN + PBUF_LINK_HLEN))) {
/* p is not big enough to contain link headers
* allocate a new one and copy p into it
@@ -136,7 +164,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);
@@ -153,19 +181,19 @@ icmp_input(struct pbuf *p, struct netif *inp)
goto memerr;
}
}
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
/* At this point, all checks are OK. */
/* We generate an answer by switching the dest and src ip addresses,
* setting the icmp type to ECHO_RESPONSE and updating the checksum. */
iecho = p->payload;
tmpaddr.addr = iphdr->src.addr;
iphdr->src.addr = iphdr->dest.addr;
iphdr->dest.addr = tmpaddr.addr;
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. */
@@ -185,7 +213,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));
@@ -205,11 +234,13 @@ lenerr:
ICMP_STATS_INC(icmp.lenerr);
snmp_inc_icmpinerrors();
return;
#if LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN
memerr:
pbuf_free(p);
ICMP_STATS_INC(icmp.err);
snmp_inc_icmpinerrors();
return;
#endif /* LWIP_ICMP_ECHO_CHECK_INPUT_PBUF_LEN */
}
/**
@@ -224,40 +255,7 @@ memerr:
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
/* ICMP header + IP header + 8 bytes of data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
iphdr = p->payload;
idur = q->payload;
ICMPH_TYPE_SET(idur, ICMP_DUR);
ICMPH_CODE_SET(idur, t);
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), p->payload,
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
/* calculate checksum */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpoutdestunreachs();
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
icmp_send_response(p, ICMP_DUR, t);
}
#if IP_FORWARD || IP_REASSEMBLY
@@ -270,48 +268,67 @@ icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
*/
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
{
icmp_send_response(p, ICMP_TE, t);
}
#endif /* IP_FORWARD || IP_REASSEMBLY */
/**
* Send an icmp packet in response to an incoming packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IP header
* @param type Type of the ICMP header
* @param code Code of the ICMP header
*/
static void
icmp_send_response(struct pbuf *p, u8_t type, u8_t code)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
/* 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_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp_echo_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMP packet.\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (sizeof(struct icmp_dur_hdr) + IP_HLEN + ICMP_DEST_UNREACH_DATASIZE)));
(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"));
tehdr = q->payload;
ICMPH_TYPE_SET(tehdr, ICMP_TE);
ICMPH_CODE_SET(tehdr, t);
icmphdr = (struct icmp_echo_hdr *)q->payload;
icmphdr->type = type;
icmphdr->code = code;
icmphdr->id = 0;
icmphdr->seqno = 0;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_dur_hdr), (u8_t *)p->payload,
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp_echo_hdr), (u8_t *)p->payload,
IP_HLEN + ICMP_DEST_UNREACH_DATASIZE);
/* calculate checksum */
tehdr->chksum = 0;
tehdr->chksum = inet_chksum(tehdr, q->len);
icmphdr->chksum = 0;
icmphdr->chksum = inet_chksum(icmphdr, q->len);
ICMP_STATS_INC(icmp.xmit);
/* increase number of messages attempted to send */
snmp_inc_icmpoutmsgs();
/* increase number of destination unreachable messages attempted to send */
snmp_inc_icmpouttimeexcds();
ip_output(q, NULL, &(iphdr->src), ICMP_TTL, 0, IP_PROTO_ICMP);
ip_addr_copy(iphdr_src, iphdr->src);
ip_output(q, NULL, &iphdr_src, ICMP_TTL, 0, IP_PROTO_ICMP);
pbuf_free(q);
}
#endif /* IP_FORWARD */
#endif /* LWIP_ICMP */

View File

@@ -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,59 @@ 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_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 +173,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 %x\n", (int) group->interface));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", group->netif));
group = group->next;
}
LWIP_DEBUGF(IGMP_DEBUG, ("\n"));
@@ -147,7 +192,7 @@ igmp_start(struct netif *netif)
{
struct igmp_group* group;
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %x\n", (int) netif));
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: starting IGMP processing on if %p\n", netif));
group = igmp_lookup_group(netif, &allsystems);
@@ -159,8 +204,8 @@ igmp_start(struct netif *netif)
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_start: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, &allsystems);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
netif->igmp_mac_filter( netif, &allsystems, IGMP_ADD_MAC_FILTER);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, &allsystems, IGMP_ADD_MAC_FILTER);
}
return ERR_OK;
@@ -185,7 +230,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;
@@ -198,7 +243,7 @@ igmp_stop(struct netif *netif)
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_stop: igmp_mac_filter(DEL "));
ip_addr_debug_print(IGMP_DEBUG, &group->group_address);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, &(group->group_address), IGMP_DEL_MAC_FILTER);
}
/* free group */
@@ -219,15 +264,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 %x\n", (int) netif));
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 +287,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 +313,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 +325,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;
@@ -295,7 +340,7 @@ igmp_lookup_group(struct netif *ifp, struct ip_addr *addr)
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_lookup_group: %sallocated a new group with address ", (group?"":"impossible to ")));
ip_addr_debug_print(IGMP_DEBUG, addr);
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) ifp));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", ifp));
return group;
}
@@ -306,7 +351,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;
@@ -336,21 +381,21 @@ igmp_remove_group(struct igmp_group *group)
/**
* Called from ip_input() if a new IGMP packet is received.
*
* @param p received igmp packet, p->payload pointing to the ip header
* @param p received igmp packet, p->payload pointing to the igmp header
* @param inp network interface on which the packet was received
* @param dest destination ip address of the igmp packet
*/
void
igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
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;
if (pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4)) || (p->len < IGMP_MINLEN)) {
if (p->len < IGMP_MINLEN) {
pbuf_free(p);
IGMP_STATS_INC(igmp.lenerr);
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: length error\n"));
@@ -358,10 +403,10 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
}
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: message from "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->src));
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->src));
LWIP_DEBUGF(IGMP_DEBUG, (" to address "));
ip_addr_debug_print(IGMP_DEBUG, &(iphdr->dest));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %x\n", (int) inp));
ip_addr_debug_print(IGMP_DEBUG, &(ip_current_header()->dest));
LWIP_DEBUGF(IGMP_DEBUG, (" on if %p\n", inp));
/* Now calculate and check the checksum */
igmp = (struct igmp_msg *)p->payload;
@@ -373,11 +418,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 +432,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 */
@@ -439,7 +491,9 @@ igmp_input(struct pbuf *p, struct netif *inp, struct ip_addr *dest)
break;
}
default: {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_input: unexpected msg %x in state %x on group %x on if %x\n", (int) igmp->igmp_msgtype, (int) group->group_state, (int) &group, (int) group->interface));
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->netif));
IGMP_STATS_INC(igmp.proterr);
break;
}
}
@@ -456,7 +510,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;
@@ -488,11 +542,11 @@ igmp_joingroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
if ((group->use==0) && (netif->igmp_mac_filter != NULL)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_joingroup: igmp_mac_filter(ADD "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_ADD_MAC_FILTER);
}
IGMP_STATS_INC(igmp.join_sent);
IGMP_STATS_INC(igmp.tx_join);
igmp_send(group, IGMP_V2_MEMB_REPORT);
igmp_start_timer(group, IGMP_JOIN_DELAYING_MEMBER_TMR);
@@ -526,7 +580,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;
@@ -555,7 +609,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);
}
@@ -563,7 +617,7 @@ igmp_leavegroup(struct ip_addr *ifaddr, struct ip_addr *groupaddr)
if (netif->igmp_mac_filter != NULL) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_leavegroup: igmp_mac_filter(DEL "));
ip_addr_debug_print(IGMP_DEBUG, groupaddr);
LWIP_DEBUGF(IGMP_DEBUG, (") on if %x\n", (int) netif));
LWIP_DEBUGF(IGMP_DEBUG, (") on if %p\n", netif));
netif->igmp_mac_filter(netif, groupaddr, IGMP_DEL_MAC_FILTER);
}
@@ -601,8 +655,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);
}
@@ -617,15 +671,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 %x\n", (int) 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);
}
}
@@ -637,24 +692,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;
}
/**
* Stop a timer for an igmp_group
*
* @param group the igmp_group for which to stop the timer
*/
void
igmp_stop_timer(struct igmp_group *group)
{
group->timer = 0;
/* 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;
}
/**
@@ -663,11 +709,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);
if ((group->group_state == IGMP_GROUP_IDLE_MEMBER) ||
((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;
}
}
@@ -691,68 +739,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)
{
static u16_t ip_id = 0;
struct ip_hdr * iphdr = NULL;
u16_t * ra = NULL;
/* First write in the "router alert" */
if (pbuf_header(p, ROUTER_ALERTLEN)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
return ERR_BUF;
}
/* This is the "router alert" option */
ra = p->payload;
ra[0] = htons (ROUTER_ALERT);
u16_t ra[2];
ra[0] = PP_HTONS(ROUTER_ALERT);
ra[1] = 0x0000; /* Router shall examine packet */
/* now the normal ip header */
if (pbuf_header(p, IP_HLEN)) {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: not enough room for IP header in pbuf\n"));
return ERR_BUF;
}
iphdr = p->payload;
/* Should the IP header be generated or is it already included in p? */
if (dest != IP_HDRINCL) {
/** @todo should be shared with ip.c - ip_output_if */
IPH_TTL_SET(iphdr, ttl);
IPH_PROTO_SET(iphdr, proto);
ip_addr_set(&(iphdr->dest), dest);
IPH_VHLTOS_SET(iphdr, 4, ((IP_HLEN + ROUTER_ALERTLEN) / 4), 0/*tos*/);
IPH_LEN_SET(iphdr, htons(p->tot_len));
IPH_OFFSET_SET(iphdr, 0);
IPH_ID_SET(iphdr, htons(ip_id));
++ip_id;
if (ip_addr_isany(src)) {
ip_addr_set(&(iphdr->src), &(netif->ip_addr));
} else {
ip_addr_set(&(iphdr->src), src);
}
IPH_CHKSUM_SET(iphdr, 0);
#if CHECKSUM_GEN_IP
IPH_CHKSUM_SET(iphdr, inet_chksum(iphdr, (IP_HLEN + ROUTER_ALERTLEN)));
#endif
} else {
dest = &(iphdr->dest);
}
#if IP_DEBUG
ip_debug_print(p);
#endif
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_ip_output_if: sending to if %x\n", (int) netif));
return netif->output(netif, p, dest);
IGMP_STATS_INC(igmp.xmit);
return ip_output_if_opt(p, src, dest, IGMP_TTL, 0, IP_PROTO_IGMP, netif, ra, ROUTER_ALERTLEN);
}
/**
@@ -761,32 +756,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);
}
}
@@ -794,14 +788,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);
pbuf_free(p);
} else {
LWIP_DEBUGF(IGMP_DEBUG, ("igmp_send: not enough memory for igmp_send\n"));
IGMP_STATS_INC(igmp.memerr);
}
}

View File

@@ -43,19 +43,62 @@
#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 */
/** Global data for both IPv4 and IPv6 */
struct ip_globals ip_data;
/** 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
* searches the list of network interfaces linearly. A match is found
@@ -66,7 +109,7 @@
* @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;
@@ -81,7 +124,8 @@ ip_route(struct ip_addr *dest)
}
}
if ((netif_default == NULL) || (!netif_is_up(netif_default))) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_route: No route to 0x%"X32_F"\n", dest->addr));
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;
@@ -99,28 +143,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(ip_current_dest_addr())) {
LWIP_DEBUGF(IP_DEBUG, ("ip_forward: not forwarding LLA %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1_16(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
goto return_noroute;
}
/* Find network interface where to forward this IP packet to. */
netif = ip_route((struct ip_addr *)&(iphdr->dest));
netif = ip_route(ip_current_dest_addr());
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(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
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 */
@@ -134,18 +185,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(ip_current_dest_addr()), ip4_addr2_16(ip_current_dest_addr()),
ip4_addr3_16(ip_current_dest_addr()), ip4_addr4_16(ip_current_dest_addr())));
IP_STATS_INC(ip.fw);
IP_STATS_INC(ip.xmit);
@@ -153,8 +205,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, ip_current_dest_addr());
return;
return_noroute:
snmp_inc_ipoutnoroutes();
}
#endif /* IP_FORWARD */
@@ -179,17 +233,17 @@ 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 | 1, ("IP packet dropped due to bad version number %"U16_F"\n", IPH_V(iphdr)));
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);
pbuf_free(p);
IP_STATS_INC(ip.err);
@@ -207,13 +261,16 @@ ip_input(struct pbuf *p, struct netif *inp)
/* header length exceeds first pbuf length, or ip length exceeds total pbuf length? */
if ((iphdr_hlen > p->len) || (iphdr_len > p->tot_len)) {
if (iphdr_hlen > p->len)
LWIP_DEBUGF(IP_DEBUG | 2, ("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_hlen, p->len));
if (iphdr_len > p->tot_len)
LWIP_DEBUGF(IP_DEBUG | 2, ("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), "
"IP packet dropped.\n",
iphdr_len, p->tot_len));
if (iphdr_hlen > p->len) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("IP header (len %"U16_F") does not fit in first pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_hlen, p->len));
}
if (iphdr_len > p->tot_len) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("IP (len %"U16_F") is longer than pbuf (len %"U16_F"), IP packet dropped.\n",
iphdr_len, p->tot_len));
}
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.lenerr);
@@ -226,7 +283,8 @@ ip_input(struct pbuf *p, struct netif *inp)
#if CHECKSUM_CHECK_IP
if (inet_chksum(iphdr, iphdr_hlen) != 0) {
LWIP_DEBUGF(IP_DEBUG | 2, ("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("Checksum (0x%"X16_F") failed, IP packet dropped.\n", inet_chksum(iphdr, iphdr_hlen)));
ip_debug_print(p);
pbuf_free(p);
IP_STATS_INC(ip.chkerr);
@@ -240,10 +298,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(*ipX_2_ip(&ip_data.current_iphdr_dest), iphdr->dest);
ip_addr_copy(*ipX_2_ip(&ip_data.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(ip_current_dest_addr())) {
if ((inp->flags & NETIF_FLAG_IGMP) && (igmp_lookfor_group(inp, ip_current_dest_addr()))) {
netif = inp;
} else {
netif = NULL;
@@ -258,22 +320,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(ip_current_dest_addr(), &(netif->ip_addr)) ||
/* or broadcast on this interface network address? */
ip_addr_isbroadcast(&(iphdr->dest), netif)) {
ip_addr_isbroadcast(ip_current_dest_addr(), 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(ip_current_dest_addr(), &(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;
@@ -287,33 +360,40 @@ 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) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: UDP packet to DHCP client port %"U16_F"\n",
ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest)));
if (ntohs(((struct udp_hdr *)((u8_t *)iphdr + iphdr_hlen))->dest) == DHCP_CLIENT_PORT) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: DHCP packet accepted.\n"));
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(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 (check_ip_src)
#endif /* LWIP_DHCP */
{ if ((ip_addr_isbroadcast(&(iphdr->src), inp)) ||
(ip_addr_ismulticast(&(iphdr->src)))) {
#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 && !ip_addr_isany(ip_current_src_addr()))
#endif /* IP_ACCEPT_LINK_LAYER_ADDRESSING */
{ if ((ip_addr_isbroadcast(ip_current_src_addr(), inp)) ||
(ip_addr_ismulticast(ip_current_src_addr()))) {
/* packet source is not valid */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet source is not valid.\n"));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_WARNING, ("ip_input: packet source is not valid.\n"));
/* free (drop) packet pbufs */
pbuf_free(p);
IP_STATS_INC(ip.drop);
@@ -326,10 +406,10 @@ ip_input(struct pbuf *p, struct netif *inp)
/* packet not for us? */
if (netif == NULL) {
/* packet not for us, route or discard */
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_TRACE | 1, ("ip_input: packet not for us.\n"));
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(ip_current_dest_addr(), inp)) {
/* try to forward IP packet on (other) interfaces */
ip_forward(p, iphdr, inp);
} else
@@ -342,20 +422,20 @@ 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 | 2, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since it was fragmented (0x%"X16_F") (while IP_REASSEMBLY == 0).\n",
ntohs(IPH_OFFSET(iphdr))));
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
@@ -369,11 +449,11 @@ 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 */
LWIP_DEBUGF(IP_DEBUG | 2, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("IP packet dropped since there were IP options (while IP_OPTIONS_ALLOWED == 0).\n"));
pbuf_free(p);
IP_STATS_INC(ip.opterr);
IP_STATS_INC(ip.drop);
@@ -388,11 +468,16 @@ ip_input(struct pbuf *p, struct netif *inp)
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("ip_input: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len));
ip_data.current_netif = inp;
ip_data.current_ip4_header = iphdr;
ip_data.current_ip_header_tot_len = IPH_HL(iphdr) * 4;
#if LWIP_RAW
/* raw input did not eat the packet? */
if (raw_input(p, inp) == 0)
#endif /* LWIP_RAW */
{
pbuf_header(p, -iphdr_hlen); /* Move to payload, no check necessary. */
switch (IPH_PROTO(iphdr)) {
#if LWIP_UDP
@@ -418,21 +503,22 @@ 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, ip_current_dest_addr());
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(ip_current_dest_addr(), inp) &&
!ip_addr_ismulticast(ip_current_dest_addr())) {
pbuf_header(p, iphdr_hlen); /* Move to ip header, no check necessary. */
p->payload = iphdr;
icmp_dest_unreach(p, ICMP_DUR_PROTO);
}
#endif /* LWIP_ICMP */
pbuf_free(p);
LWIP_DEBUGF(IP_DEBUG | 2, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("Unsupported transport protocol %"U16_F"\n", IPH_PROTO(iphdr)));
IP_STATS_INC(ip.proterr);
IP_STATS_INC(ip.drop);
@@ -440,6 +526,13 @@ ip_input(struct pbuf *p, struct netif *inp)
}
}
/* @todo: this is not really necessary... */
ip_data.current_netif = NULL;
ip_data.current_ip4_header = NULL;
ip_data.current_ip_header_tot_len = 0;
ip_addr_set_any(ip_current_src_addr());
ip_addr_set_any(ip_current_dest_addr());
return ERR_OK;
}
@@ -469,70 +562,161 @@ 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)
{
#if IP_OPTIONS_SEND
return ip_output_if_opt(p, src, dest, ttl, tos, proto, netif, NULL, 0);
}
/**
* Same as ip_output_if() but with the possibility to include IP options:
*
* @ param ip_options pointer to the IP options, copied into the IP header
* @ param optlen length of ip_options
*/
err_t ip_output_if_opt(struct pbuf *p, 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();
/* Should the IP header be generated or is it already included in p? */
if (dest != IP_HDRINCL) {
u16_t ip_hlen = IP_HLEN;
#if IP_OPTIONS_SEND
u16_t optlen_aligned = 0;
if (optlen != 0) {
#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;
/* First write in the IP options */
if (pbuf_header(p, optlen_aligned)) {
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output_if_opt: not enough room for IP options in pbuf\n"));
IP_STATS_INC(ip.err);
snmp_inc_ipoutdiscards();
return ERR_BUF;
}
MEMCPY(p->payload, ip_options, optlen);
if (optlen < optlen_aligned) {
/* zero the remaining bytes */
memset(((char*)p->payload) + optlen, 0, optlen_aligned - optlen);
}
#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 */
if (pbuf_header(p, IP_HLEN)) {
LWIP_DEBUGF(IP_DEBUG | 2, ("ip_output: not enough room for IP header in pbuf\n"));
LWIP_DEBUGF(IP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("ip_output: not enough room for IP header in pbuf\n"));
IP_STATS_INC(ip.err);
snmp_inc_ipoutdiscards();
return ERR_BUF;
}
iphdr = p->payload;
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);
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));
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;
}
#if IP_FRAG
/* don't fragment if interface has mtu set to 0 [loopif] */
if (netif->mtu && (p->tot_len > netif->mtu))
return ip_frag(p,netif,dest);
#endif
IP_STATS_INC(ip.xmit);
LWIP_DEBUGF(IP_DEBUG, ("ip_output_if: %c%c%"U16_F"\n", netif->name[0], netif->name[1], netif->num));
ip_debug_print(p);
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
#if ENABLE_LOOPBACK
if (ip_addr_cmp(dest, &netif->ip_addr)) {
/* Packet to self, enqueue it for loopback */
LWIP_DEBUGF(IP_DEBUG, ("netif_loop_output()"));
return netif_loop_output(netif, p, dest);
}
#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);
}
#endif /* IP_FRAG */
LWIP_DEBUGF(IP_DEBUG, ("netif->output()"));
return netif->output(netif, p, dest);
}
@@ -554,18 +738,70 @@ ip_output_if(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 %"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;
}
return ip_output_if(p, src, dest, ttl, tos, proto, netif);
}
#if LWIP_NETIF_HWADDRHINT
/** Like ip_output, but takes and addr_hint pointer that is passed on to netif->addr_hint
* before calling ip_output_if.
*
* @param p the packet to send (p->payload points to the data, e.g. next
protocol header; if dest == IP_HDRINCL, p already includes an IP
header and p->payload points to that IP header)
* @param src the source IP address to send from (if src == IP_ADDR_ANY, the
* IP address of the netif used to send is used as source address)
* @param dest the destination IP address to send the packet to
* @param ttl the TTL value to be set in the IP header
* @param tos the TOS value to be set in the IP header
* @param proto the PROTOCOL to be set in the IP header
* @param addr_hint address hint pointer set to netif->addr_hint before
* calling ip_output_if()
*
* @return ERR_RTE if no route is found
* see ip_output_if() for more return values
*/
err_t
ip_output_hinted(struct pbuf *p, 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 %"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;
}
NETIF_SET_HWADDRHINT(netif, addr_hint);
err = ip_output_if(p, src, dest, ttl, tos, proto, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
return err;
}
#endif /* LWIP_NETIF_HWADDRHINT*/
#if IP_DEBUG
/* Print an IP header by using LWIP_DEBUGF
* @param p an IP packet, p->payload pointing to the IP header
@@ -573,7 +809,7 @@ ip_output(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;
@@ -599,16 +835,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 */

View File

@@ -1,14 +1,14 @@
/**
* @file
* Functions common to all TCP/IPv4 modules, such as the byte order functions.
* This is the IPv4 address tools implementation.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* 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,
@@ -17,28 +17,97 @@
* 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.
* 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
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#include "lwip/inet.h"
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
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
*
* @param addr address to be checked
* @param netif the network interface against which the address is checked
* @return returns non-zero if the address is a broadcast address
*/
u8_t
ip4_addr_isbroadcast(u32_t addr, const struct netif *netif)
{
ip_addr_t ipaddr;
ip4_addr_set_u32(&ipaddr, addr);
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((~addr == IPADDR_ANY) ||
(addr == IPADDR_ANY)) {
return 1;
/* no broadcast support on this network interface? */
} else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0) {
/* the given address cannot be a broadcast address
* nor can we check against any broadcast addresses */
return 0;
/* address matches network interface address exactly? => no broadcast */
} else if (addr == ip4_addr_get_u32(&netif->ip_addr)) {
return 0;
/* on the same (sub) network... */
} else if (ip_addr_netcmp(&ipaddr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr & ~ip4_addr_get_u32(&netif->netmask)) ==
(IPADDR_BROADCAST & ~ip4_addr_get_u32(&netif->netmask)))) {
/* => network broadcast address */
return 1;
} 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
@@ -48,8 +117,8 @@
#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
#endif
/**
* Ascii internet address interpretation routine.
* The value returned is in network order.
@@ -58,14 +127,14 @@
* @return ip address in network order
*/
u32_t
inet_addr(const char *cp)
ipaddr_addr(const char *cp)
{
struct in_addr val;
ip_addr_t val;
if (inet_aton(cp, &val)) {
return (val.s_addr);
if (ipaddr_aton(cp, &val)) {
return ip4_addr_get_u32(&val);
}
return (INADDR_NONE);
return (IPADDR_NONE);
}
/**
@@ -80,10 +149,11 @@ inet_addr(const char *cp)
* @return 1 if cp could be converted to addr, 0 on failure
*/
int
inet_aton(const char *cp, struct in_addr *addr)
ipaddr_aton(const char *cp, ip_addr_t *addr)
{
u32_t val;
int base, n, c;
u8_t base;
char c;
u32_t parts[4];
u32_t *pp = parts;
@@ -123,8 +193,9 @@ inet_aton(const char *cp, struct in_addr *addr)
* a.b.c (with c treated as 16 bits)
* a.b (with b treated as 24 bits)
*/
if (pp >= parts + 3)
if (pp >= parts + 3) {
return (0);
}
*pp++ = val;
c = *++cp;
} else
@@ -133,14 +204,14 @@ inet_aton(const char *cp, struct in_addr *addr)
/*
* Check for trailing characters.
*/
if (c != '\0' && (!isprint(c) || !isspace(c)))
if (c != '\0' && !isspace(c)) {
return (0);
}
/*
* Concoct the address according to
* the number of parts specified.
*/
n = pp - parts + 1;
switch (n) {
switch (pp - parts + 1) {
case 0:
return (0); /* initial nondigit */
@@ -149,25 +220,32 @@ inet_aton(const char *cp, struct in_addr *addr)
break;
case 2: /* a.b -- 8.24 bits */
if (val > 0xffffffUL)
if (val > 0xffffffUL) {
return (0);
}
val |= parts[0] << 24;
break;
case 3: /* a.b.c -- 8.8.16 bits */
if (val > 0xffff)
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)
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));
}
if (addr)
addr->s_addr = htonl(val);
return (1);
}
@@ -180,18 +258,35 @@ inet_aton(const char *cp, struct in_addr *addr)
* represenation of addr
*/
char *
inet_ntoa(struct in_addr addr)
ipaddr_ntoa(const ip_addr_t *addr)
{
static char str[16];
u32_t s_addr = addr.s_addr;
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;
rp = str;
s_addr = ip4_addr_get_u32(addr);
rp = buf;
ap = (u8_t *)&s_addr;
for(n = 0; n < 4; n++) {
i = 0;
@@ -200,79 +295,18 @@ inet_ntoa(struct in_addr addr)
*ap /= (u8_t)10;
inv[i++] = '0' + rem;
} while(*ap);
while(i--)
while(i--) {
if (len++ >= buflen) {
return NULL;
}
*rp++ = inv[i];
}
if (len++ >= buflen) {
return NULL;
}
*rp++ = '.';
ap++;
}
*--rp = 0;
return str;
return buf;
}
/**
* 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) */

View File

@@ -1,84 +0,0 @@
/**
* @file
* This is the IPv4 address tools implementation.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
#include "lwip/netif.h"
#define IP_ADDR_ANY_VALUE 0x00000000UL
#define IP_ADDR_BROADCAST_VALUE 0xffffffffUL
/* used by IP_ADDR_ANY and IP_ADDR_BROADCAST in ip_addr.h */
const struct ip_addr ip_addr_any = { IP_ADDR_ANY_VALUE };
const struct ip_addr ip_addr_broadcast = { IP_ADDR_BROADCAST_VALUE };
/**
* Determine if an address is a broadcast address on a network interface
*
* @param addr address to be checked
* @param netif the network interface against which the address is checked
* @return returns non-zero if the address is a broadcast address
*/
u8_t ip_addr_isbroadcast(struct ip_addr *addr, struct netif *netif)
{
u32_t addr2test;
addr2test = addr->addr;
/* all ones (broadcast) or all zeroes (old skool broadcast) */
if ((~addr2test == IP_ADDR_ANY_VALUE) ||
(addr2test == IP_ADDR_ANY_VALUE))
return 1;
/* no broadcast support on this network interface? */
else if ((netif->flags & NETIF_FLAG_BROADCAST) == 0)
/* the given address cannot be a broadcast address
* nor can we check against any broadcast addresses */
return 0;
/* address matches network interface address exactly? => no broadcast */
else if (addr2test == netif->ip_addr.addr)
return 0;
/* on the same (sub) network... */
else if (ip_addr_netcmp(addr, &(netif->ip_addr), &(netif->netmask))
/* ...and host identifier bits are all ones? =>... */
&& ((addr2test & ~netif->netmask.addr) ==
(IP_ADDR_BROADCAST_VALUE & ~netif->netmask.addr)))
/* => network broadcast address */
return 1;
else
return 0;
}

View File

@@ -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,12 +80,24 @@
/** This is a helper struct which holds the starting
* offset and the ending offset of this fragment to
* easily chain the fragments.
* 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"
#endif
PACK_STRUCT_BEGIN
struct ip_reass_helper {
struct pbuf *next_pbuf;
u16_t start;
u16_t end;
};
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
PACK_STRUCT_FIELD(u16_t start);
PACK_STRUCT_FIELD(u16_t end);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IP_ADDRESSES_AND_ID_MATCH(iphdrA, iphdrB) \
(ip_addr_cmp(&(iphdrA)->src, &(iphdrB)->src) && \
@@ -146,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;
@@ -166,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 */
@@ -180,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);
@@ -254,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 */
@@ -539,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,
@@ -599,7 +615,39 @@ nullreturn:
#if IP_FRAG
#if IP_FRAG_USES_STATIC_BUF
static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
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 */
/**
@@ -616,13 +664,15 @@ static u8_t buf[LWIP_MEM_ALIGN_SIZE(IP_FRAG_MAX_MTU)];
* @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;
@@ -633,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
@@ -653,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 */
@@ -674,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;
@@ -683,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,
@@ -695,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;
@@ -703,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 */
@@ -735,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

View File

@@ -1,8 +1,14 @@
/**
* @file
*
* DHCPv6.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
@@ -11,42 +17,34 @@
* 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.
* 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
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
* Author: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __NETIF_LOOPIF_H__
#define __NETIF_LOOPIF_H__
#include "lwip/netif.h"
#include "lwip/err.h"
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
#if !LWIP_LOOPIF_MULTITHREADING
void loopif_poll(struct netif *netif);
#endif
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
err_t loopif_init(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif /* __NETIF_LOOPIF_H__ */
#endif /* LWIP_IPV6_DHCP6 */

195
src/core/ipv6/ethip6.c Normal file
View File

@@ -0,0 +1,195 @@
/**
* @file
*
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_ETHERNET
#include "lwip/ethip6.h"
#include "lwip/nd6.h"
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp6.h"
#include <string.h>
#define ETHTYPE_IPV6 0x86DD
/** The ethernet address */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_addr {
PACK_STRUCT_FIELD(u8_t addr[6]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Ethernet header */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct eth_hdr {
#if ETH_PAD_SIZE
PACK_STRUCT_FIELD(u8_t padding[ETH_PAD_SIZE]);
#endif
PACK_STRUCT_FIELD(struct eth_addr dest);
PACK_STRUCT_FIELD(struct eth_addr src);
PACK_STRUCT_FIELD(u16_t type);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define SIZEOF_ETH_HDR (14 + ETH_PAD_SIZE)
/**
* Send an IPv6 packet on the network using netif->linkoutput
* The ethernet header is filled in before sending.
*
* @params netif the lwIP network interface on which to send the packet
* @params p the packet to send, p->payload pointing to the (uninitialized) ethernet header
* @params src the source MAC address to be copied into the ethernet header
* @params dst the destination MAC address to be copied into the ethernet header
* @return ERR_OK if the packet was sent, any other err_t on failure
*/
static err_t
ethip6_send(struct netif *netif, struct pbuf *p, struct eth_addr *src, struct eth_addr *dst)
{
struct eth_hdr *ethhdr = (struct eth_hdr *)p->payload;
LWIP_ASSERT("netif->hwaddr_len must be 6 for ethip6!",
(netif->hwaddr_len == 6));
SMEMCPY(&ethhdr->dest, dst, 6);
SMEMCPY(&ethhdr->src, src, 6);
ethhdr->type = PP_HTONS(ETHTYPE_IPV6);
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE, ("ethip6_send: sending packet %p\n", (void *)p));
/* send the packet */
return netif->linkoutput(netif, p);
}
/**
* Resolve and fill-in Ethernet address header for outgoing IPv6 packet.
*
* For IPv6 multicast, corresponding Ethernet addresses
* are selected and the packet is transmitted on the link.
*
* For unicast addresses, ...
*
* @TODO anycast addresses
*
* @param netif The lwIP network interface which the IP packet will be sent on.
* @param q The pbuf(s) containing the IP packet to be sent.
* @param ip6addr The IP address of the packet destination.
*
* @return
* - ERR_RTE No route to destination (no gateway to external networks),
* or the return type of either etharp_query() or etharp_send_ip().
*/
err_t
ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr)
{
struct eth_addr dest;
s8_t i;
/* make room for Ethernet header - should not fail */
if (pbuf_header(q, sizeof(struct eth_hdr)) != 0) {
/* bail out */
LWIP_DEBUGF(ETHARP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS,
("etharp_output: could not allocate room for header.\n"));
return ERR_BUF;
}
/* multicast destination IP address? */
if (ip6_addr_ismulticast(ip6addr)) {
/* Hash IP multicast address to MAC address.*/
dest.addr[0] = 0x33;
dest.addr[1] = 0x33;
dest.addr[2] = ((u8_t *)(&(ip6addr->addr[3])))[0];
dest.addr[3] = ((u8_t *)(&(ip6addr->addr[3])))[1];
dest.addr[4] = ((u8_t *)(&(ip6addr->addr[3])))[2];
dest.addr[5] = ((u8_t *)(&(ip6addr->addr[3])))[3];
/* Send out. */
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
}
/* We have a unicast destination IP address */
/* TODO anycast? */
/* Get next hop record. */
i = nd6_get_next_hop_entry(ip6addr, netif);
if (i < 0) {
/* failed to get a next hop neighbor record. */
return ERR_MEM;
}
/* Now that we have a destination record, send or queue the packet. */
if (neighbor_cache[i].state == ND6_STALE) {
/* Switch to delay state. */
neighbor_cache[i].state = ND6_DELAY;
neighbor_cache[i].counter.delay_time = LWIP_ND6_DELAY_FIRST_PROBE_TIME;
}
/* TODO should we send or queue if PROBE? send for now, to let unicast NS pass. */
if ((neighbor_cache[i].state == ND6_REACHABLE) ||
(neighbor_cache[i].state == ND6_DELAY) ||
(neighbor_cache[i].state == ND6_PROBE)) {
/* Send out. */
SMEMCPY(dest.addr, neighbor_cache[i].lladdr, 6);
return ethip6_send(netif, q, (struct eth_addr*)(netif->hwaddr), &dest);
}
/* We should queue packet on this interface. */
pbuf_header(q, -(s16_t)SIZEOF_ETH_HDR);
nd6_queue_packet(i, q);
return ERR_OK;
}
#endif /* LWIP_IPV6 && LWIP_ETHERNET */

View File

@@ -1,5 +1,11 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -26,154 +32,270 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Author: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
/* Some ICMP messages should be passed to the transport protocols. This
is not implemented. */
#include "lwip/opt.h"
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/icmp.h"
#include "lwip/inet.h"
#include "lwip/ip.h"
#include "lwip/def.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/nd6.h"
#include "lwip/mld6.h"
#include "lwip/stats.h"
#include <string.h>
#ifndef LWIP_ICMP6_DATASIZE
#define LWIP_ICMP6_DATASIZE 8
#endif
#if LWIP_ICMP6_DATASIZE == 0
#define LWIP_ICMP6_DATASIZE 8
#endif
/* Forward declarations */
static void icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type);
/**
* Process an input ICMPv6 message. Called by ip6_input.
*
* Will generate a reply for echo requests. Other messages are forwarded
* to nd6_input, or mld6_input.
*
* @param p the mld packet, p->payload pointing to the icmpv6 header
* @param inp the netif on which this packet was received
*/
void
icmp_input(struct pbuf *p, struct netif *inp)
icmp6_input(struct pbuf *p, struct netif *inp)
{
u8_t type;
struct icmp_echo_hdr *iecho;
struct ip_hdr *iphdr;
struct ip_addr tmpaddr;
struct icmp6_hdr *icmp6hdr;
struct pbuf * r;
ip6_addr_t * reply_src;
ICMP_STATS_INC(icmp.recv);
ICMP6_STATS_INC(icmp6.recv);
/* TODO: check length before accessing payload! */
/* Check that ICMPv6 header fits in payload */
if (p->len < sizeof(struct icmp6_hdr)) {
/* drop short packets */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.lenerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
type = ((u8_t *)p->payload)[0];
icmp6hdr = (struct icmp6_hdr *)p->payload;
switch (type) {
case ICMP6_ECHO:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ping\n"));
if (p->tot_len < sizeof(struct icmp_echo_hdr)) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: bad ICMP echo received\n"));
#if LWIP_ICMP6_CHECKSUM_CHECK
if (ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->tot_len, ip6_current_src_addr(),
ip6_current_dest_addr()) != 0) {
/* Checksum failed */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.chkerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
#endif /* LWIP_ICMP6_CHECKSUM_CHECK */
switch (icmp6hdr->type) {
case ICMP6_TYPE_NA: /* Neighbor advertisement */
case ICMP6_TYPE_NS: /* Neighbor solicitation */
case ICMP6_TYPE_RA: /* Router advertisement */
case ICMP6_TYPE_RD: /* Redirect */
case ICMP6_TYPE_PTB: /* Packet too big */
nd6_input(p, inp);
return;
break;
case ICMP6_TYPE_RS:
#if LWIP_IPV6_FORWARD
/* TODO implement router functionality */
#endif
break;
#if LWIP_IPV6_MLD
case ICMP6_TYPE_MLQ:
case ICMP6_TYPE_MLR:
case ICMP6_TYPE_MLD:
mld6_input(p, inp);
return;
break;
#endif
case ICMP6_TYPE_EREQ:
#if !LWIP_MULTICAST_PING
/* multicast destination address? */
if (ip6_addr_ismulticast(ip6_current_dest_addr())) {
/* drop */
pbuf_free(p);
ICMP_STATS_INC(icmp.lenerr);
ICMP6_STATS_INC(icmp6.drop);
return;
}
iecho = p->payload;
iphdr = (struct ip_hdr *)((u8_t *)p->payload - IP_HLEN);
if (inet_chksum_pbuf(p) != 0) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
ICMP_STATS_INC(icmp.chkerr);
/* return;*/
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp: p->len %"S16_F" p->tot_len %"S16_F"\n", p->len, p->tot_len));
ip_addr_set(&tmpaddr, &(iphdr->src));
ip_addr_set(&(iphdr->src), &(iphdr->dest));
ip_addr_set(&(iphdr->dest), &tmpaddr);
iecho->type = ICMP6_ER;
/* adjust the checksum */
if (iecho->chksum >= htons(0xffff - (ICMP6_ECHO << 8))) {
iecho->chksum += htons(ICMP6_ECHO << 8) + 1;
} else {
iecho->chksum += htons(ICMP6_ECHO << 8);
}
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: checksum failed for received ICMP echo (%"X16_F")\n", inet_chksum_pseudo(p, &(iphdr->src), &(iphdr->dest), IP_PROTO_ICMP, p->tot_len)));
ICMP_STATS_INC(icmp.xmit);
#endif /* LWIP_MULTICAST_PING */
/* Allocate reply. */
r = pbuf_alloc(PBUF_IP, p->tot_len, PBUF_RAM);
if (r == NULL) {
/* drop */
pbuf_free(p);
ICMP6_STATS_INC(icmp6.memerr);
return;
}
/* Copy echo request. */
if (pbuf_copy(r, p) != ERR_OK) {
/* drop */
pbuf_free(p);
pbuf_free(r);
ICMP6_STATS_INC(icmp6.err);
return;
}
/* Determine reply source IPv6 address. */
reply_src = ip6_select_source_address(inp, ip6_current_src_addr());
if (reply_src == NULL) {
/* drop */
pbuf_free(p);
pbuf_free(r);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
/* Set fields in reply. */
((struct icmp6_echo_hdr *)(r->payload))->type = ICMP6_TYPE_EREP;
((struct icmp6_echo_hdr *)(r->payload))->chksum = 0;
((struct icmp6_echo_hdr *)(r->payload))->chksum = ip6_chksum_pseudo(r,
IP6_NEXTH_ICMP6, r->tot_len, reply_src, ip6_current_src_addr());
/* Send reply. */
ICMP6_STATS_INC(icmp6.xmit);
ip6_output_if(r, reply_src, ip6_current_src_addr(),
LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6, inp);
pbuf_free(r);
/* LWIP_DEBUGF("icmp: p->len %"U16_F" p->tot_len %"U16_F"\n", p->len, p->tot_len);*/
ip_output_if (p, &(iphdr->src), IP_HDRINCL,
iphdr->hoplim, IP_PROTO_ICMP, inp);
break;
default:
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_input: ICMP type %"S16_F" not supported.\n", (s16_t)type));
ICMP_STATS_INC(icmp.proterr);
ICMP_STATS_INC(icmp.drop);
ICMP6_STATS_INC(icmp6.proterr);
ICMP6_STATS_INC(icmp6.drop);
break;
}
pbuf_free(p);
}
/**
* Send an icmpv6 'destination unreachable' packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IPv6 header
* @param c ICMPv6 code for the unreachable type
*/
void
icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t)
icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_dur_hdr *idur;
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
pbuf_free(p);
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (8 + IP_HLEN + 8)));
iphdr = p->payload;
idur = q->payload;
idur->type = (u8_t)ICMP6_DUR;
idur->icode = (u8_t)t;
SMEMCPY((u8_t *)q->payload + 8, p->payload, IP_HLEN + 8);
/* calculate checksum */
idur->chksum = 0;
idur->chksum = inet_chksum(idur, q->len);
ICMP_STATS_INC(icmp.xmit);
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
pbuf_free(q);
icmp6_send_response(p, c, 0, ICMP6_TYPE_DUR);
}
/**
* Send an icmpv6 'packet too big' packet.
*
* @param p the input packet for which the 'packet too big' should be sent,
* p->payload pointing to the IPv6 header
* @param mtu the maximum mtu that we can accept
*/
void
icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t)
icmp6_packet_too_big(struct pbuf *p, u32_t mtu)
{
icmp6_send_response(p, 0, mtu, ICMP6_TYPE_PTB);
}
/**
* Send an icmpv6 'time exceeded' packet.
*
* @param p the input packet for which the 'unreachable' should be sent,
* p->payload pointing to the IPv6 header
* @param c ICMPv6 code for the time exceeded type
*/
void
icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c)
{
icmp6_send_response(p, c, 0, ICMP6_TYPE_TE);
}
/**
* Send an icmpv6 'parameter problem' packet.
*
* @param p the input packet for which the 'param problem' should be sent,
* p->payload pointing to the IP header
* @param c ICMPv6 code for the param problem type
* @param pointer the pointer to the byte where the parameter is found
*/
void
icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer)
{
icmp6_send_response(p, c, pointer, ICMP6_TYPE_PP);
}
/**
* Send an ICMPv6 packet in response to an incoming packet.
*
* @param p the input packet for which the response should be sent,
* p->payload pointing to the IPv6 header
* @param code Code of the ICMPv6 header
* @param data Additional 32-bit parameter in the ICMPv6 header
* @param type Type of the ICMPv6 header
*/
static void
icmp6_send_response(struct pbuf *p, u8_t code, u32_t data, u8_t type)
{
struct pbuf *q;
struct ip_hdr *iphdr;
struct icmp_te_hdr *tehdr;
struct icmp6_hdr *icmp6hdr;
ip6_addr_t * reply_src;
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded\n"));
/* @todo: can this be PBUF_LINK instead of PBUF_IP? */
q = pbuf_alloc(PBUF_IP, 8 + IP_HLEN + 8, PBUF_RAM);
/* ICMP header + IP header + 8 bytes of data */
/* ICMPv6 header + IPv6 header + data */
q = pbuf_alloc(PBUF_IP, sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE,
PBUF_RAM);
if (q == NULL) {
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_dest_unreach: failed to allocate pbuf for ICMP packet.\n"));
pbuf_free(p);
LWIP_DEBUGF(ICMP_DEBUG, ("icmp_time_exceeded: failed to allocate pbuf for ICMPv6 packet.\n"));
ICMP6_STATS_INC(icmp6.memerr);
return;
}
LWIP_ASSERT("check that first pbuf can hold icmp message",
(q->len >= (8 + IP_HLEN + 8)));
LWIP_ASSERT("check that first pbuf can hold icmp 6message",
(q->len >= (sizeof(struct icmp6_hdr) + IP6_HLEN + LWIP_ICMP6_DATASIZE)));
iphdr = p->payload;
tehdr = q->payload;
tehdr->type = (u8_t)ICMP6_TE;
tehdr->icode = (u8_t)t;
icmp6hdr = (struct icmp6_hdr *)q->payload;
icmp6hdr->type = type;
icmp6hdr->code = code;
icmp6hdr->data = data;
/* copy fields from original packet */
SMEMCPY((u8_t *)q->payload + 8, (u8_t *)p->payload, IP_HLEN + 8);
SMEMCPY((u8_t *)q->payload + sizeof(struct icmp6_hdr), (u8_t *)p->payload,
IP6_HLEN + LWIP_ICMP6_DATASIZE);
/* Select an address to use as source. */
reply_src = ip6_select_source_address(ip_current_netif(), ip6_current_src_addr());
if (reply_src == NULL) {
/* drop */
pbuf_free(q);
ICMP6_STATS_INC(icmp6.rterr);
return;
}
/* calculate checksum */
tehdr->chksum = 0;
tehdr->chksum = inet_chksum(tehdr, q->len);
ICMP_STATS_INC(icmp.xmit);
ip_output(q, NULL,
(struct ip_addr *)&(iphdr->src), ICMP_TTL, IP_PROTO_ICMP);
icmp6hdr->chksum = 0;
icmp6hdr->chksum = ip6_chksum_pseudo(q, IP6_NEXTH_ICMP6, q->tot_len,
reply_src, ip6_current_src_addr());
ICMP6_STATS_INC(icmp6.xmit);
ip6_output(q, reply_src, ip6_current_src_addr(), LWIP_ICMP6_HL, 0, IP6_NEXTH_ICMP6);
pbuf_free(q);
}
#endif /* LWIP_ICMP */
#endif /* LWIP_ICMP6 && LWIP_IPV6 */

View File

@@ -1,12 +1,11 @@
/**
* @file
* Functions common to all TCP/IPv6 modules, such as the Internet checksum and the
* byte order functions.
*
* INET v6 addresses.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -33,131 +32,20 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Author: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/def.h"
#include "lwip/inet.h"
#include "lwip/inet6.h"
/* chksum:
*
* Sums up all 16 bit words in a memory portion. Also includes any odd byte.
* This function is used by the other checksum functions.
*
* For now, this is not optimized. Must be optimized for the particular processor
* arcitecture on which it is to run. Preferebly coded in assembler.
*/
/** @see ip6_addr.c for implementation of functions. */
static u32_t
chksum(void *dataptr, u16_t len)
{
u16_t *sdataptr = dataptr;
u32_t acc;
for(acc = 0; len > 1; len -= 2) {
acc += *sdataptr++;
}
/* add up any odd byte */
if (len == 1) {
acc += htons((u16_t)(*(u8_t *)dataptr) << 8);
}
return acc;
}
/* inet_chksum_pseudo:
*
* Calculates the pseudo Internet checksum used by TCP and UDP for a pbuf chain.
*/
u16_t
inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u32_t proto_len)
{
u32_t acc;
struct pbuf *q;
u8_t swapped, i;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
for(i = 0; i < 8; i++) {
acc += ((u16_t *)src->addr)[i] & 0xffff;
acc += ((u16_t *)dest->addr)[i] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
}
acc += (u16_t)htons((u16_t)proto);
acc += ((u16_t *)&proto_len)[0] & 0xffff;
acc += ((u16_t *)&proto_len)[1] & 0xffff;
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
return ~(acc & 0xffff);
}
/* inet_chksum:
*
* Calculates the Internet checksum over a portion of memory. Used primarely for IP
* and ICMP.
*/
u16_t
inet_chksum(void *dataptr, u16_t len)
{
u32_t acc, sum;
acc = chksum(dataptr, len);
sum = (acc & 0xffff) + (acc >> 16);
sum += (sum >> 16);
return ~(sum & 0xffff);
}
u16_t
inet_chksum_pbuf(struct pbuf *p)
{
u32_t acc;
struct pbuf *q;
u8_t swapped;
acc = 0;
swapped = 0;
for(q = p; q != NULL; q = q->next) {
acc += chksum(q->payload, q->len);
while (acc >> 16) {
acc = (acc & 0xffff) + (acc >> 16);
}
if (q->len % 2 != 0) {
swapped = 1 - swapped;
acc = (acc & 0xff << 8) | (acc & 0xff00 >> 8);
}
}
if (swapped) {
acc = ((acc & 0xff) << 8) | ((acc & 0xff00) >> 8);
}
return ~(acc & 0xffff);
}
#endif /* LWIP_IPV6 */

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,11 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
@@ -26,47 +32,210 @@
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Author: Ivan Delamer <delamer@inicotech.com>
*
* Functions for handling IPv6 addresses.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#include "lwip/ip_addr.h"
#include "lwip/inet.h"
u8_t
ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask)
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
/* used by IP6_ADDR_ANY in ip6_addr.h */
const ip6_addr_t ip6_addr_any = { { 0ul, 0ul, 0ul, 0ul } };
#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')
#define xchar(i) ((i) < 10 ? '0' + (i) : 'A' + (i) - 10)
#endif
/**
* Check whether "cp" is a valid ascii representation
* of an IPv6 address and convert to a binary address.
* Returns 1 if the address is valid, 0 if not.
*
* @param cp IPv6 address in ascii represenation (e.g. "FF01::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
ip6addr_aton(const char *cp, ip6_addr_t *addr)
{
return((addr1->addr[0] & mask->addr[0]) == (addr2->addr[0] & mask->addr[0]) &&
(addr1->addr[1] & mask->addr[1]) == (addr2->addr[1] & mask->addr[1]) &&
(addr1->addr[2] & mask->addr[2]) == (addr2->addr[2] & mask->addr[2]) &&
(addr1->addr[3] & mask->addr[3]) == (addr2->addr[3] & mask->addr[3]));
u32_t addr_index, zero_blocks, current_block_index, current_block_value;
const char * s;
/* Count the number of colons, to count the number of blocks in a "::" sequence
zero_blocks may be 1 even if there are no :: sequences */
zero_blocks = 8;
for (s = cp; *s != 0; s++) {
if (*s == ':')
zero_blocks--;
else if (!isxdigit(*s))
break;
}
/* parse each block */
addr_index = 0;
current_block_index = 0;
current_block_value = 0;
for (s = cp; *s != 0; s++) {
if (*s == ':') {
if (current_block_index & 0x1) {
addr->addr[addr_index++] |= current_block_value;
}
else {
addr->addr[addr_index] = current_block_value << 16;
}
current_block_index++;
current_block_value = 0;
if (current_block_index > 7) {
/* address too long! */
return 0;
} if (s[1] == ':') {
s++;
/* "::" found, set zeros */
while (zero_blocks-- > 0) {
if (current_block_index & 0x1) {
addr_index++;
}
else {
addr->addr[addr_index] = 0;
}
current_block_index++;
}
}
} else if (isxdigit(*s)) {
/* add current digit */
current_block_value = (current_block_value << 4) +
(isdigit(*s) ? *s - '0' :
10 + (islower(*s) ? *s - 'a' : *s - 'A'));
} else {
/* unexpected digit, space? CRLF? */
break;
}
}
if (current_block_index & 0x1) {
addr->addr[addr_index++] |= current_block_value;
}
else {
addr->addr[addr_index] = current_block_value << 16;
}
/* convert to network byte order. */
for (addr_index = 0; addr_index < 4; addr_index++) {
addr->addr[addr_index] = htonl(addr->addr[addr_index]);
}
if (current_block_index != 7) {
return 0;
}
return 1;
}
u8_t
ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2)
/**
* Convert numeric IPv6 address into ASCII representation.
* returns ptr to static buffer; not reentrant!
*
* @param addr ip6 address in network order to convert
* @return pointer to a global static (!) buffer that holds the ASCII
* represenation of addr
*/
char *
ip6addr_ntoa(const ip6_addr_t *addr)
{
return(addr1->addr[0] == addr2->addr[0] &&
addr1->addr[1] == addr2->addr[1] &&
addr1->addr[2] == addr2->addr[2] &&
addr1->addr[3] == addr2->addr[3]);
static char str[40];
return ip6addr_ntoa_r(addr, str, 40);
}
void
ip_addr_set(struct ip_addr *dest, struct ip_addr *src)
/**
* Same as ipaddr_ntoa, but reentrant since a user-supplied buffer is used.
*
* @param addr ip6 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 *
ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen)
{
SMEMCPY(dest, src, sizeof(struct ip_addr));
/* dest->addr[0] = src->addr[0];
dest->addr[1] = src->addr[1];
dest->addr[2] = src->addr[2];
dest->addr[3] = src->addr[3];*/
}
u32_t current_block_index, current_block_value;
s32_t zero_flag, i;
u8_t
ip_addr_isany(struct ip_addr *addr)
{
if (addr == NULL) return 1;
return((addr->addr[0] | addr->addr[1] | addr->addr[2] | addr->addr[3]) == 0);
i = 0;
zero_flag = 0; /* used to indicate a zero chain for "::' */
for (current_block_index = 0; current_block_index < 8; current_block_index++) {
/* get the current 16-bit block */
current_block_value = htonl(addr->addr[current_block_index >> 1]);
if ((current_block_index & 0x1) == 0) {
current_block_value = current_block_value >> 16;
}
current_block_value &= 0xffff;
if (current_block_value == 0) {
/* generate empty block "::" */
if (!zero_flag) {
if (current_block_index > 0) {
zero_flag = 1;
buf[i++] = ':';
if (i >= buflen) return NULL;
}
}
}
else {
if (current_block_index > 0) {
buf[i++] = ':';
if (i >= buflen) return NULL;
}
if ((current_block_value & 0xf000) == 0) {
zero_flag = 1;
}
else {
buf[i++] = xchar(((current_block_value & 0xf000) >> 12));
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf00) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf00) >> 8));
if (i >= buflen) return NULL;
}
if (((current_block_value & 0xf0) == 0) && (zero_flag)) {
/* do nothing */
}
else {
buf[i++] = xchar(((current_block_value & 0xf0) >> 4));
if (i >= buflen) return NULL;
}
buf[i++] = xchar((current_block_value & 0xf));
if (i >= buflen) return NULL;
zero_flag = 0;
}
}
buf[i] = 0;
return buf;
}
#endif /* LWIP_IPV6 */

689
src/core/ipv6/ip6_frag.c Normal file
View File

@@ -0,0 +1,689 @@
/**
* @file
*
* IPv6 fragmentation and reassembly.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#include "lwip/opt.h"
#include "lwip/ip6_frag.h"
#include "lwip/ip6.h"
#include "lwip/icmp6.h"
#include "lwip/nd6.h"
#include "lwip/pbuf.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include <string.h>
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
/** Setting this to 0, you can turn off checking the fragments for overlapping
* regions. The code gets a little smaller. Only use this if you know that
* overlapping won't occur on your network! */
#ifndef IP_REASS_CHECK_OVERLAP
#define IP_REASS_CHECK_OVERLAP 1
#endif /* IP_REASS_CHECK_OVERLAP */
/** Set to 0 to prevent freeing the oldest datagram when the reassembly buffer is
* full (IP_REASS_MAX_PBUFS pbufs are enqueued). The code gets a little smaller.
* Datagrams will be freed by timeout only. Especially useful when MEMP_NUM_REASSDATA
* is set to 1, so one datagram can be reassembled at a time, only. */
#ifndef IP_REASS_FREE_OLDEST
#define IP_REASS_FREE_OLDEST 1
#endif /* IP_REASS_FREE_OLDEST */
#define IP_REASS_FLAG_LASTFRAG 0x01
/** This is a helper struct which holds the starting
* offset and the ending offset of this fragment to
* easily chain the fragments.
* It has the same packing requirements as the IPv6 header, since it replaces
* the Fragment Header in memory in incoming fragments to keep
* track of the various fragments.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_reass_helper {
PACK_STRUCT_FIELD(struct pbuf *next_pbuf);
PACK_STRUCT_FIELD(u16_t start);
PACK_STRUCT_FIELD(u16_t end);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* static variables */
static struct ip6_reassdata *reassdatagrams;
static u16_t ip6_reass_pbufcount;
/* Forward declarations. */
static void ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr);
#if IP_REASS_FREE_OLDEST
static void ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed);
#endif /* IP_REASS_FREE_OLDEST */
void
ip6_reass_tmr(void)
{
struct ip6_reassdata *r, *tmp;
r = reassdatagrams;
while (r != NULL) {
/* Decrement the timer. Once it reaches 0,
* clean up the incomplete fragment assembly */
if (r->timer > 0) {
r->timer--;
r = r->next;
} else {
/* reassembly timed out */
tmp = r;
/* get the next pointer before freeing */
r = r->next;
/* free the helper struct and all enqueued pbufs */
ip6_reass_free_complete_datagram(tmp);
}
}
}
/**
* Free a datagram (struct ip6_reassdata) and all its pbufs.
* Updates the total count of enqueued pbufs (ip6_reass_pbufcount),
* sends an ICMP time exceeded packet.
*
* @param ipr datagram to free
*/
static void
ip6_reass_free_complete_datagram(struct ip6_reassdata *ipr)
{
struct ip6_reassdata *prev;
u16_t pbufs_freed = 0;
u8_t clen;
struct pbuf *p;
struct ip6_reass_helper *iprh;
#if LWIP_ICMP6
iprh = (struct ip6_reass_helper *)ipr->p->payload;
if (iprh->start == 0) {
/* The first fragment was received, send ICMP time exceeded. */
/* First, de-queue the first pbuf from r->p. */
p = ipr->p;
ipr->p = iprh->next_pbuf;
/* Then, move back to the original header (we are now pointing to Fragment header). */
pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
icmp6_time_exceeded(p, ICMP6_TE_FRAG);
clen = pbuf_clen(p);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(p);
}
#endif /* LWIP_ICMP6 */
/* First, free all received pbufs. The individual pbufs need to be released
separately as they have not yet been chained */
p = ipr->p;
while (p != NULL) {
struct pbuf *pcur;
iprh = (struct ip6_reass_helper *)p->payload;
pcur = p;
/* get the next pointer before freeing */
p = iprh->next_pbuf;
clen = pbuf_clen(pcur);
LWIP_ASSERT("pbufs_freed + clen <= 0xffff", pbufs_freed + clen <= 0xffff);
pbufs_freed += clen;
pbuf_free(pcur);
}
/* Then, unchain the struct ip6_reassdata from the list and free it. */
if (ipr == reassdatagrams) {
reassdatagrams = ipr->next;
} else {
prev = reassdatagrams;
while (prev != NULL) {
if (prev->next == ipr) {
break;
}
prev = prev->next;
}
if (prev != NULL) {
prev->next = ipr->next;
}
}
memp_free(MEMP_IP6_REASSDATA, ipr);
/* Finally, update number of pbufs in reassembly queue */
LWIP_ASSERT("ip_reass_pbufcount >= clen", ip6_reass_pbufcount >= pbufs_freed);
ip6_reass_pbufcount -= pbufs_freed;
}
#if IP_REASS_FREE_OLDEST
/**
* Free the oldest datagram to make room for enqueueing new fragments.
* The datagram ipr is not freed!
*
* @param ipr ip6_reassdata for the current fragment
* @param pbufs_needed number of pbufs needed to enqueue
* (used for freeing other datagrams if not enough space)
*/
static void
ip6_reass_remove_oldest_datagram(struct ip6_reassdata *ipr, int pbufs_needed)
{
struct ip6_reassdata *r, *oldest;
/* Free datagrams until being allowed to enqueue 'pbufs_needed' pbufs,
* but don't free the current datagram! */
do {
r = oldest = reassdatagrams;
while (r != NULL) {
if (r != ipr) {
if (r->timer <= oldest->timer) {
/* older than the previous oldest */
oldest = r;
}
}
r = r->next;
}
if (oldest != NULL) {
ip6_reass_free_complete_datagram(oldest);
}
} while (((ip6_reass_pbufcount + pbufs_needed) > IP_REASS_MAX_PBUFS) && (reassdatagrams != NULL));
}
#endif /* IP_REASS_FREE_OLDEST */
/**
* Reassembles incoming IPv6 fragments into an IPv6 datagram.
*
* @param p points to the IPv6 Fragment Header
* @param len the length of the payload (after Fragment Header)
* @return NULL if reassembly is incomplete, pbuf pointing to
* IPv6 Header if reassembly is complete
*/
struct pbuf *
ip6_reass(struct pbuf *p)
{
struct ip6_reassdata *ipr, *ipr_prev;
struct ip6_reass_helper *iprh, *iprh_tmp, *iprh_prev=NULL;
struct ip6_frag_hdr * frag_hdr;
u16_t offset, len;
u8_t clen, valid = 1;
struct pbuf *q;
IP6_FRAG_STATS_INC(ip6_frag.recv);
frag_hdr = (struct ip6_frag_hdr *) p->payload;
clen = pbuf_clen(p);
offset = ntohs(frag_hdr->_fragment_offset);
/* Calculate fragment length from IPv6 payload length.
* Adjust for headers before Fragment Header.
* And finally adjust by Fragment Header length. */
len = ntohs(ip6_current_header()->_plen);
len -= ((u8_t*)p->payload - (u8_t*)ip6_current_header()) - IP6_HLEN;
len -= IP6_FRAG_HLEN;
/* Look for the datagram the fragment belongs to in the current datagram queue,
* remembering the previous in the queue for later dequeueing. */
for (ipr = reassdatagrams, ipr_prev = NULL; ipr != NULL; ipr = ipr->next) {
/* Check if the incoming fragment matches the one currently present
in the reassembly buffer. If so, we proceed with copying the
fragment into the buffer. */
if ((frag_hdr->_identification == ipr->identification) &&
ip6_addr_cmp(ip6_current_src_addr(), &(ipr->iphdr->src)) &&
ip6_addr_cmp(ip6_current_dest_addr(), &(ipr->iphdr->dest))) {
IP6_FRAG_STATS_INC(ip6_frag.cachehit);
break;
}
ipr_prev = ipr;
}
if (ipr == NULL) {
/* Enqueue a new datagram into the datagram queue */
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
if (ipr == NULL) {
#if IP_REASS_FREE_OLDEST
/* Make room and try again. */
ip6_reass_remove_oldest_datagram(ipr, clen);
ipr = (struct ip6_reassdata *)memp_malloc(MEMP_IP6_REASSDATA);
if (ipr == NULL)
#endif /* IP_REASS_FREE_OLDEST */
{
IP6_FRAG_STATS_INC(ip6_frag.memerr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
memset(ipr, 0, sizeof(struct ip6_reassdata));
ipr->timer = IP_REASS_MAXAGE;
/* enqueue the new structure to the front of the list */
ipr->next = reassdatagrams;
reassdatagrams = ipr;
/* Use the current IPv6 header for src/dest address reference.
* Eventually, we will replace it when we get the first fragment
* (it might be this one, in any case, it is done later). */
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
/* copy the fragmented packet id. */
ipr->identification = frag_hdr->_identification;
/* copy the nexth field */
ipr->nexth = frag_hdr->_nexth;
}
/* Check if we are allowed to enqueue more datagrams. */
if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS) {
#if IP_REASS_FREE_OLDEST
ip6_reass_remove_oldest_datagram(ipr, clen);
if ((ip6_reass_pbufcount + clen) > IP_REASS_MAX_PBUFS)
#endif /* IP_REASS_FREE_OLDEST */
{
/* @todo: send ICMPv6 time exceeded here? */
/* drop this pbuf */
IP6_FRAG_STATS_INC(ip6_frag.memerr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
/* Overwrite Fragment Header with our own helper struct. */
iprh = (struct ip6_reass_helper *)p->payload;
iprh->next_pbuf = NULL;
iprh->start = (offset & IP6_FRAG_OFFSET_MASK);
iprh->end = (offset & IP6_FRAG_OFFSET_MASK) + len;
/* find the right place to insert this pbuf */
/* Iterate through until we either get to the end of the list (append),
* or we find on with a larger offset (insert). */
for (q = ipr->p; q != NULL;) {
iprh_tmp = (struct ip6_reass_helper*)q->payload;
if (iprh->start < iprh_tmp->start) {
#if IP_REASS_CHECK_OVERLAP
if (iprh->end > iprh_tmp->start) {
/* fragment overlaps with following, throw away */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
if (iprh_prev != NULL) {
if (iprh->start < iprh_prev->end) {
/* fragment overlaps with previous, throw away */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
}
}
#endif /* IP_REASS_CHECK_OVERLAP */
/* the new pbuf should be inserted before this */
iprh->next_pbuf = q;
if (iprh_prev != NULL) {
/* not the fragment with the lowest offset */
iprh_prev->next_pbuf = p;
} else {
/* fragment with the lowest offset */
ipr->p = p;
}
break;
} else if(iprh->start == iprh_tmp->start) {
/* received the same datagram twice: no need to keep the datagram */
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
#if IP_REASS_CHECK_OVERLAP
} else if(iprh->start < iprh_tmp->end) {
/* overlap: no need to keep the new datagram */
IP6_FRAG_STATS_INC(ip6_frag.proterr);
IP6_FRAG_STATS_INC(ip6_frag.drop);
goto nullreturn;
#endif /* IP_REASS_CHECK_OVERLAP */
} else {
/* Check if the fragments received so far have no gaps. */
if (iprh_prev != NULL) {
if (iprh_prev->end != iprh_tmp->start) {
/* There is a fragment missing between the current
* and the previous fragment */
valid = 0;
}
}
}
q = iprh_tmp->next_pbuf;
iprh_prev = iprh_tmp;
}
/* If q is NULL, then we made it to the end of the list. Determine what to do now */
if (q == NULL) {
if (iprh_prev != NULL) {
/* this is (for now), the fragment with the highest offset:
* chain it to the last fragment */
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("check fragments don't overlap", iprh_prev->end <= iprh->start);
#endif /* IP_REASS_CHECK_OVERLAP */
iprh_prev->next_pbuf = p;
if (iprh_prev->end != iprh->start) {
valid = 0;
}
} else {
#if IP_REASS_CHECK_OVERLAP
LWIP_ASSERT("no previous fragment, this must be the first fragment!",
ipr->p == NULL);
#endif /* IP_REASS_CHECK_OVERLAP */
/* this is the first fragment we ever received for this ip datagram */
ipr->p = p;
}
}
/* Track the current number of pbufs current 'in-flight', in order to limit
the number of fragments that may be enqueued at any one time */
ip6_reass_pbufcount += clen;
/* Remember IPv6 header if this is the first fragment. */
if (iprh->start == 0) {
ipr->iphdr = (struct ip6_hdr *)ip6_current_header();
}
/* If this is the last fragment, calculate total packet length. */
if ((offset & IP6_FRAG_MORE_FLAG) == 0) {
ipr->datagram_len = iprh->end;
}
/* Additional validity tests: we have received first and last fragment. */
iprh_tmp = (struct ip6_reass_helper*)ipr->p->payload;
if (iprh_tmp->start != 0) {
valid = 0;
}
if (ipr->datagram_len == 0) {
valid = 0;
}
/* Final validity test: no gaps between current and last fragment. */
iprh_prev = iprh;
q = iprh->next_pbuf;
while (q != NULL) {
iprh = (struct ip6_reass_helper*)q->payload;
if (iprh_prev->end != iprh->start) {
valid = 0;
break;
}
iprh_prev = iprh;
q = iprh->next_pbuf;
}
if (valid) {
/* All fragments have been received */
/* chain together the pbufs contained within the ip6_reassdata list. */
iprh = (struct ip6_reass_helper*) ipr->p->payload;
while(iprh != NULL) {
if (iprh->next_pbuf != NULL) {
/* Save next helper struct (will be hidden in next step). */
iprh_tmp = (struct ip6_reass_helper*) iprh->next_pbuf->payload;
/* hide the fragment header for every succeding fragment */
pbuf_header(iprh->next_pbuf, -IP6_FRAG_HLEN);
pbuf_cat(ipr->p, iprh->next_pbuf);
}
else {
iprh_tmp = NULL;
}
iprh = iprh_tmp;
}
/* Adjust datagram length by adding header lengths. */
ipr->datagram_len += ((u8_t*)ipr->p->payload - (u8_t*)ipr->iphdr)
+ IP6_FRAG_HLEN
- IP6_HLEN ;
/* Set payload length in ip header. */
ipr->iphdr->_plen = htons(ipr->datagram_len);
/* Get the furst pbuf. */
p = ipr->p;
/* Restore Fragment Header in first pbuf. Mark as "single fragment"
* packet. Restore nexth. */
frag_hdr = (struct ip6_frag_hdr *) p->payload;
frag_hdr->_nexth = ipr->nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = 0;
frag_hdr->_identification = 0;
/* Move pbuf back to IPv6 header. */
pbuf_header(p, (u8_t*)p->payload - (u8_t*)ipr->iphdr);
/* release the sources allocate for the fragment queue entry */
if (reassdatagrams == ipr) {
/* it was the first in the list */
reassdatagrams = ipr->next;
} else {
/* it wasn't the first, so it must have a valid 'prev' */
LWIP_ASSERT("sanity check linked list", ipr_prev != NULL);
ipr_prev->next = ipr->next;
}
memp_free(MEMP_IP6_REASSDATA, ipr);
/* and adjust the number of pbufs currently queued for reassembly. */
ip6_reass_pbufcount -= pbuf_clen(p);
/* Return the pbuf chain */
return p;
}
/* the datagram is not (yet?) reassembled completely */
return NULL;
nullreturn:
pbuf_free(p);
return NULL;
}
#endif /* LWIP_IPV6 ^^ LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_FRAG
/** Allocate a new struct pbuf_custom_ref */
static struct pbuf_custom_ref*
ip6_frag_alloc_pbuf_custom_ref(void)
{
return (struct pbuf_custom_ref*)memp_malloc(MEMP_FRAG_PBUF);
}
/** Free a struct pbuf_custom_ref */
static void
ip6_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
ip6_frag_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);
}
ip6_frag_free_pbuf_custom_ref(pcr);
}
/**
* Fragment an IPv6 datagram if too large for the netif or path MTU.
*
* Chop the datagram in MTU sized chunks and send them in order
* by pointing PBUF_REFs into p
*
* @param p ipv6 packet to send
* @param netif the netif on which to send
* @param dest destination ipv6 address to which to send
*
* @return ERR_OK if sent successfully, err_t otherwise
*/
err_t
ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest)
{
struct ip6_hdr *original_ip6hdr;
struct ip6_hdr *ip6hdr;
struct ip6_frag_hdr * frag_hdr;
struct pbuf *rambuf;
struct pbuf *newpbuf;
static u32_t identification;
u16_t nfb;
u16_t left, cop;
u16_t mtu;
u16_t fragment_offset = 0;
u16_t last;
u16_t poff = IP6_HLEN;
u16_t newpbuflen = 0;
u16_t left_to_copy;
identification++;
original_ip6hdr = (struct ip6_hdr *)p->payload;
mtu = nd6_get_destination_mtu(dest, netif);
/* TODO we assume there are no options in the unfragmentable part (IPv6 header). */
left = p->tot_len - IP6_HLEN;
nfb = (mtu - (IP6_HLEN + IP6_FRAG_HLEN)) & IP6_FRAG_OFFSET_MASK;
while (left) {
last = (left <= nfb);
/* Fill this fragment */
cop = last ? left : nfb;
/* When not using a static buffer, create a chain of pbufs.
* The first will be a PBUF_RAM holding the link, IPv6, and Fragment header.
* The rest will be PBUF_REFs mirroring the pbuf chain to be fragged,
* but limited to the size of an mtu.
*/
rambuf = pbuf_alloc(PBUF_LINK, IP6_HLEN + IP6_FRAG_HLEN, PBUF_RAM);
if (rambuf == NULL) {
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
LWIP_ASSERT("this needs a pbuf in one piece!",
(p->len >= (IP6_HLEN + IP6_FRAG_HLEN)));
SMEMCPY(rambuf->payload, original_ip6hdr, IP6_HLEN);
ip6hdr = (struct ip6_hdr *)rambuf->payload;
frag_hdr = (struct ip6_frag_hdr *)((u8_t*)rambuf->payload + IP6_HLEN);
/* Can just adjust p directly for needed offset. */
p->payload = (u8_t *)p->payload + poff;
p->len -= poff;
p->tot_len -= poff;
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;
}
pcr = ip6_frag_alloc_pbuf_custom_ref();
if (pcr == NULL) {
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
/* Mirror this pbuf, although we might not need all of it. */
newpbuf = pbuf_alloced_custom(PBUF_RAW, newpbuflen, PBUF_REF, &pcr->pc, p->payload, newpbuflen);
if (newpbuf == NULL) {
ip6_frag_free_pbuf_custom_ref(pcr);
pbuf_free(rambuf);
IP6_FRAG_STATS_INC(ip6_frag.memerr);
return ERR_MEM;
}
pbuf_ref(p);
pcr->original = p;
pcr->pc.custom_free_function = ip6_frag_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) {
p = p->next;
}
}
poff = newpbuflen;
/* Set headers */
frag_hdr->_nexth = original_ip6hdr->_nexth;
frag_hdr->reserved = 0;
frag_hdr->_fragment_offset = htons((fragment_offset & IP6_FRAG_OFFSET_MASK) | (last ? 0 : IP6_FRAG_MORE_FLAG));
frag_hdr->_identification = htonl(identification);
IP6H_NEXTH_SET(ip6hdr, IP6_NEXTH_FRAGMENT);
IP6H_PLEN_SET(ip6hdr, cop + IP6_FRAG_HLEN);
/* No need for separate header pbuf - we allowed room for it in rambuf
* when allocated.
*/
IP6_FRAG_STATS_INC(ip6_frag.xmit);
netif->output_ip6(netif, rambuf, dest);
/* Unfortunately we can't reuse rambuf - the hardware may still be
* using the buffer. Instead we free it (and the ensuing chain) and
* recreate it next time round the loop. If we're lucky the hardware
* will have already sent the packet, the free will really free, and
* there will be zero memory penalty.
*/
pbuf_free(rambuf);
left -= cop;
fragment_offset += cop;
}
return ERR_OK;
}
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */

578
src/core/ipv6/mld6.c Normal file
View File

@@ -0,0 +1,578 @@
/**
* @file
*
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
/* Based on igmp.c implementation of igmp v2 protocol */
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/mld6.h"
#include "lwip/icmp6.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include <string.h>
/*
* MLD constants
*/
#define MLD6_HL 1
#define MLD6_JOIN_DELAYING_MEMBER_TMR_MS (500)
#define MLD6_GROUP_NON_MEMBER 0
#define MLD6_GROUP_DELAYING_MEMBER 1
#define MLD6_GROUP_IDLE_MEMBER 2
/* The list of joined groups. */
static struct mld_group* mld_group_list;
/* Forward declarations. */
static struct mld_group * mld6_new_group(struct netif *ifp, ip6_addr_t *addr);
static err_t mld6_free_group(struct mld_group *group);
static void mld6_delayed_report(struct mld_group *group, u16_t maxresp);
static void mld6_send(struct mld_group *group, u8_t type);
/**
* Stop MLD processing on interface
*
* @param netif network interface on which stop MLD processing
*/
err_t
mld6_stop(struct netif *netif)
{
struct mld_group *group = mld_group_list;
struct mld_group *prev = NULL;
struct mld_group *next;
/* look for groups joined on this interface further down the list */
while (group != NULL) {
next = group->next;
/* is it a group joined on this interface? */
if (group->netif == netif) {
/* is it the first group of the list? */
if (group == mld_group_list) {
mld_group_list = next;
}
/* is there a "previous" group defined? */
if (prev != NULL) {
prev->next = next;
}
/* disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, &(group->group_address), MLD6_DEL_MAC_FILTER);
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
} else {
/* change the "previous" */
prev = group;
}
/* move to "next" */
group = next;
}
return ERR_OK;
}
/**
* Report MLD memberships for this interface
*
* @param netif network interface on which report MLD memberships
*/
void
mld6_report_groups(struct netif *netif)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if (group->netif == netif) {
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
group = group->next;
}
}
/**
* Search for a group that is joined on a netif
*
* @param ifp the network interface for which to look
* @param addr the group ipv6 address to search for
* @return a struct mld_group* if the group has been found,
* NULL if the group wasn't found.
*/
struct mld_group *
mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if ((group->netif == ifp) && (ip6_addr_cmp(&(group->group_address), addr))) {
return group;
}
group = group->next;
}
return NULL;
}
/**
* create a new group
*
* @param ifp the network interface for which to create
* @param addr the new group ipv6
* @return a struct mld_group*,
* NULL on memory error.
*/
static struct mld_group *
mld6_new_group(struct netif *ifp, ip6_addr_t *addr)
{
struct mld_group *group;
group = (struct mld_group *)memp_malloc(MEMP_MLD6_GROUP);
if (group != NULL) {
group->netif = ifp;
ip6_addr_set(&(group->group_address), addr);
group->timer = 0; /* Not running */
group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
group->use = 0;
group->next = mld_group_list;
mld_group_list = group;
}
return group;
}
/**
* Remove a group in the mld_group_list and free
*
* @param group the group to remove
* @return ERR_OK if group was removed from the list, an err_t otherwise
*/
static err_t
mld6_free_group(struct mld_group *group)
{
err_t err = ERR_OK;
/* Is it the first group? */
if (mld_group_list == group) {
mld_group_list = group->next;
} else {
/* look for group further down the list */
struct mld_group *tmpGroup;
for (tmpGroup = mld_group_list; tmpGroup != NULL; tmpGroup = tmpGroup->next) {
if (tmpGroup->next == group) {
tmpGroup->next = group->next;
break;
}
}
/* Group not find group */
if (tmpGroup == NULL)
err = ERR_ARG;
}
/* free group */
memp_free(MEMP_MLD6_GROUP, group);
return err;
}
/**
* Process an input MLD message. Called by icmp6_input.
*
* @param p the mld packet, p->payload pointing to the icmpv6 header
* @param inp the netif on which this packet was received
*/
void
mld6_input(struct pbuf *p, struct netif *inp)
{
struct mld_header * mld_hdr;
struct mld_group* group;
MLD6_STATS_INC(mld6.recv);
/* Check that mld header fits in packet. */
if (p->len < sizeof(struct mld_header)) {
/* TODO debug message */
pbuf_free(p);
MLD6_STATS_INC(mld6.lenerr);
MLD6_STATS_INC(mld6.drop);
return;
}
mld_hdr = (struct mld_header *)p->payload;
switch (mld_hdr->type) {
case ICMP6_TYPE_MLQ: /* Multicast listener query. */
{
/* Is it a general query? */
if (ip6_addr_isallnodes_linklocal(ip6_current_dest_addr()) &&
ip6_addr_isany(&(mld_hdr->multicast_address))) {
MLD6_STATS_INC(mld6.rx_general);
/* Report all groups, except all nodes group, and if-local groups. */
group = mld_group_list;
while (group != NULL) {
if ((group->netif == inp) &&
(!(ip6_addr_ismulticast_iflocal(&(group->group_address)))) &&
(!(ip6_addr_isallnodes_linklocal(&(group->group_address))))) {
mld6_delayed_report(group, mld_hdr->max_resp_delay);
}
group = group->next;
}
}
else {
/* Have we joined this group?
* We use IP6 destination address to have a memory aligned copy.
* mld_hdr->multicast_address should be the same. */
MLD6_STATS_INC(mld6.rx_group);
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
if (group != NULL) {
/* Schedule a report. */
mld6_delayed_report(group, mld_hdr->max_resp_delay);
}
}
break; /* ICMP6_TYPE_MLQ */
}
case ICMP6_TYPE_MLR: /* Multicast listener report. */
{
/* Have we joined this group?
* We use IP6 destination address to have a memory aligned copy.
* mld_hdr->multicast_address should be the same. */
MLD6_STATS_INC(mld6.rx_report);
group = mld6_lookfor_group(inp, ip6_current_dest_addr());
if (group != NULL) {
/* If we are waiting to report, cancel it. */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
group->timer = 0; /* stopped */
group->group_state = MLD6_GROUP_IDLE_MEMBER;
group->last_reporter_flag = 0;
}
}
break; /* ICMP6_TYPE_MLR */
}
case ICMP6_TYPE_MLD: /* Multicast listener done. */
{
/* Do nothing, router will query us. */
break; /* ICMP6_TYPE_MLD */
}
default:
MLD6_STATS_INC(mld6.proterr);
MLD6_STATS_INC(mld6.drop);
break;
}
pbuf_free(p);
}
/**
* Join a group on a network interface.
*
* @param srcaddr ipv6 address of the network interface which should
* join a new group. If IP6_ADDR_ANY, join on all netifs
* @param groupaddr the ipv6 address of the group to join
* @return ERR_OK if group was joined on the netif(s), an err_t otherwise
*/
err_t
mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct mld_group *group;
struct netif *netif;
u8_t match;
u8_t i;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we join this interface ? */
match = 0;
if (ip6_addr_isany(srcaddr)) {
match = 1;
}
else {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
match = 1;
break;
}
}
}
if (match) {
/* find group or create a new one if not found */
group = mld6_lookfor_group(netif, groupaddr);
if (group == NULL) {
/* Joining a new group. Create a new group entry. */
group = mld6_new_group(netif, groupaddr);
if (group == NULL) {
return ERR_MEM;
}
/* Activate this address on the MAC layer. */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_ADD_MAC_FILTER);
}
/* Report our membership. */
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
mld6_delayed_report(group, MLD6_JOIN_DELAYING_MEMBER_TMR_MS);
}
/* Increment group use */
group->use++;
err = ERR_OK;
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* Leave a group on a network interface.
*
* @param srcaddr ipv6 address of the network interface which should
* leave the group. If IP6_ISANY, leave on all netifs
* @param groupaddr the ipv6 address of the group to leave
* @return ERR_OK if group was left on the netif(s), an err_t otherwise
*/
err_t
mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr)
{
err_t err = ERR_VAL; /* no matching interface */
struct mld_group *group;
struct netif *netif;
u8_t match;
u8_t i;
/* loop through netif's */
netif = netif_list;
while (netif != NULL) {
/* Should we leave this interface ? */
match = 0;
if (ip6_addr_isany(srcaddr)) {
match = 1;
}
else {
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(srcaddr, netif_ip6_addr(netif, i))) {
match = 1;
break;
}
}
}
if (match) {
/* find group */
group = mld6_lookfor_group(netif, groupaddr);
if (group != NULL) {
/* Leave if there is no other use of the group */
if (group->use <= 1) {
/* If we are the last reporter for this group */
if (group->last_reporter_flag) {
MLD6_STATS_INC(mld6.tx_leave);
mld6_send(group, ICMP6_TYPE_MLD);
}
/* Disable the group at the MAC level */
if (netif->mld_mac_filter != NULL) {
netif->mld_mac_filter(netif, groupaddr, MLD6_DEL_MAC_FILTER);
}
/* Free the group */
mld6_free_group(group);
} else {
/* Decrement group use */
group->use--;
}
/* Leave on this interface */
err = ERR_OK;
}
}
/* proceed to next network interface */
netif = netif->next;
}
return err;
}
/**
* Periodic timer for mld processing. Must be called every
* MLD6_TMR_INTERVAL milliseconds (100).
*
* When a delaying member expires, a membership report is sent.
*/
void
mld6_tmr(void)
{
struct mld_group *group = mld_group_list;
while (group != NULL) {
if (group->timer > 0) {
group->timer--;
if (group->timer == 0) {
/* If the state is MLD6_GROUP_DELAYING_MEMBER then we send a report for this group */
if (group->group_state == MLD6_GROUP_DELAYING_MEMBER) {
MLD6_STATS_INC(mld6.tx_report);
mld6_send(group, ICMP6_TYPE_MLR);
group->group_state = MLD6_GROUP_IDLE_MEMBER;
}
}
}
group = group->next;
}
}
/**
* Schedule a delayed membership report for a group
*
* @param group the mld_group for which "delaying" membership report
* should be sent
* @param maxresp the max resp delay provided in the query
*/
static void
mld6_delayed_report(struct mld_group *group, u16_t maxresp)
{
/* Convert maxresp from milliseconds to tmr ticks */
maxresp = maxresp / MLD6_TMR_INTERVAL;
if (maxresp == 0) {
maxresp = 1;
}
/* Randomize maxresp. */
maxresp = (LWIP_RAND() % (maxresp - 1)) + 1;
/* Apply timer value if no report has been scheduled already. */
if ((group->group_state == MLD6_GROUP_IDLE_MEMBER) ||
((group->group_state == MLD6_GROUP_DELAYING_MEMBER) &&
((group->timer == 0) || (maxresp < group->timer)))) {
group->timer = maxresp;
group->group_state = MLD6_GROUP_DELAYING_MEMBER;
}
}
/**
* Send a MLD message (report or done).
*
* An IPv6 hop-by-hop options header with a router alert option
* is prepended.
*
* @param group the group to report or quit
* @param type ICMP6_TYPE_MLR (report) or ICMP6_TYPE_MLD (done)
*/
static void
mld6_send(struct mld_group *group, u8_t type)
{
struct mld_header * mld_hdr;
struct pbuf * p;
ip6_addr_t * src_addr;
/* Allocate a packet. Size is MLD header + IPv6 Hop-by-hop options header. */
p = pbuf_alloc(PBUF_IP, sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr), PBUF_RAM);
if ((p == NULL) || (p->len < (sizeof(struct mld_header) + sizeof(struct ip6_hbh_hdr)))) {
/* We couldn't allocate a suitable pbuf. drop it. */
if (p != NULL) {
pbuf_free(p);
}
MLD6_STATS_INC(mld6.memerr);
return;
}
/* Move to make room for Hop-by-hop options header. */
if (pbuf_header(p, -IP6_HBH_HLEN)) {
pbuf_free(p);
MLD6_STATS_INC(mld6.lenerr);
return;
}
/* Select our source address. */
if (!ip6_addr_isvalid(netif_ip6_addr_state(group->netif, 0))) {
/* This is a special case, when we are performing duplicate address detection.
* We must join the multicast group, but we don't have a valid address yet. */
src_addr = IP6_ADDR_ANY;
} else {
/* Use link-local address as source address. */
src_addr = netif_ip6_addr(group->netif, 0);
}
/* MLD message header pointer. */
mld_hdr = (struct mld_header *)p->payload;
/* Set fields. */
mld_hdr->type = type;
mld_hdr->code = 0;
mld_hdr->chksum = 0;
mld_hdr->max_resp_delay = 0;
mld_hdr->reserved = 0;
ip6_addr_set(&(mld_hdr->multicast_address), &(group->group_address));
mld_hdr->chksum = ip6_chksum_pseudo(p, IP6_NEXTH_ICMP6, p->len,
src_addr, &(group->group_address));
/* Add hop-by-hop headers options: router alert with MLD value. */
ip6_options_add_hbh_ra(p, IP6_NEXTH_ICMP6, IP6_ROUTER_ALERT_VALUE_MLD);
/* Send the packet out. */
MLD6_STATS_INC(mld6.xmit);
ip6_output_if(p, (ip6_addr_isany(src_addr)) ? NULL : src_addr, &(group->group_address),
MLD6_HL, 0, IP6_NEXTH_HOPBYHOP, group->netif);
pbuf_free(p);
}
#endif /* LWIP_IPV6 */

1730
src/core/ipv6/nd6.c Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -61,20 +61,13 @@
#include "lwip/mem.h"
#include "lwip/sys.h"
#include "lwip/stats.h"
#include "lwip/err.h"
#include <string.h>
#if MEM_USE_POOLS
/* lwIP head implemented with different sized pools */
/**
* This structure is used to save the pool one element came from.
*/
struct mem_helper
{
memp_t poolnr;
};
/**
* Allocate memory: determine the smallest pool that is big enough
* to contain an element of 'size' and get an element from that pool.
@@ -85,13 +78,18 @@ struct mem_helper
void *
mem_malloc(mem_size_t size)
{
struct mem_helper *element;
void *ret;
struct memp_malloc_helper *element;
memp_t poolnr;
mem_size_t required_size = size + LWIP_MEM_ALIGN_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 */
/* is this pool big enough to hold an element of the required size
plus a struct mem_helper that saves the pool this element came from? */
if ((size + sizeof(struct mem_helper)) <= memp_sizes[poolnr]) {
plus a struct memp_malloc_helper that saves the pool this element came from? */
if (required_size <= memp_sizes[poolnr]) {
break;
}
}
@@ -99,20 +97,26 @@ mem_malloc(mem_size_t size)
LWIP_ASSERT("mem_malloc(): no pool is that big!", 0);
return NULL;
}
element = (struct mem_helper*)memp_malloc(poolnr);
element = (struct memp_malloc_helper*)memp_malloc(poolnr);
if (element == NULL) {
/* No need to DEBUGF or ASSERT: This error is already
taken care of in memp.c */
/** @todo: we could try a bigger pool if this one is empty! */
#if MEM_USE_POOLS_TRY_BIGGER_POOL
/** Try a bigger pool if this one is empty! */
if (poolnr < MEMP_POOL_LAST) {
poolnr++;
goto again;
}
#endif /* MEM_USE_POOLS_TRY_BIGGER_POOL */
return NULL;
}
/* save the pool number this element came from */
element->poolnr = poolnr;
/* and return a pointer to the memory directly after the struct mem_helper */
element++;
/* and return a pointer to the memory directly after the struct memp_malloc_helper */
ret = (u8_t*)element + LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper));
return element;
return ret;
}
/**
@@ -125,13 +129,13 @@ mem_malloc(mem_size_t size)
void
mem_free(void *rmem)
{
struct mem_helper *hmem = (struct mem_helper*)rmem;
struct memp_malloc_helper *hmem;
LWIP_ASSERT("rmem != NULL", (rmem != NULL));
LWIP_ASSERT("rmem == MEM_ALIGN(rmem)", (rmem == LWIP_MEM_ALIGN(rmem)));
/* get the original struct mem_helper */
hmem--;
/* get the original struct memp_malloc_helper */
hmem = (struct memp_malloc_helper*)(void*)((u8_t*)rmem - LWIP_MEM_ALIGN_SIZE(sizeof(struct memp_malloc_helper)));
LWIP_ASSERT("hmem != NULL", (hmem != NULL));
LWIP_ASSERT("hmem == MEM_ALIGN(hmem)", (hmem == LWIP_MEM_ALIGN(hmem)));
@@ -152,7 +156,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;
@@ -169,16 +173,53 @@ 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! */
static struct mem *ram_end;
/** pointer to the lowest free block, this is used for faster search */
static struct mem *lfree;
/** concurrent access protection */
static sys_sem_t mem_sem;
#if !NO_SYS
static sys_mutex_t mem_mutex;
#endif
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
static volatile u8_t mem_free_count;
/* Allow mem_free from other (e.g. interrupt) context */
#define LWIP_MEM_FREE_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_free)
#define LWIP_MEM_FREE_PROTECT() SYS_ARCH_PROTECT(lev_free)
#define LWIP_MEM_FREE_UNPROTECT() SYS_ARCH_UNPROTECT(lev_free)
#define LWIP_MEM_ALLOC_DECL_PROTECT() SYS_ARCH_DECL_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_PROTECT() SYS_ARCH_PROTECT(lev_alloc)
#define LWIP_MEM_ALLOC_UNPROTECT() SYS_ARCH_UNPROTECT(lev_alloc)
#else /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/* Protect the heap only by using a semaphore */
#define LWIP_MEM_FREE_DECL_PROTECT()
#define LWIP_MEM_FREE_PROTECT() sys_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()
#define LWIP_MEM_ALLOC_UNPROTECT()
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/**
* "Plug holes" by combining adjacent empty struct mems.
@@ -186,7 +227,7 @@ static sys_sem_t mem_sem;
* 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.
@@ -204,25 +245,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);
}
}
@@ -238,26 +279,26 @@ 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;
#if MEM_STATS
lwip_stats.mem.avail = MEM_SIZE_ALIGNED;
#endif /* MEM_STATS */
MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED);
if(sys_mutex_new(&mem_mutex) != ERR_OK) {
LWIP_ASSERT("failed to create mem_mutex", 0);
}
}
/**
@@ -270,29 +311,30 @@ void
mem_free(void *rmem)
{
struct mem *mem;
LWIP_MEM_FREE_DECL_PROTECT();
if (rmem == NULL) {
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | 2, ("mem_free(p == NULL) was called.\n"));
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("mem_free(p == NULL) was called.\n"));
return;
}
LWIP_ASSERT("mem_free: sanity check alignment", (((mem_ptr_t)rmem) & (MEM_ALIGNMENT-1)) == 0);
/* protect the heap from concurrent access */
sys_arch_sem_wait(mem_sem, 0);
LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
(u8_t *)rmem < (u8_t *)ram_end);
if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
#if MEM_STATS
++lwip_stats.mem.err;
#endif /* MEM_STATS */
sys_sem_signal(mem_sem);
SYS_ARCH_DECL_PROTECT(lev);
LWIP_DEBUGF(MEM_DEBUG | LWIP_DBG_LEVEL_SEVERE, ("mem_free: illegal memory\n"));
/* protect mem stats from concurrent access */
SYS_ARCH_PROTECT(lev);
MEM_STATS_INC(illegal);
SYS_ARCH_UNPROTECT(lev);
return;
}
/* protect the heap from concurrent access */
LWIP_MEM_FREE_PROTECT();
/* Get the corresponding struct mem ... */
mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
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. */
@@ -303,31 +345,34 @@ mem_free(void *rmem)
lfree = mem;
}
#if MEM_STATS
lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram);
#endif /* MEM_STATS */
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);
sys_sem_signal(mem_sem);
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_FREE_UNPROTECT();
}
/**
* In contrast to its name, mem_realloc can only shrink memory, not expand it.
* Since the only use (for now) is in pbuf_realloc (which also can only shrink),
* this shouldn't be a problem!
* 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
* equal to the previous size)
* @return for compatibility reasons: is always == rmem, at the moment
* or NULL if newsize is > old size, in which case rmem is NOT touched
* or freed!
*/
void *
mem_realloc(void *rmem, mem_size_t newsize)
mem_trim(void *rmem, mem_size_t newsize)
{
mem_size_t size;
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
/* use the FREE_PROTECT here: it protects with sem OR SYS_ARCH_PROTECT */
LWIP_MEM_FREE_DECL_PROTECT();
/* Expand the size of the allocated memory region so that we can
adjust for alignment. */
@@ -342,20 +387,25 @@ 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) {
LWIP_DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
SYS_ARCH_DECL_PROTECT(lev);
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);
SYS_ARCH_UNPROTECT(lev);
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;
@@ -366,13 +416,9 @@ mem_realloc(void *rmem, mem_size_t newsize)
}
/* protect the heap from concurrent access */
sys_arch_sem_wait(mem_sem, 0);
LWIP_MEM_FREE_PROTECT();
#if MEM_STATS
lwip_stats.mem.used -= (size - newsize);
#endif /* MEM_STATS */
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;
@@ -381,9 +427,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;
@@ -395,8 +441,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
@@ -407,7 +454,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;
}
@@ -416,8 +463,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 {
@@ -426,7 +474,10 @@ mem_realloc(void *rmem, mem_size_t newsize)
-> don't do anyhting.
-> the remaining space stays unused since it is too small
} */
sys_sem_signal(mem_sem);
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
mem_free_count = 1;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_FREE_UNPROTECT();
return rmem;
}
@@ -444,6 +495,10 @@ mem_malloc(mem_size_t size)
{
mem_size_t ptr, ptr2;
struct mem *mem, *mem2;
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
u8_t local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_MEM_ALLOC_DECL_PROTECT();
if (size == 0) {
return NULL;
@@ -463,90 +518,103 @@ 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 */
do {
local_mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size;
ptr = ((struct mem *)&ram[ptr])->next) {
mem = (struct mem *)&ram[ptr];
if ((!mem->used) &&
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
/* mem is not used and at least perfect fit is possible:
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
* struct mem would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
/* create mem2 struct */
mem2 = (struct mem *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
/* and insert it between mem and mem->next */
mem->next = ptr2;
mem->used = 1;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)&ram[mem2->next])->prev = ptr2;
}
#if MEM_STATS
lwip_stats.mem.used += (size + SIZEOF_STRUCT_MEM);
if (lwip_stats.mem.max < lwip_stats.mem.used) {
lwip_stats.mem.max = lwip_stats.mem.used;
}
#endif /* MEM_STATS */
} else {
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
mem->used = 1;
#if MEM_STATS
lwip_stats.mem.used += mem->next - ((u8_t *)mem - ram);
if (lwip_stats.mem.max < lwip_stats.mem.used) {
lwip_stats.mem.max = lwip_stats.mem.used;
}
#endif /* MEM_STATS */
/* Scan through the heap searching for a free block that is big enough,
* beginning with the lowest free block.
*/
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();
/* allow mem_free to run */
LWIP_MEM_ALLOC_PROTECT();
if (mem_free_count != 0) {
local_mem_free_count = mem_free_count;
}
mem_free_count = 0;
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
if (mem == lfree) {
/* Find next free block after mem and update lowest free pointer */
while (lfree->used && lfree != ram_end) {
lfree = (struct mem *)&ram[lfree->next];
if ((!mem->used) &&
(mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {
/* mem is not used and at least perfect fit is possible:
* mem->next - (ptr + SIZEOF_STRUCT_MEM) gives us the 'user data size' of mem */
if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {
/* (in addition to the above, we test if another struct mem (SIZEOF_STRUCT_MEM) containing
* at least MIN_SIZE_ALIGNED of data also fits in the 'user data space' of 'mem')
* -> split large block, create empty remainder,
* remainder must be large enough to contain MIN_SIZE_ALIGNED data: if
* mem->next - (ptr + (2*SIZEOF_STRUCT_MEM)) == size,
* struct mem would fit in but no data between mem2 and mem2->next
* @todo we could leave out MIN_SIZE_ALIGNED. We would create an empty
* region that couldn't hold data, but when mem->next gets freed,
* the 2 regions would be combined, resulting in more free memory
*/
ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
/* create mem2 struct */
mem2 = (struct mem *)(void *)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next;
mem2->prev = ptr;
/* and insert it between mem and mem->next */
mem->next = ptr2;
mem->used = 1;
if (mem2->next != MEM_SIZE_ALIGNED) {
((struct mem *)(void *)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size + SIZEOF_STRUCT_MEM));
} else {
/* (a mem2 struct does no fit into the user data space of mem and mem->next will always
* be used at this point: if not we have 2 unused structs in a row, plug_holes should have
* take care of this).
* -> near fit or excact fit: do not split, no mem2 creation
* also can't move mem->next directly behind mem, since mem->next
* will always be used at this point!
*/
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next - (mem_size_t)((u8_t *)mem - ram));
}
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
sys_sem_signal(mem_sem);
LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
(mem_ptr_t)mem + SIZEOF_STRUCT_MEM + size <= (mem_ptr_t)ram_end);
LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
(unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
LWIP_ASSERT("mem_malloc: sanity check alignment",
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
if (mem == lfree) {
/* Find next free block after mem and update lowest free pointer */
while (lfree->used && lfree != ram_end) {
LWIP_MEM_ALLOC_UNPROTECT();
/* prevent high interrupt latency... */
LWIP_MEM_ALLOC_PROTECT();
lfree = (struct mem *)(void *)&ram[lfree->next];
}
LWIP_ASSERT("mem_malloc: !lfree->used", ((lfree == ram_end) || (!lfree->used)));
}
LWIP_MEM_ALLOC_UNPROTECT();
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.",
((mem_ptr_t)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
LWIP_ASSERT("mem_malloc: sanity check alignment",
(((mem_ptr_t)mem) & (MEM_ALIGNMENT-1)) == 0);
return (u8_t *)mem + SIZEOF_STRUCT_MEM;
}
}
}
LWIP_DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %"S16_F" bytes\n", (s16_t)size));
#if MEM_STATS
++lwip_stats.mem.err;
#endif /* MEM_STATS */
sys_sem_signal(mem_sem);
#if LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT
/* if we got interrupted by a mem_free, try again */
} while(local_mem_free_count != 0);
#endif /* LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */
LWIP_DEBUGF(MEM_DEBUG | 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_mutex_unlock(&mem_mutex);
return NULL;
}

View File

@@ -44,18 +44,28 @@
#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 "lwip/nd6.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#include <string.h>
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
struct memp {
struct memp *next;
#if MEMP_OVERFLOW_CHECK
@@ -109,15 +119,23 @@ struct memp {
* Elements form a linked list. */
static struct memp *memp_tab[MEMP_MAX];
#else /* MEMP_MEM_MALLOC */
#define MEMP_ALIGN_SIZE(x) (LWIP_MEM_ALIGN_SIZE(x))
#endif /* MEMP_MEM_MALLOC */
/** This array holds the element sizes of each pool. */
#if !MEM_USE_POOLS
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
static
#endif
const u16_t memp_sizes[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) MEMP_ALIGN_SIZE(size),
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/memp_std.h"
};
#if !MEMP_MEM_MALLOC /* don't build if not configured for use in lwipopts.h */
/** This array holds the number of elements in each pool. */
static const u16_t memp_num[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) (num),
@@ -132,12 +150,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
@@ -162,15 +201,55 @@ 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_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) {
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
}
/**
* 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;
@@ -178,15 +257,18 @@ memp_overflow_check_element(struct memp *p, u16_t memp_size)
m = (u8_t*)p + MEMP_SIZE - MEMP_SANITY_REGION_BEFORE_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_BEFORE_ALIGNED; k++) {
if (m[k] != 0xcd) {
LWIP_ASSERT("detected memp underflow!", 0);
}
}
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
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_size - MEMP_SANITY_REGION_AFTER_ALIGNED;
for (k = 0; k < MEMP_SANITY_REGION_AFTER_ALIGNED; k++) {
if (m[k] != 0xcd) {
LWIP_ASSERT("detected memp overflow!", 0);
LWIP_ASSERT(errstr, 0);
}
}
#endif
@@ -203,12 +285,20 @@ 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(p, memp_sizes[i]);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);
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_underflow(p, i);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
}
@@ -223,7 +313,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) {
@@ -232,10 +322,10 @@ memp_overflow_init(void)
memset(m, 0xcd, MEMP_SANITY_REGION_BEFORE_ALIGNED);
#endif
#if MEMP_SANITY_REGION_AFTER_ALIGNED > 0
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i] - MEMP_SANITY_REGION_AFTER_ALIGNED;
m = (u8_t*)p + MEMP_SIZE + memp_sizes[i];
memset(m, 0xcd, MEMP_SANITY_REGION_AFTER_ALIGNED);
#endif
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i]);
p = (struct memp*)((u8_t*)p + MEMP_SIZE + memp_sizes[i] + MEMP_SANITY_REGION_AFTER_ALIGNED);
}
}
}
@@ -252,23 +342,31 @@ memp_init(void)
struct memp *memp;
u16_t i, j;
#if MEMP_STATS
for (i = 0; i < MEMP_MAX; ++i) {
lwip_stats.memp[i].used = lwip_stats.memp[i].max =
lwip_stats.memp[i].err = 0;
lwip_stats.memp[i].avail = memp_num[i];
MEMP_STATS_AVAIL(used, i, 0);
MEMP_STATS_AVAIL(max, i, 0);
MEMP_STATS_AVAIL(err, i, 0);
MEMP_STATS_AVAIL(avail, i, memp_num[i]);
}
#endif /* MEMP_STATS */
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
);
}
}
#if MEMP_OVERFLOW_CHECK
@@ -308,27 +406,20 @@ memp_malloc_fn(memp_t type, const char* file, const int line)
memp = memp_tab[type];
if (memp != NULL) {
memp_tab[type] = memp->next;
if (memp != NULL) {
memp_tab[type] = memp->next;
#if MEMP_OVERFLOW_CHECK
memp->next = NULL;
memp->file = file;
memp->line = line;
#endif /* MEMP_OVERFLOW_CHECK */
#if MEMP_STATS
++lwip_stats.memp[type].used;
if (lwip_stats.memp[type].used > lwip_stats.memp[type].max) {
lwip_stats.memp[type].max = lwip_stats.memp[type].used;
}
#endif /* MEMP_STATS */
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 | 2, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
#if MEMP_STATS
++lwip_stats.memp[type].err;
#endif /* MEMP_STATS */
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);
}
SYS_ARCH_UNPROTECT(old_level);
@@ -354,20 +445,19 @@ 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 */
#if MEMP_STATS
lwip_stats.memp[type].used--;
#endif /* MEMP_STATS */
MEMP_STATS_DEC(used, type);
memp->next = memp_tab[type];
memp_tab[type] = memp;
@@ -378,3 +468,5 @@ memp_free(memp_t type, void *mem)
SYS_ARCH_UNPROTECT(old_level);
}
#endif /* MEMP_MEM_MALLOC */

View File

@@ -40,27 +40,94 @@
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_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
#include "lwip/tcpip.h"
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_AUTOIP
#include "lwip/autoip.h"
#endif /* LWIP_AUTOIP */
#if LWIP_DHCP
#include "lwip/dhcp.h"
#endif /* LWIP_DHCP */
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_IPV6_MLD
#include "lwip/mld6.h"
#endif /* LWIP_IPV6_MLD */
#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;
static u8_t netif_num;
#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.
*
@@ -76,18 +143,25 @@ 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;
#if LWIP_IPV6
u32_t i;
#endif
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);
#if LWIP_IPV6
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
ip6_addr_set_zero(&netif->ip6_addr[i]);
netif_ip6_addr_set_state(netif, i, IP6_ADDR_INVALID);
}
#endif /* LWIP_IPV6 */
netif->flags = 0;
#if LWIP_DHCP
/* netif not under DHCP control by default */
@@ -97,6 +171,17 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
/* netif not under AutoIP control by default */
netif->autoip = NULL;
#endif /* LWIP_AUTOIP */
#if LWIP_IPV6_AUTOCONFIG
/* IPv6 address autoconfiguration not enabled by default */
netif->ip6_autoconfig_enabled = 0;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/* netif not under DHCPv6 control by default */
netif->dhcp6 = NULL;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_STATUS_CALLBACK
netif->status_callback = NULL;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
@@ -106,14 +191,22 @@ netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
#if LWIP_IGMP
netif->igmp_mac_filter = NULL;
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
netif->mld_mac_filter = NULL;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if ENABLE_LOOPBACK
netif->loop_first = NULL;
netif->loop_last = NULL;
#endif /* ENABLE_LOOPBACK */
/* remember netif specific state information data */
netif->state = state;
netif->num = netifnum++;
netif->num = netif_num++;
netif->input = input;
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
NETIF_SET_HWADDRHINT(netif, NULL);
#if ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS
netif->loop_cnt_current = 0;
#endif /* ENABLE_LOOPBACK && LWIP_LOOPBACK_MAX_PBUFS */
netif_set_addr(netif, ipaddr, netmask, gw);
@@ -130,7 +223,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 */
@@ -155,8 +248,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);
@@ -168,41 +261,51 @@ 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 LWIP_IPV6 && LWIP_IPV6_MLD
/* stop MLD processing */
mld6_stop(netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
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") );
}
@@ -246,7 +349,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 */
@@ -255,17 +358,21 @@ 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 | 1, ("netif_set_ipaddr: netif address being changed\n"));
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(ipX_2_ip(&pcb->local_ip), &(netif->ip_addr))
#if LWIP_AUTOIP
/* connections to link-local addresses must persist (RFC3927 ch. 1.9) */
&& !ip_addr_islinklocal(ipX_2_ip(&pcb->local_ip))
#endif /* LWIP_AUTOIP */
) {
/* this connection must be aborted */
struct tcp_pcb *next = pcb->next;
LWIP_DEBUGF(NETIF_DEBUG | 1, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_STATE, ("netif_set_ipaddr: aborting TCP pcb %p\n", (void *)pcb));
tcp_abort(pcb);
pcb = next;
} else {
@@ -274,11 +381,11 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
}
for (lpcb = tcp_listen_pcbs.listen_pcbs; lpcb != NULL; lpcb = lpcb->next) {
/* PCB bound to current local interface address? */
if ((!(ip_addr_isany(&(lpcb->local_ip)))) &&
(ip_addr_cmp(&(lpcb->local_ip), &(netif->ip_addr)))) {
if ((!(ip_addr_isany(ipX_2_ip(&lpcb->local_ip)))) &&
(ip_addr_cmp(ipX_2_ip(&lpcb->local_ip), &(netif->ip_addr)))) {
/* The PCB is listening to the old ipaddr and
* is set to listen to the new one instead */
ip_addr_set(&(lpcb->local_ip), ipaddr);
ip_addr_set(ipX_2_ip(&lpcb->local_ip), ipaddr);
}
}
}
@@ -290,12 +397,12 @@ netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr)
snmp_insert_ipaddridx_tree(netif);
snmp_insert_iprteidx_tree(0,netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: IP address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
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)));
}
/**
@@ -307,15 +414,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 | 3, ("netif: GW address of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
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)));
}
/**
@@ -328,18 +435,18 @@ 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 */
ip_addr_set(&(netif->netmask), netmask);
snmp_insert_iprteidx_tree(0, netif);
LWIP_DEBUGF(NETIF_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE | 3, ("netif: netmask of interface %c%c set to %"U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
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)));
}
/**
@@ -351,13 +458,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);
}
@@ -377,27 +481,40 @@ 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"; this is an ARP packet sent by a node in order
* to spontaneously cause other nodes to update an entry in their
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
*/
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_query(netif, &(netif->ip_addr), NULL);
}
/* For Ethernet network interfaces, we would like to send a "gratuitous ARP" */
if (netif->flags & (NETIF_FLAG_ETHARP)) {
etharp_gratuitous(netif);
}
#endif /* LWIP_ARP */
#if LWIP_IGMP
/* resend IGMP memberships */
if (netif->flags & NETIF_FLAG_IGMP) {
igmp_report_groups( netif);
}
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/* send mld memberships */
mld6_report_groups( netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
/* Send Router Solicitation messages. */
netif->rs_count = LWIP_ND6_MAX_MULTICAST_SOLICIT;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
}
}
}
@@ -411,64 +528,69 @@ 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);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
if (netif->autoip) {
autoip_network_changed(netif);
}
#endif /* LWIP_AUTOIP */
if (netif->flags & NETIF_FLAG_UP) {
#if LWIP_ARP
/** For Ethernet network interfaces, we would like to send a
* "gratuitous ARP"; this is an ARP packet sent by a node in order
* to spontaneously cause other nodes to update an entry in their
* ARP cache. From RFC 3220 "IP Mobility Support for IPv4" section 4.6.
*/
if (netif->flags & NETIF_FLAG_ETHARP) {
etharp_query(netif, &(netif->ip_addr), NULL);
}
/* 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);
#if LWIP_IPV6 && LWIP_IPV6_MLD
/* send mld memberships */
mld6_report_groups( netif);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
}
NETIF_LINK_CALLBACK(netif);
}
}
/**
@@ -476,24 +598,261 @@ 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;
if (netif) {
netif->link_callback = link_callback;
}
}
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if ENABLE_LOOPBACK
/**
* Send an IP packet to be received on the same netif (loopif-like).
* The pbuf is simply copied and handed back to netif->input.
* In multithreaded mode, this is done directly since netif->input must put
* the packet on a queue.
* In callback mode, the packet is put on an internal queue and is fed to
* netif->input by netif_poll().
*
* @param netif the lwip network interface structure
* @param p the (IP) packet to 'send'
* @param ipaddr the ip address to send the packet to (not used)
* @return ERR_OK if the packet has been sent
* ERR_MEM if the pbuf used to copy the packet couldn't be allocated
*/
err_t
netif_loop_output(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr)
{
struct pbuf *r;
err_t err;
struct pbuf *last;
#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);
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 */
/* Copy the whole pbuf queue p into the single pbuf r */
if ((err = pbuf_copy(r, p)) != ERR_OK) {
pbuf_free(r);
LINK_STATS_INC(link.memerr);
LINK_STATS_INC(link.drop);
snmp_inc_ifoutdiscards(stats_if);
return err;
}
/* Put the packet on a linked list which gets emptied through calling
netif_poll(). */
/* let last point to the last pbuf in chain r */
for (last = r; last->next != NULL; last = last->next);
SYS_ARCH_PROTECT(lev);
if(netif->loop_first != NULL) {
LWIP_ASSERT("if first != NULL, last must also be != NULL", netif->loop_last != NULL);
netif->loop_last->next = r;
netif->loop_last = last;
} else {
netif->loop_first = r;
netif->loop_last = last;
}
SYS_ARCH_UNPROTECT(lev);
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((tcpip_callback_fn)netif_poll, netif);
#endif /* LWIP_NETIF_LOOPBACK_MULTITHREADING */
return ERR_OK;
}
/**
* Call netif_poll() in the main loop of your application. This is to prevent
* reentering non-reentrant functions like tcp_input(). Packets passed to
* netif_loop_output() are put on a list that is passed to netif->input() by
* netif_poll().
*/
void
netif_poll(struct netif *netif)
{
struct pbuf *in;
/* 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) {
struct pbuf *in_end = in;
#if LWIP_LOOPBACK_MAX_PBUFS
u8_t clen = pbuf_clen(in);
/* adjust the number of pbufs on queue */
LWIP_ASSERT("netif->loop_cnt_current underflow",
((netif->loop_cnt_current - clen) < netif->loop_cnt_current));
netif->loop_cnt_current -= clen;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
while (in_end->len != in_end->tot_len) {
LWIP_ASSERT("bogus pbuf: len != tot_len but next == NULL!", in_end->next != NULL);
in_end = in_end->next;
}
/* 'in_end' now points to the last pbuf from 'in' */
if (in_end == netif->loop_last) {
/* this was the last pbuf in the list */
netif->loop_first = netif->loop_last = NULL;
} else {
/* pop the pbuf off the list */
netif->loop_first = in_end->next;
LWIP_ASSERT("should not be null since first != last!", netif->loop_first != NULL);
}
/* De-queue the pbuf from its successors on the 'loop_' list. */
in_end->next = NULL;
}
SYS_ARCH_UNPROTECT(lev);
if (in != NULL) {
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) {
pbuf_free(in);
}
/* Don't reference the packet any more! */
in = NULL;
}
/* go on while there is a packet on the list */
} while (netif->loop_first != NULL);
}
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
/**
* Calls netif_poll() for every netif on the netif_list.
*/
void
netif_poll_all(void)
{
struct netif *netif = netif_list;
/* loop through netifs */
while (netif != NULL) {
netif_poll(netif);
/* proceed to next network interface */
netif = netif->next;
}
}
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_IPV6
s8_t
netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr)
{
s8_t i;
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
if (ip6_addr_cmp(netif_ip6_addr(netif, i), ip6addr)) {
return i;
}
}
return -1;
}
void
netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit)
{
u8_t i, addr_index;
/* Link-local prefix. */
netif->ip6_addr[0].addr[0] = PP_HTONL(0xfe800000ul);
netif->ip6_addr[0].addr[1] = 0;
/* Generate interface ID. */
if (from_mac_48bit) {
/* Assume hwaddr is a 48-bit IEEE 802 MAC. Convert to EUI-64 address. Complement Group bit. */
netif->ip6_addr[0].addr[2] = htonl((((u32_t)(netif->hwaddr[0] ^ 0x02)) << 24) |
((u32_t)(netif->hwaddr[1]) << 16) |
((u32_t)(netif->hwaddr[2]) << 8) |
(0xff));
netif->ip6_addr[0].addr[3] = htonl((0xfeul << 24) |
((u32_t)(netif->hwaddr[3]) << 16) |
((u32_t)(netif->hwaddr[4]) << 8) |
(netif->hwaddr[5]));
}
else {
/* Use hwaddr directly as interface ID. */
netif->ip6_addr[0].addr[2] = 0;
netif->ip6_addr[0].addr[3] = 0;
addr_index = 3;
for (i = 0; i < 8; i++) {
if (i == 4) {
addr_index--;
}
netif->ip6_addr[0].addr[addr_index] |= ((u32_t)(netif->hwaddr[netif->hwaddr_len - i - 1])) << (8 * (i & 0x03));
}
}
/* Set address state. */
#if LWIP_IPV6_DUP_DETECT_ATTEMPTS
/* Will perform duplicate address detection (DAD). */
netif->ip6_addr_state[0] = IP6_ADDR_TENTATIVE;
#else
/* Consider address valid. */
netif->ip6_addr_state[0] = IP6_ADDR_PREFERRED;
#endif /* LWIP_IPV6_AUTOCONFIG */
}
#endif /* LWIP_IPV6 */

View File

@@ -70,6 +70,12 @@
#include "lwip/pbuf.h"
#include "lwip/sys.h"
#include "arch/perf.h"
#if TCP_QUEUE_OOSEQ
#include "lwip/tcp_impl.h"
#endif
#if LWIP_CHECKSUM_ON_COPY
#include "lwip/inet_chksum.h"
#endif
#include <string.h>
@@ -78,6 +84,72 @@
aligned there. Therefore, PBUF_POOL_BUFSIZE_ALIGNED can be used here. */
#define PBUF_POOL_BUFSIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(PBUF_POOL_BUFSIZE)
#if !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS
#define PBUF_POOL_IS_EMPTY()
#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
#endif /* PBUF_POOL_FREE_OOSEQ */
#if PBUF_POOL_FREE_OOSEQ
#include "lwip/tcpip.h"
#define PBUF_POOL_IS_EMPTY() pbuf_pool_is_empty()
static u8_t pbuf_free_ooseq_queued;
/**
* Attempt to reclaim some memory from queued out-of-sequence TCP segments
* if we run out of pool pbufs. It's better to give priority to new packets
* if we're running out.
*
* This must be done in the correct thread context therefore this function
* can only be used with NO_SYS=0 and through tcpip_callback.
*/
static void
pbuf_free_ooseq(void* arg)
{
struct tcp_pcb* pcb;
SYS_ARCH_DECL_PROTECT(old_level);
LWIP_UNUSED_ARG(arg);
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_queued = 0;
SYS_ARCH_UNPROTECT(old_level);
for (pcb = tcp_active_pcbs; NULL != pcb; pcb = pcb->next) {
if (NULL != pcb->ooseq) {
/** Free the ooseq pbufs of one PCB only */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free_ooseq: freeing out-of-sequence pbufs\n"));
tcp_segs_free(pcb->ooseq);
pcb->ooseq = NULL;
return;
}
}
}
/** Queue a call to pbuf_free_ooseq if not already queued. */
static void
pbuf_pool_is_empty(void)
{
u8_t queued;
SYS_ARCH_DECL_PROTECT(old_level);
SYS_ARCH_PROTECT(old_level);
queued = pbuf_free_ooseq_queued;
pbuf_free_ooseq_queued = 1;
SYS_ARCH_UNPROTECT(old_level);
if(!queued) {
/* queue a call to pbuf_free_ooseq if not already queued */
if(tcpip_callback_with_block(pbuf_free_ooseq, NULL, 0) != ERR_OK) {
SYS_ARCH_PROTECT(old_level);
pbuf_free_ooseq_queued = 0;
SYS_ARCH_UNPROTECT(old_level);
}
}
}
#endif /* PBUF_POOL_FREE_OOSEQ */
#endif /* !LWIP_TCP || !TCP_QUEUE_OOSEQ || NO_SYS */
/**
* Allocates a pbuf of the given type (possibly a chain for PBUF_POOL type).
*
@@ -115,24 +187,24 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
struct pbuf *p, *q, *r;
u16_t offset;
s32_t rem_len; /* remaining length */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F")\n", length));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F")\n", length));
/* determine header offset */
offset = 0;
switch (layer) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset += PBUF_TRANSPORT_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset += PBUF_IP_HLEN;
/* FALLTHROUGH */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset += PBUF_LINK_HLEN;
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
offset = 0;
break;
default:
LWIP_ASSERT("pbuf_alloc: bad pbuf layer", 0);
@@ -142,9 +214,10 @@ 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);
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc: allocated pbuf %p\n", (void *)p));
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();
return NULL;
}
p->type = type;
@@ -161,6 +234,8 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
LWIP_ASSERT("check p->payload + p->len does not overflow pbuf",
((u8_t*)p->payload + p->len <=
(u8_t*)p + SIZEOF_STRUCT_PBUF + PBUF_POOL_BUFSIZE_ALIGNED));
LWIP_ASSERT("PBUF_POOL_BUFSIZE must be bigger than MEM_ALIGNMENT",
(PBUF_POOL_BUFSIZE_ALIGNED - LWIP_MEM_ALIGN_SIZE(offset)) > 0 );
/* set reference count (needed here in case we fail) */
p->ref = 1;
@@ -172,8 +247,9 @@ 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 */
pbuf_free(p);
/* bail out unsuccesfully */
@@ -225,9 +301,10 @@ 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_TRACE | 2, ("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_alloc: Could not allocate MEMP_PBUF for PBUF_%s.\n",
(type == PBUF_ROM) ? "ROM" : "REF"));
return NULL;
}
@@ -245,10 +322,71 @@ pbuf_alloc(pbuf_layer layer, u16_t length, pbuf_type type)
p->ref = 1;
/* set flags */
p->flags = 0;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_alloc(length=%"U16_F") == %p\n", length, (void *)p));
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 */
switch (l) {
case PBUF_TRANSPORT:
/* add room for transport (often TCP) layer header */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN + PBUF_TRANSPORT_HLEN;
break;
case PBUF_IP:
/* add room for IP layer header */
offset = PBUF_LINK_HLEN + PBUF_IP_HLEN;
break;
case PBUF_LINK:
/* add room for link layer header */
offset = PBUF_LINK_HLEN;
break;
case PBUF_RAW:
offset = 0;
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.
@@ -272,6 +410,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
u16_t rem_len; /* remaining length */
s32_t grow;
LWIP_ASSERT("pbuf_realloc: p != NULL", p != NULL);
LWIP_ASSERT("pbuf_realloc: sane p->type", p->type == PBUF_POOL ||
p->type == PBUF_ROM ||
p->type == PBUF_RAM ||
@@ -299,6 +438,7 @@ pbuf_realloc(struct pbuf *p, u16_t new_len)
q->tot_len += (u16_t)grow;
/* proceed to next pbuf in chain */
q = q->next;
LWIP_ASSERT("pbuf_realloc: q != NULL", q != NULL);
}
/* we have now reached the new last pbuf (in q) */
/* rem_len == desired length for pbuf q */
@@ -307,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;
@@ -352,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;
@@ -383,9 +524,9 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
p->payload = (u8_t *)p->payload - header_size_increment;
/* boundary check fails? */
if ((u8_t *)p->payload < (u8_t *)p + SIZEOF_STRUCT_PBUF) {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
(void *)p->payload,
(void *)(p + 1)));\
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_header: failed as %p < %p (not enough space for new header size)\n",
(void *)p->payload, (void *)(p + 1)));
/* restore old payload pointer */
p->payload = payload;
/* bail out unsuccesfully */
@@ -402,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;
@@ -412,7 +552,7 @@ pbuf_header(struct pbuf *p, s16_t header_size_increment)
p->len += header_size_increment;
p->tot_len += header_size_increment;
LWIP_DEBUGF(PBUF_DEBUG, ("pbuf_header: old %p new %p (%"S16_F")\n",
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_header: old %p new %p (%"S16_F")\n",
(void *)payload, (void *)p->payload, header_size_increment));
return 0;
@@ -461,10 +601,11 @@ pbuf_free(struct pbuf *p)
if (p == NULL) {
LWIP_ASSERT("p != NULL", p != NULL);
/* if assertions are disabled, proceed with debug output */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 2, ("pbuf_free(p == NULL) was called.\n"));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("pbuf_free(p == NULL) was called.\n"));
return 0;
}
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_free(%p)\n", (void *)p));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free(%p)\n", (void *)p));
PERF_START;
@@ -491,17 +632,27 @@ pbuf_free(struct pbuf *p)
if (ref == 0) {
/* remember next pbuf in chain for next iteration */
q = p->next;
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: deallocating %p\n", (void *)p));
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 */
@@ -509,7 +660,7 @@ pbuf_free(struct pbuf *p)
/* p->ref > 0, this pbuf is still referenced to */
/* (and so the remaining pbufs in chain as well) */
} else {
LWIP_DEBUGF( PBUF_DEBUG | 2, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
LWIP_DEBUGF( PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_free: %p has ref %"U16_F", ending here.\n", (void *)p, ref));
/* stop walking through the chain */
p = NULL;
}
@@ -614,7 +765,7 @@ pbuf_chain(struct pbuf *h, struct pbuf *t)
pbuf_cat(h, t);
/* t is now referenced by h */
pbuf_ref(t);
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_FRESH | 2, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_chain: %p references %p\n", (void *)h, (void *)t));
}
/**
@@ -643,10 +794,10 @@ pbuf_dechain(struct pbuf *p)
/* total length of pbuf p is its own length only */
p->tot_len = p->len;
/* q is no longer referenced by p, free it */
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_dechain: unreferencing %p\n", (void *)q));
tail_gone = pbuf_free(q);
if (tail_gone > 0) {
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_STATE,
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE,
("pbuf_dechain: deallocated %p (as it is no longer referenced)\n", (void *)q));
}
/* return remaining tail or NULL if deallocated */
@@ -667,8 +818,8 @@ pbuf_dechain(struct pbuf *p)
*
* @note Only one packet is copied, no packet queue!
*
* @param p_to pbuf source of the copy
* @param p_from pbuf destination of the copy
* @param p_to pbuf destination of the copy
* @param p_from pbuf source of the copy
*
* @return ERR_OK if pbuf was copied
* ERR_ARG if one of the pbufs is NULL or p_to is not big
@@ -679,7 +830,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
{
u16_t offset_to=0, offset_from=0, len;
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 3, ("pbuf_copy(%p, %p)\n",
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy(%p, %p)\n",
(void*)p_to, (void*)p_from));
/* is the target big enough to hold the source? */
@@ -725,7 +876,7 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
(p_to->next == NULL), return ERR_VAL;);
}
} while (p_from);
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE | 1, ("pbuf_copy: end of chain reached.\n"));
LWIP_DEBUGF(PBUF_DEBUG | LWIP_DBG_TRACE, ("pbuf_copy: end of chain reached.\n"));
return ERR_OK;
}
@@ -735,8 +886,10 @@ pbuf_copy(struct pbuf *p_to, struct pbuf *p_from)
*
* @param buf the pbuf from which to copy data
* @param dataptr the application supplied buffer
* @param len length of data to copy (dataptr must be big enough)
* @param len length of data to copy (dataptr must be big enough). No more
* than buf->tot_len will be copied, irrespective of len
* @param offset offset into the packet buffer from where to begin copying len bytes
* @return the number of bytes copied, or 0 on failure
*/
u16_t
pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
@@ -746,8 +899,8 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
u16_t buf_copy_len;
u16_t copied_total = 0;
LWIP_ERROR("netbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("netbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
LWIP_ERROR("pbuf_copy_partial: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("pbuf_copy_partial: invalid dataptr", (dataptr != NULL), return 0;);
left = 0;
@@ -775,3 +928,229 @@ pbuf_copy_partial(struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
}
return copied_total;
}
/**
* Copy application supplied data into a pbuf.
* This function can only be used to copy the equivalent of buf->tot_len data.
*
* @param buf pbuf to fill with data
* @param dataptr application supplied data buffer
* @param len length of the application supplied data buffer
*
* @return ERR_OK if successful, ERR_MEM if the pbuf is not big enough
*/
err_t
pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len)
{
struct pbuf *p;
u16_t buf_copy_len;
u16_t total_copy_len = len;
u16_t copied_total = 0;
LWIP_ERROR("pbuf_take: invalid buf", (buf != NULL), return 0;);
LWIP_ERROR("pbuf_take: invalid dataptr", (dataptr != NULL), return 0;);
if ((buf == NULL) || (dataptr == NULL) || (buf->tot_len < len)) {
return ERR_ARG;
}
/* Note some systems use byte copy if dataptr or one of the pbuf payload pointers are unaligned. */
for(p = buf; total_copy_len != 0; p = p->next) {
LWIP_ASSERT("pbuf_take: invalid pbuf", p != NULL);
buf_copy_len = total_copy_len;
if (buf_copy_len > p->len) {
/* this pbuf cannot hold all remaining data */
buf_copy_len = p->len;
}
/* copy the necessary parts of the buffer */
MEMCPY(p->payload, &((char*)dataptr)[copied_total], buf_copy_len);
total_copy_len -= buf_copy_len;
copied_total += buf_copy_len;
}
LWIP_ASSERT("did not copy all data", total_copy_len == 0 && copied_total == len);
return ERR_OK;
}
/**
* Creates a single pbuf out of a queue of pbufs.
*
* @remark: 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
*
* @return a new, single pbuf (p->next is NULL)
* or the old pbuf if allocation fails
*/
struct pbuf*
pbuf_coalesce(struct pbuf *p, pbuf_layer layer)
{
struct pbuf *q;
err_t err;
if (p->next == NULL) {
return p;
}
q = pbuf_alloc(layer, p->tot_len, PBUF_RAM);
if (q == NULL) {
/* @todo: what do we do now? */
return p;
}
err = pbuf_copy(q, p);
LWIP_ASSERT("pbuf_copy failed", err == ERR_OK);
pbuf_free(p);
return q;
}
#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);
}

View File

@@ -44,13 +44,13 @@
#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 "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include <string.h>
@@ -81,36 +81,61 @@ raw_input(struct pbuf *p, struct netif *inp)
struct ip_hdr *iphdr;
s16_t proto;
u8_t eaten = 0;
#if LWIP_IPV6
struct ip6_hdr *ip6hdr;
#endif /* LWIP_IPV6 */
LWIP_UNUSED_ARG(inp);
iphdr = p->payload;
proto = IPH_PROTO(iphdr);
iphdr = (struct ip_hdr *)p->payload;
#if LWIP_IPV6
if (IPH_V(iphdr) == 6) {
ip6hdr = (struct ip6_hdr *)p->payload;
proto = IP6H_NEXTH(ip6hdr);
}
else
#endif /* LWIP_IPV6 */
{
proto = IPH_PROTO(iphdr);
}
prev = NULL;
pcb = raw_pcbs;
/* loop through all raw pcbs until the packet is eaten by one */
/* this allows multiple pcbs to match against the packet by design */
while ((eaten == 0) && (pcb != NULL)) {
if (pcb->protocol == proto) {
/* receive callback function available? */
if (pcb->recv != NULL) {
/* the receive callback function did not eat the packet? */
if (pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src)) != 0)
{
/* receive function ate the packet */
p = NULL;
eaten = 1;
if (prev != NULL) {
/* move the pcb to the front of raw_pcbs so that is
found faster next time */
prev->next = pcb->next;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
if ((pcb->protocol == proto) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip) ||
ipX_addr_cmp(PCB_ISIPV6(pcb), &(pcb->local_ip), ipX_current_dest_addr()))) {
#if IP_SOF_BROADCAST_RECV
/* broadcast filter? */
if (((pcb->so_options & SOF_BROADCAST) || !ip_addr_isbroadcast(ip_current_dest_addr(), inp))
#if LWIP_IPV6
&& !PCB_ISIPV6(pcb)
#endif /* LWIP_IPV6 */
)
#endif /* IP_SOF_BROADCAST_RECV */
{
/* receive callback function available? */
if (pcb->recv.ip4 != NULL) {
/* the receive callback function did not eat the packet? */
eaten = pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr());
if (eaten != 0) {
/* receive function ate the packet */
p = NULL;
eaten = 1;
if (prev != NULL) {
/* move the pcb to the front of raw_pcbs so that is
found faster next time */
prev->next = pcb->next;
pcb->next = raw_pcbs;
raw_pcbs = pcb;
}
}
}
/* no receive callback function was set for this raw PCB */
}
/* no receive callback function was set for this raw PCB */
/* drop the packet */
}
prev = pcb;
@@ -134,9 +159,9 @@ 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);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
return ERR_OK;
}
@@ -154,9 +179,9 @@ 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);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
return ERR_OK;
}
@@ -175,13 +200,10 @@ 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;
pcb->recv.ip4 = recv;
pcb->recv_arg = recv_arg;
}
@@ -198,39 +220,51 @@ 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;
ipX_addr_t *src_ip;
struct pbuf *q; /* q will be sent down the stack */
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 3, ("raw_sendto\n"));
s16_t header_size;
ipX_addr_t *dst_ip = ip_2_ipX(ipaddr);
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE, ("raw_sendto\n"));
header_size = (
#if LWIP_IPV6
PCB_ISIPV6(pcb) ? IP6_HLEN :
#endif /* LWIP_IPV6 */
IP_HLEN);
/* not enough space to add an IP header to first pbuf in given p chain? */
if (pbuf_header(p, IP_HLEN)) {
if (pbuf_header(p, header_size)) {
/* allocate header in new pbuf */
q = pbuf_alloc(PBUF_IP, 0, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_TRACE | 2, ("raw_sendto: could not allocate header\n"));
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 {
/* first pbuf q equals given pbuf */
q = p;
if(pbuf_header(q, -IP_HLEN)) {
if(pbuf_header(q, -header_size)) {
LWIP_ASSERT("Can't restore header we just removed!", 0);
return ERR_MEM;
}
}
if ((netif = ip_route(ipaddr)) == NULL) {
LWIP_DEBUGF(RAW_DEBUG | 1, ("raw_sendto: No route to 0x%"X32_F"\n", ipaddr->addr));
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip);
if (netif == NULL) {
LWIP_DEBUGF(RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, ("raw_sendto: No route to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), RAW_DEBUG | LWIP_DBG_LEVEL_WARNING, dst_ip);
/* free any temporary header pbuf allocated by pbuf_header() */
if (q != p) {
pbuf_free(q);
@@ -238,21 +272,43 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
return ERR_RTE;
}
if (ip_addr_isany(&pcb->local_ip)) {
#if IP_SOF_BROADCAST
#if LWIP_IPV6
/* @todo: why does IPv6 not filter broadcast with SOF_BROADCAST enabled? */
if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
{
/* broadcast filter? */
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) {
pbuf_free(q);
}
return ERR_VAL;
}
}
#endif /* IP_SOF_BROADCAST */
if (ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->local_ip)) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
src_ip = ipX_netif_get_local_ipX(PCB_ISIPV6(pcb), netif, dst_ip);
#if LWIP_IPV6
if (src_ip == NULL) {
if (q != p) {
pbuf_free(q);
}
return ERR_RTE;
}
#endif /* LWIP_IPV6 */
} else {
/* use RAW PCB local IP address as source address */
src_ip = &(pcb->local_ip);
src_ip = &pcb->local_ip;
}
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if (q, src_ip, ipaddr, pcb->ttl, pcb->tos, pcb->protocol, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
NETIF_SET_HWADDRHINT(netif, &pcb->addr_hint);
err = ipX_output_if(PCB_ISIPV6(pcb), q, ipX_2_ip(src_ip), ipX_2_ip(dst_ip), pcb->ttl, pcb->tos, pcb->protocol, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* did we chain a header earlier? */
if (q != p) {
@@ -272,7 +328,7 @@ raw_sendto(struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr)
err_t
raw_send(struct raw_pcb *pcb, struct pbuf *p)
{
return raw_sendto(pcb, p, &pcb->remote_ip);
return raw_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip));
}
/**
@@ -315,12 +371,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 | 3, ("raw_new\n"));
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 */
@@ -333,4 +390,26 @@ raw_new(u8_t proto) {
return pcb;
}
#if LWIP_IPV6
/**
* Create a RAW PCB for IPv6.
*
* @return The RAW PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @param proto the protocol number (next header) of the IPv6 packet payload
* (e.g. IP6_NEXTH_ICMP6)
*
* @see raw_remove()
*/
struct raw_pcb *
raw_new_ip6(u8_t proto)
{
struct raw_pcb *pcb;
pcb = raw_new(proto);
ip_set_v6(pcb, 1);
return pcb;
}
#endif /* LWIP_IPV6 */
#endif /* LWIP_RAW */

View File

@@ -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

View File

@@ -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

File diff suppressed because it is too large Load Diff

View File

@@ -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;
@@ -118,7 +119,7 @@ snmp_netiftoifindex(struct netif *netif, s32_t *ifidx)
u16_t i;
i = 0;
while (nif != netif)
while ((nif != NULL) && (nif != netif))
{
nif = nif->next;
i++;
@@ -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 */

View File

@@ -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,
@@ -589,9 +607,10 @@ snmp_msg_set_event(u8_t request_id, struct snmp_msg_pstat *msg_ps)
{
struct mib_external_node *en;
/** set_value_a() @todo: use reply value?? */
/** set_value_a() */
en = msg_ps->ext_mib_node;
en->set_value_a(request_id, &msg_ps->ext_object_def, 0, NULL);
en->set_value_a(request_id, &msg_ps->ext_object_def,
msg_ps->vb_ptr->value_len, msg_ps->vb_ptr->value);
/** @todo use set_value_pc() if toobig */
msg_ps->state = SNMP_MSG_INTERNAL_SET_VALUE;
@@ -652,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))
@@ -787,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);
}
}
else
{
/* datagram not for us */
/* 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;
}
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))
{
/* 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);
}
/**
@@ -977,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 */
@@ -1145,7 +1126,7 @@ snmp_pdu_dec_varbindlist(struct pbuf *p, u16_t ofs, u16_t *ofs_ret, struct snmp_
derr = snmp_asn1_dec_length(p, ofs+1, &len_octets, &len);
if ((derr != ERR_OK) ||
(type != (SNMP_ASN1_UNIV | SNMP_ASN1_CONSTR | SNMP_ASN1_SEQ)) ||
(len <= 0) || (len > vb_len))
(len == 0) || (len > vb_len))
{
snmp_inc_snmpinasnparseerrs();
/* free varbinds (if available) */
@@ -1194,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);
@@ -1210,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);
@@ -1222,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
@@ -1253,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)
{
@@ -1276,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
@@ -1322,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)
{
@@ -1334,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)
@@ -1357,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;
}
}
@@ -1384,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

View File

@@ -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:

View File

@@ -48,13 +48,31 @@
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)
stats_display_proto(struct stats_proto *proto, const char *name)
{
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
LWIP_PLATFORM_DIAG(("xmit: %"STAT_COUNTER_F"\n\t", proto->xmit));
LWIP_PLATFORM_DIAG(("rexmit: %"STAT_COUNTER_F"\n\t", proto->rexmit));
LWIP_PLATFORM_DIAG(("recv: %"STAT_COUNTER_F"\n\t", proto->recv));
LWIP_PLATFORM_DIAG(("fw: %"STAT_COUNTER_F"\n\t", proto->fw));
LWIP_PLATFORM_DIAG(("drop: %"STAT_COUNTER_F"\n\t", proto->drop));
@@ -68,23 +86,31 @@ stats_display_proto(struct stats_proto *proto, char *name)
LWIP_PLATFORM_DIAG(("cachehit: %"STAT_COUNTER_F"\n", proto->cachehit));
}
#if IGMP_STATS
void
stats_display_igmp(struct stats_igmp *igmp)
stats_display_igmp(struct stats_igmp *igmp, const char *name)
{
LWIP_PLATFORM_DIAG(("\nIGMP\n\t"));
LWIP_PLATFORM_DIAG(("lenerr: %"STAT_COUNTER_F"\n\t", igmp->lenerr));
LWIP_PLATFORM_DIAG(("\n%s\n\t", name));
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 */
#if MEM_STATS || MEMP_STATS
void
stats_display_mem(struct stats_mem *mem, char *name)
stats_display_mem(struct stats_mem *mem, const char *name)
{
LWIP_PLATFORM_DIAG(("\nMEM %s\n\t", name));
LWIP_PLATFORM_DIAG(("avail: %"U32_F"\n\t", (u32_t)mem->avail));
@@ -93,48 +119,61 @@ stats_display_mem(struct stats_mem *mem, char *name)
LWIP_PLATFORM_DIAG(("err: %"U32_F"\n", (u32_t)mem->err));
}
void
stats_display(void)
{
#if MEMP_STATS
s16_t i;
void
stats_display_memp(struct stats_mem *mem, int index)
{
char * memp_names[] = {
#define LWIP_MEMPOOL(name,num,size,desc) desc,
#include "lwip/memp_std.h"
};
#endif
#if LINK_STATS
stats_display_proto(&lwip_stats.link, "LINK");
#endif
#if ETHARP_STATS
stats_display_proto(&lwip_stats.etharp, "ETHARP");
#endif
#if IPFRAG_STATS
stats_display_proto(&lwip_stats.ip_frag, "IP_FRAG");
#endif
#if IP_STATS
stats_display_proto(&lwip_stats.ip, "IP");
#endif
#if ICMP_STATS
stats_display_proto(&lwip_stats.icmp, "ICMP");
#endif
#if IGMP_STATS
stats_display_igmp(&lwip_stats.igmp);
#endif
#if UDP_STATS
stats_display_proto(&lwip_stats.udp, "UDP");
#endif
#if TCP_STATS
stats_display_proto(&lwip_stats.tcp, "TCP");
#endif
#if MEM_STATS
stats_display_mem(&lwip_stats.mem, "HEAP");
#endif
#if MEMP_STATS
for (i = 0; i < MEMP_MAX; i++) {
stats_display_mem(&lwip_stats.memp[i], memp_names[i]);
if(index < MEMP_MAX) {
stats_display_mem(mem, memp_names[index]);
}
#endif
}
#endif /* MEMP_STATS */
#endif /* MEM_STATS || MEMP_STATS */
#if SYS_STATS
void
stats_display_sys(struct stats_sys *sys)
{
LWIP_PLATFORM_DIAG(("\nSYS\n\t"));
LWIP_PLATFORM_DIAG(("sem.used: %"U32_F"\n\t", (u32_t)sys->sem.used));
LWIP_PLATFORM_DIAG(("sem.max: %"U32_F"\n\t", (u32_t)sys->sem.max));
LWIP_PLATFORM_DIAG(("sem.err: %"U32_F"\n\t", (u32_t)sys->sem.err));
LWIP_PLATFORM_DIAG(("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 */
void
stats_display(void)
{
s16_t i;
LINK_STATS_DISPLAY();
ETHARP_STATS_DISPLAY();
IPFRAG_STATS_DISPLAY();
IP6_FRAG_STATS_DISPLAY();
IP_STATS_DISPLAY();
ND6_STATS_DISPLAY();
IP6_STATS_DISPLAY();
IGMP_STATS_DISPLAY();
MLD6_STATS_DISPLAY();
ICMP_STATS_DISPLAY();
ICMP6_STATS_DISPLAY();
UDP_STATS_DISPLAY();
TCP_STATS_DISPLAY();
MEM_STATS_DISPLAY();
for (i = 0; i < MEMP_MAX; i++) {
MEMP_STATS_DISPLAY(i);
}
SYS_STATS_DISPLAY();
}
#endif /* LWIP_STATS_DISPLAY */

View File

@@ -38,307 +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"
/* Most of the functions defined in sys.h must be implemented in the
* architecture-dependent file sys_arch.c */
#if !NO_SYS
/**
* 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;
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 = sys_arch_mbox_fetch(mbox, msg, 0);
LOCK_TCPIP_CORE();
} else {
if (timeouts->next->time > 0) {
UNLOCK_TCPIP_CORE();
time = sys_arch_mbox_fetch(mbox, msg, timeouts->next->time);
LOCK_TCPIP_CORE();
} else {
time = SYS_ARCH_TIMEOUT;
}
if (time == 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 < timeouts->next->time) {
timeouts->next->time -= time;
} 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;
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 = sys_arch_sem_wait(sem, timeouts->next->time);
} else {
time = SYS_ARCH_TIMEOUT;
}
if (time == 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 < timeouts->next->time) {
timeouts->next->time -= time;
} else {
timeouts->next->time = 0;
}
}
}
}
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_mbox_fetch()
* - while waiting for a semaphore using sys_sem_wait() or sys_sem_wait_timeout()
* - while sleeping using the inbuilt sys_msleep()
*
* @param msecs time in milliseconds after that the timer should expire
* @param h callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
void
sys_timeout(u32_t msecs, sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *timeout, *t;
timeout = memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = h;
timeout->arg = arg;
timeout->time = msecs;
timeouts = sys_arch_timeouts();
LWIP_DEBUGF(SYS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" h=%p arg=%p\n",
(void *)timeout, msecs, (void*)&h, (void *)arg));
if (timeouts == NULL) {
LWIP_ASSERT("sys_timeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
timeouts->next = timeout;
return;
}
if (timeouts->next->time > msecs) {
timeouts->next->time -= msecs;
timeout->next = timeouts->next;
timeouts->next = timeout;
} else {
for(t = timeouts->next; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'h' in the list of timeouts.
*
* @param h callback function that would be called by the timeout
* @param arg callback argument that would be passed to h
*/
void
sys_untimeout(sys_timeout_handler h, void *arg)
{
struct sys_timeouts *timeouts;
struct sys_timeo *prev_t, *t;
timeouts = sys_arch_timeouts();
if (timeouts == NULL) {
LWIP_ASSERT("sys_untimeout: timeouts != NULL", timeouts != NULL);
return;
}
if (timeouts->next == NULL) {
return;
}
for (t = timeouts->next, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == h) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL)
timeouts->next = t->next;
else
prev_t->next = t->next;
/* If not the last one, add time of this one back to next */
if (t->next != NULL)
t->next->time += t->time;
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
/**
* Timeout handler function for sys_sem_wait_timeout()
*
* @param arg struct sswt_cb* used to signal a semaphore and end waiting.
*/
static void
sswt_handler(void *arg)
{
struct sswt_cb *sswt_cb = (struct sswt_cb *) arg;
/* Timeout. Set flag to TRUE and signal semaphore */
sswt_cb->timeflag = 1;
sys_sem_signal(*(sswt_cb->psem));
}
/**
* Wait for a semaphore with timeout (specified in ms)
*
* @param sem semaphore to wait
* @param timeout timeout in ms (0: wait forever)
* @return 0 on timeout, 1 otherwise
*/
int
sys_sem_wait_timeout(sys_sem_t sem, u32_t timeout)
{
struct sswt_cb sswt_cb;
sswt_cb.psem = &sem;
sswt_cb.timeflag = 0;
/* If timeout is zero, then just wait forever */
if (timeout > 0) {
/* Create a timer and pass it the address of our flag */
sys_timeout(timeout, sswt_handler, &sswt_cb);
}
sys_sem_wait(sem);
/* Was it a timeout? */
if (sswt_cb.timeflag) {
/* timeout */
return 0;
} else {
/* Not a timeout. Remove timeout entry */
sys_untimeout(sswt_handler, &sswt_cb);
return 1;
}
}
/**
* Sleep for some ms. Timeouts are processed while sleeping.
* 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 */

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

542
src/core/timers.c Normal file
View File

@@ -0,0 +1,542 @@
/**
* @file
* Stack-internal timers implementation.
* This file includes timer callbacks for stack-internal timers as well as
* functions to set up or stop timers and check for expired timers.
*
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
* Simon Goldschmidt
*
*/
#include "lwip/opt.h"
#include "lwip/timers.h"
#include "lwip/tcp_impl.h"
#if LWIP_TIMERS
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/tcpip.h"
#include "lwip/ip_frag.h"
#include "netif/etharp.h"
#include "lwip/dhcp.h"
#include "lwip/autoip.h"
#include "lwip/igmp.h"
#include "lwip/dns.h"
#include "lwip/nd6.h"
#include "lwip/ip6_frag.h"
#include "lwip/mld6.h"
#include "lwip/sys.h"
/** The one and only timeout list */
static struct sys_timeo *next_timeout;
#if NO_SYS
static u32_t timeouts_last_time;
#endif /* NO_SYS */
#if LWIP_TCP
/** global variable that shows if the tcp timer is currently scheduled or not */
static int tcpip_tcp_timer_active;
/**
* Timer callback function that calls tcp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
tcpip_tcp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
/* call TCP timer handler */
tcp_tmr();
/* timer still needed? */
if (tcp_active_pcbs || tcp_tw_pcbs) {
/* restart timer */
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
} else {
/* disable timer */
tcpip_tcp_timer_active = 0;
}
}
/**
* Called from TCP_REG when registering a new PCB:
* the reason is to have the TCP timer only running when
* there are active (or time-wait) PCBs.
*/
void
tcp_timer_needed(void)
{
/* timer is off but needed again? */
if (!tcpip_tcp_timer_active && (tcp_active_pcbs || tcp_tw_pcbs)) {
/* enable and start timer */
tcpip_tcp_timer_active = 1;
sys_timeout(TCP_TMR_INTERVAL, tcpip_tcp_timer, NULL);
}
}
#endif /* LWIP_TCP */
#if IP_REASSEMBLY
/**
* Timer callback function that calls ip_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip_reass_tmr()\n"));
ip_reass_tmr();
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
}
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
/**
* Timer callback function that calls etharp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
arp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: etharp_tmr()\n"));
etharp_tmr();
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
}
#endif /* LWIP_ARP */
#if LWIP_DHCP
/**
* Timer callback function that calls dhcp_coarse_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_coarse(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_coarse_tmr()\n"));
dhcp_coarse_tmr();
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
}
/**
* Timer callback function that calls dhcp_fine_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dhcp_timer_fine(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dhcp_fine_tmr()\n"));
dhcp_fine_tmr();
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
}
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
/**
* Timer callback function that calls autoip_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
autoip_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: autoip_tmr()\n"));
autoip_tmr();
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
}
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
/**
* Timer callback function that calls igmp_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
igmp_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: igmp_tmr()\n"));
igmp_tmr();
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
}
#endif /* LWIP_IGMP */
#if LWIP_DNS
/**
* Timer callback function that calls dns_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
dns_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: dns_tmr()\n"));
dns_tmr();
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
}
#endif /* LWIP_DNS */
#if LWIP_IPV6
/**
* Timer callback function that calls nd6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
nd6_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: nd6_tmr()\n"));
nd6_tmr();
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
}
#if LWIP_IPV6_REASS
/**
* Timer callback function that calls ip6_reass_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
ip6_reass_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: ip6_reass_tmr()\n"));
ip6_reass_tmr();
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
}
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
/**
* Timer callback function that calls mld6_tmr() and reschedules itself.
*
* @param arg unused argument
*/
static void
mld6_timer(void *arg)
{
LWIP_UNUSED_ARG(arg);
LWIP_DEBUGF(TIMERS_DEBUG, ("tcpip: mld6_tmr()\n"));
mld6_tmr();
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
}
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
/** Initialize this module */
void sys_timeouts_init(void)
{
#if IP_REASSEMBLY
sys_timeout(IP_TMR_INTERVAL, ip_reass_timer, NULL);
#endif /* IP_REASSEMBLY */
#if LWIP_ARP
sys_timeout(ARP_TMR_INTERVAL, arp_timer, NULL);
#endif /* LWIP_ARP */
#if LWIP_DHCP
sys_timeout(DHCP_COARSE_TIMER_MSECS, dhcp_timer_coarse, NULL);
sys_timeout(DHCP_FINE_TIMER_MSECS, dhcp_timer_fine, NULL);
#endif /* LWIP_DHCP */
#if LWIP_AUTOIP
sys_timeout(AUTOIP_TMR_INTERVAL, autoip_timer, NULL);
#endif /* LWIP_AUTOIP */
#if LWIP_IGMP
sys_timeout(IGMP_TMR_INTERVAL, igmp_timer, NULL);
#endif /* LWIP_IGMP */
#if LWIP_DNS
sys_timeout(DNS_TMR_INTERVAL, dns_timer, NULL);
#endif /* LWIP_DNS */
#if LWIP_IPV6
sys_timeout(ND6_TMR_INTERVAL, nd6_timer, NULL);
#if LWIP_IPV6_REASS
sys_timeout(IP6_REASS_TMR_INTERVAL, ip6_reass_timer, NULL);
#endif /* LWIP_IPV6_REASS */
#if LWIP_IPV6_MLD
sys_timeout(MLD6_TMR_INTERVAL, mld6_timer, NULL);
#endif /* LWIP_IPV6_MLD */
#endif /* LWIP_IPV6 */
#if NO_SYS
/* Initialise timestamp for sys_check_timeouts */
timeouts_last_time = sys_now();
#endif
}
/**
* Create a one-shot timer (aka timeout). Timeouts are processed in the
* following cases:
* - while waiting for a message using sys_timeouts_mbox_fetch()
* - by calling sys_check_timeouts() (NO_SYS==1 only)
*
* @param msecs time in milliseconds after that the timer should expire
* @param handler callback function to call when msecs have elapsed
* @param arg argument to pass to the callback function
*/
#if LWIP_DEBUG_TIMERNAMES
void
sys_timeout_debug(u32_t msecs, sys_timeout_handler handler, void *arg, const char* handler_name)
#else /* LWIP_DEBUG_TIMERNAMES */
void
sys_timeout(u32_t msecs, sys_timeout_handler handler, void *arg)
#endif /* LWIP_DEBUG_TIMERNAMES */
{
struct sys_timeo *timeout, *t;
timeout = (struct sys_timeo *)memp_malloc(MEMP_SYS_TIMEOUT);
if (timeout == NULL) {
LWIP_ASSERT("sys_timeout: timeout != NULL, pool MEMP_SYS_TIMEOUT is empty", timeout != NULL);
return;
}
timeout->next = NULL;
timeout->h = handler;
timeout->arg = arg;
timeout->time = msecs;
#if LWIP_DEBUG_TIMERNAMES
timeout->handler_name = handler_name;
LWIP_DEBUGF(TIMERS_DEBUG, ("sys_timeout: %p msecs=%"U32_F" handler=%s arg=%p\n",
(void *)timeout, msecs, handler_name, (void *)arg));
#endif /* LWIP_DEBUG_TIMERNAMES */
if (next_timeout == NULL) {
next_timeout = timeout;
return;
}
if (next_timeout->time > msecs) {
next_timeout->time -= msecs;
timeout->next = next_timeout;
next_timeout = timeout;
} else {
for(t = next_timeout; t != NULL; t = t->next) {
timeout->time -= t->time;
if (t->next == NULL || t->next->time > timeout->time) {
if (t->next != NULL) {
t->next->time -= timeout->time;
}
timeout->next = t->next;
t->next = timeout;
break;
}
}
}
}
/**
* Go through timeout list (for this task only) and remove the first matching
* entry, even though the timeout has not triggered yet.
*
* @note This function only works as expected if there is only one timeout
* calling 'handler' in the list of timeouts.
*
* @param handler callback function that would be called by the timeout
* @param arg callback argument that would be passed to handler
*/
void
sys_untimeout(sys_timeout_handler handler, void *arg)
{
struct sys_timeo *prev_t, *t;
if (next_timeout == NULL) {
return;
}
for (t = next_timeout, prev_t = NULL; t != NULL; prev_t = t, t = t->next) {
if ((t->h == handler) && (t->arg == arg)) {
/* We have a match */
/* Unlink from previous in list */
if (prev_t == NULL) {
next_timeout = t->next;
} else {
prev_t->next = t->next;
}
/* If not the last one, add time of this one back to next */
if (t->next != NULL) {
t->next->time += t->time;
}
memp_free(MEMP_SYS_TIMEOUT, t);
return;
}
}
return;
}
#if NO_SYS
/** Handle timeouts for NO_SYS==1 (i.e. without using
* tcpip_thread/sys_timeouts_mbox_fetch(). Uses sys_now() to call timeout
* handler functions when timeouts expire.
*
* Must be called periodically from your main loop.
*/
void
sys_check_timeouts(void)
{
struct sys_timeo *tmptimeout;
u32_t diff;
sys_timeout_handler handler;
void *arg;
int had_one;
u32_t now;
now = sys_now();
if (next_timeout) {
/* this cares for wraparounds */
diff = LWIP_U32_DIFF(now, timeouts_last_time);
do
{
had_one = 0;
tmptimeout = next_timeout;
if (tmptimeout->time <= diff) {
/* timeout has expired */
had_one = 1;
timeouts_last_time = now;
diff -= tmptimeout->time;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("sct calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
handler(arg);
}
}
/* repeat until all expired timers have been called */
}while(had_one);
}
}
/** Set back the timestamp of the last call to sys_check_timeouts()
* This is necessary if sys_check_timeouts() hasn't been called for a long
* time (e.g. while saving energy) to prevent all timer functions of that
* period being called.
*/
void
sys_restart_timeouts(void)
{
timeouts_last_time = sys_now();
}
#else /* NO_SYS */
/**
* Wait (forever) for a message to arrive in an mbox.
* While waiting, timeouts are processed.
*
* @param mbox the mbox to fetch the message from
* @param msg the place to store the message
*/
void
sys_timeouts_mbox_fetch(sys_mbox_t *mbox, void **msg)
{
u32_t time_needed;
struct sys_timeo *tmptimeout;
sys_timeout_handler handler;
void *arg;
again:
if (!next_timeout) {
time_needed = sys_arch_mbox_fetch(mbox, msg, 0);
} else {
if (next_timeout->time > 0) {
time_needed = sys_arch_mbox_fetch(mbox, msg, next_timeout->time);
} else {
time_needed = SYS_ARCH_TIMEOUT;
}
if (time_needed == SYS_ARCH_TIMEOUT) {
/* If time == SYS_ARCH_TIMEOUT, a timeout occured before a message
could be fetched. We should now call the timeout handler and
deallocate the memory allocated for the timeout. */
tmptimeout = next_timeout;
next_timeout = tmptimeout->next;
handler = tmptimeout->h;
arg = tmptimeout->arg;
#if LWIP_DEBUG_TIMERNAMES
if (handler != NULL) {
LWIP_DEBUGF(TIMERS_DEBUG, ("stmf calling h=%s arg=%p\n",
tmptimeout->handler_name, arg));
}
#endif /* LWIP_DEBUG_TIMERNAMES */
memp_free(MEMP_SYS_TIMEOUT, tmptimeout);
if (handler != NULL) {
/* For LWIP_TCPIP_CORE_LOCKING, lock the core before calling the
timeout handler function. */
LOCK_TCPIP_CORE();
handler(arg);
UNLOCK_TCPIP_CORE();
}
LWIP_TCPIP_THREAD_ALIVE();
/* We try again to fetch a message from the mbox. */
goto again;
} else {
/* If time != SYS_ARCH_TIMEOUT, a message was received before the timeout
occured. The time variable is set to the number of
milliseconds we waited for the message. */
if (time_needed < next_timeout->time) {
next_timeout->time -= time_needed;
} else {
next_timeout->time = 0;
}
}
}
}
#endif /* NO_SYS */
#else /* LWIP_TIMERS */
/* Satisfy the TCP code which calls this function */
void
tcp_timer_needed(void)
{
}
#endif /* LWIP_TIMERS */

View File

@@ -53,11 +53,14 @@
#include "lwip/udp.h"
#include "lwip/def.h"
#include "lwip/memp.h"
#include "lwip/inet.h"
#include "lwip/inet_chksum.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet_chksum.h"
#include "lwip/netif.h"
#include "lwip/icmp.h"
#include "lwip/icmp6.h"
#include "lwip/stats.h"
#include "lwip/snmp.h"
#include "arch/perf.h"
@@ -77,7 +80,7 @@ struct udp_pcb *udp_pcbs;
* recv function. If no pcb is found or the datagram is incorrect, the
* pbuf is freed.
*
* @param p pbuf to be demultiplexed to a UDP PCB.
* @param p pbuf to be demultiplexed to a UDP PCB (p->payload pointing to the UDP header)
* @param inp network interface on which the datagram was received.
*
*/
@@ -87,19 +90,17 @@ udp_input(struct pbuf *p, struct netif *inp)
struct udp_hdr *udphdr;
struct udp_pcb *pcb, *prev;
struct udp_pcb *uncon_pcb;
struct ip_hdr *iphdr;
u16_t src, dest;
u8_t local_match;
u8_t broadcast;
u8_t for_us;
PERF_START;
UDP_STATS_INC(udp.recv);
iphdr = p->payload;
/* Check minimum length (IP header + UDP header)
* and move payload pointer to UDP header */
if (p->tot_len < (IPH_HL(iphdr) * 4 + UDP_HLEN) || pbuf_header(p, -(s16_t)(IPH_HL(iphdr) * 4))) {
/* Check minimum length (UDP header) */
if (p->len < UDP_HLEN) {
/* drop short packets */
LWIP_DEBUGF(UDP_DEBUG,
("udp_input: short UDP datagram (%"U16_F" bytes) discarded\n", p->tot_len));
@@ -112,6 +113,13 @@ udp_input(struct pbuf *p, struct netif *inp)
udphdr = (struct udp_hdr *)p->payload;
/* is broadcast packet ? */
#if LWIP_IPV6
broadcast = !ip_current_is_v6() && ip_addr_isbroadcast(ip_current_dest_addr(), inp);
#else /* LWIP_IPV6 */
broadcast = ip_addr_isbroadcast(ip_current_dest_addr(), inp);
#endif /* LWIP_IPV6 */
LWIP_DEBUGF(UDP_DEBUG, ("udp_input: received datagram of length %"U16_F"\n", p->tot_len));
/* convert src and dest ports to host byte order */
@@ -121,13 +129,11 @@ udp_input(struct pbuf *p, struct netif *inp)
udp_debug_print(udphdr);
/* print the UDP source and destination */
LWIP_DEBUGF(UDP_DEBUG,
("udp (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") <-- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1(&iphdr->dest), ip4_addr2(&iphdr->dest),
ip4_addr3(&iphdr->dest), ip4_addr4(&iphdr->dest), ntohs(udphdr->dest),
ip4_addr1(&iphdr->src), ip4_addr2(&iphdr->src),
ip4_addr3(&iphdr->src), ip4_addr4(&iphdr->src), ntohs(udphdr->src)));
LWIP_DEBUGF(UDP_DEBUG, ("udp ("));
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_dest_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", ntohs(udphdr->dest)));
ipX_addr_debug_print(ip_current_is_v6(), UDP_DEBUG, ipX_current_src_addr());
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", ntohs(udphdr->src)));
#if LWIP_DHCP
pcb = NULL;
@@ -139,9 +145,10 @@ udp_input(struct pbuf *p, struct netif *inp)
if ((inp->dhcp != NULL) && (inp->dhcp->pcb != NULL)) {
/* accept the packe if
(- broadcast or directed to us) -> DHCP is link-layer-addressed, local ip is always ANY!
- inp->dhcp->pcb->remote == ANY or iphdr->src */
if ((ip_addr_isany(&inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(&(inp->dhcp->pcb->remote_ip), &(iphdr->src)))) {
- inp->dhcp->pcb->remote == ANY or iphdr->src
(no need to check for IPv6 since the dhcp struct always uses IPv4) */
if (ipX_addr_isany(0, &inp->dhcp->pcb->remote_ip) ||
ip_addr_cmp(ipX_2_ip(&(inp->dhcp->pcb->remote_ip)), ip_current_src_addr())) {
pcb = inp->dhcp->pcb;
}
}
@@ -159,34 +166,48 @@ udp_input(struct pbuf *p, struct netif *inp)
for (pcb = udp_pcbs; pcb != NULL; pcb = pcb->next) {
local_match = 0;
/* print the PCB local and remote address */
LWIP_DEBUGF(UDP_DEBUG,
("pcb (%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F") --- "
"(%"U16_F".%"U16_F".%"U16_F".%"U16_F", %"U16_F")\n",
ip4_addr1(&pcb->local_ip), ip4_addr2(&pcb->local_ip),
ip4_addr3(&pcb->local_ip), ip4_addr4(&pcb->local_ip), pcb->local_port,
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip), pcb->remote_port));
LWIP_DEBUGF(UDP_DEBUG, ("pcb ("));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->local_ip);
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F") <-- (", pcb->local_port));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG, &pcb->remote_ip);
LWIP_DEBUGF(UDP_DEBUG, (", %"U16_F")\n", pcb->remote_port));
/* compare PCB local addr+port to UDP destination addr+port */
if ((pcb->local_port == dest) &&
(ip_addr_isany(&pcb->local_ip) ||
ip_addr_cmp(&(pcb->local_ip), &(iphdr->dest)) ||
#if LWIP_IPV6
((PCB_ISIPV6(pcb) && (ip_current_is_v6()) &&
(ip6_addr_isany(ipX_2_ip6(&pcb->local_ip)) ||
#if LWIP_IPV6_MLD
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6_MLD */
ip6_addr_cmp(ipX_2_ip6(&pcb->local_ip), ip6_current_dest_addr()))) ||
(!PCB_ISIPV6(pcb) &&
(ip_current_header() != NULL) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ipX_addr_isany(0, &pcb->local_ip)) ||
ip_addr_cmp(ipX_2_ip(&pcb->local_ip), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(&(iphdr->dest)) ||
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
ip_addr_isbroadcast(&(iphdr->dest), inp))) {
#if IP_SOF_BROADCAST_RECV
(broadcast && (pcb->so_options & SOF_BROADCAST)))))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))))) {
#endif /* IP_SOF_BROADCAST_RECV */
local_match = 1;
if ((uncon_pcb == NULL) &&
((pcb->flags & UDP_FLAGS_CONNECTED) == 0)) {
/* the first unconnected matching PCB */
/* the first unconnected matching PCB */
uncon_pcb = pcb;
}
}
/* compare PCB remote addr+port to UDP source addr+port */
if ((local_match != 0) &&
(pcb->remote_port == src) &&
(ip_addr_isany(&pcb->remote_ip) ||
ip_addr_cmp(&(pcb->remote_ip), &(iphdr->src)))) {
(pcb->remote_port == src) && IP_PCB_IPVER_INPUT_MATCH(pcb) &&
(ipX_addr_isany(PCB_ISIPV6(pcb), &pcb->remote_ip) ||
ipX_addr_cmp(PCB_ISIPV6(pcb), &pcb->remote_ip, ipX_current_src_addr()))) {
/* the first fully matching PCB */
if (prev != NULL) {
/* move the pcb to the front of udp_pcbs so that is
@@ -208,12 +229,24 @@ udp_input(struct pbuf *p, struct netif *inp)
}
/* Check checksum if this is a match or if it was directed at us. */
if (pcb != NULL || ip_addr_cmp(&inp->ip_addr, &iphdr->dest)) {
if (pcb != NULL) {
for_us = 1;
} else {
#if LWIP_IPV6
if (ip_current_is_v6()) {
for_us = netif_matches_ip6_addr(inp, ip6_current_dest_addr());
} else
#endif /* LWIP_IPV6 */
{
for_us = ip_addr_cmp(&inp->ip_addr, ip_current_dest_addr());
}
}
if (for_us) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: calculating checksum\n"));
#if LWIP_UDPLITE
if (IPH_PROTO(iphdr) == IP_PROTO_UDPLITE) {
/* Do the UDP Lite checksum */
#if CHECKSUM_CHECK_UDP
#if LWIP_UDPLITE
if (ip_current_header_proto() == IP_PROTO_UDPLITE) {
/* Do the UDP Lite checksum */
u16_t chklen = ntohs(udphdr->len);
if (chklen < sizeof(struct udp_hdr)) {
if (chklen == 0) {
@@ -223,44 +256,26 @@ udp_input(struct pbuf *p, struct netif *inp)
} else {
/* At least the UDP-Lite header must be covered by the
checksum! (Again, see RFC 3828 chap. 3.1) */
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
goto chkerr;
}
}
if (inet_chksum_pseudo_partial(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
IP_PROTO_UDPLITE, p->tot_len, chklen) != 0) {
LWIP_DEBUGF(UDP_DEBUG | 2,
("udp_input: UDP Lite datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
if (ipX_chksum_pseudo_partial(ip_current_is_v6(), p, IP_PROTO_UDPLITE,
p->tot_len, chklen,
ipX_current_src_addr(), ipX_current_dest_addr()) != 0) {
goto chkerr;
}
#endif /* CHECKSUM_CHECK_UDP */
} else
#endif /* LWIP_UDPLITE */
{
#if CHECKSUM_CHECK_UDP
if (udphdr->chksum != 0) {
if (inet_chksum_pseudo(p, (struct ip_addr *)&(iphdr->src),
(struct ip_addr *)&(iphdr->dest),
IP_PROTO_UDP, p->tot_len) != 0) {
LWIP_DEBUGF(UDP_DEBUG | 2,
("udp_input: UDP datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
goto end;
if (ipX_chksum_pseudo(ip_current_is_v6(), p, IP_PROTO_UDP, p->tot_len,
ipX_current_src_addr(),
ipX_current_dest_addr()) != 0) {
goto chkerr;
}
}
#endif /* CHECKSUM_CHECK_UDP */
}
#endif /* CHECKSUM_CHECK_UDP */
if(pbuf_header(p, -UDP_HLEN)) {
/* Can we cope with this failing? Just assert for now */
LWIP_ASSERT("pbuf_header failed\n", 0);
@@ -271,10 +286,87 @@ udp_input(struct pbuf *p, struct netif *inp)
}
if (pcb != NULL) {
snmp_inc_udpindatagrams();
#if SO_REUSE && SO_REUSE_RXTOALL
if ((broadcast ||
#if LWIP_IPV6
ip6_addr_ismulticast(ip6_current_dest_addr()) ||
#endif /* LWIP_IPV6 */
ip_addr_ismulticast(ip_current_dest_addr())) &&
((pcb->so_options & SOF_REUSEADDR) != 0)) {
/* pass broadcast- or multicast packets to all multicast pcbs
if SOF_REUSEADDR is set on the first match */
struct udp_pcb *mpcb;
u8_t p_header_changed = 0;
s16_t hdrs_len = (s16_t)(ip_current_header_tot_len() + UDP_HLEN);
for (mpcb = udp_pcbs; mpcb != NULL; mpcb = mpcb->next) {
if (mpcb != pcb) {
/* compare PCB local addr+port to UDP destination addr+port */
if ((mpcb->local_port == dest) &&
#if LWIP_IPV6
((PCB_ISIPV6(mpcb) &&
(ip6_addr_ismulticast(ip6_current_dest_addr()) ||
ip6_addr_cmp(ipX_2_ip6(&mpcb->local_ip), ip6_current_dest_addr()))) ||
(!PCB_ISIPV6(mpcb) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
((!broadcast && ipX_addr_isany(0, &mpcb->local_ip)) ||
ip_addr_cmp(ipX_2_ip(&mpcb->local_ip), ip_current_dest_addr()) ||
#if LWIP_IGMP
ip_addr_ismulticast(ip_current_dest_addr()) ||
#endif /* LWIP_IGMP */
#if IP_SOF_BROADCAST_RECV
(broadcast && (mpcb->so_options & SOF_BROADCAST)))))) {
#else /* IP_SOF_BROADCAST_RECV */
(broadcast))))) {
#endif /* IP_SOF_BROADCAST_RECV */
/* pass a copy of the packet to all local matches */
if (mpcb->recv.ip4 != NULL) {
struct pbuf *q;
/* for that, move payload to IP header again */
if (p_header_changed == 0) {
pbuf_header(p, hdrs_len);
p_header_changed = 1;
}
q = pbuf_alloc(PBUF_RAW, p->tot_len, PBUF_RAM);
if (q != NULL) {
err_t err = pbuf_copy(q, p);
if (err == ERR_OK) {
/* move payload to UDP data */
pbuf_header(q, -hdrs_len);
#if LWIP_IPV6
if (PCB_ISIPV6(mpcb)) {
mpcb->recv.ip6(mpcb->recv_arg, mpcb, q, ip6_current_src_addr(), src);
}
else
#endif /* LWIP_IPV6 */
{
mpcb->recv.ip4(mpcb->recv_arg, mpcb, q, ip_current_src_addr(), src);
}
}
}
}
}
}
}
if (p_header_changed) {
/* and move payload to UDP data again */
pbuf_header(p, -hdrs_len);
}
}
#endif /* SO_REUSE && SO_REUSE_RXTOALL */
/* callback */
if (pcb->recv != NULL) {
if (pcb->recv.ip4 != NULL) {
/* now the recv function is responsible for freeing p */
pcb->recv(pcb->recv_arg, pcb, p, &(iphdr->src), src);
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
pcb->recv.ip6(pcb->recv_arg, pcb, p, ip6_current_src_addr(), src);
}
else
#endif /* LWIP_IPV6 */
{
pcb->recv.ip4(pcb->recv_arg, pcb, p, ip_current_src_addr(), src);
}
} else {
/* no recv function registered? then we have to free the pbuf! */
pbuf_free(p);
@@ -283,17 +375,19 @@ udp_input(struct pbuf *p, struct netif *inp)
} else {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_input: not for us.\n"));
#if LWIP_ICMP
#if LWIP_ICMP || LWIP_ICMP6
/* No match was found, send ICMP destination port unreachable unless
destination address was broadcast/multicast. */
if (!ip_addr_isbroadcast(&iphdr->dest, inp) &&
!ip_addr_ismulticast(&iphdr->dest)) {
if (!broadcast &&
#if LWIP_IPV6
!ip6_addr_ismulticast(ip6_current_dest_addr()) &&
#endif /* LWIP_IPV6 */
!ip_addr_ismulticast(ip_current_dest_addr())) {
/* move payload pointer back to ip header */
pbuf_header(p, (IPH_HL(iphdr) * 4) + UDP_HLEN);
LWIP_ASSERT("p->payload == iphdr", (p->payload == iphdr));
icmp_dest_unreach(p, ICMP_DUR_PORT);
pbuf_header(p, ip_current_header_tot_len() + UDP_HLEN);
icmp_port_unreach(ip_current_is_v6(), p);
}
#endif /* LWIP_ICMP */
#endif /* LWIP_ICMP || LWIP_ICMP6 */
UDP_STATS_INC(udp.proterr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpnoports();
@@ -304,6 +398,15 @@ udp_input(struct pbuf *p, struct netif *inp)
}
end:
PERF_STOP("udp_input");
return;
chkerr:
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_input: UDP (or UDP Lite) datagram discarded due to failing checksum\n"));
UDP_STATS_INC(udp.chkerr);
UDP_STATS_INC(udp.drop);
snmp_inc_udpinerrors();
pbuf_free(p);
PERF_STOP("udp_input");
}
/**
@@ -328,9 +431,22 @@ err_t
udp_send(struct udp_pcb *pcb, struct pbuf *p)
{
/* send to the packet using remote ip and port stored in the pcb */
return udp_sendto(pcb, p, &pcb->remote_ip, pcb->remote_port);
return udp_sendto(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port);
}
#if LWIP_CHECKSUM_ON_COPY
/** Same as udp_send() but with checksum
*/
err_t
udp_send_chksum(struct udp_pcb *pcb, struct pbuf *p,
u8_t have_chksum, u16_t chksum)
{
/* send to the packet using remote ip and port stored in the pcb */
return udp_sendto_chksum(pcb, p, ipX_2_ip(&pcb->remote_ip), pcb->remote_port,
have_chksum, chksum);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/**
* Send data to a specified address using UDP.
*
@@ -350,26 +466,55 @@ udp_send(struct udp_pcb *pcb, struct pbuf *p)
*/
err_t
udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port)
ip_addr_t *dst_ip, u16_t dst_port)
{
struct netif *netif;
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_chksum(pcb, p, dst_ip, dst_port, 0, 0);
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_send\n"));
/** Same as udp_sendto(), but with checksum */
err_t
udp_sendto_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
u16_t dst_port, u8_t have_chksum, u16_t chksum)
{
#endif /* LWIP_CHECKSUM_ON_COPY */
struct netif *netif;
ipX_addr_t *dst_ip_route = ip_2_ipX(dst_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send\n"));
#if LWIP_IPV6 || LWIP_IGMP
if (ipX_addr_ismulticast(PCB_ISIPV6(pcb), dst_ip_route)) {
/* For multicast, find a netif based on source address. */
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
dst_ip_route = &pcb->local_ip;
} else
#endif /* LWIP_IPV6 */
{
#if LWIP_IGMP
dst_ip_route = ip_2_ipX(&pcb->multicast_ip);
#endif /* LWIP_IGMP */
}
}
#endif /* LWIP_IPV6 || LWIP_IGMP */
/* find the outgoing network interface for this packet */
#if LWIP_IGMP
netif = ip_route((ip_addr_ismulticast(dst_ip))?(&(pcb->multicast_ip)):(dst_ip));
#else
netif = ip_route(dst_ip);
#endif /* LWIP_IGMP */
netif = ipX_route(PCB_ISIPV6(pcb), &pcb->local_ip, dst_ip_route);
/* no outgoing network interface could be found? */
if (netif == NULL) {
LWIP_DEBUGF(UDP_DEBUG | 1, ("udp_send: No route to 0x%"X32_F"\n", dst_ip->addr));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: No route to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ip_2_ipX(dst_ip));
LWIP_DEBUGF(UDP_DEBUG, ("\n"));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, have_chksum, chksum);
#else /* LWIP_CHECKSUM_ON_COPY */
return udp_sendto_if(pcb, p, dst_ip, dst_port, netif);
#endif /* LWIP_CHECKSUM_ON_COPY */
}
/**
@@ -393,19 +538,44 @@ udp_sendto(struct udp_pcb *pcb, struct pbuf *p,
*/
err_t
udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
struct ip_addr *dst_ip, u16_t dst_port, struct netif *netif)
ip_addr_t *dst_ip, u16_t dst_port, struct netif *netif)
{
#if LWIP_CHECKSUM_ON_COPY
return udp_sendto_if_chksum(pcb, p, dst_ip, dst_port, netif, 0, 0);
}
/** Same as udp_sendto_if(), but with checksum */
err_t
udp_sendto_if_chksum(struct udp_pcb *pcb, struct pbuf *p, ip_addr_t *dst_ip,
u16_t dst_port, struct netif *netif, u8_t have_chksum,
u16_t chksum)
{
#endif /* LWIP_CHECKSUM_ON_COPY */
struct udp_hdr *udphdr;
struct ip_addr *src_ip;
ip_addr_t *src_ip;
err_t err;
struct pbuf *q; /* q will be sent down the stack */
u8_t ip_proto;
#if IP_SOF_BROADCAST
/* broadcast filter? */
if ( ((pcb->so_options & SOF_BROADCAST) == 0) &&
#if LWIP_IPV6
!PCB_ISIPV6(pcb) &&
#endif /* LWIP_IPV6 */
ip_addr_isbroadcast(dst_ip, netif) ) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_LEVEL_SERIOUS,
("udp_sendto_if: SOF_BROADCAST not enabled on pcb %p\n", (void *)pcb));
return ERR_VAL;
}
#endif /* IP_SOF_BROADCAST */
/* if the PCB is not yet bound to a port, bind it here */
if (pcb->local_port == 0) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: not yet bound to a port, binding now\n"));
err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_send: not yet bound to a port, binding now\n"));
err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
if (err != ERR_OK) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: forced port bind failed\n"));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: forced port bind failed\n"));
return err;
}
}
@@ -416,11 +586,13 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
q = pbuf_alloc(PBUF_IP, UDP_HLEN, PBUF_RAM);
/* new header pbuf could not be allocated? */
if (q == NULL) {
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 2, ("udp_send: could not allocate header\n"));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_LEVEL_SERIOUS, ("udp_send: could not allocate header\n"));
return ERR_MEM;
}
/* chain header q in front of given pbuf p */
pbuf_chain(q, p);
if (p->tot_len != 0) {
/* chain header q in front of given pbuf p (only if p contains data) */
pbuf_chain(q, p);
}
/* first pbuf q points to header pbuf */
LWIP_DEBUGF(UDP_DEBUG,
("udp_send: added header pbuf %p before given pbuf %p\n", (void *)q, (void *)p));
@@ -433,20 +605,68 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
LWIP_ASSERT("check that first pbuf can hold struct udp_hdr",
(q->len >= sizeof(struct udp_hdr)));
/* q now represents the packet to be sent */
udphdr = q->payload;
udphdr = (struct udp_hdr *)q->payload;
udphdr->src = htons(pcb->local_port);
udphdr->dest = htons(dst_port);
/* in UDP, 0 checksum means 'no checksum' */
udphdr->chksum = 0x0000;
/* Multicast Loop? */
#if LWIP_IGMP
if (((pcb->flags & UDP_FLAGS_MULTICAST_LOOP) != 0) &&
#if LWIP_IPV6
(
#if LWIP_IPV6_MLD
(PCB_ISIPV6(pcb) &&
ip6_addr_ismulticast(ip_2_ip6(dst_ip))) ||
#endif /* LWIP_IPV6_MLD */
(!PCB_ISIPV6(pcb) &&
#else /* LWIP_IPV6 */
((
#endif /* LWIP_IPV6 */
ip_addr_ismulticast(dst_ip)))) {
q->flags |= PBUF_FLAG_MCASTLOOP;
}
#endif /* LWIP_IGMP */
/* PCB local address is IP_ANY_ADDR? */
if (ip_addr_isany(&pcb->local_ip)) {
#if LWIP_IPV6
if (PCB_ISIPV6(pcb)) {
if (ip6_addr_isany(ipX_2_ip6(&pcb->local_ip))) {
src_ip = ip6_2_ip(ip6_select_source_address(netif, ip_2_ip6(dst_ip)));
if (src_ip == NULL) {
/* No suitable source address was found. */
if (q != p) {
/* free the header pbuf */
pbuf_free(q);
/* p is still referenced by the caller, and will live on */
}
return ERR_RTE;
}
} else {
/* use UDP PCB local IPv6 address as source address, if still valid. */
if (netif_matches_ip6_addr(netif, ipX_2_ip6(&pcb->local_ip)) < 0) {
/* Address isn't valid anymore. */
if (q != p) {
/* free the header pbuf */
pbuf_free(q);
/* p is still referenced by the caller, and will live on */
}
return ERR_RTE;
}
src_ip = ipX_2_ip(&pcb->local_ip);
}
}
else
#endif /* LWIP_IPV6 */
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip))) {
/* use outgoing network interface IP address as source address */
src_ip = &(netif->ip_addr);
} else {
/* check if UDP PCB local IP address is correct
* this could be an old address if netif->ip_addr has changed */
if (!ip_addr_cmp(&(pcb->local_ip), &(netif->ip_addr))) {
if (!ip_addr_cmp(ipX_2_ip(&(pcb->local_ip)), &(netif->ip_addr))) {
/* local_ip doesn't match, drop the packet */
if (q != p) {
/* free the header pbuf */
@@ -457,7 +677,7 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
return ERR_VAL;
}
/* use UDP PCB local IP address as source address */
src_ip = &(pcb->local_ip);
src_ip = ipX_2_ip(&(pcb->local_ip));
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: sending datagram of length %"U16_F"\n", q->tot_len));
@@ -485,21 +705,28 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
udphdr->len = htons(chklen_hdr);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
udphdr->chksum = inet_chksum_pseudo_partial(q, src_ip, dst_ip,
IP_PROTO_UDPLITE, q->tot_len, chklen);
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
chklen = UDP_HLEN;
}
#endif /* LWIP_CHECKSUM_ON_COPY */
udphdr->chksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDPLITE,
q->tot_len, chklen, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
u32_t acc;
acc = udphdr->chksum + (u16_t)~(chksum);
udphdr->chksum = FOLD_U32T(acc);
}
#endif /* LWIP_CHECKSUM_ON_COPY */
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000)
if (udphdr->chksum == 0x0000) {
udphdr->chksum = 0xffff;
#endif /* CHECKSUM_CHECK_UDP */
/* output to IP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDPLITE,)\n"));
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDPLITE, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
}
#endif /* CHECKSUM_GEN_UDP */
ip_proto = IP_PROTO_UDPLITE;
} else
#endif /* LWIP_UDPLITE */
{ /* UDP */
@@ -507,23 +734,40 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
udphdr->len = htons(q->tot_len);
/* calculate checksum */
#if CHECKSUM_GEN_UDP
if ((pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
udphdr->chksum = inet_chksum_pseudo(q, src_ip, dst_ip, IP_PROTO_UDP, q->tot_len);
/* Checksum is mandatory over IPv6. */
if (PCB_ISIPV6(pcb) || (pcb->flags & UDP_FLAGS_NOCHKSUM) == 0) {
u16_t udpchksum;
#if LWIP_CHECKSUM_ON_COPY
if (have_chksum) {
u32_t acc;
udpchksum = ipX_chksum_pseudo_partial(PCB_ISIPV6(pcb), q, IP_PROTO_UDP,
q->tot_len, UDP_HLEN, ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
acc = udpchksum + (u16_t)~(chksum);
udpchksum = FOLD_U32T(acc);
} else
#endif /* LWIP_CHECKSUM_ON_COPY */
{
udpchksum = ipX_chksum_pseudo(PCB_ISIPV6(pcb), q, IP_PROTO_UDP, q->tot_len,
ip_2_ipX(src_ip), ip_2_ipX(dst_ip));
}
/* chksum zero must become 0xffff, as zero means 'no checksum' */
if (udphdr->chksum == 0x0000) udphdr->chksum = 0xffff;
if (udpchksum == 0x0000) {
udpchksum = 0xffff;
}
udphdr->chksum = udpchksum;
}
#endif /* CHECKSUM_CHECK_UDP */
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,IP_PROTO_UDP,)\n"));
/* output to IP */
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = &(pcb->addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT*/
err = ip_output_if(q, src_ip, dst_ip, pcb->ttl, pcb->tos, IP_PROTO_UDP, netif);
#if LWIP_NETIF_HWADDRHINT
netif->addr_hint = NULL;
#endif /* LWIP_NETIF_HWADDRHINT*/
#endif /* CHECKSUM_GEN_UDP */
ip_proto = IP_PROTO_UDP;
}
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: UDP checksum 0x%04"X16_F"\n", udphdr->chksum));
LWIP_DEBUGF(UDP_DEBUG, ("udp_send: ip_output_if (,,,,0x%02"X16_F",)\n", (u16_t)ip_proto));
/* output to IP */
NETIF_SET_HWADDRHINT(netif, &(pcb->addr_hint));
err = ipX_output_if(PCB_ISIPV6(pcb), q, src_ip, dst_ip, pcb->ttl, pcb->tos, ip_proto, netif);
NETIF_SET_HWADDRHINT(netif, NULL);
/* TODO: must this be increased even if error occured? */
snmp_inc_udpoutdatagrams();
@@ -559,14 +803,14 @@ udp_sendto_if(struct udp_pcb *pcb, struct pbuf *p,
* @see udp_disconnect()
*/
err_t
udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
udp_bind(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
u8_t rebind;
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, ("udp_bind(ipaddr = "));
ip_addr_debug_print(UDP_DEBUG, ipaddr);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | 3, (", port = %"U16_F")\n", port));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, ("udp_bind(ipaddr = "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE, ip_2_ipX(ipaddr));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE, (", port = %"U16_F")\n", port));
rebind = 0;
/* Check for double bind and rebind of the same pcb */
@@ -579,33 +823,38 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
rebind = 1;
}
/* this code does not allow upper layer to share a UDP port for
listening to broadcast or multicast traffic (See SO_REUSE_ADDR and
SO_REUSE_PORT under *BSD). TODO: See where it fits instead, OR
combine with implementation of UDP PCB flags. Leon Woestenberg. */
#ifdef LWIP_UDP_TODO
/* port matches that of PCB in list? */
else
if ((ipcb->local_port == port) &&
/* By default, we don't allow to bind to a port that any other udp
PCB is alread bound to, unless *all* PCBs with that port have tha
REUSEADDR flag set. */
#if SO_REUSE
else if (((pcb->so_options & SOF_REUSEADDR) == 0) &&
((ipcb->so_options & SOF_REUSEADDR) == 0)) {
#else /* SO_REUSE */
/* port matches that of PCB in list and REUSEADDR not set -> reject */
else {
#endif /* SO_REUSE */
if ((ipcb->local_port == port) && IP_PCB_IPVER_EQ(pcb, ipcb) &&
/* IP address matches, or one is IP_ADDR_ANY? */
(ip_addr_isany(&(ipcb->local_ip)) ||
ip_addr_isany(ipaddr) ||
ip_addr_cmp(&(ipcb->local_ip), ipaddr))) {
(ipX_addr_isany(PCB_ISIPV6(ipcb), &(ipcb->local_ip)) ||
ipX_addr_isany(PCB_ISIPV6(ipcb), ip_2_ipX(ipaddr)) ||
ipX_addr_cmp(PCB_ISIPV6(ipcb), &(ipcb->local_ip), ip_2_ipX(ipaddr)))) {
/* other PCB already binds to this local IP and port */
LWIP_DEBUGF(UDP_DEBUG,
("udp_bind: local port %"U16_F" already bound by another pcb\n", port));
return ERR_USE;
}
#endif
}
}
ip_addr_set(&pcb->local_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->local_ip, ipaddr);
/* no port specified? */
if (port == 0) {
#ifndef UDP_LOCAL_PORT_RANGE_START
#define UDP_LOCAL_PORT_RANGE_START 4096
#define UDP_LOCAL_PORT_RANGE_END 0x7fff
/* From http://www.iana.org/assignments/port-numbers:
"The Dynamic and/or Private Ports are those from 49152 through 65535" */
#define UDP_LOCAL_PORT_RANGE_START 0xc000
#define UDP_LOCAL_PORT_RANGE_END 0xffff
#endif
port = UDP_LOCAL_PORT_RANGE_START;
ipcb = udp_pcbs;
@@ -615,9 +864,10 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
port++;
/* restart scanning all udp pcbs */
ipcb = udp_pcbs;
} else
} else {
/* go on with next udp pcb */
ipcb = ipcb->next;
}
}
if (ipcb != NULL) {
/* no more ports available in local range */
@@ -633,14 +883,12 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
pcb->next = udp_pcbs;
udp_pcbs = pcb;
}
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_bind: bound to %"U16_F".%"U16_F".%"U16_F".%"U16_F", port %"U16_F"\n",
(u16_t)(ntohl(pcb->local_ip.addr) >> 24 & 0xff),
(u16_t)(ntohl(pcb->local_ip.addr) >> 16 & 0xff),
(u16_t)(ntohl(pcb->local_ip.addr) >> 8 & 0xff),
(u16_t)(ntohl(pcb->local_ip.addr) & 0xff), pcb->local_port));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_bind: bound to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, &pcb->local_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->local_port));
return ERR_OK;
}
/**
* Connect an UDP PCB.
*
@@ -659,44 +907,49 @@ udp_bind(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
* @see udp_disconnect()
*/
err_t
udp_connect(struct udp_pcb *pcb, struct ip_addr *ipaddr, u16_t port)
udp_connect(struct udp_pcb *pcb, ip_addr_t *ipaddr, u16_t port)
{
struct udp_pcb *ipcb;
if (pcb->local_port == 0) {
err_t err = udp_bind(pcb, &pcb->local_ip, pcb->local_port);
if (err != ERR_OK)
err_t err = udp_bind(pcb, ipX_2_ip(&pcb->local_ip), pcb->local_port);
if (err != ERR_OK) {
return err;
}
}
ip_addr_set(&pcb->remote_ip, ipaddr);
ipX_addr_set_ipaddr(PCB_ISIPV6(pcb), &pcb->remote_ip, ipaddr);
pcb->remote_port = port;
pcb->flags |= UDP_FLAGS_CONNECTED;
/** TODO: this functionality belongs in upper layers */
#ifdef LWIP_UDP_TODO
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(&pcb->local_ip) && !ip_addr_isany(&pcb->remote_ip)) {
struct netif *netif;
#if LWIP_IPV6
if (!PCB_ISIPV6(pcb))
#endif /* LWIP_IPV6 */
{
/* Nail down local IP for netconn_addr()/getsockname() */
if (ip_addr_isany(ipX_2_ip(&pcb->local_ip)) && !ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
struct netif *netif;
if ((netif = ip_route(&(pcb->remote_ip))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n", pcb->remote_ip.addr));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
if ((netif = ip_route(ipX_2_ip(&pcb->remote_ip))) == NULL) {
LWIP_DEBUGF(UDP_DEBUG, ("udp_connect: No route to 0x%lx\n",
ip4_addr_get_u32(ipX_2_ip(&pcb->remote_ip))));
UDP_STATS_INC(udp.rterr);
return ERR_RTE;
}
/** TODO: this will bind the udp pcb locally, to the interface which
is used to route output packets to the remote address. However, we
might want to accept incoming packets on any interface! */
ipX_addr_copy(0, pcb->local_ip, netif->ip_addr);
} else if (ip_addr_isany(ipX_2_ip(&pcb->remote_ip))) {
ipX_addr_set_any(0, &pcb->local_ip);
}
/** TODO: this will bind the udp pcb locally, to the interface which
is used to route output packets to the remote address. However, we
might want to accept incoming packets on any interface! */
pcb->local_ip = netif->ip_addr;
} else if (ip_addr_isany(&pcb->remote_ip)) {
pcb->local_ip.addr = 0;
}
#endif
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
("udp_connect: connected to %"U16_F".%"U16_F".%"U16_F".%"U16_F",port %"U16_F"\n",
(u16_t)(ntohl(pcb->remote_ip.addr) >> 24 & 0xff),
(u16_t)(ntohl(pcb->remote_ip.addr) >> 16 & 0xff),
(u16_t)(ntohl(pcb->remote_ip.addr) >> 8 & 0xff),
(u16_t)(ntohl(pcb->remote_ip.addr) & 0xff), pcb->remote_port));
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, ("udp_connect: connected to "));
ipX_addr_debug_print(PCB_ISIPV6(pcb), UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE,
&pcb->remote_ip);
LWIP_DEBUGF(UDP_DEBUG | LWIP_DBG_TRACE | LWIP_DBG_STATE, (", port %"U16_F")\n", pcb->remote_port));
/* Insert UDP PCB into the list of active UDP PCBs. */
for (ipcb = udp_pcbs; ipcb != NULL; ipcb = ipcb->next) {
@@ -720,7 +973,7 @@ void
udp_disconnect(struct udp_pcb *pcb)
{
/* reset remote address association */
ip_addr_set(&pcb->remote_ip, IP_ADDR_ANY);
ipX_addr_set_any(PCB_ISIPV6(pcb), &pcb->remote_ip);
pcb->remote_port = 0;
/* mark PCB as unconnected */
pcb->flags &= ~UDP_FLAGS_CONNECTED;
@@ -736,13 +989,10 @@ udp_disconnect(struct udp_pcb *pcb)
* @param recv_arg additional argument to pass to the callback function
*/
void
udp_recv(struct udp_pcb *pcb,
void (* recv)(void *arg, struct udp_pcb *upcb, struct pbuf *p,
struct ip_addr *addr, u16_t port),
void *recv_arg)
udp_recv(struct udp_pcb *pcb, udp_recv_fn recv, void *recv_arg)
{
/* remember recv() callback and user data */
pcb->recv = recv;
pcb->recv.ip4 = recv;
pcb->recv_arg = recv_arg;
}
@@ -765,7 +1015,7 @@ udp_remove(struct udp_pcb *pcb)
/* make list start at 2nd pcb */
udp_pcbs = udp_pcbs->next;
/* pcb not 1st in list */
} else
} else {
for (pcb2 = udp_pcbs; pcb2 != NULL; pcb2 = pcb2->next) {
/* find pcb in udp_pcbs list */
if (pcb2->next != NULL && pcb2->next == pcb) {
@@ -773,6 +1023,7 @@ udp_remove(struct udp_pcb *pcb)
pcb2->next = pcb->next;
}
}
}
memp_free(MEMP_UDP_PCB, pcb);
}
@@ -788,7 +1039,7 @@ struct udp_pcb *
udp_new(void)
{
struct udp_pcb *pcb;
pcb = memp_malloc(MEMP_UDP_PCB);
pcb = (struct udp_pcb *)memp_malloc(MEMP_UDP_PCB);
/* could allocate UDP PCB? */
if (pcb != NULL) {
/* UDP Lite: by initializing to all zeroes, chksum_len is set to 0
@@ -801,6 +1052,25 @@ udp_new(void)
return pcb;
}
#if LWIP_IPV6
/**
* Create a UDP PCB for IPv6.
*
* @return The UDP PCB which was created. NULL if the PCB data structure
* could not be allocated.
*
* @see udp_remove()
*/
struct udp_pcb *
udp_new_ip6(void)
{
struct udp_pcb *pcb;
pcb = udp_new();
ip_set_v6(pcb, 1);
return pcb;
}
#endif /* LWIP_IPV6 */
#if UDP_DEBUG
/**
* Print UDP header information for debug purposes.

View File

@@ -52,6 +52,10 @@
#include "lwip/udp.h"
#include "netif/etharp.h"
#ifdef __cplusplus
extern "C" {
#endif
/* AutoIP Timing */
#define AUTOIP_TMR_INTERVAL 100
#define AUTOIP_TICKS_PER_SECOND (1000 / AUTOIP_TMR_INTERVAL)
@@ -76,7 +80,7 @@
struct autoip
{
struct ip_addr llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
ip_addr_t llipaddr; /* the currently selected, probed, announced or used LL IP-Address */
u8_t state; /* current AutoIP state machine state */
u8_t sent_num; /* sent number of probes or announces, dependent on state */
u16_t ttw; /* ticks to wait, tick is AUTOIP_TMR_INTERVAL long */
@@ -85,8 +89,10 @@ struct autoip
};
/** Init srand, has to be called before entering mainloop */
void autoip_init(void);
#define autoip_init() /* Compatibility define, no init needed. */
/** Set a struct autoip allocated by the application to work with */
void autoip_set_struct(struct netif *netif, struct autoip *autoip);
/** Start AutoIP client */
err_t autoip_start(struct netif *netif);
@@ -100,6 +106,13 @@ void autoip_arp_reply(struct netif *netif, struct etharp_hdr *hdr);
/** Has to be called in loop every AUTOIP_TMR_INTERVAL milliseconds */
void autoip_tmr(void);
/** Handle a possible change in the network configuration */
void autoip_network_changed(struct netif *netif);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_AUTOIP */
#endif /* __LWIP_AUTOIP_H__ */

View File

@@ -33,89 +33,93 @@
#define __LWIP_ICMP_H__
#include "lwip/opt.h"
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/netif.h"
#if LWIP_IPV6 && LWIP_ICMP6
#include "lwip/icmp6.h"
#endif
#ifdef __cplusplus
extern "C" {
#endif
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ER 0 /* echo reply */
#define ICMP_DUR 3 /* destination unreachable */
#define ICMP_SQ 4 /* source quench */
#define ICMP_RD 5 /* redirect */
#define ICMP_ECHO 8 /* echo */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TE 11 /* time exceeded */
#define ICMP_PP 12 /* parameter problem */
#define ICMP_TS 13 /* timestamp */
#define ICMP_TSR 14 /* timestamp reply */
#define ICMP_IRQ 15 /* information request */
#define ICMP_IR 16 /* information reply */
#define ICMP_IR 16 /* information reply */
enum icmp_dur_type {
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_NET = 0, /* net unreachable */
ICMP_DUR_HOST = 1, /* host unreachable */
ICMP_DUR_PROTO = 2, /* protocol unreachable */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
ICMP_DUR_PORT = 3, /* port unreachable */
ICMP_DUR_FRAG = 4, /* fragmentation needed and DF set */
ICMP_DUR_SR = 5 /* source route failed */
};
enum icmp_te_type {
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_TTL = 0, /* time to live exceeded in transit */
ICMP_TE_FRAG = 1 /* fragment reassembly time exceeded */
};
void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
/** This is the standard ICMP header only that the u32_t data
* is splitted to two u16_t like ICMP echo needs it.
* This header is also used for other ICMP types that do not
* use the data part.
*/
PACK_STRUCT_BEGIN
struct icmp_echo_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_dur_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
PACK_STRUCT_BEGIN
struct icmp_te_hdr {
PACK_STRUCT_FIELD(u16_t _type_code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t unused);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ICMPH_TYPE(hdr) (ntohs((hdr)->_type_code) >> 8)
#define ICMPH_CODE(hdr) (ntohs((hdr)->_type_code) & 0xff)
#define ICMPH_TYPE(hdr) ((hdr)->type)
#define ICMPH_CODE(hdr) ((hdr)->code)
#define ICMPH_TYPE_SET(hdr, type) ((hdr)->_type_code = htons(ICMPH_CODE(hdr) | ((type) << 8)))
#define ICMPH_CODE_SET(hdr, code) ((hdr)->_type_code = htons((code) | (ICMPH_TYPE(hdr) << 8)))
/** Combines type and code to an u16_t */
#define ICMPH_TYPE_SET(hdr, t) ((hdr)->type = (t))
#define ICMPH_CODE_SET(hdr, c) ((hdr)->code = (c))
#if LWIP_ICMP /* don't build if not configured for use in lwipopts.h */
void icmp_input(struct pbuf *p, struct netif *inp);
void icmp_dest_unreach(struct pbuf *p, enum icmp_dur_type t);
void icmp_time_exceeded(struct pbuf *p, enum icmp_te_type t);
#endif /* LWIP_ICMP */
#if (LWIP_IPV6 && LWIP_ICMP6)
#define icmp_port_unreach(isipv6, pbuf) ((isipv6) ? \
icmp6_dest_unreach(pbuf, ICMP6_DUR_PORT) : \
icmp_dest_unreach(pbuf, ICMP_DUR_PORT))
#elif LWIP_ICMP
#define icmp_port_unreach(isipv6, pbuf) icmp_dest_unreach(pbuf, ICMP_DUR_PORT)
#else /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
#define icmp_port_unreach(isipv6, pbuf)
#endif /* (LWIP_IPV6 && LWIP_ICMP6) || LWIP_ICMP*/
#ifdef __cplusplus
}
#endif
#endif /* LWIP_ICMP */
#endif /* __LWIP_ICMP_H__ */

View File

@@ -46,57 +46,20 @@
extern "C" {
#endif
/*
* IGMP constants
*/
#define IP_PROTO_IGMP 2
#define IGMP_TTL 1
#define IGMP_MINLEN 8
#define ROUTER_ALERT 0x9404
#define ROUTER_ALERTLEN 4
/*
* IGMP message types, including version number.
*/
#define IGMP_MEMB_QUERY 0x11 /* Membership query */
#define IGMP_V1_MEMB_REPORT 0x12 /* Ver. 1 membership report */
#define IGMP_V2_MEMB_REPORT 0x16 /* Ver. 2 membership report */
#define IGMP_LEAVE_GROUP 0x17 /* Leave-group message */
/* IGMP timer */
#define IGMP_TMR_INTERVAL 100 /* Milliseconds */
#define IGMP_V1_DELAYING_MEMBER_TMR (1000/IGMP_TMR_INTERVAL)
#define IGMP_JOIN_DELAYING_MEMBER_TMR (500 /IGMP_TMR_INTERVAL)
/* MAC Filter Actions */
/* MAC Filter Actions, these are passed to a netif's
* igmp_mac_filter callback function. */
#define IGMP_DEL_MAC_FILTER 0
#define IGMP_ADD_MAC_FILTER 1
/* Group membership states */
#define IGMP_GROUP_NON_MEMBER 0
#define IGMP_GROUP_DELAYING_MEMBER 1
#define IGMP_GROUP_IDLE_MEMBER 2
/*
* IGMP packet format.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct igmp_msg {
PACK_STRUCT_FIELD(u8_t igmp_msgtype);
PACK_STRUCT_FIELD(u8_t igmp_maxresp);
PACK_STRUCT_FIELD(u16_t igmp_checksum);
PACK_STRUCT_FIELD(struct ip_addr igmp_group_address);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/*
* now a group structure - there is
/**
* igmp group structure - there is
* a list of groups for each interface
* these should really be linked from the interface, but
* if we keep them separate we will not affect the lwip original code
@@ -106,53 +69,34 @@ PACK_STRUCT_END
* will not run the state machine as it is used to kick off reports
* from all the other groups
*/
struct igmp_group {
/** next link */
struct igmp_group *next;
struct netif *interface;
struct ip_addr group_address;
u8_t last_reporter_flag; /* signifies we were the last person to report */
/** interface on which the group is active */
struct netif *netif;
/** multicast address */
ip_addr_t group_address;
/** signifies we were the last person to report */
u8_t last_reporter_flag;
/** current state of the group */
u8_t group_state;
/** timer for reporting, negative is OFF */
u16_t timer;
u8_t use; /* counter of simultaneous uses */
/** counter of simultaneous uses */
u8_t use;
};
/* Prototypes */
void igmp_init(void);
err_t igmp_start( struct netif *netif);
err_t igmp_stop( struct netif *netif);
void igmp_report_groups( struct netif *netif);
struct igmp_group *igmp_lookfor_group( struct netif *ifp, struct ip_addr *addr);
struct igmp_group *igmp_lookup_group( struct netif *ifp, struct ip_addr *addr);
err_t igmp_remove_group( struct igmp_group *group);
void igmp_input( struct pbuf *p, struct netif *inp, struct ip_addr *dest);
err_t igmp_joingroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
err_t igmp_leavegroup( struct ip_addr *ifaddr, struct ip_addr *groupaddr);
err_t igmp_start(struct netif *netif);
err_t igmp_stop(struct netif *netif);
void igmp_report_groups(struct netif *netif);
struct igmp_group *igmp_lookfor_group(struct netif *ifp, ip_addr_t *addr);
void igmp_input(struct pbuf *p, struct netif *inp, ip_addr_t *dest);
err_t igmp_joingroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
err_t igmp_leavegroup(ip_addr_t *ifaddr, ip_addr_t *groupaddr);
void igmp_tmr(void);
void igmp_timeout( struct igmp_group *group);
void igmp_start_timer( struct igmp_group *group, u8_t max_time);
void igmp_stop_timer( struct igmp_group *group);
void igmp_delaying_member( struct igmp_group *group, u8_t maxresp);
err_t igmp_ip_output_if( struct pbuf *p, struct ip_addr *src, struct ip_addr *dest, u8_t ttl, u8_t proto, struct netif *netif);
void igmp_send( struct igmp_group *group, u8_t type);
#ifdef __cplusplus
}
#endif

View File

@@ -33,60 +33,72 @@
#define __LWIP_INET_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
u32_t inet_addr(const char *cp);
int inet_aton(const char *cp, struct in_addr *addr);
char *inet_ntoa(struct in_addr addr); /* returns ptr to static buffer; not reentrant! */
/** For compatibility with BSD code */
struct in_addr {
u32_t s_addr;
};
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
/** 255.255.255.255 */
#define INADDR_NONE IPADDR_NONE
/** 127.0.0.1 */
#define INADDR_LOOPBACK IPADDR_LOOPBACK
/** 0.0.0.0 */
#define INADDR_ANY IPADDR_ANY
/** 255.255.255.255 */
#define INADDR_BROADCAST IPADDR_BROADCAST
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 0
#endif
/* Definitions of the bits in an Internet address integer.
#if BYTE_ORDER == BIG_ENDIAN
#define htons(x) (x)
#define ntohs(x) (x)
#define htonl(x) (x)
#define ntohl(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#ifdef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#define htons lwip_htons
#define ntohs lwip_ntohs
#define htonl lwip_htonl
#define ntohl lwip_ntohl
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
#if LWIP_PLATFORM_BYTESWAP
#define htons(x) LWIP_PLATFORM_HTONS(x)
#define ntohs(x) LWIP_PLATFORM_HTONS(x)
#define htonl(x) LWIP_PLATFORM_HTONL(x)
#define ntohl(x) LWIP_PLATFORM_HTONL(x)
#else /* LWIP_PLATFORM_BYTESWAP */
u16_t htons(u16_t x);
u16_t ntohs(u16_t x);
u32_t htonl(u32_t x);
u32_t ntohl(u32_t x);
#endif /* LWIP_PLATFORM_BYTESWAP */
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IN_CLASSA(a) IP_CLASSA(a)
#define IN_CLASSA_NET IP_CLASSA_NET
#define IN_CLASSA_NSHIFT IP_CLASSA_NSHIFT
#define IN_CLASSA_HOST IP_CLASSA_HOST
#define IN_CLASSA_MAX IP_CLASSA_MAX
#endif /* BYTE_ORDER == BIG_ENDIAN */
#define IN_CLASSB(b) IP_CLASSB(b)
#define IN_CLASSB_NET IP_CLASSB_NET
#define IN_CLASSB_NSHIFT IP_CLASSB_NSHIFT
#define IN_CLASSB_HOST IP_CLASSB_HOST
#define IN_CLASSB_MAX IP_CLASSB_MAX
#define IN_CLASSC(c) IP_CLASSC(c)
#define IN_CLASSC_NET IP_CLASSC_NET
#define IN_CLASSC_NSHIFT IP_CLASSC_NSHIFT
#define IN_CLASSC_HOST IP_CLASSC_HOST
#define IN_CLASSC_MAX IP_CLASSC_MAX
#define IN_CLASSD(d) IP_CLASSD(d)
#define IN_CLASSD_NET IP_CLASSD_NET /* These ones aren't really */
#define IN_CLASSD_NSHIFT IP_CLASSD_NSHIFT /* net and host fields, but */
#define IN_CLASSD_HOST IP_CLASSD_HOST /* routing needn't know. */
#define IN_CLASSD_MAX IP_CLASSD_MAX
#define IN_MULTICAST(a) IP_MULTICAST(a)
#define IN_EXPERIMENTAL(a) IP_EXPERIMENTAL(a)
#define IN_BADCLASS(a) IP_BADCLASS(a)
#define IN_LOOPBACKNET IP_LOOPBACKNET
#define inet_addr_from_ipaddr(target_inaddr, source_ipaddr) ((target_inaddr)->s_addr = ip4_addr_get_u32(source_ipaddr))
#define inet_addr_to_ipaddr(target_ipaddr, source_inaddr) (ip4_addr_set_u32(target_ipaddr, (source_inaddr)->s_addr))
/* ATTENTION: the next define only works because both s_addr and ip_addr_t are an u32_t effectively! */
#define inet_addr_to_ipaddr_p(target_ipaddr_p, source_inaddr) ((target_ipaddr_p) = (ip_addr_t*)&((source_inaddr)->s_addr))
/* directly map this to the lwip internal functions */
#define inet_addr(cp) ipaddr_addr(cp)
#define inet_aton(cp, addr) ipaddr_aton(cp, (ip_addr_t*)addr)
#define inet_ntoa(addr) ipaddr_ntoa((ip_addr_t*)&(addr))
#define inet_ntoa_r(addr, buf, buflen) ipaddr_ntoa_r((ip_addr_t*)&(addr), buf, buflen)
#ifdef __cplusplus
}

View File

@@ -29,86 +29,33 @@
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#ifndef __LWIP_IP4_H__
#define __LWIP_IP4_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#define ip_init() /* Compatibility define, not init needed. */
struct netif *ip_route(struct ip_addr *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto);
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t tos, u8_t proto,
struct netif *netif);
/** Currently, the function ip_output_if_opt() is only used with IGMP */
#define IP_OPTIONS_SEND LWIP_IGMP
#define IP_HLEN 20
#define IP_PROTO_ICMP 1
#define IP_PROTO_IGMP 2
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP 6
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
/* ip addresses in network byte order */ \
struct ip_addr local_ip; \
struct ip_addr remote_ip; \
/* Socket options */ \
u16_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
#define SOF_DEBUG (u16_t)0x0001U /* turn on debugging info recording */
#define SOF_ACCEPTCONN (u16_t)0x0002U /* socket has had listen() */
#define SOF_REUSEADDR (u16_t)0x0004U /* allow local address reuse */
#define SOF_KEEPALIVE (u16_t)0x0008U /* keep connections alive */
#define SOF_DONTROUTE (u16_t)0x0010U /* just use interface addresses */
#define SOF_BROADCAST (u16_t)0x0020U /* permit sending of broadcast msgs */
#define SOF_USELOOPBACK (u16_t)0x0040U /* bypass hardware when possible */
#define SOF_LINGER (u16_t)0x0080U /* linger on close if data present */
#define SOF_OOBINLINE (u16_t)0x0100U /* leave received OOB data in line */
#define SOF_REUSEPORT (u16_t)0x0200U /* allow local address & port reuse */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
@@ -123,17 +70,19 @@ struct ip_hdr {
PACK_STRUCT_FIELD(u16_t _id);
/* fragment offset field */
PACK_STRUCT_FIELD(u16_t _offset);
#define IP_RF 0x8000 /* reserved fragment flag */
#define IP_DF 0x4000 /* dont fragment flag */
#define IP_MF 0x2000 /* more fragments flag */
#define IP_OFFMASK 0x1fff /* mask for fragmenting bits */
/* time to live / protocol*/
PACK_STRUCT_FIELD(u16_t _ttl_proto);
#define IP_RF 0x8000U /* reserved fragment flag */
#define IP_DF 0x4000U /* dont fragment flag */
#define IP_MF 0x2000U /* more fragments flag */
#define IP_OFFMASK 0x1fffU /* mask for fragmenting bits */
/* time to live */
PACK_STRUCT_FIELD(u8_t _ttl);
/* protocol*/
PACK_STRUCT_FIELD(u8_t _proto);
/* checksum */
PACK_STRUCT_FIELD(u16_t _chksum);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(struct ip_addr src);
PACK_STRUCT_FIELD(struct ip_addr dest);
PACK_STRUCT_FIELD(ip_addr_p_t src);
PACK_STRUCT_FIELD(ip_addr_p_t dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
@@ -146,18 +95,39 @@ PACK_STRUCT_END
#define IPH_LEN(hdr) ((hdr)->_len)
#define IPH_ID(hdr) ((hdr)->_id)
#define IPH_OFFSET(hdr) ((hdr)->_offset)
#define IPH_TTL(hdr) (ntohs((hdr)->_ttl_proto) >> 8)
#define IPH_PROTO(hdr) (ntohs((hdr)->_ttl_proto) & 0xff)
#define IPH_TTL(hdr) ((hdr)->_ttl)
#define IPH_PROTO(hdr) ((hdr)->_proto)
#define IPH_CHKSUM(hdr) ((hdr)->_chksum)
#define IPH_VHLTOS_SET(hdr, v, hl, tos) (hdr)->_v_hl_tos = (htons(((v) << 12) | ((hl) << 8) | (tos)))
#define IPH_LEN_SET(hdr, len) (hdr)->_len = (len)
#define IPH_ID_SET(hdr, id) (hdr)->_id = (id)
#define IPH_OFFSET_SET(hdr, off) (hdr)->_offset = (off)
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl_proto = (htons(IPH_PROTO(hdr) | ((u16_t)(ttl) << 8)))
#define IPH_PROTO_SET(hdr, proto) (hdr)->_ttl_proto = (htons((proto) | (IPH_TTL(hdr) << 8)))
#define IPH_TTL_SET(hdr, ttl) (hdr)->_ttl = (u8_t)(ttl)
#define IPH_PROTO_SET(hdr, proto) (hdr)->_proto = (u8_t)(proto)
#define IPH_CHKSUM_SET(hdr, chksum) (hdr)->_chksum = (chksum)
#define ip_init() /* Compatibility define, no init needed. */
struct netif *ip_route(ip_addr_t *dest);
err_t ip_input(struct pbuf *p, struct netif *inp);
err_t ip_output(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto);
err_t ip_output_if(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto,
struct netif *netif);
#if LWIP_NETIF_HWADDRHINT
err_t ip_output_hinted(struct pbuf *p, ip_addr_t *src, ip_addr_t *dest,
u8_t ttl, u8_t tos, u8_t proto, u8_t *addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT */
#if IP_OPTIONS_SEND
err_t ip_output_if_opt(struct pbuf *p, 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 */
#define ip_netif_get_local_ipX(netif) (((netif) != NULL) ? ip_2_ipX(&((netif)->ip_addr)) : NULL)
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#else

View File

@@ -0,0 +1,244 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP4_ADDR_H__
#define __LWIP_IP4_ADDR_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This is the aligned version of ip_addr_t,
used as local variable, on the stack, etc. */
struct ip_addr {
u32_t addr;
};
/* This is the packed version of ip_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr_packed {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** ip_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip_addr_t as well as on ip_addr_p_t. */
typedef struct ip_addr ip_addr_t;
typedef struct ip_addr_packed ip_addr_p_t;
/*
* struct ipaddr2 is used in the definition of the ARP packet format in
* order to support compilers that don't have structure packing.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Forward declaration to not include netif.h */
struct netif;
extern const ip_addr_t ip_addr_any;
extern const ip_addr_t ip_addr_broadcast;
/** IP_ADDR_ can be used as a fixed IP address
* for the wildcard and the broadcast address
*/
#define IP_ADDR_ANY ((ip_addr_t *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((ip_addr_t *)&ip_addr_broadcast)
/** 255.255.255.255 */
#define IPADDR_NONE ((u32_t)0xffffffffUL)
/** 127.0.0.1 */
#define IPADDR_LOOPBACK ((u32_t)0x7f000001UL)
/** 0.0.0.0 */
#define IPADDR_ANY ((u32_t)0x00000000UL)
/** 255.255.255.255 */
#define IPADDR_BROADCAST ((u32_t)0xffffffffUL)
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IP_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IP_CLASSA_NET 0xff000000
#define IP_CLASSA_NSHIFT 24
#define IP_CLASSA_HOST (0xffffffff & ~IP_CLASSA_NET)
#define IP_CLASSA_MAX 128
#define IP_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IP_CLASSB_NET 0xffff0000
#define IP_CLASSB_NSHIFT 16
#define IP_CLASSB_HOST (0xffffffff & ~IP_CLASSB_NET)
#define IP_CLASSB_MAX 65536
#define IP_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IP_CLASSC_NET 0xffffff00
#define IP_CLASSC_NSHIFT 8
#define IP_CLASSC_HOST (0xffffffff & ~IP_CLASSC_NET)
#define IP_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IP_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IP_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IP_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IP_MULTICAST(a) IP_CLASSD(a)
#define IP_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IP_LOOPBACKNET 127 /* official! */
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IP address given by the four byte-parts */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IP address given by the four byte-parts.
Little-endian version that prevents the use of htonl. */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
/** MEMCPY-like copying of IP addresses where addresses are known to be
* 16-bit-aligned if the port is correctly configured (so a port could define
* this to copying 2 u16_t's) - no NULL-pointer-checking needed. */
#ifndef IPADDR2_COPY
#define IPADDR2_COPY(dest, src) SMEMCPY(dest, src, sizeof(ip_addr_t))
#endif
/** Copy IP address - faster than ip_addr_set: no NULL check */
#define ip_addr_copy(dest, src) ((dest).addr = (src).addr)
/** Safely copy one IP address to another (src may be NULL) */
#define ip_addr_set(dest, src) ((dest)->addr = \
((src) == NULL ? 0 : \
(src)->addr))
/** Set complete address to zero */
#define ip_addr_set_zero(ipaddr) ((ipaddr)->addr = 0)
/** Set address to IPADDR_ANY (no need for htonl()) */
#define ip_addr_set_any(ipaddr) ((ipaddr)->addr = IPADDR_ANY)
/** Set address to loopback address */
#define ip_addr_set_loopback(ipaddr) ((ipaddr)->addr = PP_HTONL(IPADDR_LOOPBACK))
/** Safely copy one IP address to another and change byte order
* from host- to network-order. */
#define ip_addr_set_hton(dest, src) ((dest)->addr = \
((src) == NULL ? 0:\
htonl((src)->addr)))
/** IPv4 only: set the IP address given as an u32_t */
#define ip4_addr_set_u32(dest_ipaddr, src_u32) ((dest_ipaddr)->addr = (src_u32))
/** IPv4 only: get the IP address as an u32_t */
#define ip4_addr_get_u32(src_ipaddr) ((src_ipaddr)->addr)
/** Get the network address by combining host address with netmask */
#define ip_addr_get_network(target, host, netmask) ((target)->addr = ((host)->addr) & ((netmask)->addr))
/**
* Determine if two address are on the same network.
*
* @arg addr1 IP address 1
* @arg addr2 IP address 2
* @arg mask network identifier mask
* @return !0 if the network identifiers of both address match
*/
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
(mask)->addr) == \
((addr2)->addr & \
(mask)->addr))
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == IPADDR_ANY)
#define ip_addr_isbroadcast(ipaddr, netif) ip4_addr_isbroadcast((ipaddr)->addr, (netif))
u8_t ip4_addr_isbroadcast(u32_t addr, const struct netif *netif);
#define ip_addr_netmask_valid(netmask) ip4_addr_netmask_valid((netmask)->addr)
u8_t ip4_addr_netmask_valid(u32_t netmask);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & PP_HTONL(0xf0000000UL)) == PP_HTONL(0xe0000000UL))
#define ip_addr_islinklocal(addr1) (((addr1)->addr & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xa9fe0000UL))
#define ip_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
ipaddr != NULL ? ip4_addr1_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr2_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr3_16(ipaddr) : 0, \
ipaddr != NULL ? ip4_addr4_16(ipaddr) : 0))
/* Get one byte from the 4-byte address */
#define ip4_addr1(ipaddr) (((u8_t*)(ipaddr))[0])
#define ip4_addr2(ipaddr) (((u8_t*)(ipaddr))[1])
#define ip4_addr3(ipaddr) (((u8_t*)(ipaddr))[2])
#define ip4_addr4(ipaddr) (((u8_t*)(ipaddr))[3])
/* These are cast to u16_t, with the intent that they are often arguments
* to printf using the U16_F format from cc.h. */
#define ip4_addr1_16(ipaddr) ((u16_t)ip4_addr1(ipaddr))
#define ip4_addr2_16(ipaddr) ((u16_t)ip4_addr2(ipaddr))
#define ip4_addr3_16(ipaddr) ((u16_t)ip4_addr3(ipaddr))
#define ip4_addr4_16(ipaddr) ((u16_t)ip4_addr4(ipaddr))
/** For backwards compatibility */
#define ip_ntoa(ipaddr) ipaddr_ntoa(ipaddr)
u32_t ipaddr_addr(const char *cp);
int ipaddr_aton(const char *cp, ip_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ipaddr_ntoa(const ip_addr_t *addr);
char *ipaddr_ntoa_r(const ip_addr_t *addr, char *buf, int buflen);
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View File

@@ -1,170 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr {
PACK_STRUCT_FIELD(u32_t addr);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/*
* struct ipaddr2 is used in the definition of the ARP packet format in
* order to support compilers that don't have structure packing.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* For compatibility with BSD code */
struct in_addr {
u32_t s_addr;
};
struct netif;
extern const struct ip_addr ip_addr_any;
extern const struct ip_addr ip_addr_broadcast;
/** IP_ADDR_ can be used as a fixed IP address
* for the wildcard and the broadcast address
*/
#define IP_ADDR_ANY ((struct ip_addr *)&ip_addr_any)
#define IP_ADDR_BROADCAST ((struct ip_addr *)&ip_addr_broadcast)
#define INADDR_NONE ((u32_t)0xffffffffUL) /* 255.255.255.255 */
#define INADDR_LOOPBACK ((u32_t)0x7f000001UL) /* 127.0.0.1 */
/* Definitions of the bits in an Internet address integer.
On subnets, host and network parts are found according to
the subnet mask, not these masks. */
#define IN_CLASSA(a) ((((u32_t)(a)) & 0x80000000UL) == 0)
#define IN_CLASSA_NET 0xff000000
#define IN_CLASSA_NSHIFT 24
#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET)
#define IN_CLASSA_MAX 128
#define IN_CLASSB(a) ((((u32_t)(a)) & 0xc0000000UL) == 0x80000000UL)
#define IN_CLASSB_NET 0xffff0000
#define IN_CLASSB_NSHIFT 16
#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET)
#define IN_CLASSB_MAX 65536
#define IN_CLASSC(a) ((((u32_t)(a)) & 0xe0000000UL) == 0xc0000000UL)
#define IN_CLASSC_NET 0xffffff00
#define IN_CLASSC_NSHIFT 8
#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET)
#define IN_CLASSD(a) (((u32_t)(a) & 0xf0000000UL) == 0xe0000000UL)
#define IN_CLASSD_NET 0xf0000000 /* These ones aren't really */
#define IN_CLASSD_NSHIFT 28 /* net and host fields, but */
#define IN_CLASSD_HOST 0x0fffffff /* routing needn't know. */
#define IN_MULTICAST(a) IN_CLASSD(a)
#define IN_EXPERIMENTAL(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_BADCLASS(a) (((u32_t)(a) & 0xf0000000UL) == 0xf0000000UL)
#define IN_LOOPBACKNET 127 /* official! */
#define IP4_ADDR(ipaddr, a,b,c,d) \
(ipaddr)->addr = htonl(((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff))
#define ip_addr_set(dest, src) (dest)->addr = \
((src) == NULL? 0:\
(src)->addr)
/**
* Determine if two address are on the same network.
*
* @arg addr1 IP address 1
* @arg addr2 IP address 2
* @arg mask network identifier mask
* @return !0 if the network identifiers of both address match
*/
#define ip_addr_netcmp(addr1, addr2, mask) (((addr1)->addr & \
(mask)->addr) == \
((addr2)->addr & \
(mask)->addr))
#define ip_addr_cmp(addr1, addr2) ((addr1)->addr == (addr2)->addr)
#define ip_addr_isany(addr1) ((addr1) == NULL || (addr1)->addr == 0)
u8_t ip_addr_isbroadcast(struct ip_addr *, struct netif *);
#define ip_addr_ismulticast(addr1) (((addr1)->addr & ntohl(0xf0000000UL)) == ntohl(0xe0000000UL))
#define ip_addr_islinklocal(addr1) (((addr1)->addr & ntohl(0xffff0000UL)) == ntohl(0xa9fe0000UL))
#define ip_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"U16_F".%"U16_F".%"U16_F".%"U16_F, \
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff : 0, \
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff : 0, \
ipaddr ? (u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff : 0, \
ipaddr ? (u16_t)ntohl((ipaddr)->addr) & 0xff : 0))
/* These are cast to u16_t, with the intent that they are often arguments
* to printf using the U16_F format from cc.h. */
#define ip4_addr1(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 24) & 0xff)
#define ip4_addr2(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 16) & 0xff)
#define ip4_addr3(ipaddr) ((u16_t)(ntohl((ipaddr)->addr) >> 8) & 0xff)
#define ip4_addr4(ipaddr) ((u16_t)(ntohl((ipaddr)->addr)) & 0xff)
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View File

@@ -66,7 +66,22 @@ struct pbuf * ip_reass(struct pbuf *p);
#endif /* IP_REASSEMBLY */
#if IP_FRAG
err_t ip_frag(struct pbuf *p, struct netif *netif, struct ip_addr *dest);
#if !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
#ifndef __LWIP_PBUF_CUSTOM_REF__
#define __LWIP_PBUF_CUSTOM_REF__
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
#endif /* !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
err_t ip_frag(struct pbuf *p, struct netif *netif, ip_addr_t *dest);
#endif /* IP_FRAG */
#ifdef __cplusplus

View File

@@ -1,8 +1,14 @@
/**
* @file
*
* IPv6 address autoconfiguration as per RFC 4862.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
@@ -11,58 +17,42 @@
* 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.
* 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
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
* Author: Ivan Delamer <delamer@inicotech.com>
*
* IPv6 address autoconfiguration as per RFC 4862.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_INET_H__
#define __LWIP_INET_H__
#ifndef __LWIP_IP6_DHCP6_H__
#define __LWIP_IP6_DHCP6_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6_DHCP6 /* don't build if not configured for use in lwipopts.h */
u16_t inet_chksum(void *data, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u32_t proto_len);
u32_t inet_addr(const char *cp);
s8_t inet_aton(const char *cp, struct in_addr *addr);
struct dhcp6
{
//TODO: implement DHCP6
};
#ifndef _MACHINE_ENDIAN_H_
#ifndef _NETINET_IN_H
#ifndef _LINUX_BYTEORDER_GENERIC_H
u16_t htons(u16_t n);
u16_t ntohs(u16_t n);
u32_t htonl(u32_t n);
u32_t ntohl(u32_t n);
#endif /* _LINUX_BYTEORDER_GENERIC_H */
#endif /* _NETINET_IN_H */
#endif /* _MACHINE_ENDIAN_H_ */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */
#endif /* LWIP_IPV6_DHCP6 */
#endif /* __LWIP_IP6_DHCP6_H__ */

View File

@@ -1,8 +1,14 @@
/**
* @file
*
* Ethernet output for IPv6. Uses ND tables for link-layer addressing.
*/
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
@@ -11,48 +17,52 @@
* 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.
* 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
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
* Author: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_INET_CHKSUM_H__
#define __LWIP_INET_CHKSUM_H__
#ifndef __LWIP_ETHIP6_H__
#define __LWIP_ETHIP6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_ETHERNET /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len);
u16_t inet_chksum_pseudo_partial(struct pbuf *p,
struct ip_addr *src, struct ip_addr *dest,
u8_t proto, u16_t proto_len, u16_t chksum_len);
err_t ethip6_output(struct netif *netif, struct pbuf *q, ip6_addr_t *ip6addr);
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */
#endif /* LWIP_IPV6 && LWIP_ETHERNET */
#endif /* __LWIP_ETHIP6_H__ */

View File

@@ -0,0 +1,152 @@
/**
* @file
*
* IPv6 version of ICMP, as per RFC 4443.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_ICMP6_H__
#define __LWIP_ICMP6_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
enum icmp6_type {
ICMP6_TYPE_DUR = 1, /* Destination unreachable */
ICMP6_TYPE_PTB = 2, /* Packet too big */
ICMP6_TYPE_TE = 3, /* Time exceeded */
ICMP6_TYPE_PP = 4, /* Parameter problem */
ICMP6_TYPE_PE1 = 100, /* Private experimentation */
ICMP6_TYPE_PE2 = 101, /* Private experimentation */
ICMP6_TYPE_RSV_ERR = 127, /* Reserved for expansion of error messages */
ICMP6_TYPE_EREQ = 128, /* Echo request */
ICMP6_TYPE_EREP = 129, /* Echo reply */
ICMP6_TYPE_MLQ = 130, /* Multicast listener query */
ICMP6_TYPE_MLR = 131, /* Multicast listener report */
ICMP6_TYPE_MLD = 132, /* Multicast listener done */
ICMP6_TYPE_RS = 133, /* Router solicitation */
ICMP6_TYPE_RA = 134, /* Router advertisement */
ICMP6_TYPE_NS = 135, /* Neighbor solicitation */
ICMP6_TYPE_NA = 136, /* Neighbor advertisement */
ICMP6_TYPE_RD = 137, /* Redirect */
ICMP6_TYPE_MRA = 151, /* Multicast router advertisement */
ICMP6_TYPE_MRS = 152, /* Multicast router solicitation */
ICMP6_TYPE_MRT = 153, /* Multicast router termination */
ICMP6_TYPE_PE3 = 200, /* Private experimentation */
ICMP6_TYPE_PE4 = 201, /* Private experimentation */
ICMP6_TYPE_RSV_INF = 255 /* Reserved for expansion of informational messages */
};
enum icmp6_dur_code {
ICMP6_DUR_NO_ROUTE = 0, /* No route to destination */
ICMP6_DUR_PROHIBITED = 1, /* Communication with destination administratively prohibited */
ICMP6_DUR_SCOPE = 2, /* Beyond scope of source address */
ICMP6_DUR_ADDRESS = 3, /* Address unreachable */
ICMP6_DUR_PORT = 4, /* Port unreachable */
ICMP6_DUR_POLICY = 5, /* Source address failed ingress/egress policy */
ICMP6_DUR_REJECT_ROUTE = 6 /* Reject route to destination */
};
enum icmp6_te_code {
ICMP6_TE_HL = 0, /* Hop limit exceeded in transit */
ICMP6_TE_FRAG = 1 /* Fragment reassembly time exceeded */
};
enum icmp6_pp_code {
ICMP6_PP_FIELD = 0, /* Erroneous header field encountered */
ICMP6_PP_HEADER = 1, /* Unrecognized next header type encountered */
ICMP6_PP_OPTION = 2, /* Unrecognized IPv6 option encountered */
};
/** This is the standard ICMP6 header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp6_hdr {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t data);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** This is the ICMP6 header adapted for echo req/resp. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct icmp6_echo_hdr {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t id);
PACK_STRUCT_FIELD(u16_t seqno);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#if LWIP_ICMP6 && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
void icmp6_input(struct pbuf *p, struct netif *inp);
void icmp6_dest_unreach(struct pbuf *p, enum icmp6_dur_code c);
void icmp6_packet_too_big(struct pbuf *p, u32_t mtu);
void icmp6_time_exceeded(struct pbuf *p, enum icmp6_te_code c);
void icmp6_param_problem(struct pbuf *p, enum icmp6_pp_code c, u32_t pointer);
#endif /* LWIP_ICMP6 && LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_ICMP6_H__ */

View File

@@ -0,0 +1,89 @@
/**
* @file
*
* INET v6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_INET6_H__
#define __LWIP_INET6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 && LWIP_SOCKET /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#ifdef __cplusplus
extern "C" {
#endif
/** For compatibility with BSD code */
struct in6_addr {
u32_t s_addr[4];
};
#define IN6ADDR_ANY_INIT {0,0,0,0}
#define IN6ADDR_LOOPBACK_INIT {0,0,0,PP_HTONL(1)}
#define inet6_addr_from_ip6addr(target_in6addr, source_ip6addr) {(target_in6addr)->s_addr[0] = (source_ip6addr)->addr[0]; \
(target_in6addr)->s_addr[1] = (source_ip6addr)->addr[1]; \
(target_in6addr)->s_addr[2] = (source_ip6addr)->addr[2]; \
(target_in6addr)->s_addr[3] = (source_ip6addr)->addr[3];}
#define inet6_addr_to_ip6addr(target_ip6addr, source_in6addr) {(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0]; \
(target_ip6addr)->addr[0] = (source_in6addr)->s_addr[0];}
/* ATTENTION: the next define only works because both in6_addr and ip6_addr_t are an u32_t[4] effectively! */
#define inet6_addr_to_ip6addr_p(target_ip6addr_p, source_in6addr) ((target_ip6addr_p) = (ip6_addr_t*)(source_in6addr))
/* directly map this to the lwip internal functions */
#define inet6_aton(cp, addr) ip6addr_aton(cp, (ip6_addr_t*)addr)
#define inet6_ntoa(addr) ip6addr_ntoa((ip6_addr_t*)&(addr))
#define inet6_ntoa_r(addr, buf, buflen) ip6addr_ntoa_r((ip6_addr_t*)&(addr), buf, buflen)
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_INET6_H__ */

View File

@@ -1,127 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IP_HLEN 40
#define IP_PROTO_ICMP 58
#define IP_PROTO_UDP 17
#define IP_PROTO_UDPLITE 136
#define IP_PROTO_TCP 6
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB struct ip_addr local_ip; \
struct ip_addr remote_ip; \
/* Socket options */ \
u16_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl; \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
/* The IPv6 header. */
struct ip_hdr {
#if BYTE_ORDER == LITTLE_ENDIAN
u8_t tclass1:4, v:4;
u8_t flow1:4, tclass2:4;
#else
u8_t v:4, tclass1:4;
u8_t tclass2:8, flow1:4;
#endif
u16_t flow2;
u16_t len; /* payload length */
u8_t nexthdr; /* next header */
u8_t hoplim; /* hop limit (TTL) */
struct ip_addr src, dest; /* source and destination IP addresses */
};
#define IPH_PROTO(hdr) (iphdr->nexthdr)
void ip_init(void);
#include "lwip/netif.h"
struct netif *ip_route(struct ip_addr *dest);
void ip_input(struct pbuf *p, struct netif *inp);
/* source and destination addresses in network byte order, please */
err_t ip_output(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t proto);
err_t ip_output_if(struct pbuf *p, struct ip_addr *src, struct ip_addr *dest,
u8_t ttl, u8_t proto,
struct netif *netif);
#if IP_DEBUG
void ip_debug_print(struct pbuf *p);
#endif /* IP_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_H__ */

197
src/include/ipv6/lwip/ip6.h Normal file
View File

@@ -0,0 +1,197 @@
/**
* @file
*
* IPv6 layer.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_H__
#define __LWIP_IP6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/ip.h"
#include "lwip/ip6_addr.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#include "lwip/err.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IP6_HLEN 40
#define IP6_NEXTH_HOPBYHOP 0
#define IP6_NEXTH_TCP 6
#define IP6_NEXTH_UDP 17
#define IP6_NEXTH_ENCAPS 41
#define IP6_NEXTH_ROUTING 43
#define IP6_NEXTH_FRAGMENT 44
#define IP6_NEXTH_ICMP6 58
#define IP6_NEXTH_NONE 59
#define IP6_NEXTH_DESTOPTS 60
#define IP6_NEXTH_UDPLITE 136
/* The IPv6 header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_hdr {
/* version / traffic class / flow label */
PACK_STRUCT_FIELD(u32_t _v_tc_fl);
/* payload length */
PACK_STRUCT_FIELD(u16_t _plen);
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* hop limit */
PACK_STRUCT_FIELD(u8_t _hoplim);
/* source and destination IP addresses */
PACK_STRUCT_FIELD(ip6_addr_p_t src);
PACK_STRUCT_FIELD(ip6_addr_p_t dest);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Hop-by-hop router alert option. */
#define IP6_HBH_HLEN 8
#define IP6_PAD1_OPTION 0
#define IP6_PADN_ALERT_OPTION 1
#define IP6_ROUTER_ALERT_OPTION 5
#define IP6_ROUTER_ALERT_VALUE_MLD 0
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_hbh_hdr {
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* header length */
PACK_STRUCT_FIELD(u8_t _hlen);
/* router alert option type */
PACK_STRUCT_FIELD(u8_t _ra_opt_type);
/* router alert option data len */
PACK_STRUCT_FIELD(u8_t _ra_opt_dlen);
/* router alert option data */
PACK_STRUCT_FIELD(u16_t _ra_opt_data);
/* PadN option type */
PACK_STRUCT_FIELD(u8_t _padn_opt_type);
/* PadN option data len */
PACK_STRUCT_FIELD(u8_t _padn_opt_dlen);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* Fragment header. */
#define IP6_FRAG_HLEN 8
#define IP6_FRAG_OFFSET_MASK 0xfff8
#define IP6_FRAG_MORE_FLAG 0x0001
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_frag_hdr {
/* next header */
PACK_STRUCT_FIELD(u8_t _nexth);
/* reserved */
PACK_STRUCT_FIELD(u8_t reserved);
/* fragment offset */
PACK_STRUCT_FIELD(u16_t _fragment_offset);
/* fragmented packet identification */
PACK_STRUCT_FIELD(u32_t _identification);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IP6H_V(hdr) ((ntohl((hdr)->_v_tc_fl) >> 28) & 0x0f)
#define IP6H_TC(hdr) ((ntohl((hdr)->_v_tc_fl) >> 20) & 0xff)
#define IP6H_FL(hdr) (ntohl((hdr)->_v_tc_fl) & 0x000fffff)
#define IP6H_PLEN(hdr) (ntohs((hdr)->_plen))
#define IP6H_NEXTH(hdr) ((hdr)->_nexth)
#define IP6H_NEXTH_P(hdr) ((u8_t *)(hdr) + 6)
#define IP6H_HOPLIM(hdr) ((hdr)->_hoplim)
#define IP6H_VTCFL_SET(hdr, v, tc, fl) (hdr)->_v_tc_fl = (htonl(((v) << 28) | ((tc) << 20) | (fl)))
#define IP6H_PLEN_SET(hdr, plen) (hdr)->_plen = htons(plen)
#define IP6H_NEXTH_SET(hdr, nexth) (hdr)->_nexth = (nexth)
#define IP6H_HOPLIM_SET(hdr, hl) (hdr)->_hoplim = (u8_t)(hl)
#define ip6_init() /* TODO should we init current addresses and header pointer? */
struct netif *ip6_route(struct ip6_addr *src, struct ip6_addr *dest);
ip6_addr_t *ip6_select_source_address(struct netif *netif, ip6_addr_t * dest);
err_t ip6_input(struct pbuf *p, struct netif *inp);
err_t ip6_output(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
u8_t hl, u8_t tc, u8_t nexth);
err_t ip6_output_if(struct pbuf *p, struct ip6_addr *src, struct ip6_addr *dest,
u8_t hl, u8_t tc, u8_t nexth, struct netif *netif);
#if LWIP_NETIF_HWADDRHINT
err_t ip6_output_hinted(struct pbuf *p, ip6_addr_t *src, ip6_addr_t *dest,
u8_t hl, u8_t tc, u8_t nexth, u8_t *addr_hint);
#endif /* LWIP_NETIF_HWADDRHINT */
#if LWIP_IPV6_MLD
err_t ip6_options_add_hbh_ra(struct pbuf * p, u8_t nexth, u8_t value);
#endif /* LWIP_IPV6_MLD */
#define ip6_netif_get_local_ipX(netif, dest) (((netif) != NULL) ? \
ip6_2_ipX(ip6_select_source_address(netif, dest)) : NULL)
#if IP6_DEBUG
void ip6_debug_print(struct pbuf *p);
#else
#define ip6_debug_print(p)
#endif /* IP6_DEBUG */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_IP6_H__ */

View File

@@ -0,0 +1,282 @@
/**
* @file
*
* IPv6 addresses.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
* Structs and macros for handling IPv6 addresses.
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_ADDR_H__
#define __LWIP_IP6_ADDR_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/* This is the aligned version of ip6_addr_t,
used as local variable, on the stack, etc. */
struct ip6_addr {
u32_t addr[4];
};
/* This is the packed version of ip6_addr_t,
used in network headers that are itself packed */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip6_addr_packed {
PACK_STRUCT_FIELD(u32_t addr[4]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** ip6_addr_t uses a struct for convenience only, so that the same defines can
* operate both on ip6_addr_t as well as on ip6_addr_p_t. */
typedef struct ip6_addr ip6_addr_t;
typedef struct ip6_addr_packed ip6_addr_p_t;
/** IP6_ADDR_ANY can be used as a fixed IPv6 address
* for the wildcard
*/
extern const ip6_addr_t ip6_addr_any;
#define IP6_ADDR_ANY ((ip6_addr_t *)&ip6_addr_any)
#if BYTE_ORDER == BIG_ENDIAN
/** Set an IPv6 partial address given by byte-parts. */
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((a) & 0xff) << 24) | \
((u32_t)((b) & 0xff) << 16) | \
((u32_t)((c) & 0xff) << 8) | \
(u32_t)((d) & 0xff)
#else
/** Set an IPv6 partial address given by byte-parts.
Little-endian version, stored in network order (no htonl). */
#define IP6_ADDR(ip6addr, index, a,b,c,d) \
(ip6addr)->addr[index] = ((u32_t)((d) & 0xff) << 24) | \
((u32_t)((c) & 0xff) << 16) | \
((u32_t)((b) & 0xff) << 8) | \
(u32_t)((a) & 0xff)
#endif
/** Access address in 16-bit block */
#define IP6_ADDR_BLOCK1(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK2(ip6addr) ((htonl((ip6addr)->addr[0])) & 0xffff)
#define IP6_ADDR_BLOCK3(ip6addr) ((htonl((ip6addr)->addr[1]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK4(ip6addr) ((htonl((ip6addr)->addr[1])) & 0xffff)
#define IP6_ADDR_BLOCK5(ip6addr) ((htonl((ip6addr)->addr[2]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK6(ip6addr) ((htonl((ip6addr)->addr[2])) & 0xffff)
#define IP6_ADDR_BLOCK7(ip6addr) ((htonl((ip6addr)->addr[3]) >> 16) & 0xffff)
#define IP6_ADDR_BLOCK8(ip6addr) ((htonl((ip6addr)->addr[3])) & 0xffff)
/** Copy IPv6 address - faster than ip6_addr_set: no NULL check */
#define ip6_addr_copy(dest, src) do{(dest).addr[0] = (src).addr[0]; \
(dest).addr[1] = (src).addr[1]; \
(dest).addr[2] = (src).addr[2]; \
(dest).addr[3] = (src).addr[3];}while(0)
/** Safely copy one IPv6 address to another (src may be NULL) */
#define ip6_addr_set(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : (src)->addr[0]; \
(dest)->addr[1] = (src) == NULL ? 0 : (src)->addr[1]; \
(dest)->addr[2] = (src) == NULL ? 0 : (src)->addr[2]; \
(dest)->addr[3] = (src) == NULL ? 0 : (src)->addr[3];}while(0)
/** Set complete address to zero */
#define ip6_addr_set_zero(ip6addr) do{(ip6addr)->addr[0] = 0; \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = 0;}while(0)
/** Set address to ipv6 'any' (no need for htonl()) */
#define ip6_addr_set_any(ip6addr) ip6_addr_set_zero(ip6addr)
/** Set address to ipv6 loopback address */
#define ip6_addr_set_loopback(ip6addr) do{(ip6addr)->addr[0] = 0; \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
/** Safely copy one IPv6 address to another and change byte order
* from host- to network-order. */
#define ip6_addr_set_hton(dest, src) do{(dest)->addr[0] = (src) == NULL ? 0 : htonl((src)->addr[0]); \
(dest)->addr[1] = (src) == NULL ? 0 : htonl((src)->addr[1]); \
(dest)->addr[2] = (src) == NULL ? 0 : htonl((src)->addr[2]); \
(dest)->addr[3] = (src) == NULL ? 0 : htonl((src)->addr[3]);}while(0)
/**
* Determine if two IPv6 address are on the same network.
*
* @arg addr1 IPv6 address 1
* @arg addr2 IPv6 address 2
* @return !0 if the network identifiers of both address match
*/
#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
((addr1)->addr[1] == (addr2)->addr[1]))
#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
((addr1)->addr[1] == (addr2)->addr[1]) && \
((addr1)->addr[2] == (addr2)->addr[2]) && \
((addr1)->addr[3] == (addr2)->addr[3]))
#define ip6_get_subnet_id(ip6addr) (htonl((ip6addr)->addr[2]) & 0x0000ffffUL)
#define ip6_addr_isany(ip6addr) (((ip6addr) == NULL) || \
(((ip6addr)->addr[0] == 0) && \
((ip6addr)->addr[1] == 0) && \
((ip6addr)->addr[2] == 0) && \
((ip6addr)->addr[3] == 0)))
#define ip6_addr_isglobal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xe0000000UL)) == PP_HTONL(0x20000000UL))
#define ip6_addr_islinklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfe800000UL))
#define ip6_addr_issitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffc00000UL)) == PP_HTONL(0xfec00000UL))
#define ip6_addr_isuniquelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xfe000000UL)) == PP_HTONL(0xfc000000UL))
#define ip6_addr_ismulticast(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL))
#define ip6_addr_multicast_transient_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00100000UL))
#define ip6_addr_multicast_prefix_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00200000UL))
#define ip6_addr_multicast_rendezvous_flag(ip6addr) ((ip6addr)->addr[0] & PP_HTONL(0x00400000UL))
#define ip6_addr_multicast_scope(ip6addr) ((htonl((ip6addr)->addr[0]) >> 16) & 0xf)
#define IP6_MULTICAST_SCOPE_RESERVED 0x0
#define IP6_MULTICAST_SCOPE_RESERVED0 0x0
#define IP6_MULTICAST_SCOPE_INTERFACE_LOCAL 0x1
#define IP6_MULTICAST_SCOPE_LINK_LOCAL 0x2
#define IP6_MULTICAST_SCOPE_RESERVED3 0x3
#define IP6_MULTICAST_SCOPE_ADMIN_LOCAL 0x4
#define IP6_MULTICAST_SCOPE_SITE_LOCAL 0x5
#define IP6_MULTICAST_SCOPE_ORGANIZATION_LOCAL 0x8
#define IP6_MULTICAST_SCOPE_GLOBAL 0xe
#define IP6_MULTICAST_SCOPE_RESERVEDF 0xf
#define ip6_addr_ismulticast_iflocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff010000UL))
#define ip6_addr_ismulticast_linklocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff020000UL))
#define ip6_addr_ismulticast_adminlocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff040000UL))
#define ip6_addr_ismulticast_sitelocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff050000UL))
#define ip6_addr_ismulticast_orglocal(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff080000UL))
#define ip6_addr_ismulticast_global(ip6addr) (((ip6addr)->addr[0] & PP_HTONL(0xffff0000UL)) == PP_HTONL(0xff0e0000UL))
/* TODO define get/set for well-know multicast addresses, e.g. ff02::1 */
#define ip6_addr_isallnodes_iflocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff010000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
#define ip6_addr_isallnodes_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000001UL)))
#define ip6_addr_set_allnodes_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000001UL);}while(0)
#define ip6_addr_isallrouters_linklocal(ip6addr) (((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[1] == 0UL) && \
((ip6addr)->addr[2] == 0UL) && \
((ip6addr)->addr[3] == PP_HTONL(0x00000002UL)))
#define ip6_addr_set_allrouters_linklocal(ip6addr) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = 0; \
(ip6addr)->addr[3] = PP_HTONL(0x00000002UL);}while(0)
#define ip6_addr_issolicitednode(ip6addr) ( ((ip6addr)->addr[0] == PP_HTONL(0xff020000UL)) && \
((ip6addr)->addr[2] == PP_HTONL(0x00000001UL)) && \
(((ip6addr)->addr[3] & PP_HTONL(0xff000000UL)) == PP_HTONL(0xff000000UL)) )
#define ip6_addr_set_solicitednode(ip6addr, if_id) do{(ip6addr)->addr[0] = PP_HTONL(0xff020000UL); \
(ip6addr)->addr[1] = 0; \
(ip6addr)->addr[2] = PP_HTONL(0x00000001UL); \
(ip6addr)->addr[3] = htonl(0xff000000UL | (htonl(if_id) & 0x00ffffffUL));}while(0)
/* IPv6 address states. */
#define IP6_ADDR_INVALID 0x00
#define IP6_ADDR_TENTATIVE 0x08
#define IP6_ADDR_TENTATIVE_1 0x09 /* 1 probe sent */
#define IP6_ADDR_TENTATIVE_2 0x0a /* 2 probes sent */
#define IP6_ADDR_TENTATIVE_3 0x0b /* 3 probes sent */
#define IP6_ADDR_TENTATIVE_4 0x0c /* 4 probes sent */
#define IP6_ADDR_TENTATIVE_5 0x0d /* 5 probes sent */
#define IP6_ADDR_TENTATIVE_6 0x0e /* 6 probes sent */
#define IP6_ADDR_TENTATIVE_7 0x0f /* 7 probes sent */
#define IP6_ADDR_VALID 0x10
#define IP6_ADDR_PREFERRED 0x30
#define IP6_ADDR_DEPRECATED 0x50
#define ip6_addr_isinvalid(addr_state) (addr_state == IP6_ADDR_INVALID)
#define ip6_addr_istentative(addr_state) (addr_state & IP6_ADDR_TENTATIVE)
#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
#define ip6_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F":%"X16_F, \
ipaddr != NULL ? IP6_ADDR_BLOCK1(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK2(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK3(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK4(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK5(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK6(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK7(ipaddr) : 0, \
ipaddr != NULL ? IP6_ADDR_BLOCK8(ipaddr) : 0))
int ip6addr_aton(const char *cp, ip6_addr_t *addr);
/** returns ptr to static buffer; not reentrant! */
char *ip6addr_ntoa(const ip6_addr_t *addr);
char *ip6addr_ntoa_r(const ip6_addr_t *addr, char *buf, int buflen);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_IP6_ADDR_H__ */

View File

@@ -0,0 +1,102 @@
/**
* @file
*
* IPv6 fragmentation and reassembly.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_IP6_FRAG_H__
#define __LWIP_IP6_FRAG_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6 && LWIP_IPV6_REASS /* don't build if not configured for use in lwipopts.h */
/* The IPv6 reassembly timer interval in milliseconds. */
#define IP6_REASS_TMR_INTERVAL 1000
/* IPv6 reassembly helper struct.
* This is exported because memp needs to know the size.
*/
struct ip6_reassdata {
struct ip6_reassdata *next;
struct pbuf *p;
struct ip6_hdr * iphdr;
u32_t identification;
u16_t datagram_len;
u8_t nexth;
u8_t timer;
};
#define ip6_reass_init() /* Compatibility define */
void ip6_reass_tmr(void);
struct pbuf * ip6_reass(struct pbuf *p);
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_FRAG /* don't build if not configured for use in lwipopts.h */
/** A custom pbuf that holds a reference to another pbuf, which is freed
* when this custom pbuf is freed. This is used to create a custom PBUF_REF
* that points into the original pbuf. */
#ifndef __LWIP_PBUF_CUSTOM_REF__
#define __LWIP_PBUF_CUSTOM_REF__
struct pbuf_custom_ref {
/** 'base class' */
struct pbuf_custom pc;
/** pointer to the original pbuf that is referenced */
struct pbuf *original;
};
#endif /* __LWIP_PBUF_CUSTOM_REF__ */
err_t ip6_frag(struct pbuf *p, struct netif *netif, ip6_addr_t *dest);
#endif /* LWIP_IPV6 && LWIP_IPV6_FRAG */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP6_FRAG_H__ */

View File

@@ -1,97 +0,0 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define IP_ADDR_ANY 0
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr {
PACK_STRUCT_FIELD(u32_t addr[4]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/*
* struct ipaddr2 is used in the definition of the ARP packet format in
* order to support compilers that don't have structure packing.
*/
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ip_addr2 {
PACK_STRUCT_FIELD(u16_t addrw[2]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define IP6_ADDR(ipaddr, a,b,c,d,e,f,g,h) do { (ipaddr)->addr[0] = htonl((u32_t)((a & 0xffff) << 16) | (b & 0xffff)); \
(ipaddr)->addr[1] = htonl(((c & 0xffff) << 16) | (d & 0xffff)); \
(ipaddr)->addr[2] = htonl(((e & 0xffff) << 16) | (f & 0xffff)); \
(ipaddr)->addr[3] = htonl(((g & 0xffff) << 16) | (h & 0xffff)); } while(0)
u8_t ip_addr_netcmp(struct ip_addr *addr1, struct ip_addr *addr2,
struct ip_addr *mask);
u8_t ip_addr_cmp(struct ip_addr *addr1, struct ip_addr *addr2);
void ip_addr_set(struct ip_addr *dest, struct ip_addr *src);
u8_t ip_addr_isany(struct ip_addr *addr);
#define ip_addr_debug_print(debug, ipaddr) \
LWIP_DEBUGF(debug, ("%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F":%"X32_F"\n", \
(ntohl(ipaddr->addr[0]) >> 16) & 0xffff, \
ntohl(ipaddr->addr[0]) & 0xffff, \
(ntohl(ipaddr->addr[1]) >> 16) & 0xffff, \
ntohl(ipaddr->addr[1]) & 0xffff, \
(ntohl(ipaddr->addr[2]) >> 16) & 0xffff, \
ntohl(ipaddr->addr[2]) & 0xffff, \
(ntohl(ipaddr->addr[3]) >> 16) & 0xffff, \
ntohl(ipaddr->addr[3]) & 0xffff));
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View File

@@ -0,0 +1,118 @@
/**
* @file
*
* Multicast listener discovery for IPv6. Aims to be compliant with RFC 2710.
* No support for MLDv2.
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_MLD6_H__
#define __LWIP_MLD6_H__
#include "lwip/opt.h"
#if LWIP_IPV6_MLD && LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
struct mld_group {
/** next link */
struct mld_group *next;
/** interface on which the group is active */
struct netif *netif;
/** multicast address */
ip6_addr_t group_address;
/** signifies we were the last person to report */
u8_t last_reporter_flag;
/** current state of the group */
u8_t group_state;
/** timer for reporting */
u16_t timer;
/** counter of simultaneous uses */
u8_t use;
};
/** Multicast listener report/query/done message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct mld_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u16_t max_resp_delay);
PACK_STRUCT_FIELD(u16_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t multicast_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define MLD6_TMR_INTERVAL 100 /* Milliseconds */
/* MAC Filter Actions, these are passed to a netif's
* mld_mac_filter callback function. */
#define MLD6_DEL_MAC_FILTER 0
#define MLD6_ADD_MAC_FILTER 1
#define mld6_init() /* TODO should we init tables? */
err_t mld6_stop(struct netif *netif);
void mld6_report_groups(struct netif *netif);
void mld6_tmr(void);
struct mld_group *mld6_lookfor_group(struct netif *ifp, ip6_addr_t *addr);
void mld6_input(struct pbuf *p, struct netif *inp);
err_t mld6_joingroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
err_t mld6_leavegroup(ip6_addr_t *srcaddr, ip6_addr_t *groupaddr);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6_MLD && LWIP_IPV6 */
#endif /* __LWIP_MLD6_H__ */

368
src/include/ipv6/lwip/nd6.h Normal file
View File

@@ -0,0 +1,368 @@
/**
* @file
*
* Neighbor discovery and stateless address autoconfiguration for IPv6.
* Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862
* (Address autoconfiguration).
*/
/*
* Copyright (c) 2010 Inico Technologies Ltd.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. 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: Ivan Delamer <delamer@inicotech.com>
*
*
* Please coordinate changes and requests with Ivan Delamer
* <delamer@inicotech.com>
*/
#ifndef __LWIP_ND6_H__
#define __LWIP_ND6_H__
#include "lwip/opt.h"
#if LWIP_IPV6 /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/ip6.h"
#include "lwip/ip6_addr.h"
#include "lwip/netif.h"
#ifdef __cplusplus
extern "C" {
#endif
/* Struct for tables. */
struct nd6_neighbor_cache_entry {
ip6_addr_t next_hop_address;
struct netif * netif;
u8_t lladdr[NETIF_MAX_HWADDR_LEN];
/*u32_t pmtu;*/
#if LWIP_ND6_QUEUEING
/** Pointer to queue of pending outgoing packets on this entry. */
struct nd6_q_entry *q;
#endif /* LWIP_ND6_QUEUEING */
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time;
u32_t delay_time;
u32_t probes_sent;
u32_t stale_time;
} counter;
};
struct nd6_destination_cache_entry {
ip6_addr_t destination_addr;
ip6_addr_t next_hop_addr;
u32_t pmtu;
u32_t age;
};
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif * netif;
u32_t invalidation_timer;
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry * neighbor_entry;
u32_t invalidation_timer;
u8_t flags;
};
enum nd6_neighbor_cache_entry_state {
ND6_NO_ENTRY = 0,
ND6_INCOMPLETE,
ND6_REACHABLE,
ND6_STALE,
ND6_DELAY,
ND6_PROBE
};
#if LWIP_ND6_QUEUEING
/** struct for queueing outgoing packets for unknown address
* defined here to be accessed by memp.h
*/
struct nd6_q_entry {
struct nd6_q_entry *next;
struct pbuf *p;
};
#endif /* LWIP_ND6_QUEUEING */
/** Neighbor solicitation message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ns_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Neighbor advertisement message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct na_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u8_t reserved[3]);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
#define ND6_FLAG_ROUTER (0x80)
#define ND6_FLAG_SOLICITED (0x40)
#define ND6_FLAG_OVERRIDE (0x20)
/** Router solicitation message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct rs_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Router advertisement message header. */
#define ND6_RA_FLAG_MANAGED_ADDR_CONFIG (0x80)
#define ND6_RA_FLAG_OTHER_STATEFUL_CONFIG (0x40)
#define ND6_RA_FLAG_HOME_AGENT (0x20)
#define ND6_RA_PREFERENCE_MASK (0x18)
#define ND6_RA_PREFERENCE_HIGH (0x08)
#define ND6_RA_PREFERENCE_MEDIUM (0x00)
#define ND6_RA_PREFERENCE_LOW (0x18)
#define ND6_RA_PREFERENCE_DISABLED (0x10)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct ra_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u8_t current_hop_limit);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u16_t router_lifetime);
PACK_STRUCT_FIELD(u32_t reachable_time);
PACK_STRUCT_FIELD(u32_t retrans_timer);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Redirect message header. */
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct redirect_header {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t code);
PACK_STRUCT_FIELD(u16_t chksum);
PACK_STRUCT_FIELD(u32_t reserved);
PACK_STRUCT_FIELD(ip6_addr_p_t target_address);
PACK_STRUCT_FIELD(ip6_addr_p_t destination_address);
/* Options follow. */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Link-layer address option. */
#define ND6_OPTION_TYPE_SOURCE_LLADDR (0x01)
#define ND6_OPTION_TYPE_TARGET_LLADDR (0x02)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct lladdr_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t addr[NETIF_MAX_HWADDR_LEN]);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Prefix information option. */
#define ND6_OPTION_TYPE_PREFIX_INFO (0x03)
#define ND6_PREFIX_FLAG_ON_LINK (0x80)
#define ND6_PREFIX_FLAG_AUTONOMOUS (0x40)
#define ND6_PREFIX_FLAG_ROUTER_ADDRESS (0x20)
#define ND6_PREFIX_FLAG_SITE_PREFIX (0x10)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct prefix_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t prefix_length);
PACK_STRUCT_FIELD(u8_t flags);
PACK_STRUCT_FIELD(u32_t valid_lifetime);
PACK_STRUCT_FIELD(u32_t preferred_lifetime);
PACK_STRUCT_FIELD(u8_t reserved2[3]);
PACK_STRUCT_FIELD(u8_t site_prefix_length);
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Redirected header option. */
#define ND6_OPTION_TYPE_REDIR_HDR (0x04)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct redirected_header_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t reserved[6]);
/* Portion of redirected packet follows. */
/* PACK_STRUCT_FIELD(u8_t redirected[8]); */
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** MTU option. */
#define ND6_OPTION_TYPE_MTU (0x05)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct mtu_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u16_t reserved);
PACK_STRUCT_FIELD(u32_t mtu);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/** Route information option. */
#define ND6_OPTION_TYPE_ROUTE_INFO (24)
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/bpstruct.h"
#endif
PACK_STRUCT_BEGIN
struct route_option {
PACK_STRUCT_FIELD(u8_t type);
PACK_STRUCT_FIELD(u8_t length);
PACK_STRUCT_FIELD(u8_t prefix_length);
PACK_STRUCT_FIELD(u8_t preference);
PACK_STRUCT_FIELD(u32_t route_lifetime);
PACK_STRUCT_FIELD(ip6_addr_p_t prefix);
} PACK_STRUCT_STRUCT;
PACK_STRUCT_END
#ifdef PACK_STRUCT_USE_INCLUDES
# include "arch/epstruct.h"
#endif
/* the possible states of an IP address */
#define IP6_ADDRESS_STATE_INVALID (0)
#define IP6_ADDRESS_STATE_VALID (0x4)
#define IP6_ADDRESS_STATE_PREFERRED (0x5) /* includes valid */
#define IP6_ADDRESS_STATE_DEPRECATED (0x6) /* includes valid */
#define IP6_ADDRESS_STATE_TENTATIV (0x8)
/** 1 second period */
#define ND6_TMR_INTERVAL 1000
/* Router tables. */
/* TODO make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];
extern struct nd6_destination_cache_entry destination_cache[];
extern struct nd6_prefix_list_entry prefix_list[];
extern struct nd6_router_list_entry default_router_list[];
/* Default values, can be updated by a RA message. */
extern u32_t reachable_time;
extern u32_t retrans_timer;
#define nd6_init() /* TODO should we init tables? */
void nd6_tmr(void);
void nd6_input(struct pbuf *p, struct netif *inp);
s8_t nd6_get_next_hop_entry(ip6_addr_t * ip6addr, struct netif * netif);
s8_t nd6_select_router(ip6_addr_t * ip6addr, struct netif * netif);
u16_t nd6_get_destination_mtu(ip6_addr_t * ip6addr, struct netif * netif);
#if LWIP_ND6_QUEUEING
err_t nd6_queue_packet(s8_t neighbor_index, struct pbuf * p);
#endif /* LWIP_ND6_QUEUEING */
#if LWIP_ND6_TCP_REACHABILITY_HINTS
void nd6_reachability_hint(ip6_addr_t * ip6addr);
#endif /* LWIP_ND6_TCP_REACHABILITY_HINTS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_IPV6 */
#endif /* __LWIP_ND6_H__ */

View File

@@ -36,6 +36,8 @@
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include "lwip/netbuf.h"
#include "lwip/sys.h"
#include "lwip/ip_addr.h"
@@ -49,28 +51,69 @@ extern "C" {
* the same byte order as in the corresponding pcb.
*/
/* Flags for netconn_write */
#define NETCONN_NOFLAG 0x00
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
#define NETCONN_COPY 0x01
#define NETCONN_MORE 0x02
/* Flags for netconn_write (u8_t) */
#define NETCONN_NOFLAG 0x00
#define NETCONN_NOCOPY 0x00 /* Only for source code compatibility */
#define NETCONN_COPY 0x01
#define NETCONN_MORE 0x02
#define NETCONN_DONTBLOCK 0x04
/* Flags for struct netconn.flags (u8_t) */
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores whether to wake up the original application task
if data couldn't be sent in the first try. */
#define NETCONN_FLAG_WRITE_DELAYED 0x01
/** Should this netconn avoid blocking? */
#define NETCONN_FLAG_NON_BLOCKING 0x02
/** Was the last connect action a non-blocking one? */
#define NETCONN_FLAG_IN_NONBLOCKING_CONNECT 0x04
/** If this is set, a TCP netconn must call netconn_recved() to update
the TCP receive window (done automatically if not set). */
#define NETCONN_FLAG_NO_AUTO_RECVED 0x08
/** If a nonblocking write has been rejected before, poll_tcp needs to
check if the netconn is writable again */
#define NETCONN_FLAG_CHECK_WRITESPACE 0x10
/* Helpers to process several netconn_types by the same code */
#define NETCONNTYPE_GROUP(t) (t&0xF0)
#define NETCONNTYPE_DATAGRAM(t) (t&0xE0)
#define NETCONNTYPE_GROUP(t) ((t)&0xF0)
#define NETCONNTYPE_DATAGRAM(t) ((t)&0xE0)
#if LWIP_IPV6
#define NETCONN_TYPE_IPV6 0x08
#define NETCONNTYPE_ISIPV6(t) ((t)&0x08)
#define NETCONNTYPE_ISUDPLITE(t) (((t)&0xF7) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) (((t)&0xF7) == NETCONN_UDPNOCHKSUM)
#else /* LWIP_IPV6 */
#define NETCONNTYPE_ISUDPLITE(t) ((t) == NETCONN_UDPLITE)
#define NETCONNTYPE_ISUDPNOCHKSUM(t) ((t) == NETCONN_UDPNOCHKSUM)
#endif /* LWIP_IPV6 */
/** Protocol family and type of the netconn */
enum netconn_type {
NETCONN_INVALID = 0,
NETCONN_INVALID = 0,
/* NETCONN_TCP Group */
NETCONN_TCP = 0x10,
NETCONN_TCP = 0x10,
#if LWIP_IPV6
NETCONN_TCP_IPV6 = NETCONN_TCP | NETCONN_TYPE_IPV6 /* 0x18 */,
#endif /* LWIP_IPV6 */
/* NETCONN_UDP Group */
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM= 0x22,
NETCONN_UDP = 0x20,
NETCONN_UDPLITE = 0x21,
NETCONN_UDPNOCHKSUM = 0x22,
#if LWIP_IPV6
NETCONN_UDP_IPV6 = NETCONN_UDP | NETCONN_TYPE_IPV6 /* 0x28 */,
NETCONN_UDPLITE_IPV6 = NETCONN_UDPLITE | NETCONN_TYPE_IPV6 /* 0x29 */,
NETCONN_UDPNOCHKSUM_IPV6 = NETCONN_UDPNOCHKSUM | NETCONN_TYPE_IPV6 /* 0x2a */,
#endif /* LWIP_IPV6 */
/* NETCONN_RAW Group */
NETCONN_RAW = 0x40
NETCONN_RAW = 0x40,
#if LWIP_IPV6
NETCONN_RAW_IPV6 = NETCONN_RAW | NETCONN_TYPE_IPV6 /* 0x48 */,
#endif /* LWIP_IPV6 */
};
/** Current state of the netconn. Non-TCP netconns are always
* in state NETCONN_NONE! */
enum netconn_state {
NETCONN_NONE,
NETCONN_WRITE,
@@ -79,19 +122,22 @@ enum netconn_state {
NETCONN_CLOSE
};
/** Use to inform the callback function about changes */
enum netconn_evt {
NETCONN_EVT_RCVPLUS,
NETCONN_EVT_RCVMINUS,
NETCONN_EVT_SENDPLUS,
NETCONN_EVT_SENDMINUS
NETCONN_EVT_SENDMINUS,
NETCONN_EVT_ERROR
};
#if LWIP_IGMP
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** Used for netconn_join_leave_group() */
enum netconn_igmp {
NETCONN_JOIN,
NETCONN_LEAVE
};
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
/* forward-declare some structs to avoid to include their headers */
struct ip_pcb;
@@ -99,6 +145,7 @@ struct tcp_pcb;
struct udp_pcb;
struct raw_pcb;
struct netconn;
struct api_msg_msg;
/** A callback prototype to inform about events for a netconn */
typedef void (* netconn_callback)(struct netconn *, enum netconn_evt, u16_t len);
@@ -117,96 +164,150 @@ struct netconn {
struct raw_pcb *raw;
} pcb;
/** the last error this netconn had */
err_t err;
err_t last_err;
/** sem that is used to synchroneously execute functions in the core context */
sys_sem_t op_completed;
/** mbox where received packets are stored until they are fetched
by the netconn application thread (can grow quite big) */
sys_mbox_t recvmbox;
#if LWIP_TCP
/** mbox where new connections are stored until processed
by the application thread */
sys_mbox_t acceptmbox;
#endif /* LWIP_TCP */
/** only used for socket layer */
#if LWIP_SOCKET
int socket;
#endif /* LWIP_SOCKET */
#if LWIP_SO_RCVTIMEO
/** timeout to wait for new data to be received
(or connections to arrive for listening netconns) */
int recv_timeout;
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** maximum amount of bytes queued in recvmbox */
/** maximum amount of bytes queued in recvmbox
not used for TCP: adjust TCP_WND instead! */
int recv_bufsize;
/** number of bytes currently in recvmbox to be received,
tested against recv_bufsize to limit bytes on recvmbox
for UDP and RAW, used for FIONREAD */
s16_t recv_avail;
#endif /* LWIP_SO_RCVBUF */
u16_t recv_avail;
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores the message. */
struct api_msg_msg *write_msg;
/** flags holding more netconn-internal state, see NETCONN_FLAG_* defines */
u8_t flags;
#if LWIP_TCP
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores how much is already sent. */
int write_offset;
#if LWIP_TCPIP_CORE_LOCKING
size_t write_offset;
/** TCP: when data passed to netconn_write doesn't fit into the send buffer,
this temporarily stores whether to wake up the original application task
if data couldn't be sent in the first try. */
u8_t write_delayed;
#endif /* LWIP_TCPIP_CORE_LOCKING */
this temporarily stores the message.
Also used during connect and close. */
struct api_msg_msg *current_msg;
#endif /* LWIP_TCP */
/** A callback function that is informed about events for this netconn */
netconn_callback callback;
};
/* Register an Network connection event */
/** Register an Network connection event */
#define API_EVENT(c,e,l) if (c->callback) { \
(*c->callback)(c, e, l); \
}
/** Set conn->last_err to err but don't overwrite fatal errors */
#define NETCONN_SET_SAFE_ERR(conn, err) do { \
SYS_ARCH_DECL_PROTECT(lev); \
SYS_ARCH_PROTECT(lev); \
if (!ERR_IS_FATAL((conn)->last_err)) { \
(conn)->last_err = err; \
} \
SYS_ARCH_UNPROTECT(lev); \
} while(0);
/* Network connection functions: */
#define netconn_new(t) netconn_new_with_proto_and_callback(t, 0, NULL)
#define netconn_new_with_callback(t, c) netconn_new_with_proto_and_callback(t, 0, c)
struct
netconn *netconn_new_with_proto_and_callback(enum netconn_type t, u8_t proto,
netconn_callback callback);
err_t netconn_delete (struct netconn *conn);
enum netconn_type netconn_type (struct netconn *conn);
netconn_callback callback);
err_t netconn_delete(struct netconn *conn);
/** Get the type of a netconn (as enum netconn_type). */
#define netconn_type(conn) (conn->type)
err_t netconn_getaddr (struct netconn *conn,
struct ip_addr *addr,
u16_t *port,
u8_t local);
err_t netconn_getaddr(struct netconn *conn, ip_addr_t *addr,
u16_t *port, u8_t local);
#define netconn_peer(c,i,p) netconn_getaddr(c,i,p,0)
#define netconn_addr(c,i,p) netconn_getaddr(c,i,p,1)
err_t netconn_bind (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_connect (struct netconn *conn,
struct ip_addr *addr,
u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
err_t netconn_bind(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_connect(struct netconn *conn, ip_addr_t *addr, u16_t port);
err_t netconn_disconnect (struct netconn *conn);
err_t netconn_listen_with_backlog(struct netconn *conn, u8_t backlog);
#define netconn_listen(conn) netconn_listen_with_backlog(conn, TCP_DEFAULT_LISTEN_BACKLOG)
struct netconn * netconn_accept (struct netconn *conn);
struct netbuf * netconn_recv (struct netconn *conn);
err_t netconn_sendto (struct netconn *conn,
struct netbuf *buf, struct ip_addr *addr, u16_t port);
err_t netconn_send (struct netconn *conn,
struct netbuf *buf);
err_t netconn_write (struct netconn *conn,
const void *dataptr, int size,
u8_t apiflags);
err_t netconn_close (struct netconn *conn);
err_t netconn_accept(struct netconn *conn, struct netconn **new_conn);
err_t netconn_recv(struct netconn *conn, struct netbuf **new_buf);
err_t netconn_recv_tcp_pbuf(struct netconn *conn, struct pbuf **new_buf);
void netconn_recved(struct netconn *conn, u32_t length);
err_t netconn_sendto(struct netconn *conn, struct netbuf *buf,
ip_addr_t *addr, u16_t port);
err_t netconn_send(struct netconn *conn, struct netbuf *buf);
err_t netconn_write(struct netconn *conn, const void *dataptr, size_t size,
u8_t apiflags);
err_t netconn_close(struct netconn *conn);
err_t netconn_shutdown(struct netconn *conn, u8_t shut_rx, u8_t shut_tx);
#if LWIP_IGMP
err_t netconn_join_leave_group (struct netconn *conn,
struct ip_addr *multiaddr,
struct ip_addr *interface,
enum netconn_igmp join_or_leave);
#endif /* LWIP_IGMP */
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
err_t netconn_join_leave_group(struct netconn *conn, ip_addr_t *multiaddr,
ip_addr_t *netif_addr, enum netconn_igmp join_or_leave);
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
err_t netconn_gethostbyname(const char *name, struct ip_addr *addr);
err_t netconn_gethostbyname(const char *name, ip_addr_t *addr);
#endif /* LWIP_DNS */
#if LWIP_IPV6
#define netconn_err(conn) ((conn)->err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
#define netconn_bind_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_bind(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
#define netconn_connect_ip6(conn, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_connect(conn, ip6_2_ip(ip6addr), port) : ERR_VAL)
#define netconn_sendto_ip6(conn, buf, ip6addr, port) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_sendto(conn, buf, ip6_2_ip(ip6addr), port) : ERR_VAL)
#if LWIP_IPV6_MLD
#define netconn_join_leave_group_ip6(conn, multiaddr, srcaddr, join_or_leave) (NETCONNTYPE_ISIPV6((conn)->type) ? \
netconn_join_leave_group(conn, ip6_2_ip(multiaddr), ip6_2_ip(srcaddr), join_or_leave) :\
ERR_VAL)
#endif /* LWIP_IPV6_MLD*/
#endif /* LWIP_IPV6 */
#define netconn_err(conn) ((conn)->last_err)
#define netconn_recv_bufsize(conn) ((conn)->recv_bufsize)
/** Set the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_set_nonblocking(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NON_BLOCKING; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NON_BLOCKING; }} while(0)
/** Get the blocking status of netconn calls (@todo: write/send is missing) */
#define netconn_is_nonblocking(conn) (((conn)->flags & NETCONN_FLAG_NON_BLOCKING) != 0)
/** TCP: Set the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_set_noautorecved(conn, val) do { if(val) { \
(conn)->flags |= NETCONN_FLAG_NO_AUTO_RECVED; \
} else { \
(conn)->flags &= ~ NETCONN_FLAG_NO_AUTO_RECVED; }} while(0)
/** TCP: Get the no-auto-recved status of netconn calls (see NETCONN_FLAG_NO_AUTO_RECVED) */
#define netconn_get_noautorecved(conn) (((conn)->flags & NETCONN_FLAG_NO_AUTO_RECVED) != 0)
#if LWIP_SO_RCVTIMEO
/** Set the receive timeout in milliseconds */
#define netconn_set_recvtimeout(conn, timeout) ((conn)->recv_timeout = (timeout))
/** Get the receive timeout in milliseconds */
#define netconn_get_recvtimeout(conn) ((conn)->recv_timeout)
#endif /* LWIP_SO_RCVTIMEO */
#if LWIP_SO_RCVBUF
/** Set the receive buffer in bytes */
#define netconn_set_recvbufsize(conn, recvbufsize) ((conn)->recv_bufsize = (recvbufsize))
/** Get the receive buffer in bytes */
#define netconn_get_recvbufsize(conn) ((conn)->recv_bufsize)
#endif /* LWIP_SO_RCVBUF*/
#ifdef __cplusplus
}

View File

@@ -36,6 +36,8 @@
#if LWIP_NETCONN /* don't build if not configured for use in lwipopts.h */
#include <stddef.h> /* for size_t */
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/sys.h"
@@ -46,6 +48,11 @@
extern "C" {
#endif
/* For the netconn API, these values are use as a bitmask! */
#define NETCONN_SHUT_RD 1
#define NETCONN_SHUT_WR 2
#define NETCONN_SHUT_RDWR (NETCONN_SHUT_RD | NETCONN_SHUT_WR)
/* IP addresses and port numbers are expected to be in
* the same byte order as in the corresponding pcb.
*/
@@ -56,6 +63,8 @@ struct api_msg_msg {
/** The netconn which to process - always needed: it includes the semaphore
which is used to block the application thread until the function finished. */
struct netconn *conn;
/** The return value of the function executed in tcpip_thread. */
err_t err;
/** Depending on the executed function, one of these union members is used */
union {
/** used for do_send */
@@ -66,33 +75,37 @@ struct api_msg_msg {
} n;
/** used for do_bind and do_connect */
struct {
struct ip_addr *ipaddr;
ip_addr_t *ipaddr;
u16_t port;
} bc;
/** used for do_getaddr */
struct {
struct ip_addr *ipaddr;
ipX_addr_t *ipaddr;
u16_t *port;
u8_t local;
} ad;
/** used for do_write */
struct {
const void *dataptr;
int len;
size_t len;
u8_t apiflags;
} w;
/** used ofr do_recv */
/** used for do_recv */
struct {
u16_t len;
u32_t len;
} r;
#if LWIP_IGMP
/** used for do_close (/shutdown) */
struct {
u8_t shut;
} sd;
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
/** used for do_join_leave_group */
struct {
struct ip_addr *multiaddr;
struct ip_addr *interface;
ipX_addr_t *multiaddr;
ipX_addr_t *netif_addr;
enum netconn_igmp join_or_leave;
} jl;
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if TCP_LISTEN_BACKLOG
struct {
u8_t backlog;
@@ -120,10 +133,10 @@ struct dns_api_msg {
/** Hostname to query or dotted IP address string */
const char *name;
/** Rhe resolved address is stored here */
struct ip_addr *addr;
ip_addr_t *addr;
/** This semaphore is posted when the name is resolved, the application thread
should wait on it. */
sys_sem_t sem;
sys_sem_t *sem;
/** Errors are given back here */
err_t *err;
};
@@ -140,9 +153,10 @@ void do_recv ( struct api_msg_msg *msg);
void do_write ( struct api_msg_msg *msg);
void do_getaddr ( struct api_msg_msg *msg);
void do_close ( struct api_msg_msg *msg);
#if LWIP_IGMP
void do_shutdown ( struct api_msg_msg *msg);
#if LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD)
void do_join_leave_group( struct api_msg_msg *msg);
#endif /* LWIP_IGMP */
#endif /* LWIP_IGMP || (LWIP_IPV6 && LWIP_IPV6_MLD) */
#if LWIP_DNS
void do_gethostbyname(void *arg);

View File

@@ -42,6 +42,16 @@
#include "arch/cc.h"
/** Temporary: define format string for size_t if not defined in cc.h */
#ifndef SZT_F
#define SZT_F U32_F
#endif /* SZT_F */
/** Temporary upgrade helper: define format string for u8_t as hex if not
defined in cc.h */
#ifndef X8_F
#define X8_F "02x"
#endif /* X8_F */
#ifdef __cplusplus
extern "C" {
#endif
@@ -66,154 +76,154 @@ extern "C" {
#ifdef LWIP_PROVIDE_ERRNO
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EPERM 1 /* Operation not permitted */
#define ENOENT 2 /* No such file or directory */
#define ESRCH 3 /* No such process */
#define EINTR 4 /* Interrupted system call */
#define EIO 5 /* I/O error */
#define ENXIO 6 /* No such device or address */
#define E2BIG 7 /* Arg list too long */
#define ENOEXEC 8 /* Exec format error */
#define EBADF 9 /* Bad file number */
#define ECHILD 10 /* No child processes */
#define EAGAIN 11 /* Try again */
#define ENOMEM 12 /* Out of memory */
#define EACCES 13 /* Permission denied */
#define EFAULT 14 /* Bad address */
#define ENOTBLK 15 /* Block device required */
#define EBUSY 16 /* Device or resource busy */
#define EEXIST 17 /* File exists */
#define EXDEV 18 /* Cross-device link */
#define ENODEV 19 /* No such device */
#define ENOTDIR 20 /* Not a directory */
#define EISDIR 21 /* Is a directory */
#define EINVAL 22 /* Invalid argument */
#define ENFILE 23 /* File table overflow */
#define EMFILE 24 /* Too many open files */
#define ENOTTY 25 /* Not a typewriter */
#define ETXTBSY 26 /* Text file busy */
#define EFBIG 27 /* File too large */
#define ENOSPC 28 /* No space left on device */
#define ESPIPE 29 /* Illegal seek */
#define EROFS 30 /* Read-only file system */
#define EMLINK 31 /* Too many links */
#define EPIPE 32 /* Broken pipe */
#define EDOM 33 /* Math argument out of domain of func */
#define ERANGE 34 /* Math result not representable */
#define EDEADLK 35 /* Resource deadlock would occur */
#define ENAMETOOLONG 36 /* File name too long */
#define ENOLCK 37 /* No record locks available */
#define ENOSYS 38 /* Function not implemented */
#define ENOTEMPTY 39 /* Directory not empty */
#define ELOOP 40 /* Too many symbolic links encountered */
#define EWOULDBLOCK EAGAIN /* Operation would block */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define ENOMSG 42 /* No message of desired type */
#define EIDRM 43 /* Identifier removed */
#define ECHRNG 44 /* Channel number out of range */
#define EL2NSYNC 45 /* Level 2 not synchronized */
#define EL3HLT 46 /* Level 3 halted */
#define EL3RST 47 /* Level 3 reset */
#define ELNRNG 48 /* Link number out of range */
#define EUNATCH 49 /* Protocol driver not attached */
#define ENOCSI 50 /* No CSI structure available */
#define EL2HLT 51 /* Level 2 halted */
#define EBADE 52 /* Invalid exchange */
#define EBADR 53 /* Invalid request descriptor */
#define EXFULL 54 /* Exchange full */
#define ENOANO 55 /* No anode */
#define EBADRQC 56 /* Invalid request code */
#define EBADSLT 57 /* Invalid slot */
#define EDEADLOCK EDEADLK
#define EDEADLOCK EDEADLK
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define EBFONT 59 /* Bad font file format */
#define ENOSTR 60 /* Device not a stream */
#define ENODATA 61 /* No data available */
#define ETIME 62 /* Timer expired */
#define ENOSR 63 /* Out of streams resources */
#define ENONET 64 /* Machine is not on the network */
#define ENOPKG 65 /* Package not installed */
#define EREMOTE 66 /* Object is remote */
#define ENOLINK 67 /* Link has been severed */
#define EADV 68 /* Advertise error */
#define ESRMNT 69 /* Srmount error */
#define ECOMM 70 /* Communication error on send */
#define EPROTO 71 /* Protocol error */
#define EMULTIHOP 72 /* Multihop attempted */
#define EDOTDOT 73 /* RFS specific error */
#define EBADMSG 74 /* Not a data message */
#define EOVERFLOW 75 /* Value too large for defined data type */
#define ENOTUNIQ 76 /* Name not unique on network */
#define EBADFD 77 /* File descriptor in bad state */
#define EREMCHG 78 /* Remote address changed */
#define ELIBACC 79 /* Can not access a needed shared library */
#define ELIBBAD 80 /* Accessing a corrupted shared library */
#define ELIBSCN 81 /* .lib section in a.out corrupted */
#define ELIBMAX 82 /* Attempting to link in too many shared libraries */
#define ELIBEXEC 83 /* Cannot exec a shared library directly */
#define EILSEQ 84 /* Illegal byte sequence */
#define ERESTART 85 /* Interrupted system call should be restarted */
#define ESTRPIPE 86 /* Streams pipe error */
#define EUSERS 87 /* Too many users */
#define ENOTSOCK 88 /* Socket operation on non-socket */
#define EDESTADDRREQ 89 /* Destination address required */
#define EMSGSIZE 90 /* Message too long */
#define EPROTOTYPE 91 /* Protocol wrong type for socket */
#define ENOPROTOOPT 92 /* Protocol not available */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define EPROTONOSUPPORT 93 /* Protocol not supported */
#define ESOCKTNOSUPPORT 94 /* Socket type not supported */
#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */
#define EPFNOSUPPORT 96 /* Protocol family not supported */
#define EAFNOSUPPORT 97 /* Address family not supported by protocol */
#define EADDRINUSE 98 /* Address already in use */
#define EADDRNOTAVAIL 99 /* Cannot assign requested address */
#define ENETDOWN 100 /* Network is down */
#define ENETUNREACH 101 /* Network is unreachable */
#define ENETRESET 102 /* Network dropped connection because of reset */
#define ECONNABORTED 103 /* Software caused connection abort */
#define ECONNRESET 104 /* Connection reset by peer */
#define ENOBUFS 105 /* No buffer space available */
#define EISCONN 106 /* Transport endpoint is already connected */
#define ENOTCONN 107 /* Transport endpoint is not connected */
#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */
#define ETOOMANYREFS 109 /* Too many references: cannot splice */
#define ETIMEDOUT 110 /* Connection timed out */
#define ECONNREFUSED 111 /* Connection refused */
#define EHOSTDOWN 112 /* Host is down */
#define EHOSTUNREACH 113 /* No route to host */
#define EALREADY 114 /* Operation already in progress */
#define EINPROGRESS 115 /* Operation now in progress */
#define ESTALE 116 /* Stale NFS file handle */
#define EUCLEAN 117 /* Structure needs cleaning */
#define ENOTNAM 118 /* Not a XENIX named type file */
#define ENAVAIL 119 /* No XENIX semaphores available */
#define EISNAM 120 /* Is a named type file */
#define EREMOTEIO 121 /* Remote I/O error */
#define EDQUOT 122 /* Quota exceeded */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENOMEDIUM 123 /* No medium found */
#define EMEDIUMTYPE 124 /* Wrong medium type */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSROK 0 /* DNS server returned answer with no data */
#define ENSRNODATA 160 /* DNS server returned answer with no data */
#define ENSRFORMERR 161 /* DNS server claims query was misformatted */
#define ENSRSERVFAIL 162 /* DNS server returned general failure */
#define ENSRNOTFOUND 163 /* Domain name not found */
#define ENSRNOTIMP 164 /* DNS server does not implement requested operation */
#define ENSRREFUSED 165 /* DNS server refused query */
#define ENSRBADQUERY 166 /* Misformatted DNS query */
#define ENSRBADNAME 167 /* Misformatted domain name */
#define ENSRBADFAMILY 168 /* Unsupported address family */
#define ENSRBADRESP 169 /* Misformatted DNS reply */
#define ENSRCONNREFUSED 170 /* Could not contact DNS servers */
#define ENSRTIMEOUT 171 /* Timeout while contacting DNS servers */
#define ENSROF 172 /* End of file */
#define ENSRFILE 173 /* Error reading file */
#define ENSRNOMEM 174 /* Out of memory */
#define ENSRDESTRUCTION 175 /* Application terminated lookup */
#define ENSRQUERYDOMAINTOOLONG 176 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#define ENSRCNAMELOOP 177 /* Domain name is too long */
#ifndef errno
extern int errno;

View File

@@ -33,14 +33,16 @@
#define __LWIP_DEBUG_H__
#include "lwip/arch.h"
#include "lwip/opt.h"
/** lower two bits indicate debug level
* - 0 off
* - 0 all
* - 1 warning
* - 2 serious
* - 3 severe
*/
#define LWIP_DBG_LEVEL_OFF 0x00
#define LWIP_DBG_LEVEL_ALL 0x00
#define LWIP_DBG_LEVEL_OFF LWIP_DBG_LEVEL_ALL /* compatibility define only */
#define LWIP_DBG_LEVEL_WARNING 0x01 /* bad checksums, dropped packets, ... */
#define LWIP_DBG_LEVEL_SERIOUS 0x02 /* memory allocation failures, ... */
#define LWIP_DBG_LEVEL_SEVERE 0x03
@@ -61,26 +63,28 @@
#define LWIP_DBG_HALT 0x08U
#ifndef LWIP_NOASSERT
#define LWIP_ASSERT(x,y) do { if(!(y)) LWIP_PLATFORM_ASSERT(x); } while(0)
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
LWIP_PLATFORM_ASSERT(message); } while(0)
#else /* LWIP_NOASSERT */
#define LWIP_ASSERT(x,y)
#define LWIP_ASSERT(message, assertion)
#endif /* LWIP_NOASSERT */
/** print "m" message only if "e" is true, and execute "h" expression */
/** if "expression" isn't true, then print "message" and execute "handler" expression */
#ifndef LWIP_ERROR
#define LWIP_ERROR(m,e,h) do { if (!(e)) { LWIP_PLATFORM_ASSERT(m); h;}} while(0)
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
#endif /* LWIP_ERROR */
#ifdef LWIP_DEBUG
/** print debug message only if debug message type is enabled...
* AND is of correct type AND is at least LWIP_DBG_LEVEL
*/
#define LWIP_DEBUGF(debug,x) do { \
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG(x); \
LWIP_PLATFORM_DIAG(message); \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
@@ -88,7 +92,7 @@
} while(0)
#else /* LWIP_DEBUG */
#define LWIP_DEBUGF(debug,x)
#define LWIP_DEBUGF(debug, message)
#endif /* LWIP_DEBUG */
#endif /* __LWIP_DEBUG_H__ */

View File

@@ -32,8 +32,13 @@
#ifndef __LWIP_DEF_H__
#define __LWIP_DEF_H__
/* this might define NULL already */
/* arch.h might define NULL already */
#include "lwip/arch.h"
#include "lwip/opt.h"
#ifdef __cplusplus
extern "C" {
#endif
#define LWIP_MAX(x , y) (((x) > (y)) ? (x) : (y))
#define LWIP_MIN(x , y) (((x) < (y)) ? (x) : (y))
@@ -42,6 +47,81 @@
#define NULL ((void *)0)
#endif
/** Get the absolute difference between 2 u32_t values (correcting overflows)
* 'a' is expected to be 'higher' (without overflow) than 'b'. */
#define LWIP_U32_DIFF(a, b) (((a) >= (b)) ? ((a) - (b)) : (((a) + ((b) ^ 0xFFFFFFFF) + 1)))
/* Endianess-optimized shifting of two u8_t to create one u16_t */
#if BYTE_ORDER == LITTLE_ENDIAN
#define LWIP_MAKE_U16(a, b) ((a << 8) | b)
#else
#define LWIP_MAKE_U16(a, b) ((b << 8) | a)
#endif
#ifndef LWIP_PLATFORM_BYTESWAP
#define LWIP_PLATFORM_BYTESWAP 0
#endif
#ifndef LWIP_PREFIX_BYTEORDER_FUNCS
/* workaround for naming collisions on some platforms */
#ifdef htons
#undef htons
#endif /* htons */
#ifdef htonl
#undef htonl
#endif /* htonl */
#ifdef ntohs
#undef ntohs
#endif /* ntohs */
#ifdef ntohl
#undef ntohl
#endif /* ntohl */
#define htons(x) lwip_htons(x)
#define ntohs(x) lwip_ntohs(x)
#define htonl(x) lwip_htonl(x)
#define ntohl(x) lwip_ntohl(x)
#endif /* LWIP_PREFIX_BYTEORDER_FUNCS */
#if BYTE_ORDER == BIG_ENDIAN
#define lwip_htons(x) (x)
#define lwip_ntohs(x) (x)
#define lwip_htonl(x) (x)
#define lwip_ntohl(x) (x)
#define PP_HTONS(x) (x)
#define PP_NTOHS(x) (x)
#define PP_HTONL(x) (x)
#define PP_NTOHL(x) (x)
#else /* BYTE_ORDER != BIG_ENDIAN */
#if LWIP_PLATFORM_BYTESWAP
#define lwip_htons(x) LWIP_PLATFORM_HTONS(x)
#define lwip_ntohs(x) LWIP_PLATFORM_HTONS(x)
#define lwip_htonl(x) LWIP_PLATFORM_HTONL(x)
#define lwip_ntohl(x) LWIP_PLATFORM_HTONL(x)
#else /* LWIP_PLATFORM_BYTESWAP */
u16_t lwip_htons(u16_t x);
u16_t lwip_ntohs(u16_t x);
u32_t lwip_htonl(u32_t x);
u32_t lwip_ntohl(u32_t x);
#endif /* LWIP_PLATFORM_BYTESWAP */
/* These macros should be calculated by the preprocessor and are used
with compile-time constants only (so that there is no little-endian
overhead at runtime). */
#define PP_HTONS(x) ((((x) & 0xff) << 8) | (((x) & 0xff00) >> 8))
#define PP_NTOHS(x) PP_HTONS(x)
#define PP_HTONL(x) ((((x) & 0xff) << 24) | \
(((x) & 0xff00) << 8) | \
(((x) & 0xff0000UL) >> 8) | \
(((x) & 0xff000000UL) >> 24))
#define PP_NTOHL(x) PP_HTONL(x)
#endif /* BYTE_ORDER == BIG_ENDIAN */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_DEF_H__ */

View File

@@ -18,28 +18,30 @@ extern "C" {
/** period (in seconds) of the application calling dhcp_coarse_tmr() */
#define DHCP_COARSE_TIMER_SECS 60
/** period (in milliseconds) of the application calling dhcp_coarse_tmr() */
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS*1000)
#define DHCP_COARSE_TIMER_MSECS (DHCP_COARSE_TIMER_SECS * 1000UL)
/** period (in milliseconds) of the application calling dhcp_fine_tmr() */
#define DHCP_FINE_TIMER_MSECS 500
#define DHCP_CHADDR_LEN 16U
#define DHCP_SNAME_LEN 64U
#define DHCP_FILE_LEN 128U
struct dhcp
{
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
/** transaction identifier of last sent request */
u32_t xid;
/** our connection to the DHCP server */
struct udp_pcb *pcb;
/** (first) pbuf of incoming msg */
struct pbuf *p;
/** incoming msg */
struct dhcp_msg *msg_in;
/** incoming msg options */
struct dhcp_msg *options_in;
/** ingoing msg options length */
u16_t options_in_len;
/** current DHCP state machine state */
u8_t state;
/** retries of current request */
u8_t tries;
#if LWIP_DHCP_AUTOIP_COOP
u8_t autoip_coop_state;
#endif
u8_t subnet_mask_given;
struct pbuf *p_out; /* pbuf of outcoming msg */
struct dhcp_msg *msg_out; /* outgoing msg */
@@ -47,28 +49,20 @@ struct dhcp
u16_t request_timeout; /* #ticks with period DHCP_FINE_TIMER_SECS for request timeout */
u16_t t1_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for renewal time */
u16_t t2_timeout; /* #ticks with period DHCP_COARSE_TIMER_SECS for rebind time */
struct ip_addr server_ip_addr; /* dhcp server address that offered this lease */
struct ip_addr offered_ip_addr;
struct ip_addr offered_sn_mask;
struct ip_addr offered_gw_addr;
struct ip_addr offered_bc_addr;
#define DHCP_MAX_DNS 2
u32_t dns_count; /* actual number of DNS servers obtained */
struct ip_addr offered_dns_addr[DHCP_MAX_DNS]; /* DNS server addresses */
ip_addr_t server_ip_addr; /* dhcp server address that offered this lease */
ip_addr_t offered_ip_addr;
ip_addr_t offered_sn_mask;
ip_addr_t offered_gw_addr;
u32_t offered_t0_lease; /* lease period (in seconds) */
u32_t offered_t1_renew; /* recommended renew time (usually 50% of lease period) */
u32_t offered_t2_rebind; /* recommended rebind time (usually 66% of lease period) */
#if LWIP_DHCP_AUTOIP_COOP
u8_t autoip_coop_state;
#endif
/** Patch #1308
* TODO: See dhcp.c "TODO"s
*/
#if 0
struct ip_addr offered_si_addr;
u8_t *boot_file_name;
#endif
/* @todo: LWIP_DHCP_BOOTP_FILE configuration option?
integrate with possible TFTP-client for booting? */
#if LWIP_DHCP_BOOTP_FILE
ip_addr_t offered_si_addr;
char boot_file_name[DHCP_FILE_LEN];
#endif /* LWIP_DHCP_BOOTPFILE */
};
/* MUST be compiled with "pack structs" or equivalent! */
@@ -86,15 +80,12 @@ struct dhcp_msg
PACK_STRUCT_FIELD(u32_t xid);
PACK_STRUCT_FIELD(u16_t secs);
PACK_STRUCT_FIELD(u16_t flags);
PACK_STRUCT_FIELD(struct ip_addr ciaddr);
PACK_STRUCT_FIELD(struct ip_addr yiaddr);
PACK_STRUCT_FIELD(struct ip_addr siaddr);
PACK_STRUCT_FIELD(struct ip_addr giaddr);
#define DHCP_CHADDR_LEN 16U
PACK_STRUCT_FIELD(ip_addr_p_t ciaddr);
PACK_STRUCT_FIELD(ip_addr_p_t yiaddr);
PACK_STRUCT_FIELD(ip_addr_p_t siaddr);
PACK_STRUCT_FIELD(ip_addr_p_t giaddr);
PACK_STRUCT_FIELD(u8_t chaddr[DHCP_CHADDR_LEN]);
#define DHCP_SNAME_LEN 64U
PACK_STRUCT_FIELD(u8_t sname[DHCP_SNAME_LEN]);
#define DHCP_FILE_LEN 128U
PACK_STRUCT_FIELD(u8_t file[DHCP_FILE_LEN]);
PACK_STRUCT_FIELD(u32_t cookie);
#define DHCP_MIN_OPTIONS_LEN 68U
@@ -114,6 +105,10 @@ PACK_STRUCT_END
# include "arch/epstruct.h"
#endif
void dhcp_set_struct(struct netif *netif, struct dhcp *dhcp);
/** Remove a struct dhcp previously set to the netif using dhcp_set_struct() */
#define dhcp_remove_struct(netif) do { (netif)->dhcp = NULL; } while(0)
void dhcp_cleanup(struct netif *netif);
/** start DHCP configuration */
err_t dhcp_start(struct netif *netif);
/** enforce early lease renewal (not needed normally)*/
@@ -124,10 +119,12 @@ err_t dhcp_release(struct netif *netif);
void dhcp_stop(struct netif *netif);
/** inform server of our manual IP address */
void dhcp_inform(struct netif *netif);
/** Handle a possible change in the network configuration */
void dhcp_network_changed(struct netif *netif);
/** if enabled, check whether the offered IP address is not in use, using ARP */
#if DHCP_DOES_ARP_CHECK
void dhcp_arp_reply(struct netif *netif, struct ip_addr *addr);
void dhcp_arp_reply(struct netif *netif, ip_addr_t *addr);
#endif
/** to be called every minute */
@@ -136,66 +133,66 @@ void dhcp_coarse_tmr(void);
void dhcp_fine_tmr(void);
/** DHCP message item offsets and length */
#define DHCP_MSG_OFS (UDP_DATA_OFS)
#define DHCP_OP_OFS (DHCP_MSG_OFS + 0)
#define DHCP_HTYPE_OFS (DHCP_MSG_OFS + 1)
#define DHCP_HLEN_OFS (DHCP_MSG_OFS + 2)
#define DHCP_HOPS_OFS (DHCP_MSG_OFS + 3)
#define DHCP_XID_OFS (DHCP_MSG_OFS + 4)
#define DHCP_SECS_OFS (DHCP_MSG_OFS + 8)
#define DHCP_FLAGS_OFS (DHCP_MSG_OFS + 10)
#define DHCP_CIADDR_OFS (DHCP_MSG_OFS + 12)
#define DHCP_YIADDR_OFS (DHCP_MSG_OFS + 16)
#define DHCP_SIADDR_OFS (DHCP_MSG_OFS + 20)
#define DHCP_GIADDR_OFS (DHCP_MSG_OFS + 24)
#define DHCP_CHADDR_OFS (DHCP_MSG_OFS + 28)
#define DHCP_SNAME_OFS (DHCP_MSG_OFS + 44)
#define DHCP_FILE_OFS (DHCP_MSG_OFS + 108)
#define DHCP_MSG_LEN 236
#define DHCP_OP_OFS 0
#define DHCP_HTYPE_OFS 1
#define DHCP_HLEN_OFS 2
#define DHCP_HOPS_OFS 3
#define DHCP_XID_OFS 4
#define DHCP_SECS_OFS 8
#define DHCP_FLAGS_OFS 10
#define DHCP_CIADDR_OFS 12
#define DHCP_YIADDR_OFS 16
#define DHCP_SIADDR_OFS 20
#define DHCP_GIADDR_OFS 24
#define DHCP_CHADDR_OFS 28
#define DHCP_SNAME_OFS 44
#define DHCP_FILE_OFS 108
#define DHCP_MSG_LEN 236
#define DHCP_COOKIE_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN)
#define DHCP_OPTIONS_OFS (DHCP_MSG_OFS + DHCP_MSG_LEN + 4)
#define DHCP_COOKIE_OFS DHCP_MSG_LEN
#define DHCP_OPTIONS_OFS (DHCP_MSG_LEN + 4)
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
#define DHCP_CLIENT_PORT 68
#define DHCP_SERVER_PORT 67
/** DHCP client states */
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
#define DHCP_OFF 0
#define DHCP_REQUESTING 1
#define DHCP_INIT 2
#define DHCP_REBOOTING 3
#define DHCP_REBINDING 4
#define DHCP_RENEWING 5
#define DHCP_SELECTING 6
#define DHCP_INFORMING 7
#define DHCP_CHECKING 8
#define DHCP_PERMANENT 9
#define DHCP_BOUND 10
/** not yet implemented #define DHCP_RELEASING 11 */
#define DHCP_BACKING_OFF 12
#define DHCP_OFF 13
#define DHCP_BACKING_OFF 12
/** AUTOIP cooperatation flags */
#define DHCP_AUTOIP_COOP_STATE_OFF 0
#define DHCP_AUTOIP_COOP_STATE_ON 1
#define DHCP_AUTOIP_COOP_STATE_OFF 0
#define DHCP_AUTOIP_COOP_STATE_ON 1
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
#define DHCP_BOOTREQUEST 1
#define DHCP_BOOTREPLY 2
/** DHCP message types */
#define DHCP_DISCOVER 1
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
#define DHCP_OFFER 2
#define DHCP_REQUEST 3
#define DHCP_DECLINE 4
#define DHCP_ACK 5
#define DHCP_NAK 6
#define DHCP_RELEASE 7
#define DHCP_INFORM 8
/** DHCP hardware type, currently only ethernet is supported */
#define DHCP_HTYPE_ETH 1
#define DHCP_HLEN_ETH 6
#define DHCP_MAGIC_COOKIE 0x63825363UL
#define DHCP_BROADCAST_FLAG 15
#define DHCP_BROADCAST_MASK (1 << DHCP_FLAG_BROADCAST)
/* This is a list of options for BOOTP and DHCP, see RFC 2132 for descriptions */
/** BootP options */
#define DHCP_OPTION_PAD 0
@@ -217,7 +214,6 @@ void dhcp_fine_tmr(void);
#define DHCP_OPTION_MESSAGE_TYPE 53 /* RFC 2132 9.6, important for DHCP */
#define DHCP_OPTION_MESSAGE_TYPE_LEN 1
#define DHCP_OPTION_SERVER_ID 54 /* RFC 2132 9.7, server IP address */
#define DHCP_OPTION_PARAMETER_REQUEST_LIST 55 /* RFC 2132 9.8, requested option types */

View File

@@ -38,6 +38,10 @@
#if LWIP_DNS /* don't build if not configured for use in lwipopts.h */
#ifdef __cplusplus
extern "C" {
#endif
/** DNS timer period */
#define DNS_TMR_INTERVAL 1000
@@ -66,27 +70,55 @@
#define DNS_RRCLASS_HS 4 /* Hesiod [Dyer 87] */
#define DNS_RRCLASS_FLUSH 0x800 /* Flush bit */
/* The size used for the next line is rather a hack, but it prevents including socket.h in all files
that include memp.h, and that would possibly break portability (since socket.h defines some types
and constants possibly already define by the OS).
Calculation rule:
sizeof(struct addrinfo) + sizeof(struct sockaddr_in) + DNS_MAX_NAME_LENGTH + 1 byte zero-termination */
#define NETDB_ELEM_SIZE (32 + 16 + DNS_MAX_NAME_LENGTH + 1)
#if DNS_LOCAL_HOSTLIST
/** struct used for local host-list */
struct local_hostlist_entry {
/** static hostname */
const char *name;
/** static host address in network byteorder */
ip_addr_t addr;
struct local_hostlist_entry *next;
};
#if DNS_LOCAL_HOSTLIST_IS_DYNAMIC
#ifndef DNS_LOCAL_HOSTLIST_MAX_NAMELEN
#define DNS_LOCAL_HOSTLIST_MAX_NAMELEN DNS_MAX_NAME_LENGTH
#endif
#define LOCALHOSTLIST_ELEM_SIZE ((sizeof(struct local_hostlist_entry) + DNS_LOCAL_HOSTLIST_MAX_NAMELEN + 1))
#endif /* DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#endif /* DNS_LOCAL_HOSTLIST */
/** Callback which is invoked when a hostname is found.
* A function of this type must be implemented by the application using the DNS resolver.
* @param name pointer to the name that was looked up.
* @param ipaddr pointer to a struct ip_addr containing the IP address of the hostname,
* @param ipaddr pointer to an ip_addr_t containing the IP address of the hostname,
* or NULL if the name could not be found (or on any other error).
* @param callback_arg a user-specified callback argument passed to dns_gethostbyname
*/
typedef void (*dns_found_callback)(const char *name, struct ip_addr *ipaddr, void *callback_arg);
typedef void (*dns_found_callback)(const char *name, ip_addr_t *ipaddr, void *callback_arg);
void dns_init(void);
void dns_tmr(void);
void dns_setserver(u8_t numdns, struct ip_addr *dnsserver);
struct ip_addr dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, struct ip_addr *addr,
void dns_setserver(u8_t numdns, ip_addr_t *dnsserver);
ip_addr_t dns_getserver(u8_t numdns);
err_t dns_gethostbyname(const char *hostname, ip_addr_t *addr,
dns_found_callback found, void *callback_arg);
#if DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
int dns_local_removehost(const char *hostname, const ip_addr_t *addr);
err_t dns_local_addhost(const char *hostname, const ip_addr_t *addr);
#endif /* DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS */
#endif /* __LWIP_DNS_H__ */

View File

@@ -33,39 +33,43 @@
#define __LWIP_ERR_H__
#include "lwip/opt.h"
#include "lwip/arch.h"
#ifdef __cplusplus
extern "C" {
#endif
/** Define LWIP_ERR_T in cc.h if you want to use
* a different type for your platform (must be signed). */
#ifdef LWIP_ERR_T
typedef LWIP_ERR_T err_t;
#else /* LWIP_ERR_T */
typedef s8_t err_t;
#endif /* LWIP_ERR_T*/
/* Definitions for error constants. */
#define ERR_OK 0 /* No error, everything OK. */
#define ERR_MEM -1 /* Out of memory error. */
#define ERR_BUF -2 /* Buffer error. */
#define ERR_RTE -3 /* Routing problem. */
#define ERR_TIMEOUT -3 /* Timeout. */
#define ERR_RTE -4 /* Routing problem. */
#define ERR_INPROGRESS -5 /* Operation in progress */
#define ERR_VAL -6 /* Illegal value. */
#define ERR_WOULDBLOCK -7 /* Operation would block. */
#define ERR_USE -8 /* Address in use. */
#define ERR_ISCONN -9 /* Already connected. */
#define ERR_IS_FATAL(e) ((e) < ERR_RTE)
#define ERR_IS_FATAL(e) ((e) < ERR_ISCONN)
#define ERR_ABRT -4 /* Connection aborted. */
#define ERR_RST -5 /* Connection reset. */
#define ERR_CLSD -6 /* Connection closed. */
#define ERR_CONN -7 /* Not connected. */
#define ERR_ABRT -10 /* Connection aborted. */
#define ERR_RST -11 /* Connection reset. */
#define ERR_CLSD -12 /* Connection closed. */
#define ERR_CONN -13 /* Not connected. */
#define ERR_VAL -8 /* Illegal value. */
#define ERR_ARG -14 /* Illegal argument. */
#define ERR_ARG -9 /* Illegal argument. */
#define ERR_USE -10 /* Address in use. */
#define ERR_IF -11 /* Low-level netif error */
#define ERR_ISCONN -12 /* Already connected. */
#define ERR_TIMEOUT -13 /* Timeout. */
#define ERR_INPROGRESS -14 /* Operation in progress */
#define ERR_IF -15 /* Low-level netif error */
#ifdef LWIP_DEBUG

View File

@@ -0,0 +1,112 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_INET_CHKSUM_H__
#define __LWIP_INET_CHKSUM_H__
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
/** Swap the bytes in an u16_t: much like htons() for little-endian */
#ifndef SWAP_BYTES_IN_WORD
#if LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)
/* little endian and PLATFORM_BYTESWAP defined */
#define SWAP_BYTES_IN_WORD(w) LWIP_PLATFORM_HTONS(w)
#else /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN) */
/* can't use htons on big endian (or PLATFORM_BYTESWAP not defined)... */
#define SWAP_BYTES_IN_WORD(w) (((w) & 0xff) << 8) | (((w) & 0xff00) >> 8)
#endif /* LWIP_PLATFORM_BYTESWAP && (BYTE_ORDER == LITTLE_ENDIAN)*/
#endif /* SWAP_BYTES_IN_WORD */
/** Split an u32_t in two u16_ts and add them up */
#ifndef FOLD_U32T
#define FOLD_U32T(u) (((u) >> 16) + ((u) & 0x0000ffffUL))
#endif
#if LWIP_CHECKSUM_ON_COPY
/** Function-like macro: same as MEMCPY but returns the checksum of copied data
as u16_t */
#ifndef LWIP_CHKSUM_COPY
#define LWIP_CHKSUM_COPY(dst, src, len) lwip_chksum_copy(dst, src, len)
#ifndef LWIP_CHKSUM_COPY_ALGORITHM
#define LWIP_CHKSUM_COPY_ALGORITHM 1
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#endif /* LWIP_CHKSUM_COPY */
#else /* LWIP_CHECKSUM_ON_COPY */
#define LWIP_CHKSUM_COPY_ALGORITHM 0
#endif /* LWIP_CHECKSUM_ON_COPY */
#ifdef __cplusplus
extern "C" {
#endif
u16_t inet_chksum(void *dataptr, u16_t len);
u16_t inet_chksum_pbuf(struct pbuf *p);
u16_t inet_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip_addr_t *src, ip_addr_t *dest);
u16_t inet_chksum_pseudo_partial(struct pbuf *p, u8_t proto,
u16_t proto_len, u16_t chksum_len, ip_addr_t *src, ip_addr_t *dest);
#if LWIP_CHKSUM_COPY_ALGORITHM
u16_t lwip_chksum_copy(void *dst, const void *src, u16_t len);
#endif /* LWIP_CHKSUM_COPY_ALGORITHM */
#if LWIP_IPV6
u16_t ip6_chksum_pseudo(struct pbuf *p, u8_t proto, u16_t proto_len,
ip6_addr_t *src, ip6_addr_t *dest);
u16_t ip6_chksum_pseudo_partial(struct pbuf *p, u8_t proto, u16_t proto_len,
u16_t chksum_len, ip6_addr_t *src, ip6_addr_t *dest);
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
((isipv6) ? \
ip6_chksum_pseudo(p, proto, proto_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
inet_chksum_pseudo(p, proto, proto_len, ipX_2_ip(src), ipX_2_ip(dest)))
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
((isipv6) ? \
ip6_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip6(src), ipX_2_ip6(dest)) :\
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, ipX_2_ip(src), ipX_2_ip(dest)))
#else /* LWIP_IPV6 */
#define ipX_chksum_pseudo(isipv6, p, proto, proto_len, src, dest) \
inet_chksum_pseudo(p, proto, proto_len, src, dest)
#define ipX_chksum_pseudo_partial(isipv6, p, proto, proto_len, chksum_len, src, dest) \
inet_chksum_pseudo_partial(p, proto, proto_len, chksum_len, src, dest)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_INET_H__ */

View File

@@ -38,6 +38,30 @@
extern "C" {
#endif
/** X.x.x: Major version of the stack */
#define LWIP_VERSION_MAJOR 1U
/** x.X.x: Minor version of the stack */
#define LWIP_VERSION_MINOR 4U
/** x.x.X: Revision of the stack */
#define LWIP_VERSION_REVISION 1U
/** For release candidates, this is set to 1..254
* For official releases, this is set to 255 (LWIP_RC_RELEASE)
* For development versions (CVS), this is set to 0 (LWIP_RC_DEVELOPMENT) */
#define LWIP_VERSION_RC 0U
/** LWIP_VERSION_RC is set to LWIP_RC_RELEASE for official releases */
#define LWIP_RC_RELEASE 255U
/** LWIP_VERSION_RC is set to LWIP_RC_DEVELOPMENT for CVS versions */
#define LWIP_RC_DEVELOPMENT 0U
#define LWIP_VERSION_IS_RELEASE (LWIP_VERSION_RC == LWIP_RC_RELEASE)
#define LWIP_VERSION_IS_DEVELOPMENT (LWIP_VERSION_RC == LWIP_RC_DEVELOPMENT)
#define LWIP_VERSION_IS_RC ((LWIP_VERSION_RC != LWIP_RC_RELEASE) && (LWIP_VERSION_RC != LWIP_RC_DEVELOPMENT))
/** Provides the version of the stack */
#define LWIP_VERSION (LWIP_VERSION_MAJOR << 24 | LWIP_VERSION_MINOR << 16 | \
LWIP_VERSION_REVISION << 8 | LWIP_VERSION_RC)
/* Modules initialization */
void lwip_init(void);

247
src/include/lwip/ip.h Normal file
View File

@@ -0,0 +1,247 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_H__
#define __LWIP_IP_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#include "lwip/netif.h"
#include "lwip/ip4.h"
#include "lwip/ip6.h"
#ifdef __cplusplus
extern "C" {
#endif
/* This is passed as the destination address to ip_output_if (not
to ip_output), meaning that an IP header already is constructed
in the pbuf. This is used when TCP retransmits. */
#ifdef IP_HDRINCL
#undef IP_HDRINCL
#endif /* IP_HDRINCL */
#define IP_HDRINCL NULL
#if LWIP_NETIF_HWADDRHINT
#define IP_PCB_ADDRHINT ;u8_t addr_hint
#else
#define IP_PCB_ADDRHINT
#endif /* LWIP_NETIF_HWADDRHINT */
#if LWIP_IPV6
#define IP_PCB_ISIPV6_MEMBER u8_t isipv6;
#define IP_PCB_IPVER_EQ(pcb1, pcb2) ((pcb1)->isipv6 == (pcb2)->isipv6)
#define IP_PCB_IPVER_INPUT_MATCH(pcb) (ip_current_is_v6() ? \
((pcb)->isipv6 != 0) : \
((pcb)->isipv6 == 0))
#define PCB_ISIPV6(pcb) ((pcb)->isipv6)
#else
#define IP_PCB_ISIPV6_MEMBER
#define IP_PCB_IPVER_EQ(pcb1, pcb2) 1
#define IP_PCB_IPVER_INPUT_MATCH(pcb) 1
#define PCB_ISIPV6(pcb) 0
#endif /* LWIP_IPV6 */
/* This is the common part of all PCB types. It needs to be at the
beginning of a PCB type definition. It is located here so that
changes to this common part are made in one location instead of
having to change all PCB structs. */
#define IP_PCB \
IP_PCB_ISIPV6_MEMBER \
/* ip addresses in network byte order */ \
ipX_addr_t local_ip; \
ipX_addr_t remote_ip; \
/* Socket options */ \
u8_t so_options; \
/* Type Of Service */ \
u8_t tos; \
/* Time To Live */ \
u8_t ttl \
/* link layer address resolution hint */ \
IP_PCB_ADDRHINT
struct ip_pcb {
/* Common members of all PCB types */
IP_PCB;
};
/*
* Option flags per-socket. These are the same like SO_XXX.
*/
/*#define SOF_DEBUG (u8_t)0x01U Unimplemented: turn on debugging info recording */
#define SOF_ACCEPTCONN (u8_t)0x02U /* socket has had listen() */
#define SOF_REUSEADDR (u8_t)0x04U /* allow local address reuse */
#define SOF_KEEPALIVE (u8_t)0x08U /* keep connections alive */
/*#define SOF_DONTROUTE (u8_t)0x10U Unimplemented: just use interface addresses */
#define SOF_BROADCAST (u8_t)0x20U /* permit to send and to receive broadcast messages (see IP_SOF_BROADCAST option) */
/*#define SOF_USELOOPBACK (u8_t)0x40U Unimplemented: bypass hardware when possible */
#define SOF_LINGER (u8_t)0x80U /* linger on close if data present */
/*#define SOF_OOBINLINE (u16_t)0x0100U Unimplemented: leave received OOB data in line */
/*#define SOF_REUSEPORT (u16_t)0x0200U Unimplemented: allow local address & port reuse */
/* These flags are inherited (e.g. from a listen-pcb to a connection-pcb): */
#define SOF_INHERITED (SOF_REUSEADDR|SOF_KEEPALIVE|SOF_LINGER/*|SOF_DEBUG|SOF_DONTROUTE|SOF_OOBINLINE*/)
/* Global variables of this module, kept in a struct for efficient access using base+index. */
struct ip_globals
{
/** The interface that provided the packet for the current callback invocation. */
struct netif *current_netif;
/** Header of the input packet currently being processed. */
const struct ip_hdr *current_ip4_header;
#if LWIP_IPV6
/** Header of the input IPv6 packet currently being processed. */
const struct ip6_hdr *current_ip6_header;
#endif /* LWIP_IPV6 */
/** Total header length of current_ip4/6_header (i.e. after this, the UDP/TCP header starts) */
u16_t current_ip_header_tot_len;
/** Source IP address of current_header */
ipX_addr_t current_iphdr_src;
/** Destination IP address of current_header */
ipX_addr_t current_iphdr_dest;
};
extern struct ip_globals ip_data;
/** Get the interface that received the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_netif() (ip_data.current_netif)
/** Get the IP header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip_current_header() (ip_data.current_ip4_header)
/** Total header length of ip(6)_current_header() (i.e. after this, the UDP/TCP header starts) */
#define ip_current_header_tot_len() (ip_data.current_ip_header_tot_len)
/** Source IP address of current_header */
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
/** Destination IP address of current_header */
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
#if LWIP_IPV6
/** Get the IPv6 header of the current packet.
* This function must only be called from a receive callback (udp_recv,
* raw_recv, tcp_accept). It will return NULL otherwise. */
#define ip6_current_header() (ip_data.current_ip6_header)
/** Returns TRUE if the current IP input packet is IPv6, FALSE if it is IPv4 */
#define ip_current_is_v6() (ip6_current_header() != NULL)
/** Source IPv6 address of current_header */
#define ip6_current_src_addr() (ipX_2_ip6(&ip_data.current_iphdr_src))
/** Destination IPv6 address of current_header */
#define ip6_current_dest_addr() (ipX_2_ip6(&ip_data.current_iphdr_dest))
/** Get the transport layer protocol */
#define ip_current_header_proto() (ip_current_is_v6() ? \
IP6H_NEXTH(ip6_current_header()) :\
IPH_PROTO(ip_current_header()))
/** Get the transport layer header */
#define ipX_next_header_ptr() ((void*)((ip_current_is_v6() ? \
(u8_t*)ip6_current_header() : (u8_t*)ip_current_header()) + ip_current_header_tot_len()))
/** Set an IP_PCB to IPv6 (IPv4 is the default) */
#define ip_set_v6(pcb, val) do{if(pcb != NULL) { pcb->isipv6 = val; }}while(0)
/** Source IP4 address of current_header */
#define ip_current_src_addr() (ipX_2_ip(&ip_data.current_iphdr_src))
/** Destination IP4 address of current_header */
#define ip_current_dest_addr() (ipX_2_ip(&ip_data.current_iphdr_dest))
#else /* LWIP_IPV6 */
/** Always returns FALSE when only supporting IPv4 */
#define ip_current_is_v6() 0
/** Get the transport layer protocol */
#define ip_current_header_proto() IPH_PROTO(ip_current_header())
/** Get the transport layer header */
#define ipX_next_header_ptr() ((void*)((u8_t*)ip_current_header() + ip_current_header_tot_len()))
/** Source IP4 address of current_header */
#define ip_current_src_addr() (&ip_data.current_iphdr_src)
/** Destination IP4 address of current_header */
#define ip_current_dest_addr() (&ip_data.current_iphdr_dest)
#endif /* LWIP_IPV6 */
/** Union source address of current_header */
#define ipX_current_src_addr() (&ip_data.current_iphdr_src)
/** Union destination address of current_header */
#define ipX_current_dest_addr() (&ip_data.current_iphdr_dest)
#if LWIP_IPV6
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
((isipv6) ? \
ip6_output(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto) : \
ip_output(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto))
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
((isipv6) ? \
ip6_output_if(p, ip_2_ip6(src), ip_2_ip6(dest), ttl, tos, proto, netif) : \
ip_output_if(p, (src), (dest), ttl, tos, proto, netif))
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
((isipv6) ? \
ip6_output_hinted(p, ipX_2_ip6(src), ipX_2_ip6(dest), ttl, tos, proto, addr_hint) : \
ip_output_hinted(p, ipX_2_ip(src), ipX_2_ip(dest), ttl, tos, proto, addr_hint))
#define ipX_route(isipv6, src, dest) \
((isipv6) ? \
ip6_route(ipX_2_ip6(src), ipX_2_ip6(dest)) : \
ip_route(ipX_2_ip(dest)))
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
((isipv6) ? \
ip6_netif_get_local_ipX(netif, ipX_2_ip6(dest)) : \
ip_netif_get_local_ipX(netif))
#define ipX_debug_print(is_ipv6, p) ((is_ipv6) ? ip6_debug_print(p) : ip_debug_print(p))
#else /* LWIP_IPV6 */
#define ipX_output(isipv6, p, src, dest, ttl, tos, proto) \
ip_output(p, src, dest, ttl, tos, proto)
#define ipX_output_if(isipv6, p, src, dest, ttl, tos, proto, netif) \
ip_output_if(p, src, dest, ttl, tos, proto, netif)
#define ipX_output_hinted(isipv6, p, src, dest, ttl, tos, proto, addr_hint) \
ip_output_hinted(p, src, dest, ttl, tos, proto, addr_hint)
#define ipX_route(isipv6, src, dest) \
ip_route(ipX_2_ip(dest))
#define ipX_netif_get_local_ipX(isipv6, netif, dest) \
ip_netif_get_local_ipX(netif)
#define ipX_debug_print(is_ipv6, p) ip_debug_print(p)
#endif /* LWIP_IPV6 */
#define ipX_route_get_local_ipX(isipv6, src, dest, netif, ipXaddr) do { \
(netif) = ipX_route(isipv6, src, dest); \
(ipXaddr) = ipX_netif_get_local_ipX(isipv6, netif, dest); \
}while(0)
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_H__ */

130
src/include/lwip/ip_addr.h Normal file
View File

@@ -0,0 +1,130 @@
/*
* Copyright (c) 2001-2004 Swedish Institute of Computer Science.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification,
* are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. The name of the author may not be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
* SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
* OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
* IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
* OF SUCH DAMAGE.
*
* This file is part of the lwIP TCP/IP stack.
*
* Author: Adam Dunkels <adam@sics.se>
*
*/
#ifndef __LWIP_IP_ADDR_H__
#define __LWIP_IP_ADDR_H__
#include "lwip/opt.h"
#include "lwip/def.h"
#include "lwip/ip4_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
#if LWIP_IPV6
/* A union struct for both IP version's addresses. */
typedef union {
ip_addr_t ip4;
ip6_addr_t ip6;
} ipX_addr_t;
/** These functions only exist for type-safe conversion from ip_addr_t to
ip6_addr_t and back */
#if LWIP_ALLOW_STATIC_FN_IN_HEADER
static ip6_addr_t* ip_2_ip6(ip_addr_t *ipaddr)
{ return (ip6_addr_t*)ipaddr;}
static ip_addr_t* ip6_2_ip(ip6_addr_t *ip6addr)
{ return (ip_addr_t*)ip6addr; }
static ipX_addr_t* ip_2_ipX(ip_addr_t *ipaddr)
{ return (ipX_addr_t*)ipaddr; }
static ipX_addr_t* ip6_2_ipX(ip6_addr_t *ip6addr)
{ return (ipX_addr_t*)ip6addr; }
#else /* LWIP_ALLOW_STATIC_FN_IN_HEADER */
#define ip_2_ip6(ipaddr) ((ip6_addr_t*)(ipaddr))
#define ip6_2_ip(ip6addr) ((ip_addr_t*)(ip6addr))
#define ip_2_ipX(ipaddr) ((ipX_addr_t*)ipaddr)
#define ip6_2_ipX(ip6addr) ((ipX_addr_t*)ip6addr)
#endif /* LWIP_ALLOW_STATIC_FN_IN_HEADER*/
#define ipX_2_ip6(ip6addr) (&((ip6addr)->ip6))
#define ipX_2_ip(ipaddr) (&((ipaddr)->ip4))
#define ipX_addr_copy(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_copy((dest).ip6, (src).ip6); }else{ \
ip_addr_copy((dest).ip4, (src).ip4); }}while(0)
#define ipX_addr_set(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set(ipX_2_ip6(dest), ipX_2_ip6(src)); }else{ \
ip_addr_set(ipX_2_ip(dest), ipX_2_ip(src)); }}while(0)
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set(ipX_2_ip6(dest), ip_2_ip6(src)); }else{ \
ip_addr_set(ipX_2_ip(dest), src); }}while(0)
#define ipX_addr_set_zero(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_zero(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_zero(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_any(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_any(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_any(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_loopback(is_ipv6, ipaddr) do{if(is_ipv6){ \
ip6_addr_set_loopback(ipX_2_ip6(ipaddr)); }else{ \
ip_addr_set_loopback(ipX_2_ip(ipaddr)); }}while(0)
#define ipX_addr_set_hton(is_ipv6, dest, src) do{if(is_ipv6){ \
ip6_addr_set_hton(ipX_2_ip6(ipaddr), (src)) ;}else{ \
ip_addr_set_hton(ipX_2_ip(ipaddr), (src));}}while(0)
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ((is_ipv6) ? \
ip6_addr_cmp(ipX_2_ip6(addr1), ipX_2_ip6(addr2)) : \
ip_addr_cmp(ipX_2_ip(addr1), ipX_2_ip(addr2)))
#define ipX_addr_isany(is_ipv6, ipaddr) ((is_ipv6) ? \
ip6_addr_isany(ipX_2_ip6(ipaddr)) : \
ip_addr_isany(ipX_2_ip(ipaddr)))
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ((is_ipv6) ? \
ip6_addr_ismulticast(ipX_2_ip6(ipaddr)) : \
ip_addr_ismulticast(ipX_2_ip(ipaddr)))
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) do { if(is_ipv6) { \
ip6_addr_debug_print(debug, ipX_2_ip6(ipaddr)); } else { \
ip_addr_debug_print(debug, ipX_2_ip(ipaddr)); }}while(0)
#else /* LWIP_IPV6 */
typedef ip_addr_t ipX_addr_t;
#define ipX_2_ip(ipaddr) (ipaddr)
#define ip_2_ipX(ipaddr) (ipaddr)
#define ipX_addr_copy(is_ipv6, dest, src) ip_addr_copy(dest, src)
#define ipX_addr_set(is_ipv6, dest, src) ip_addr_set(dest, src)
#define ipX_addr_set_ipaddr(is_ipv6, dest, src) ip_addr_set(dest, src)
#define ipX_addr_set_zero(is_ipv6, ipaddr) ip_addr_set_zero(ipaddr)
#define ipX_addr_set_any(is_ipv6, ipaddr) ip_addr_set_any(ipaddr)
#define ipX_addr_set_loopback(is_ipv6, ipaddr) ip_addr_set_loopback(ipaddr)
#define ipX_addr_set_hton(is_ipv6, dest, src) ip_addr_set_hton(dest, src)
#define ipX_addr_cmp(is_ipv6, addr1, addr2) ip_addr_cmp(addr1, addr2)
#define ipX_addr_isany(is_ipv6, ipaddr) ip_addr_isany(ipaddr)
#define ipX_addr_ismulticast(is_ipv6, ipaddr) ip_addr_ismulticast(ipaddr)
#define ipX_addr_debug_print(is_ipv6, debug, ipaddr) ip_addr_debug_print(debug, ipaddr)
#endif /* LWIP_IPV6 */
#ifdef __cplusplus
}
#endif
#endif /* __LWIP_IP_ADDR_H__ */

View File

@@ -50,48 +50,67 @@ typedef size_t mem_size_t;
* allow these defines to be overridden.
*/
#ifndef mem_free
#define mem_free(x) free(x)
#define mem_free free
#endif
#ifndef mem_malloc
#define mem_malloc(x) malloc(x)
#define mem_malloc malloc
#endif
#ifndef mem_calloc
#define mem_calloc(x, y) calloc(x, y)
#define mem_calloc calloc
#endif
#ifndef mem_realloc
#define mem_realloc(x, size) (x)
/* Since there is no C library allocation function to shrink memory without
moving it, define this to nothing. */
#ifndef mem_trim
#define mem_trim(mem, size) (mem)
#endif
#else /* MEM_LIBC_MALLOC */
/* MEM_SIZE would have to be aligned, but using 64000 here instead of
* 65535 leaves some room for alignment...
*/
#if MEM_SIZE > 64000l
#if MEM_SIZE > 64000L
typedef u32_t mem_size_t;
#define MEM_SIZE_F U32_F
#else
typedef u16_t mem_size_t;
#define MEM_SIZE_F U16_F
#endif /* MEM_SIZE > 64000 */
#if MEM_USE_POOLS
/** mem_init is not used when using pools instead of a heap */
#define mem_init()
/** mem_realloc is not used when using pools instead of a heap:
/** mem_trim is not used when using pools instead of a heap:
we can't free part of a pool element and don't want to copy the rest */
#define mem_realloc(mem, size) (mem)
#define mem_trim(mem, size) (mem)
#else /* MEM_USE_POOLS */
/* lwIP alternative malloc */
void mem_init(void);
void *mem_realloc(void *mem, mem_size_t size);
void *mem_trim(void *mem, mem_size_t size);
#endif /* MEM_USE_POOLS */
void *mem_malloc(mem_size_t size);
void *mem_calloc(mem_size_t count, mem_size_t size);
void mem_free(void *mem);
#endif /* MEM_LIBC_MALLOC */
/** Calculate memory size for an aligned buffer - returns the next highest
* multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
* LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4).
*/
#ifndef LWIP_MEM_ALIGN_SIZE
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1))
#endif
/** Calculate safe memory size for an aligned buffer when using an unaligned
* type as storage. This includes a safety-margin on (MEM_ALIGNMENT - 1) at the
* start (e.g. if buffer is u8_t[] and actual data will be u32_t*)
*/
#ifndef LWIP_MEM_ALIGN_BUFFER
#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1))
#endif
/** Align a memory pointer to the alignment defined by MEM_ALIGNMENT
* so that ADDR % MEM_ALIGNMENT == 0
*/
#ifndef LWIP_MEM_ALIGN
#define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1)))
#endif

View File

@@ -73,8 +73,28 @@ typedef enum {
We use this helper type and these defines so we can avoid using const memp_t values */
#define MEMP_POOL_FIRST ((memp_t) MEMP_POOL_HELPER_FIRST)
#define MEMP_POOL_LAST ((memp_t) MEMP_POOL_HELPER_LAST)
#endif /* MEM_USE_POOLS */
#if MEMP_MEM_MALLOC || MEM_USE_POOLS
extern const u16_t memp_sizes[MEMP_MAX];
#endif /* MEMP_MEM_MALLOC || MEM_USE_POOLS */
#if MEMP_MEM_MALLOC
#include "mem.h"
#define memp_init()
#define memp_malloc(type) mem_malloc(memp_sizes[type])
#define memp_free(type, mem) mem_free(mem)
#else /* MEMP_MEM_MALLOC */
#if MEM_USE_POOLS
/** This structure is used to save the pool one element came from. */
struct memp_malloc_helper
{
memp_t poolnr;
};
#endif /* MEM_USE_POOLS */
void memp_init(void);
@@ -87,6 +107,8 @@ void *memp_malloc(memp_t type);
#endif
void memp_free(memp_t type, void *mem);
#endif /* MEMP_MEM_MALLOC */
#ifdef __cplusplus
}
#endif

View File

@@ -10,8 +10,9 @@
* above, then will declare #2 & #3 to be just standard mempools.
*/
#ifndef LWIP_MALLOC_MEMPOOL
/* This treats "malloc pools" just like any other pool */
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, size, "MALLOC_"#size)
/* This treats "malloc pools" just like any other pool.
The pools are a little bigger to provide 'size' as the amount of user data. */
#define LWIP_MALLOC_MEMPOOL(num, size) LWIP_MEMPOOL(POOL_##size, num, (size + sizeof(struct memp_malloc_helper)), "MALLOC_"#size)
#define LWIP_MALLOC_MEMPOOL_START
#define LWIP_MALLOC_MEMPOOL_END
#endif /* LWIP_MALLOC_MEMPOOL */
@@ -46,6 +47,9 @@ LWIP_MEMPOOL(TCP_SEG, MEMP_NUM_TCP_SEG, sizeof(struct tcp_seg),
#if IP_REASSEMBLY
LWIP_MEMPOOL(REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip_reassdata), "REASSDATA")
#endif /* IP_REASSEMBLY */
#if (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF) || LWIP_IPv6_FRAG
LWIP_MEMPOOL(FRAG_PBUF, MEMP_NUM_FRAG_PBUF, sizeof(struct pbuf_custom_ref),"FRAG_PBUF")
#endif /* IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF */
#if LWIP_NETCONN
LWIP_MEMPOOL(NETBUF, MEMP_NUM_NETBUF, sizeof(struct netbuf), "NETBUF")
@@ -54,7 +58,9 @@ LWIP_MEMPOOL(NETCONN, MEMP_NUM_NETCONN, sizeof(struct netconn),
#if NO_SYS==0
LWIP_MEMPOOL(TCPIP_MSG_API, MEMP_NUM_TCPIP_MSG_API, sizeof(struct tcpip_msg), "TCPIP_MSG_API")
#if !LWIP_TCPIP_CORE_LOCKING_INPUT
LWIP_MEMPOOL(TCPIP_MSG_INPKT,MEMP_NUM_TCPIP_MSG_INPKT, sizeof(struct tcpip_msg), "TCPIP_MSG_INPKT")
#endif /* !LWIP_TCPIP_CORE_LOCKING_INPUT */
#endif /* NO_SYS==0 */
#if ARP_QUEUEING
@@ -65,9 +71,37 @@ LWIP_MEMPOOL(ARP_QUEUE, MEMP_NUM_ARP_QUEUE, sizeof(struct etharp_q_en
LWIP_MEMPOOL(IGMP_GROUP, MEMP_NUM_IGMP_GROUP, sizeof(struct igmp_group), "IGMP_GROUP")
#endif /* LWIP_IGMP */
#if NO_SYS==0
#if (!NO_SYS || (NO_SYS && !NO_SYS_NO_TIMERS)) /* LWIP_TIMERS */
LWIP_MEMPOOL(SYS_TIMEOUT, MEMP_NUM_SYS_TIMEOUT, sizeof(struct sys_timeo), "SYS_TIMEOUT")
#endif /* NO_SYS==0 */
#endif /* LWIP_TIMERS */
#if LWIP_SNMP
LWIP_MEMPOOL(SNMP_ROOTNODE, MEMP_NUM_SNMP_ROOTNODE, sizeof(struct mib_list_rootnode), "SNMP_ROOTNODE")
LWIP_MEMPOOL(SNMP_NODE, MEMP_NUM_SNMP_NODE, sizeof(struct mib_list_node), "SNMP_NODE")
LWIP_MEMPOOL(SNMP_VARBIND, MEMP_NUM_SNMP_VARBIND, sizeof(struct snmp_varbind), "SNMP_VARBIND")
LWIP_MEMPOOL(SNMP_VALUE, MEMP_NUM_SNMP_VALUE, SNMP_MAX_VALUE_SIZE, "SNMP_VALUE")
#endif /* LWIP_SNMP */
#if LWIP_DNS && LWIP_SOCKET
LWIP_MEMPOOL(NETDB, MEMP_NUM_NETDB, NETDB_ELEM_SIZE, "NETDB")
#endif /* LWIP_DNS && LWIP_SOCKET */
#if LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC
LWIP_MEMPOOL(LOCALHOSTLIST, MEMP_NUM_LOCALHOSTLIST, LOCALHOSTLIST_ELEM_SIZE, "LOCALHOSTLIST")
#endif /* LWIP_DNS && DNS_LOCAL_HOSTLIST && DNS_LOCAL_HOSTLIST_IS_DYNAMIC */
#if PPP_SUPPORT && PPPOE_SUPPORT
LWIP_MEMPOOL(PPPOE_IF, MEMP_NUM_PPPOE_INTERFACES, sizeof(struct pppoe_softc), "PPPOE_IF")
#endif /* PPP_SUPPORT && PPPOE_SUPPORT */
#if LWIP_IPV6 && LWIP_ND6_QUEUEING
LWIP_MEMPOOL(ND6_QUEUE, MEMP_NUM_ND6_QUEUE, sizeof(struct nd6_q_entry), "ND6_QUEUE")
#endif /* LWIP_IPV6 && LWIP_ND6_QUEUEING */
#if LWIP_IPV6 && LWIP_IPV6_REASS
LWIP_MEMPOOL(IP6_REASSDATA, MEMP_NUM_REASSDATA, sizeof(struct ip6_reassdata), "IP6_REASSDATA")
#endif /* LWIP_IPV6 && LWIP_IPV6_REASS */
#if LWIP_IPV6 && LWIP_IPV6_MLD
LWIP_MEMPOOL(MLD6_GROUP, MEMP_NUM_MLD6_GROUP, sizeof(struct mld_group), "MLD6_GROUP")
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/*

View File

@@ -34,15 +34,31 @@
#include "lwip/opt.h"
#include "lwip/pbuf.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
/** This netbuf has dest-addr/port set */
#define NETBUF_FLAG_DESTADDR 0x01
/** This netbuf includes a checksum */
#define NETBUF_FLAG_CHKSUM 0x02
struct netbuf {
struct pbuf *p, *ptr;
struct ip_addr *addr;
ipX_addr_t addr;
u16_t port;
#if LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY
#if LWIP_CHECKSUM_ON_COPY
u8_t flags;
#endif /* LWIP_CHECKSUM_ON_COPY */
u16_t toport_chksum;
#if LWIP_NETBUF_RECVINFO
ipX_addr_t toaddr;
#endif /* LWIP_NETBUF_RECVINFO */
#endif /* LWIP_NETBUF_RECVINFO || LWIP_CHECKSUM_ON_COPY */
};
/* Network buffer functions: */
@@ -51,13 +67,12 @@ void netbuf_delete (struct netbuf *buf);
void * netbuf_alloc (struct netbuf *buf, u16_t size);
void netbuf_free (struct netbuf *buf);
err_t netbuf_ref (struct netbuf *buf,
const void *dataptr, u16_t size);
const void *dataptr, u16_t size);
void netbuf_chain (struct netbuf *head,
struct netbuf *tail);
u16_t netbuf_len (struct netbuf *buf);
err_t netbuf_data (struct netbuf *buf,
void **dataptr, u16_t *len);
void **dataptr, u16_t *len);
s8_t netbuf_next (struct netbuf *buf);
void netbuf_first (struct netbuf *buf);
@@ -65,9 +80,30 @@ void netbuf_first (struct netbuf *buf);
#define netbuf_copy_partial(buf, dataptr, len, offset) \
pbuf_copy_partial((buf)->p, (dataptr), (len), (offset))
#define netbuf_copy(buf,dataptr,len) netbuf_copy_partial(buf, dataptr, len, 0)
#define netbuf_take(buf, dataptr, len) pbuf_take((buf)->p, dataptr, len)
#define netbuf_len(buf) ((buf)->p->tot_len)
#define netbuf_fromaddr(buf) ((buf)->addr)
#define netbuf_fromaddr(buf) (ipX_2_ip(&((buf)->addr)))
#define netbuf_set_fromaddr(buf, fromaddr) ip_addr_set(ipX_2_ip(&((buf)->addr)), fromaddr)
#define netbuf_fromport(buf) ((buf)->port)
#if LWIP_NETBUF_RECVINFO
#define netbuf_destaddr(buf) (ipX_2_ip(&((buf)->toaddr)))
#define netbuf_set_destaddr(buf, destaddr) ip_addr_set(ipX_2_ip(&((buf)->toaddr)), destaddr)
#define netbuf_destport(buf) (((buf)->flags & NETBUF_FLAG_DESTADDR) ? (buf)->toport_chksum : 0)
#endif /* LWIP_NETBUF_RECVINFO */
#if LWIP_CHECKSUM_ON_COPY
#define netbuf_set_chksum(buf, chksum) do { (buf)->flags = NETBUF_FLAG_CHKSUM; \
(buf)->toport_chksum = chksum; } while(0)
#endif /* LWIP_CHECKSUM_ON_COPY */
#if LWIP_IPV6
#define netbuf_fromaddr_ip6(buf) (ipX_2_ip6(&((buf)->addr)))
#define netbuf_set_fromaddr_ip6(buf, fromaddr) ip6_addr_set(ipX_2_ip6(&((buf)->addr)), fromaddr)
#define netbuf_destaddr_ip6(buf) (ipX_2_ip6(&((buf)->toaddr)))
#define netbuf_set_destaddr_ip6(buf, destaddr) ip6_addr_set(ipX_2_ip6(&((buf)->toaddr)), destaddr)
#endif /* LWIP_IPV6 */
#define netbuf_fromaddr_ipX(buf) (&((buf)->addr))
#define netbuf_destaddr_ipX(buf) (&((buf)->toaddr))
#ifdef __cplusplus
}

View File

@@ -26,13 +26,22 @@
* Author: Simon Goldschmidt
*
*/
#ifndef __LWIP_NETDB_H__
#define __LWIP_NETDB_H__
#include "lwip/opt.h"
#if LWIP_DNS && LWIP_SOCKET
#include <stddef.h> /* for size_t */
#include "lwip/inet.h"
#include "lwip/sockets.h"
#ifdef __cplusplus
extern "C" {
#endif
/* some rarely used options */
#ifndef LWIP_DNS_API_DECLARE_H_ERRNO
#define LWIP_DNS_API_DECLARE_H_ERRNO 1
@@ -101,9 +110,15 @@ int lwip_getaddrinfo(const char *nodename,
#define gethostbyname(name) lwip_gethostbyname(name)
#define gethostbyname_r(name, ret, buf, buflen, result, h_errnop) \
lwip_gethostbyname_r(name, ret, buf, buflen, result, h_errnop)
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(a)
#define freeaddrinfo(addrinfo) lwip_freeaddrinfo(addrinfo)
#define getaddrinfo(nodname, servname, hints, res) \
lwip_getaddrinfo(nodname, servname, hints, res)
#endif /* LWIP_COMPAT_SOCKETS */
#ifdef __cplusplus
}
#endif
#endif /* LWIP_DNS && LWIP_SOCKET */
#endif /* __LWIP_NETDB_H__ */

View File

@@ -34,11 +34,14 @@
#include "lwip/opt.h"
#define ENABLE_LOOPBACK (LWIP_NETIF_LOOPBACK || LWIP_HAVE_LOOPIF)
#include "lwip/err.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include "lwip/pbuf.h"
#if LWIP_DHCP
struct dhcp;
@@ -46,6 +49,9 @@ struct dhcp;
#if LWIP_AUTOIP
struct autoip;
#endif
#if LWIP_IPV6_DHCP6
#include "lwip/dhcp6.h"
#endif /* LWIP_IPV6_DHCP6 */
#ifdef __cplusplus
extern "C" {
@@ -58,61 +64,138 @@ extern "C" {
across all types of interfaces in use */
#define NETIF_MAX_HWADDR_LEN 6U
/** TODO: define the use (where, when, whom) of netif flags */
/** whether the network interface is 'up'. this is
/** Whether the network interface is 'up'. This is
* a software flag used to control whether this network
* interface is enabled and processes traffic.
* It is set by the startup code (for static IP configuration) or
* by dhcp/autoip when an address has been assigned.
*/
#define NETIF_FLAG_UP 0x01U
/** if set, the netif has broadcast capability */
/** If set, the netif has broadcast capability.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_BROADCAST 0x02U
/** if set, the netif is one end of a point-to-point connection */
/** If set, the netif is one end of a point-to-point connection.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_POINTTOPOINT 0x04U
/** if set, the interface is configured using DHCP */
/** If set, the interface is configured using DHCP.
* Set by the DHCP code when starting or stopping DHCP. */
#define NETIF_FLAG_DHCP 0x08U
/** if set, the interface has an active link
* (set by the network interface driver) */
/** If set, the interface has an active link
* (set by the network interface driver).
* Either set by the netif driver in its init function (if the link
* is up at that time) or at a later point once the link comes up
* (if link detection is supported by the hardware). */
#define NETIF_FLAG_LINK_UP 0x10U
/** if set, the netif is an device using ARP */
/** If set, the netif is an ethernet device using ARP.
* Set by the netif driver in its init function.
* Used to check input packet types and use of DHCP. */
#define NETIF_FLAG_ETHARP 0x20U
/** if set, the netif has IGMP capability */
#define NETIF_FLAG_IGMP 0x40U
/** If set, the netif is an ethernet device. It might not use
* ARP or TCP/IP if it is used for PPPoE only.
*/
#define NETIF_FLAG_ETHERNET 0x40U
/** If set, the netif has IGMP capability.
* Set by the netif driver in its init function. */
#define NETIF_FLAG_IGMP 0x80U
/** Function prototype for netif init functions. Set up flags and output/linkoutput
* callback functions in this function.
*
* @param netif The netif to initialize
*/
typedef err_t (*netif_init_fn)(struct netif *netif);
/** Function prototype for netif->input functions. This function is saved as 'input'
* callback function in the netif struct. Call it when a packet has been received.
*
* @param p The received packet, copied into a pbuf
* @param inp The netif which received the packet
*/
typedef err_t (*netif_input_fn)(struct pbuf *p, struct netif *inp);
/** Function prototype for netif->output functions. Called by lwIP when a packet
* shall be sent. For ethernet netif, set this to 'etharp_output' and set
* 'linkoutput'.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (p->payload points to IP header)
* @param ipaddr The IP address to which the packet shall be sent
*/
typedef err_t (*netif_output_fn)(struct netif *netif, struct pbuf *p,
ip_addr_t *ipaddr);
#if LWIP_IPV6
/** Function prototype for netif->output_ip6 functions. Called by lwIP when a packet
* shall be sent. For ethernet netif, set this to 'nd_output' and set
* 'linkoutput'.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (p->payload points to IP header)
* @param ipaddr The IPv6 address to which the packet shall be sent
*/
typedef err_t (*netif_output_ip6_fn)(struct netif *netif, struct pbuf *p,
ip6_addr_t *ipaddr);
#endif /* LWIP_IPV6 */
/** Function prototype for netif->linkoutput functions. Only used for ethernet
* netifs. This function is called by ARP when a packet shall be sent.
*
* @param netif The netif which shall send a packet
* @param p The packet to send (raw ethernet packet)
*/
typedef err_t (*netif_linkoutput_fn)(struct netif *netif, struct pbuf *p);
/** Function prototype for netif status- or link-callback functions. */
typedef void (*netif_status_callback_fn)(struct netif *netif);
/** Function prototype for netif igmp_mac_filter functions */
typedef err_t (*netif_igmp_mac_filter_fn)(struct netif *netif,
ip_addr_t *group, u8_t action);
#if LWIP_IPV6 && LWIP_IPV6_MLD
/** Function prototype for netif mld_mac_filter functions */
typedef err_t (*netif_mld_mac_filter_fn)(struct netif *netif,
ip6_addr_t *group, u8_t action);
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
/** Generic data structure used for all lwIP network interfaces.
* The following fields should be filled in by the initialization
* function for the device driver: hwaddr_len, hwaddr[], mtu, flags */
struct netif {
/** pointer to next in linked list */
struct netif *next;
/** IP address configuration in network byte order */
struct ip_addr ip_addr;
struct ip_addr netmask;
struct ip_addr gw;
ip_addr_t ip_addr;
ip_addr_t netmask;
ip_addr_t gw;
#if LWIP_IPV6
/** Array of IPv6 addresses for this netif. */
ip6_addr_t ip6_addr[LWIP_IPV6_NUM_ADDRESSES];
/** The state of each IPv6 address (Tentative, Preferred, etc).
* @see ip6_addr.h */
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6 */
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
err_t (* input)(struct pbuf *p, struct netif *inp);
netif_input_fn input;
/** This function is called by the IP module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
err_t (* output)(struct netif *netif, struct pbuf *p,
struct ip_addr *ipaddr);
netif_output_fn output;
/** This function is called by the ARP module when it wants
* to send a packet on the interface. This function outputs
* the pbuf as-is on the link medium. */
err_t (* linkoutput)(struct netif *netif, struct pbuf *p);
netif_linkoutput_fn linkoutput;
#if LWIP_IPV6
/** This function is called by the IPv6 module when it wants
* to send a packet on the interface. This function typically
* first resolves the hardware address, then sends the packet. */
netif_output_ip6_fn output_ip6;
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_STATUS_CALLBACK
/** This function is called when the netif state is set to up or down
*/
void (* status_callback)(struct netif *netif);
netif_status_callback_fn status_callback;
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
/** This function is called when the netif link is set to up or down
*/
void (* link_callback)(struct netif *netif);
netif_status_callback_fn link_callback;
#endif /* LWIP_NETIF_LINK_CALLBACK */
/** This field can be set by the device driver and could point
* to state information for the device. */
@@ -125,16 +208,28 @@ struct netif {
/** the AutoIP client state information for this netif */
struct autoip *autoip;
#endif
#if LWIP_IPV6_AUTOCONFIG
/** is this netif enabled for IPv6 autoconfiguration */
u8_t ip6_autoconfig_enabled;
#endif /* LWIP_IPV6_AUTOCONFIG */
#if LWIP_IPV6_SEND_ROUTER_SOLICIT
/** Number of Router Solicitation messages that remain to be sent. */
u8_t rs_count;
#endif /* LWIP_IPV6_SEND_ROUTER_SOLICIT */
#if LWIP_IPV6_DHCP6
/** the DHCPv6 client state information for this netif */
struct dhcp6 *dhcp6;
#endif /* LWIP_IPV6_DHCP6 */
#if LWIP_NETIF_HOSTNAME
/* the hostname for this netif, NULL is a valid value */
char* hostname;
#endif /* LWIP_NETIF_HOSTNAME */
/** maximum transfer unit (in bytes) */
u16_t mtu;
/** number of bytes used in hwaddr */
u8_t hwaddr_len;
/** link level hardware address of this interface */
u8_t hwaddr[NETIF_MAX_HWADDR_LEN];
/** maximum transfer unit (in bytes) */
u16_t mtu;
/** flags (see NETIF_FLAG_ above) */
u8_t flags;
/** descriptive abbreviation */
@@ -159,29 +254,43 @@ struct netif {
u32_t ifoutdiscards;
#endif /* LWIP_SNMP */
#if LWIP_IGMP
/* This function could be called to add or delete a entry in the multicast filter table of the ethernet MAC.*/
err_t (*igmp_mac_filter)( struct netif *netif, struct ip_addr *group, u8_t action);
/** This function could be called to add or delete an entry in the multicast
filter table of the ethernet MAC.*/
netif_igmp_mac_filter_fn igmp_mac_filter;
#endif /* LWIP_IGMP */
#if LWIP_IPV6 && LWIP_IPV6_MLD
/** This function could be called to add or delete an entry in the IPv6 multicast
filter table of the ethernet MAC. */
netif_mld_mac_filter_fn mld_mac_filter;
#endif /* LWIP_IPV6 && LWIP_IPV6_MLD */
#if LWIP_NETIF_HWADDRHINT
u8_t *addr_hint;
#endif /* LWIP_NETIF_HWADDRHINT */
#if ENABLE_LOOPBACK
/* List of packets to be queued for ourselves. */
struct pbuf *loop_first;
struct pbuf *loop_last;
#if LWIP_LOOPBACK_MAX_PBUFS
u16_t loop_cnt_current;
#endif /* LWIP_LOOPBACK_MAX_PBUFS */
#endif /* ENABLE_LOOPBACK */
};
#if LWIP_SNMP
#define NETIF_INIT_SNMP(netif, type, speed) \
/* use "snmp_ifType" enum from snmp.h for "type", snmp_ifType_ethernet_csmacd by example */ \
netif->link_type = type; \
(netif)->link_type = (type); \
/* your link speed here (units: bits per second) */ \
netif->link_speed = speed; \
netif->ts = 0; \
netif->ifinoctets = 0; \
netif->ifinucastpkts = 0; \
netif->ifinnucastpkts = 0; \
netif->ifindiscards = 0; \
netif->ifoutoctets = 0; \
netif->ifoutucastpkts = 0; \
netif->ifoutnucastpkts = 0; \
netif->ifoutdiscards = 0
(netif)->link_speed = (speed); \
(netif)->ts = 0; \
(netif)->ifinoctets = 0; \
(netif)->ifinucastpkts = 0; \
(netif)->ifinnucastpkts = 0; \
(netif)->ifindiscards = 0; \
(netif)->ifoutoctets = 0; \
(netif)->ifoutucastpkts = 0; \
(netif)->ifoutnucastpkts = 0; \
(netif)->ifoutdiscards = 0
#else /* LWIP_SNMP */
#define NETIF_INIT_SNMP(netif, type, speed)
#endif /* LWIP_SNMP */
@@ -192,17 +301,14 @@ extern struct netif *netif_list;
/** The default network interface. */
extern struct netif *netif_default;
#define netif_init() /* Compatibility define, not init needed. */
void netif_init(void);
struct netif *netif_add(struct netif *netif, struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif));
struct netif *netif_add(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw, void *state, netif_init_fn init, netif_input_fn input);
void
netif_set_addr(struct netif *netif,struct ip_addr *ipaddr, struct ip_addr *netmask,
struct ip_addr *gw);
netif_set_addr(struct netif *netif, ip_addr_t *ipaddr, ip_addr_t *netmask,
ip_addr_t *gw);
void netif_remove(struct netif * netif);
/* Returns a network interface given its name. The name is of the form
@@ -213,31 +319,60 @@ struct netif *netif_find(char *name);
void netif_set_default(struct netif *netif);
void netif_set_ipaddr(struct netif *netif, struct ip_addr *ipaddr);
void netif_set_netmask(struct netif *netif, struct ip_addr *netmask);
void netif_set_gw(struct netif *netif, struct ip_addr *gw);
void netif_set_ipaddr(struct netif *netif, ip_addr_t *ipaddr);
void netif_set_netmask(struct netif *netif, ip_addr_t *netmask);
void netif_set_gw(struct netif *netif, ip_addr_t *gw);
void netif_set_up(struct netif *netif);
void netif_set_down(struct netif *netif);
u8_t netif_is_up(struct netif *netif);
/** Ask if an interface is up */
#define netif_is_up(netif) (((netif)->flags & NETIF_FLAG_UP) ? (u8_t)1 : (u8_t)0)
#if LWIP_NETIF_STATUS_CALLBACK
/*
* Set callback to be called when interface is brought up/down
*/
void netif_set_status_callback(struct netif *netif, void (* status_callback)(struct netif *netif));
void netif_set_status_callback(struct netif *netif, netif_status_callback_fn status_callback);
#endif /* LWIP_NETIF_STATUS_CALLBACK */
#if LWIP_NETIF_LINK_CALLBACK
void netif_set_link_up(struct netif *netif);
void netif_set_link_down(struct netif *netif);
u8_t netif_is_link_up(struct netif *netif);
/*
* Set callback to be called when link is brought up/down
*/
void netif_set_link_callback(struct netif *netif, void (* link_callback)(struct netif *netif));
/** Ask if a link is up */
#define netif_is_link_up(netif) (((netif)->flags & NETIF_FLAG_LINK_UP) ? (u8_t)1 : (u8_t)0)
#if LWIP_NETIF_LINK_CALLBACK
void netif_set_link_callback(struct netif *netif, netif_status_callback_fn link_callback);
#endif /* LWIP_NETIF_LINK_CALLBACK */
#if LWIP_NETIF_HOSTNAME
#define netif_set_hostname(netif, name) do { if((netif) != NULL) { (netif)->hostname = name; }}while(0)
#define netif_get_hostname(netif) (((netif) != NULL) ? ((netif)->hostname) : NULL)
#endif /* LWIP_NETIF_HOSTNAME */
#if LWIP_IGMP
#define netif_set_igmp_mac_filter(netif, function) do { if((netif) != NULL) { (netif)->igmp_mac_filter = function; }}while(0)
#define netif_get_igmp_mac_filter(netif) (((netif) != NULL) ? ((netif)->igmp_mac_filter) : NULL)
#endif /* LWIP_IGMP */
#if ENABLE_LOOPBACK
err_t netif_loop_output(struct netif *netif, struct pbuf *p, ip_addr_t *dest_ip);
void netif_poll(struct netif *netif);
#if !LWIP_NETIF_LOOPBACK_MULTITHREADING
void netif_poll_all(void);
#endif /* !LWIP_NETIF_LOOPBACK_MULTITHREADING */
#endif /* ENABLE_LOOPBACK */
#if LWIP_IPV6
#define netif_ip6_addr(netif, i) (&(netif->ip6_addr[(i)]))
#define netif_ip6_addr_state(netif, i) (netif->ip6_addr_state[(i)])
#define netif_ip6_addr_set_state(netif, i, state) (netif->ip6_addr_state[(i)] = (state))
s8_t netif_matches_ip6_addr(struct netif * netif, ip6_addr_t * ip6addr);
void netif_create_ip6_linklocal_address(struct netif * netif, u8_t from_mac_48bit);
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_HWADDRHINT
#define NETIF_SET_HWADDRHINT(netif, hint) ((netif)->addr_hint = (hint))
#else /* LWIP_NETIF_HWADDRHINT */
#define NETIF_SET_HWADDRHINT(netif, hint)
#endif /* LWIP_NETIF_HWADDRHINT */
#ifdef __cplusplus
}
#endif

View File

@@ -41,6 +41,9 @@
extern "C" {
#endif
typedef void (*netifapi_void_fn)(struct netif *netif);
typedef err_t (*netifapi_errt_fn)(struct netif *netif);
struct netifapi_msg_msg {
#if !LWIP_TCPIP_CORE_LOCKING
sys_sem_t sem;
@@ -49,16 +52,16 @@ struct netifapi_msg_msg {
struct netif *netif;
union {
struct {
struct ip_addr *ipaddr;
struct ip_addr *netmask;
struct ip_addr *gw;
ip_addr_t *ipaddr;
ip_addr_t *netmask;
ip_addr_t *gw;
void *state;
err_t (* init) (struct netif *netif);
err_t (* input)(struct pbuf *p, struct netif *netif);
netif_init_fn init;
netif_input_fn input;
} add;
struct {
void (* voidfunc)(struct netif *netif);
err_t (* errtfunc)(struct netif *netif);
netifapi_void_fn voidfunc;
netifapi_errt_fn errtfunc;
} common;
} msg;
};
@@ -71,16 +74,21 @@ struct netifapi_msg {
/* API for application */
err_t netifapi_netif_add ( struct netif *netif,
struct ip_addr *ipaddr,
struct ip_addr *netmask,
struct ip_addr *gw,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw,
void *state,
err_t (* init)(struct netif *netif),
err_t (* input)(struct pbuf *p, struct netif *netif) );
netif_init_fn init,
netif_input_fn input);
err_t netifapi_netif_set_addr ( struct netif *netif,
ip_addr_t *ipaddr,
ip_addr_t *netmask,
ip_addr_t *gw );
err_t netifapi_netif_common ( struct netif *netif,
void (* voidfunc)(struct netif *netif),
err_t (* errtfunc)(struct netif *netif) );
netifapi_void_fn voidfunc,
netifapi_errt_fn errtfunc);
#define netifapi_netif_remove(n) netifapi_netif_common(n, netif_remove, NULL)
#define netifapi_netif_set_up(n) netifapi_netif_common(n, netif_set_up, NULL)

File diff suppressed because it is too large Load Diff

View File

@@ -40,8 +40,19 @@
extern "C" {
#endif
/** Currently, the pbuf_custom code is only needed for one specific configuration
* of IP_FRAG */
#define LWIP_SUPPORT_CUSTOM_PBUF (IP_FRAG && !IP_FRAG_USES_STATIC_BUF && !LWIP_NETIF_TX_SINGLE_PBUF)
/* @todo: We need a mechanism to prevent wasting memory in every pbuf
(TCP vs. UDP, IPv4 vs. IPv6: UDP/IPv4 packets may waste up to 28 bytes) */
#define PBUF_TRANSPORT_HLEN 20
#if LWIP_IPV6
#define PBUF_IP_HLEN 40
#else
#define PBUF_IP_HLEN 20
#endif
typedef enum {
PBUF_TRANSPORT,
@@ -59,7 +70,12 @@ typedef enum {
/** indicates this packet's data should be immediately passed to the application */
#define PBUF_FLAG_PUSH 0x01U
#define PBUF_FLAG_PUSH 0x01U
/** indicates this is a custom pbuf: pbuf_free and pbuf_header handle such a
a pbuf differently */
#define PBUF_FLAG_IS_CUSTOM 0x02U
/** indicates this pbuf is UDP multicast to be looped back */
#define PBUF_FLAG_MCASTLOOP 0x04U
struct pbuf {
/** next pbuf in singly linked pbuf chain */
@@ -67,7 +83,7 @@ struct pbuf {
/** pointer to the actual data in the buffer */
void *payload;
/**
* total length of this buffer and all next buffers in chain
* belonging to the same packet.
@@ -76,9 +92,9 @@ struct pbuf {
* p->tot_len == p->len + (p->next? p->next->tot_len: 0)
*/
u16_t tot_len;
/** length of this buffer */
u16_t len;
u16_t len;
/** pbuf_type as u8_t instead of enum to save space */
u8_t /*pbuf_type*/ type;
@@ -92,17 +108,33 @@ struct pbuf {
* the stack itself, or pbuf->next pointers from a chain.
*/
u16_t ref;
};
#if LWIP_SUPPORT_CUSTOM_PBUF
/** Prototype for a function to free a custom pbuf */
typedef void (*pbuf_free_custom_fn)(struct pbuf *p);
/** A custom pbuf: like a pbuf, but following a function pointer to free it. */
struct pbuf_custom {
/** The actual pbuf */
struct pbuf pbuf;
/** This function is called when pbuf_free deallocates this pbuf(_custom) */
pbuf_free_custom_fn custom_free_function;
};
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
/* Initializes the pbuf module. This call is empty for now, but may not be in future. */
#define pbuf_init()
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t size, pbuf_type type);
struct pbuf *pbuf_alloc(pbuf_layer l, u16_t length, pbuf_type type);
#if LWIP_SUPPORT_CUSTOM_PBUF
struct pbuf *pbuf_alloced_custom(pbuf_layer l, u16_t length, pbuf_type type,
struct pbuf_custom *p, void *payload_mem,
u16_t payload_mem_len);
#endif /* LWIP_SUPPORT_CUSTOM_PBUF */
void pbuf_realloc(struct pbuf *p, u16_t size);
u8_t pbuf_header(struct pbuf *p, s16_t header_size);
void pbuf_ref(struct pbuf *p);
void pbuf_ref_chain(struct pbuf *p);
u8_t pbuf_free(struct pbuf *p);
u8_t pbuf_clen(struct pbuf *p);
void pbuf_cat(struct pbuf *head, struct pbuf *tail);
@@ -110,6 +142,17 @@ void pbuf_chain(struct pbuf *head, struct pbuf *tail);
struct pbuf *pbuf_dechain(struct pbuf *p);
err_t pbuf_copy(struct pbuf *p_to, struct pbuf *p_from);
u16_t pbuf_copy_partial(struct pbuf *p, void *dataptr, u16_t len, u16_t offset);
err_t pbuf_take(struct pbuf *buf, const void *dataptr, u16_t len);
struct pbuf *pbuf_coalesce(struct pbuf *p, pbuf_layer layer);
#if LWIP_CHECKSUM_ON_COPY
err_t pbuf_fill_chksum(struct pbuf *p, u16_t start_offset, const void *dataptr,
u16_t len, u16_t *chksum);
#endif /* LWIP_CHECKSUM_ON_COPY */
u8_t pbuf_get_at(struct pbuf* p, u16_t offset);
u16_t pbuf_memcmp(struct pbuf* p, u16_t offset, const void* s2, u16_t n);
u16_t pbuf_memfind(struct pbuf* p, const void* mem, u16_t mem_len, u16_t start_offset);
u16_t pbuf_strstr(struct pbuf* p, const char* substr);
#ifdef __cplusplus
}

View File

@@ -37,34 +37,64 @@
#if LWIP_RAW /* don't build if not configured for use in lwipopts.h */
#include "lwip/pbuf.h"
#include "lwip/inet.h"
#include "lwip/def.h"
#include "lwip/ip.h"
#include "lwip/ip_addr.h"
#include "lwip/ip6_addr.h"
#ifdef __cplusplus
extern "C" {
#endif
struct raw_pcb;
/** Function prototype for raw pcb receive callback functions.
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
typedef u8_t (*raw_recv_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ip_addr_t *addr);
#if LWIP_IPV6
/** Function prototype for raw pcb IPv6 receive callback functions.
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IPv6 address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
typedef u8_t (*raw_recv_ip6_fn)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
ip6_addr_t *addr);
#endif /* LWIP_IPV6 */
#if LWIP_IPV6
#define RAW_PCB_RECV_IP6 raw_recv_ip6_fn ip6;
#else
#define RAW_PCB_RECV_IP6
#endif /* LWIP_IPV6 */
struct raw_pcb {
/* Common members of all PCB types */
/* Common members of all PCB types */
IP_PCB;
struct raw_pcb *next;
u8_t protocol;
/* receive callback function
* @param arg user supplied argument (raw_pcb.recv_arg)
* @param pcb the raw_pcb which received data
* @param p the packet buffer that was received
* @param addr the remote IP address from which the packet was received
* @return 1 if the packet was 'eaten' (aka. deleted),
* 0 if the packet lives on
* If returning 1, the callback is responsible for freeing the pbuf
* if it's not used any more.
*/
u8_t (* recv)(void *arg, struct raw_pcb *pcb, struct pbuf *p,
struct ip_addr *addr);
/** receive callback function */
union {
raw_recv_fn ip4;
RAW_PCB_RECV_IP6
} recv;
/* user-supplied argument for the recv callback */
void *recv_arg;
};
@@ -73,17 +103,21 @@ struct raw_pcb {
RAW code. */
struct raw_pcb * raw_new (u8_t proto);
void raw_remove (struct raw_pcb *pcb);
err_t raw_bind (struct raw_pcb *pcb, struct ip_addr *ipaddr);
err_t raw_connect (struct raw_pcb *pcb, struct ip_addr *ipaddr);
err_t raw_bind (struct raw_pcb *pcb, ip_addr_t *ipaddr);
err_t raw_connect (struct raw_pcb *pcb, ip_addr_t *ipaddr);
void raw_recv (struct raw_pcb *pcb,
u8_t (* recv)(void *arg, struct raw_pcb *pcb,
struct pbuf *p,
struct ip_addr *addr),
void *recv_arg);
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, struct ip_addr *ipaddr);
void raw_recv (struct raw_pcb *pcb, raw_recv_fn recv, void *recv_arg);
err_t raw_sendto (struct raw_pcb *pcb, struct pbuf *p, ip_addr_t *ipaddr);
err_t raw_send (struct raw_pcb *pcb, struct pbuf *p);
#if LWIP_IPV6
struct raw_pcb * raw_new_ip6 (u8_t proto);
#define raw_bind_ip6(pcb, ip6addr) raw_bind(pcb, ip6_2_ip(ip6addr))
#define raw_connect_ip6(pcb, ip6addr) raw_connect(pcb, ip6_2_ip(ip6addr))
#define raw_recv_ip6(pcb, recv_ip6_fn, recv_arg) raw_recv(pcb, (raw_recv_fn)recv_ip6_fn, recv_arg)
#define raw_sendto_ip6(pcb, pbuf, ip6addr) raw_sendto(pcb, pbuf, ip6_2_ip(ip6addr))
#endif /* LWIP_IPV6 */
/* The following functions are the lower layer interface to RAW. */
u8_t raw_input (struct pbuf *p, struct netif *inp);
#define raw_init() /* Compatibility define, not init needed. */

View File

@@ -32,40 +32,110 @@
* It needs to be implemented by those platforms which need SLIP or PPP
*/
#ifndef __SIO_H__
#define __SIO_H__
#include "lwip/arch.h"
#ifdef __cplusplus
extern "C" {
#endif
/* If you want to define sio_fd_t elsewhere or differently,
define this in your cc.h file. */
#ifndef __sio_fd_t_defined
typedef void * sio_fd_t;
#endif
/* The following functions can be defined to something else in your cc.h file
or be implemented in your custom sio.c file. */
#ifndef sio_open
sio_fd_t sio_open(u8_t);
/**
* Opens a serial device for communication.
*
* @param devnum device number
* @return handle to serial device if successful, NULL otherwise
*/
sio_fd_t sio_open(u8_t devnum);
#endif
#ifndef sio_send
void sio_send(u8_t, sio_fd_t);
/**
* Sends a single character to the serial device.
*
* @param c character to send
* @param fd serial device handle
*
* @note This function will block until the character can be sent.
*/
void sio_send(u8_t c, sio_fd_t fd);
#endif
#ifndef sio_recv
u8_t sio_recv(sio_fd_t);
/**
* Receives a single character from the serial device.
*
* @param fd serial device handle
*
* @note This function will block until a character is received.
*/
u8_t sio_recv(sio_fd_t fd);
#endif
#ifndef sio_read
u32_t sio_read(sio_fd_t, u8_t *, u32_t);
/**
* Reads from the serial device.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received - may be 0 if aborted by sio_read_abort
*
* @note This function will block until data can be received. The blocking
* can be cancelled by calling sio_read_abort().
*/
u32_t sio_read(sio_fd_t fd, u8_t *data, u32_t len);
#endif
#ifndef sio_tryread
/**
* Tries to read from the serial device. Same as sio_read but returns
* immediately if no data is available and never blocks.
*
* @param fd serial device handle
* @param data pointer to data buffer for receiving
* @param len maximum length (in bytes) of data to receive
* @return number of bytes actually received
*/
u32_t sio_tryread(sio_fd_t fd, u8_t *data, u32_t len);
#endif
#ifndef sio_write
u32_t sio_write(sio_fd_t, u8_t *, u32_t);
/**
* Writes to the serial device.
*
* @param fd serial device handle
* @param data pointer to data to send
* @param len length (in bytes) of data to send
* @return number of bytes actually sent
*
* @note This function will block until all data can be sent.
*/
u32_t sio_write(sio_fd_t fd, u8_t *data, u32_t len);
#endif
#ifndef sio_read_abort
void sio_read_abort(sio_fd_t);
/**
* Aborts a blocking sio_read() call.
*
* @param fd serial device handle
*/
void sio_read_abort(sio_fd_t fd);
#endif
#ifdef __cplusplus
}
#endif
#endif /* __SIO_H__ */

View File

@@ -34,13 +34,16 @@
#define __LWIP_SNMP_H__
#include "lwip/opt.h"
#include "lwip/netif.h"
#include "lwip/udp.h"
#ifdef __cplusplus
extern "C" {
#endif
#include "lwip/ip_addr.h"
struct udp_pcb;
struct netif;
/**
* @see RFC1213, "MIB-II, 6. Definitions"
*/
@@ -118,8 +121,8 @@ void snmp_inc_iflist(void);
void snmp_dec_iflist(void);
/* ARP (for atTable and ipNetToMediaTable) */
void snmp_insert_arpidx_tree(struct netif *ni, struct ip_addr *ip);
void snmp_delete_arpidx_tree(struct netif *ni, struct ip_addr *ip);
void snmp_insert_arpidx_tree(struct netif *ni, ip_addr_t *ip);
void snmp_delete_arpidx_tree(struct netif *ni, ip_addr_t *ip);
/* IP */
void snmp_inc_ipinreceives(void);

View File

@@ -40,16 +40,18 @@
#include "lwip/pbuf.h"
#include "lwip/snmp.h"
#if LWIP_SNMP
#ifdef __cplusplus
extern "C" {
#endif
#define SNMP_ASN1_UNIV (!0x80 | !0x40)
#define SNMP_ASN1_APPLIC (!0x80 | 0x40)
#define SNMP_ASN1_CONTXT ( 0x80 | !0x40)
#define SNMP_ASN1_UNIV (0) /* (!0x80 | !0x40) */
#define SNMP_ASN1_APPLIC (0x40) /* (!0x80 | 0x40) */
#define SNMP_ASN1_CONTXT (0x80) /* ( 0x80 | !0x40) */
#define SNMP_ASN1_CONSTR (0x20)
#define SNMP_ASN1_PRIMIT (!0x20)
#define SNMP_ASN1_CONSTR (0x20) /* ( 0x20) */
#define SNMP_ASN1_PRIMIT (0) /* (!0x20) */
/* universal tags */
#define SNMP_ASN1_INTEG 2
@@ -85,13 +87,15 @@ void snmp_asn1_enc_s32t_cnt(s32_t value, u16_t *octets_needed);
void snmp_asn1_enc_oid_cnt(u8_t ident_len, s32_t *ident, u16_t *octets_needed);
err_t snmp_asn1_enc_type(struct pbuf *p, u16_t ofs, u8_t type);
err_t snmp_asn1_enc_length(struct pbuf *p, u16_t ofs, u16_t length);
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u8_t octets_needed, s32_t value);
err_t snmp_asn1_enc_u32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, u32_t value);
err_t snmp_asn1_enc_s32t(struct pbuf *p, u16_t ofs, u16_t octets_needed, s32_t value);
err_t snmp_asn1_enc_oid(struct pbuf *p, u16_t ofs, u8_t ident_len, s32_t *ident);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u8_t raw_len, u8_t *raw);
err_t snmp_asn1_enc_raw(struct pbuf *p, u16_t ofs, u16_t raw_len, u8_t *raw);
#ifdef __cplusplus
}
#endif
#endif /* LWIP_SNMP */
#endif /* __LWIP_SNMP_ASN1_H__ */

View File

@@ -38,8 +38,14 @@
#include "lwip/opt.h"
#include "lwip/snmp.h"
#include "lwip/snmp_structs.h"
#include "lwip/ip_addr.h"
#include "lwip/err.h"
#if LWIP_SNMP
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
@@ -217,7 +223,7 @@ struct snmp_msg_pstat
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* source IP address */
struct ip_addr sip;
ip_addr_t sip;
/* source UDP port */
u16_t sp;
/* request type */
@@ -256,7 +262,7 @@ struct snmp_msg_trap
/* lwIP local port (161) binding */
struct udp_pcb *pcb;
/* destination IP address in network order */
struct ip_addr dip;
ip_addr_t dip;
/* source enterprise ID (sysObjectID) */
struct snmp_obj_id *enterprise;
@@ -284,7 +290,7 @@ extern struct snmp_msg_trap trap_msg;
/** Agent setup, start listening to port 161. */
void snmp_init(void);
void snmp_trap_dst_enable(u8_t dst_idx, u8_t enable);
void snmp_trap_dst_ip_set(u8_t dst_idx, struct ip_addr *dst);
void snmp_trap_dst_ip_set(u8_t dst_idx, ip_addr_t *dst);
/** Varbind-list functions. */
struct snmp_varbind* snmp_varbind_alloc(struct snmp_obj_id *oid, u8_t type, u8_t len);
@@ -304,4 +310,6 @@ void snmp_authfail_trap(void);
}
#endif
#endif /* LWIP_SNMP */
#endif /* __LWIP_SNMP_MSG_H__ */

View File

@@ -44,6 +44,8 @@
#include "lwip/snmp.h"
#if SNMP_PRIVATE_MIB
/* When using a private MIB, you have to create a file 'private_mib.h' that contains
* a 'struct mib_array_node mib_private' which contains your MIB. */
#include "private_mib.h"
#endif
@@ -56,11 +58,15 @@ extern "C" {
#define MIB_OBJECT_SCALAR 1
#define MIB_OBJECT_TAB 2
/* MIB access types */
#define MIB_ACCESS_READ 1
#define MIB_ACCESS_WRITE 2
/* MIB object access */
#define MIB_OBJECT_READ_ONLY 0
#define MIB_OBJECT_READ_WRITE 1
#define MIB_OBJECT_WRITE_ONLY 2
#define MIB_OBJECT_NOT_ACCESSIBLE 3
#define MIB_OBJECT_READ_ONLY MIB_ACCESS_READ
#define MIB_OBJECT_READ_WRITE (MIB_ACCESS_READ | MIB_ACCESS_WRITE)
#define MIB_OBJECT_WRITE_ONLY MIB_ACCESS_WRITE
#define MIB_OBJECT_NOT_ACCESSIBLE 0
/** object definition returned by (get_object_def)() */
struct obj_def
@@ -109,9 +115,9 @@ struct mib_node
/** sets object value, only to be called when set_test() */
void (*set_value)(struct obj_def *od, u16_t len, void *value);
/** One out of MIB_NODE_AR, MIB_NODE_LR or MIB_NODE_EX */
const u8_t node_type;
u8_t node_type;
/* array or max list length */
const u16_t maxlength;
u16_t maxlength;
};
/** derived node for scalars .0 index */
@@ -122,15 +128,15 @@ typedef struct mib_node mib_scalar_node;
struct mib_array_node
{
/* inherited "base class" members */
void (* const get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (* const get_value)(struct obj_def *od, u16_t len, void *value);
void (*get_object_def)(u8_t ident_len, s32_t *ident, struct obj_def *od);
void (*get_value)(struct obj_def *od, u16_t len, void *value);
u8_t (*set_test)(struct obj_def *od, u16_t len, void *value);
void (*set_value)(struct obj_def *od, u16_t len, void *value);
const u8_t node_type;
const u16_t maxlength;
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/* additional struct members */
const s32_t *objid;
struct mib_node* const *nptr;
};
@@ -174,7 +180,7 @@ struct mib_list_rootnode
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/* additional struct members */
struct mib_list_node *head;
struct mib_list_node *tail;
/* counts list nodes in list */
@@ -194,8 +200,8 @@ struct mib_external_node
u8_t node_type;
u16_t maxlength;
/* aditional struct members */
/** points to an extenal (in memory) record of some sort of addressing
/* additional struct members */
/** points to an external (in memory) record of some sort of addressing
information, passed to and interpreted by the funtions below */
void* addr_inf;
/** tree levels under this node */
@@ -234,8 +240,8 @@ void noleafs_get_value(struct obj_def *od, u16_t len, void *value);
u8_t noleafs_set_test(struct obj_def *od, u16_t len, void *value);
void noleafs_set_value(struct obj_def *od, u16_t len, void *value);
void snmp_oidtoip(s32_t *ident, struct ip_addr *ip);
void snmp_iptooid(struct ip_addr *ip, s32_t *ident);
void snmp_oidtoip(s32_t *ident, ip_addr_t *ip);
void snmp_iptooid(ip_addr_t *ip, s32_t *ident);
void snmp_ifindextonetif(s32_t ifindex, struct netif **netif);
void snmp_netiftoifindex(struct netif *netif, s32_t *ifidx);

Some files were not shown because too many files have changed in this diff Show More